wps-ap-nfc.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #!/usr/bin/python
  2. #
  3. # Example nfcpy to hostapd wrapper for WPS NFC operations
  4. # Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
  5. #
  6. # This software may be distributed under the terms of the BSD license.
  7. # See README for more details.
  8. import os
  9. import sys
  10. import time
  11. import nfc
  12. import nfc.ndef
  13. import nfc.llcp
  14. import nfc.handover
  15. import logging
  16. logging.basicConfig()
  17. import wpaspy
  18. wpas_ctrl = '/var/run/hostapd'
  19. def wpas_connect():
  20. ifaces = []
  21. if os.path.isdir(wpas_ctrl):
  22. try:
  23. ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
  24. except OSError, error:
  25. print "Could not find hostapd: ", error
  26. return None
  27. if len(ifaces) < 1:
  28. print "No hostapd control interface found"
  29. return None
  30. for ctrl in ifaces:
  31. try:
  32. wpas = wpaspy.Ctrl(ctrl)
  33. return wpas
  34. except Exception, e:
  35. pass
  36. return None
  37. def wpas_tag_read(message):
  38. wpas = wpas_connect()
  39. if (wpas == None):
  40. return
  41. print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
  42. def wpas_get_config_token():
  43. wpas = wpas_connect()
  44. if (wpas == None):
  45. return None
  46. return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
  47. def wpas_get_password_token():
  48. wpas = wpas_connect()
  49. if (wpas == None):
  50. return None
  51. return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
  52. def wpas_get_handover_sel():
  53. wpas = wpas_connect()
  54. if (wpas == None):
  55. return None
  56. return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
  57. def wpas_report_handover(req, sel):
  58. wpas = wpas_connect()
  59. if (wpas == None):
  60. return None
  61. return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
  62. str(req).encode("hex") + " " +
  63. str(sel).encode("hex"))
  64. class HandoverServer(nfc.handover.HandoverServer):
  65. def __init__(self):
  66. super(HandoverServer, self).__init__()
  67. def process_request(self, request):
  68. print "HandoverServer - request received"
  69. print "Parsed handover request: " + request.pretty()
  70. sel = nfc.ndef.HandoverSelectMessage(version="1.2")
  71. for carrier in request.carriers:
  72. print "Remote carrier type: " + carrier.type
  73. if carrier.type == "application/vnd.wfa.wsc":
  74. print "WPS carrier type match - add WPS carrier record"
  75. self.received_carrier = carrier.record
  76. data = wpas_get_handover_sel()
  77. if data is None:
  78. print "Could not get handover select carrier record from hostapd"
  79. continue
  80. print "Handover select carrier record from hostapd:"
  81. print data.encode("hex")
  82. self.sent_carrier = data
  83. message = nfc.ndef.Message(data);
  84. sel.add_carrier(message[0], "active", message[1:])
  85. print "Handover select:"
  86. print sel.pretty()
  87. print str(sel).encode("hex")
  88. print "Sending handover select"
  89. return sel
  90. def wps_handover_resp(peer):
  91. print "Trying to handle WPS handover"
  92. srv = HandoverServer()
  93. srv.sent_carrier = None
  94. nfc.llcp.activate(peer);
  95. try:
  96. print "Trying handover";
  97. srv.start()
  98. print "Wait for disconnect"
  99. while nfc.llcp.connected():
  100. time.sleep(0.1)
  101. print "Disconnected after handover"
  102. except nfc.llcp.ConnectRefused:
  103. print "Handover connection refused"
  104. nfc.llcp.shutdown()
  105. return
  106. if srv.sent_carrier:
  107. wpas_report_handover(srv.received_carrier, srv.sent_carrier)
  108. print "Remove peer"
  109. nfc.llcp.shutdown()
  110. print "Done with handover"
  111. def wps_tag_read(tag):
  112. if len(tag.ndef.message):
  113. message = nfc.ndef.Message(tag.ndef.message)
  114. print "message type " + message.type
  115. for record in message:
  116. print "record type " + record.type
  117. if record.type == "application/vnd.wfa.wsc":
  118. print "WPS tag - send to hostapd"
  119. wpas_tag_read(tag.ndef.message)
  120. break
  121. else:
  122. print "Empty tag"
  123. print "Remove tag"
  124. while tag.is_present:
  125. time.sleep(0.1)
  126. def wps_write_config_tag(clf):
  127. print "Write WPS config token"
  128. data = wpas_get_config_token()
  129. if (data == None):
  130. print "Could not get WPS config token from hostapd"
  131. return
  132. print "Touch an NFC tag"
  133. while True:
  134. tag = clf.poll()
  135. if tag == None:
  136. time.sleep(0.1)
  137. continue
  138. break
  139. print "Tag found - writing"
  140. tag.ndef.message = data
  141. print "Done - remove tag"
  142. while tag.is_present:
  143. time.sleep(0.1)
  144. def wps_write_password_tag(clf):
  145. print "Write WPS password token"
  146. data = wpas_get_password_token()
  147. if (data == None):
  148. print "Could not get WPS password token from hostapd"
  149. return
  150. print "Touch an NFC tag"
  151. while True:
  152. tag = clf.poll()
  153. if tag == None:
  154. time.sleep(0.1)
  155. continue
  156. break
  157. print "Tag found - writing"
  158. tag.ndef.message = data
  159. print "Done - remove tag"
  160. while tag.is_present:
  161. time.sleep(0.1)
  162. def find_peer(clf):
  163. while True:
  164. if nfc.llcp.connected():
  165. print "LLCP connected"
  166. general_bytes = nfc.llcp.startup({})
  167. peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
  168. if isinstance(peer, nfc.DEP):
  169. print "listen -> DEP";
  170. if peer.general_bytes.startswith("Ffm"):
  171. print "Found DEP"
  172. return peer
  173. print "mismatch in general_bytes"
  174. print peer.general_bytes
  175. peer = clf.poll(general_bytes)
  176. if isinstance(peer, nfc.DEP):
  177. print "poll -> DEP";
  178. if peer.general_bytes.startswith("Ffm"):
  179. print "Found DEP"
  180. return peer
  181. print "mismatch in general_bytes"
  182. print peer.general_bytes
  183. if peer:
  184. print "Found tag"
  185. return peer
  186. def main():
  187. clf = nfc.ContactlessFrontend()
  188. try:
  189. if len(sys.argv) > 1 and sys.argv[1] == "write-config":
  190. wps_write_config_tag(clf)
  191. raise SystemExit
  192. if len(sys.argv) > 1 and sys.argv[1] == "write-password":
  193. wps_write_password_tag(clf)
  194. raise SystemExit
  195. while True:
  196. print "Waiting for a tag or peer to be touched"
  197. tag = find_peer(clf)
  198. if isinstance(tag, nfc.DEP):
  199. wps_handover_resp(tag)
  200. continue
  201. if tag.ndef:
  202. wps_tag_read(tag)
  203. continue
  204. print "Not an NDEF tag - remove tag"
  205. while tag.is_present:
  206. time.sleep(0.1)
  207. except KeyboardInterrupt:
  208. raise SystemExit
  209. finally:
  210. clf.close()
  211. raise SystemExit
  212. if __name__ == '__main__':
  213. main()