wps-nfc.py 11 KB

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