wps-ap-nfc.py 7.0 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 wpactrl
  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 = wpactrl.WPACtrl(ctrl)
  33. return wpas
  34. except wpactrl.error, error:
  35. print "Error: ", error
  36. pass
  37. return None
  38. def wpas_tag_read(message):
  39. wpas = wpas_connect()
  40. if (wpas == None):
  41. return
  42. print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
  43. def wpas_get_config_token():
  44. wpas = wpas_connect()
  45. if (wpas == None):
  46. return None
  47. return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
  48. def wpas_get_password_token():
  49. wpas = wpas_connect()
  50. if (wpas == None):
  51. return None
  52. return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
  53. def wpas_get_handover_sel():
  54. wpas = wpas_connect()
  55. if (wpas == None):
  56. return None
  57. return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
  58. def wpas_report_handover(req, sel):
  59. wpas = wpas_connect()
  60. if (wpas == None):
  61. return None
  62. return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
  63. str(req).encode("hex") + " " +
  64. str(sel).encode("hex"))
  65. class HandoverServer(nfc.handover.HandoverServer):
  66. def __init__(self):
  67. super(HandoverServer, self).__init__()
  68. def process_request(self, request):
  69. print "HandoverServer - request received"
  70. print "Parsed handover request: " + request.pretty()
  71. sel = nfc.ndef.HandoverSelectMessage(version="1.2")
  72. for carrier in request.carriers:
  73. print "Remote carrier type: " + carrier.type
  74. if carrier.type == "application/vnd.wfa.wsc":
  75. print "WPS carrier type match - add WPS carrier record"
  76. self.received_carrier = carrier.record
  77. data = wpas_get_handover_sel()
  78. if data is None:
  79. print "Could not get handover select carrier record from hostapd"
  80. continue
  81. print "Handover select carrier record from hostapd:"
  82. print data.encode("hex")
  83. self.sent_carrier = data
  84. message = nfc.ndef.Message(data);
  85. sel.add_carrier(message[0], "active", message[1:])
  86. print "Handover select:"
  87. print sel.pretty()
  88. print str(sel).encode("hex")
  89. print "Sending handover select"
  90. return sel
  91. def wps_handover_resp(peer):
  92. print "Trying to handle WPS handover"
  93. srv = HandoverServer()
  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()