wps-nfc.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #!/usr/bin/python
  2. #
  3. # Example nfcpy to wpa_supplicant 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 random
  12. import StringIO
  13. import nfc
  14. import nfc.ndef
  15. import nfc.llcp
  16. import nfc.handover
  17. import logging
  18. logging.basicConfig()
  19. import wpactrl
  20. wpas_ctrl = '/var/run/wpa_supplicant'
  21. def wpas_connect():
  22. ifaces = []
  23. if os.path.isdir(wpas_ctrl):
  24. try:
  25. ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
  26. except OSError, error:
  27. print "Could not find wpa_supplicant: ", error
  28. return None
  29. if len(ifaces) < 1:
  30. print "No wpa_supplicant control interface found"
  31. return None
  32. for ctrl in ifaces:
  33. try:
  34. wpas = wpactrl.WPACtrl(ctrl)
  35. return wpas
  36. except wpactrl.error, error:
  37. print "Error: ", error
  38. pass
  39. return None
  40. def wpas_tag_read(message):
  41. wpas = wpas_connect()
  42. if (wpas == None):
  43. return
  44. print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
  45. def wpas_get_config_token():
  46. wpas = wpas_connect()
  47. if (wpas == None):
  48. return None
  49. return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
  50. def wpas_get_er_config_token(uuid):
  51. wpas = wpas_connect()
  52. if (wpas == None):
  53. return None
  54. return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
  55. def wpas_get_password_token():
  56. wpas = wpas_connect()
  57. if (wpas == None):
  58. return None
  59. return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
  60. def wpas_get_handover_req():
  61. wpas = wpas_connect()
  62. if (wpas == None):
  63. return None
  64. return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
  65. def wpas_report_handover(req, sel):
  66. wpas = wpas_connect()
  67. if (wpas == None):
  68. return None
  69. return wpas.request("NFC_REPORT_HANDOVER INIT WPS " +
  70. str(req).encode("hex") + " " +
  71. str(sel).encode("hex"))
  72. def wps_handover_init(peer):
  73. print "Trying to initiate WPS handover"
  74. data = wpas_get_handover_req()
  75. if (data == None):
  76. print "Could not get handover request carrier record from wpa_supplicant"
  77. return
  78. print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
  79. record = nfc.ndef.Record()
  80. f = StringIO.StringIO(data)
  81. record._read(f)
  82. record = nfc.ndef.HandoverCarrierRecord(record)
  83. print "Parsed handover request carrier record:"
  84. print record.pretty()
  85. message = nfc.ndef.HandoverRequestMessage(version="1.2")
  86. message.nonce = random.randint(0, 0xffff)
  87. message.add_carrier(record, "active")
  88. print "Handover request:"
  89. print message.pretty()
  90. nfc.llcp.activate(peer);
  91. client = nfc.handover.HandoverClient()
  92. try:
  93. print "Trying handover";
  94. client.connect()
  95. print "Connected for handover"
  96. except nfc.llcp.ConnectRefused:
  97. print "Handover connection refused"
  98. nfc.llcp.shutdown()
  99. client.close()
  100. return
  101. print "Sending handover request"
  102. if not client.send(message):
  103. print "Failed to send handover request"
  104. print "Receiving handover response"
  105. message = client._recv()
  106. if message is None:
  107. print "No response received"
  108. nfc.llcp.shutdown()
  109. client.close()
  110. return
  111. if message.type != "urn:nfc:wkt:Hs":
  112. print "Response was not Hs - received: " + message.type
  113. nfc.llcp.shutdown()
  114. client.close()
  115. return
  116. print "Received message"
  117. print message.pretty()
  118. message = nfc.ndef.HandoverSelectMessage(message)
  119. print "Handover select received"
  120. print message.pretty()
  121. for carrier in message.carriers:
  122. print "Remote carrier type: " + carrier.type
  123. if carrier.type == "application/vnd.wfa.wsc":
  124. print "WPS carrier type match - send to wpa_supplicant"
  125. wpas_report_handover(data, carrier.record)
  126. wifi = nfc.ndef.WifiConfigRecord(carrier.record)
  127. print wifi.pretty()
  128. print "Remove peer"
  129. nfc.llcp.shutdown()
  130. client.close()
  131. print "Done with handover"
  132. def wps_tag_read(tag):
  133. if len(tag.ndef.message):
  134. message = nfc.ndef.Message(tag.ndef.message)
  135. print "message type " + message.type
  136. for record in message:
  137. print "record type " + record.type
  138. if record.type == "application/vnd.wfa.wsc":
  139. print "WPS tag - send to wpa_supplicant"
  140. wpas_tag_read(tag.ndef.message)
  141. break
  142. else:
  143. print "Empty tag"
  144. print "Remove tag"
  145. while tag.is_present:
  146. time.sleep(0.1)
  147. def wps_write_config_tag(clf):
  148. print "Write WPS config token"
  149. data = wpas_get_config_token()
  150. if (data == None):
  151. print "Could not get WPS config token from wpa_supplicant"
  152. return
  153. print "Touch an NFC tag"
  154. while True:
  155. tag = clf.poll()
  156. if tag == None:
  157. time.sleep(0.1)
  158. continue
  159. break
  160. print "Tag found - writing"
  161. tag.ndef.message = data
  162. print "Done - remove tag"
  163. while tag.is_present:
  164. time.sleep(0.1)
  165. def wps_write_er_config_tag(clf, uuid):
  166. print "Write WPS ER config token"
  167. data = wpas_get_er_config_token(uuid)
  168. if (data == None):
  169. print "Could not get WPS config token from wpa_supplicant"
  170. return
  171. print "Touch an NFC tag"
  172. while True:
  173. tag = clf.poll()
  174. if tag == None:
  175. time.sleep(0.1)
  176. continue
  177. break
  178. print "Tag found - writing"
  179. tag.ndef.message = data
  180. print "Done - remove tag"
  181. while tag.is_present:
  182. time.sleep(0.1)
  183. def wps_write_password_tag(clf):
  184. print "Write WPS password token"
  185. data = wpas_get_password_token()
  186. if (data == None):
  187. print "Could not get WPS password token from wpa_supplicant"
  188. return
  189. print "Touch an NFC tag"
  190. while True:
  191. tag = clf.poll()
  192. if tag == None:
  193. time.sleep(0.1)
  194. continue
  195. break
  196. print "Tag found - writing"
  197. tag.ndef.message = data
  198. print "Done - remove tag"
  199. while tag.is_present:
  200. time.sleep(0.1)
  201. def find_peer(clf):
  202. while True:
  203. if nfc.llcp.connected():
  204. print "LLCP connected"
  205. general_bytes = nfc.llcp.startup({})
  206. peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
  207. if isinstance(peer, nfc.DEP):
  208. print "listen -> DEP";
  209. if peer.general_bytes.startswith("Ffm"):
  210. print "Found DEP"
  211. return peer
  212. print "mismatch in general_bytes"
  213. print peer.general_bytes
  214. peer = clf.poll(general_bytes)
  215. if isinstance(peer, nfc.DEP):
  216. print "poll -> DEP";
  217. if peer.general_bytes.startswith("Ffm"):
  218. print "Found DEP"
  219. return peer
  220. print "mismatch in general_bytes"
  221. print peer.general_bytes
  222. if peer:
  223. print "Found tag"
  224. return peer
  225. def main():
  226. clf = nfc.ContactlessFrontend()
  227. try:
  228. if len(sys.argv) > 1 and sys.argv[1] == "write-config":
  229. wps_write_config_tag(clf)
  230. raise SystemExit
  231. if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
  232. wps_write_er_config_tag(clf, sys.argv[2])
  233. raise SystemExit
  234. if len(sys.argv) > 1 and sys.argv[1] == "write-password":
  235. wps_write_password_tag(clf)
  236. raise SystemExit
  237. while True:
  238. print "Waiting for a tag or peer to be touched"
  239. tag = find_peer(clf)
  240. if isinstance(tag, nfc.DEP):
  241. wps_handover_init(tag)
  242. continue
  243. if tag.ndef:
  244. wps_tag_read(tag)
  245. continue
  246. print "Not an NDEF tag - remove tag"
  247. while tag.is_present:
  248. time.sleep(0.1)
  249. except KeyboardInterrupt:
  250. raise SystemExit
  251. finally:
  252. clf.close()
  253. raise SystemExit
  254. if __name__ == '__main__':
  255. main()