wps-nfc.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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_get_handover_sel(uuid):
  66. wpas = wpas_connect()
  67. if (wpas == None):
  68. return None
  69. if uuid is None:
  70. return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
  71. return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
  72. def wpas_report_handover(req, sel, type):
  73. wpas = wpas_connect()
  74. if (wpas == None):
  75. return None
  76. return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
  77. str(req).encode("hex") + " " +
  78. str(sel).encode("hex"))
  79. class HandoverServer(nfc.handover.HandoverServer):
  80. def __init__(self):
  81. super(HandoverServer, self).__init__()
  82. def process_request(self, request):
  83. print "HandoverServer - request received"
  84. print "Parsed handover request: " + request.pretty()
  85. sel = nfc.ndef.HandoverSelectMessage(version="1.2")
  86. for carrier in request.carriers:
  87. print "Remote carrier type: " + carrier.type
  88. if carrier.type == "application/vnd.wfa.wsc":
  89. print "WPS carrier type match - add WPS carrier record"
  90. self.received_carrier = carrier.record
  91. data = wpas_get_handover_sel(self.uuid)
  92. if data is None:
  93. print "Could not get handover select carrier record from wpa_supplicant"
  94. continue
  95. print "Handover select carrier record from wpa_supplicant:"
  96. print data.encode("hex")
  97. self.sent_carrier = data
  98. message = nfc.ndef.Message(data);
  99. sel.add_carrier(message[0], "active", message[1:])
  100. print "Handover select:"
  101. print sel.pretty()
  102. print str(sel).encode("hex")
  103. print "Sending handover select"
  104. return sel
  105. def wps_handover_resp(peer, uuid):
  106. if uuid is None:
  107. print "Trying to handle WPS handover"
  108. else:
  109. print "Trying to handle WPS handover with AP " + uuid
  110. srv = HandoverServer()
  111. srv.sent_carrier = None
  112. srv.uuid = uuid
  113. nfc.llcp.activate(peer);
  114. try:
  115. print "Trying handover";
  116. srv.start()
  117. print "Wait for disconnect"
  118. while nfc.llcp.connected():
  119. time.sleep(0.1)
  120. print "Disconnected after handover"
  121. except nfc.llcp.ConnectRefused:
  122. print "Handover connection refused"
  123. nfc.llcp.shutdown()
  124. return
  125. if srv.sent_carrier:
  126. wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
  127. print "Remove peer"
  128. nfc.llcp.shutdown()
  129. print "Done with handover"
  130. time.sleep(1)
  131. def wps_handover_init(peer):
  132. print "Trying to initiate WPS handover"
  133. data = wpas_get_handover_req()
  134. if (data == None):
  135. print "Could not get handover request carrier record from wpa_supplicant"
  136. return
  137. print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
  138. record = nfc.ndef.Record()
  139. f = StringIO.StringIO(data)
  140. record._read(f)
  141. record = nfc.ndef.HandoverCarrierRecord(record)
  142. print "Parsed handover request carrier record:"
  143. print record.pretty()
  144. message = nfc.ndef.HandoverRequestMessage(version="1.2")
  145. message.nonce = random.randint(0, 0xffff)
  146. message.add_carrier(record, "active")
  147. print "Handover request:"
  148. print message.pretty()
  149. nfc.llcp.activate(peer);
  150. client = nfc.handover.HandoverClient()
  151. try:
  152. print "Trying handover";
  153. client.connect()
  154. print "Connected for handover"
  155. except nfc.llcp.ConnectRefused:
  156. print "Handover connection refused"
  157. nfc.llcp.shutdown()
  158. client.close()
  159. return
  160. print "Sending handover request"
  161. if not client.send(message):
  162. print "Failed to send handover request"
  163. print "Receiving handover response"
  164. message = client._recv()
  165. if message is None:
  166. print "No response received"
  167. nfc.llcp.shutdown()
  168. client.close()
  169. return
  170. if message.type != "urn:nfc:wkt:Hs":
  171. print "Response was not Hs - received: " + message.type
  172. nfc.llcp.shutdown()
  173. client.close()
  174. return
  175. print "Received message"
  176. print message.pretty()
  177. message = nfc.ndef.HandoverSelectMessage(message)
  178. print "Handover select received"
  179. print message.pretty()
  180. for carrier in message.carriers:
  181. print "Remote carrier type: " + carrier.type
  182. if carrier.type == "application/vnd.wfa.wsc":
  183. print "WPS carrier type match - send to wpa_supplicant"
  184. wpas_report_handover(data, carrier.record, "INIT")
  185. wifi = nfc.ndef.WifiConfigRecord(carrier.record)
  186. print wifi.pretty()
  187. print "Remove peer"
  188. nfc.llcp.shutdown()
  189. client.close()
  190. print "Done with handover"
  191. def wps_tag_read(tag):
  192. if len(tag.ndef.message):
  193. message = nfc.ndef.Message(tag.ndef.message)
  194. print "message type " + message.type
  195. for record in message:
  196. print "record type " + record.type
  197. if record.type == "application/vnd.wfa.wsc":
  198. print "WPS tag - send to wpa_supplicant"
  199. wpas_tag_read(tag.ndef.message)
  200. break
  201. else:
  202. print "Empty tag"
  203. print "Remove tag"
  204. while tag.is_present:
  205. time.sleep(0.1)
  206. def wps_write_config_tag(clf):
  207. print "Write WPS config token"
  208. data = wpas_get_config_token()
  209. if (data == None):
  210. print "Could not get WPS config token from wpa_supplicant"
  211. return
  212. print "Touch an NFC tag"
  213. while True:
  214. tag = clf.poll()
  215. if tag == None:
  216. time.sleep(0.1)
  217. continue
  218. break
  219. print "Tag found - writing"
  220. tag.ndef.message = data
  221. print "Done - remove tag"
  222. while tag.is_present:
  223. time.sleep(0.1)
  224. def wps_write_er_config_tag(clf, uuid):
  225. print "Write WPS ER config token"
  226. data = wpas_get_er_config_token(uuid)
  227. if (data == None):
  228. print "Could not get WPS config token from wpa_supplicant"
  229. return
  230. print "Touch an NFC tag"
  231. while True:
  232. tag = clf.poll()
  233. if tag == None:
  234. time.sleep(0.1)
  235. continue
  236. break
  237. print "Tag found - writing"
  238. tag.ndef.message = data
  239. print "Done - remove tag"
  240. while tag.is_present:
  241. time.sleep(0.1)
  242. def wps_write_password_tag(clf):
  243. print "Write WPS password token"
  244. data = wpas_get_password_token()
  245. if (data == None):
  246. print "Could not get WPS password token from wpa_supplicant"
  247. return
  248. print "Touch an NFC tag"
  249. while True:
  250. tag = clf.poll()
  251. if tag == None:
  252. time.sleep(0.1)
  253. continue
  254. break
  255. print "Tag found - writing"
  256. tag.ndef.message = data
  257. print "Done - remove tag"
  258. while tag.is_present:
  259. time.sleep(0.1)
  260. def find_peer(clf):
  261. while True:
  262. if nfc.llcp.connected():
  263. print "LLCP connected"
  264. general_bytes = nfc.llcp.startup({})
  265. peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
  266. if isinstance(peer, nfc.DEP):
  267. print "listen -> DEP";
  268. if peer.general_bytes.startswith("Ffm"):
  269. print "Found DEP"
  270. return peer
  271. print "mismatch in general_bytes"
  272. print peer.general_bytes
  273. peer = clf.poll(general_bytes)
  274. if isinstance(peer, nfc.DEP):
  275. print "poll -> DEP";
  276. if peer.general_bytes.startswith("Ffm"):
  277. print "Found DEP"
  278. return peer
  279. print "mismatch in general_bytes"
  280. print peer.general_bytes
  281. if peer:
  282. print "Found tag"
  283. return peer
  284. def main():
  285. clf = nfc.ContactlessFrontend()
  286. try:
  287. arg_uuid = None
  288. if len(sys.argv) > 1:
  289. arg_uuid = sys.argv[1]
  290. if len(sys.argv) > 1 and sys.argv[1] == "write-config":
  291. wps_write_config_tag(clf)
  292. raise SystemExit
  293. if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
  294. wps_write_er_config_tag(clf, sys.argv[2])
  295. raise SystemExit
  296. if len(sys.argv) > 1 and sys.argv[1] == "write-password":
  297. wps_write_password_tag(clf)
  298. raise SystemExit
  299. while True:
  300. print "Waiting for a tag or peer to be touched"
  301. tag = find_peer(clf)
  302. if isinstance(tag, nfc.DEP):
  303. if arg_uuid is None:
  304. wps_handover_init(tag)
  305. elif arg_uuid is "ap":
  306. wps_handover_resp(tag, None)
  307. else:
  308. wps_handover_resp(tag, arg_uuid)
  309. continue
  310. if tag.ndef:
  311. wps_tag_read(tag)
  312. continue
  313. print "Not an NDEF tag - remove tag"
  314. while tag.is_present:
  315. time.sleep(0.1)
  316. except KeyboardInterrupt:
  317. raise SystemExit
  318. finally:
  319. clf.close()
  320. raise SystemExit
  321. if __name__ == '__main__':
  322. main()