wps-nfc.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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_password_token():
  46. wpas = wpas_connect()
  47. if (wpas == None):
  48. return None
  49. return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
  50. def wpas_get_handover_req():
  51. wpas = wpas_connect()
  52. if (wpas == None):
  53. return None
  54. return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
  55. def wpas_report_handover(req, sel):
  56. wpas = wpas_connect()
  57. if (wpas == None):
  58. return None
  59. return wpas.request("NFC_REPORT_HANDOVER INIT WPS " +
  60. str(req).encode("hex") + " " +
  61. str(sel).encode("hex"))
  62. def wps_handover_init(peer):
  63. print "Trying to initiate WPS handover"
  64. data = wpas_get_handover_req()
  65. if (data == None):
  66. print "Could not get handover request carrier record from wpa_supplicant"
  67. return
  68. print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
  69. record = nfc.ndef.Record()
  70. f = StringIO.StringIO(data)
  71. record._read(f)
  72. record = nfc.ndef.HandoverCarrierRecord(record)
  73. print "Parsed handover request carrier record:"
  74. print record.pretty()
  75. message = nfc.ndef.HandoverRequestMessage(version="1.2")
  76. message.nonce = random.randint(0, 0xffff)
  77. message.add_carrier(record, "active")
  78. print "Handover request:"
  79. print message.pretty()
  80. nfc.llcp.activate(peer);
  81. client = nfc.handover.HandoverClient()
  82. try:
  83. print "Trying handover";
  84. client.connect()
  85. print "Connected for handover"
  86. except nfc.llcp.ConnectRefused:
  87. print "Handover connection refused"
  88. nfc.llcp.shutdown()
  89. client.close()
  90. return
  91. print "Sending handover request"
  92. if not client.send(message):
  93. print "Failed to send handover request"
  94. print "Receiving handover response"
  95. message = client._recv()
  96. if message is None:
  97. print "No response received"
  98. nfc.llcp.shutdown()
  99. client.close()
  100. return
  101. if message.type != "urn:nfc:wkt:Hs":
  102. print "Response was not Hs - received: " + message.type
  103. nfc.llcp.shutdown()
  104. client.close()
  105. return
  106. print "Received message"
  107. print message.pretty()
  108. message = nfc.ndef.HandoverSelectMessage(message)
  109. print "Handover select received"
  110. print message.pretty()
  111. for carrier in message.carriers:
  112. print "Remote carrier type: " + carrier.type
  113. if carrier.type == "application/vnd.wfa.wsc":
  114. print "WPS carrier type match - send to wpa_supplicant"
  115. wpas_report_handover(data, carrier.record)
  116. wifi = nfc.ndef.WifiConfigRecord(carrier.record)
  117. print wifi.pretty()
  118. print "Remove peer"
  119. nfc.llcp.shutdown()
  120. client.close()
  121. print "Done with handover"
  122. def wps_tag_read(tag):
  123. if len(tag.ndef.message):
  124. message = nfc.ndef.Message(tag.ndef.message)
  125. print "message type " + message.type
  126. for record in message:
  127. print "record type " + record.type
  128. if record.type == "application/vnd.wfa.wsc":
  129. print "WPS tag - send to wpa_supplicant"
  130. wpas_tag_read(tag.ndef.message)
  131. break
  132. else:
  133. print "Empty tag"
  134. print "Remove tag"
  135. while tag.is_present:
  136. time.sleep(0.1)
  137. def wps_write_password_tag(clf):
  138. print "Write WPS password token"
  139. data = wpas_get_password_token()
  140. if (data == None):
  141. print "Could not get WPS password token from wpa_supplicant"
  142. return
  143. print "Touch an NFC tag"
  144. while True:
  145. tag = clf.poll()
  146. if tag == None:
  147. time.sleep(0.1)
  148. continue
  149. break
  150. print "Tag found - writing"
  151. tag.ndef.message = data
  152. print "Done - remove tag"
  153. while tag.is_present:
  154. time.sleep(0.1)
  155. def find_peer(clf):
  156. while True:
  157. if nfc.llcp.connected():
  158. print "LLCP connected"
  159. general_bytes = nfc.llcp.startup({})
  160. peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
  161. if isinstance(peer, nfc.DEP):
  162. print "listen -> DEP";
  163. if peer.general_bytes.startswith("Ffm"):
  164. print "Found DEP"
  165. return peer
  166. print "mismatch in general_bytes"
  167. print peer.general_bytes
  168. peer = clf.poll(general_bytes)
  169. if isinstance(peer, nfc.DEP):
  170. print "poll -> DEP";
  171. if peer.general_bytes.startswith("Ffm"):
  172. print "Found DEP"
  173. return peer
  174. print "mismatch in general_bytes"
  175. print peer.general_bytes
  176. if peer:
  177. print "Found tag"
  178. return peer
  179. def main():
  180. clf = nfc.ContactlessFrontend()
  181. try:
  182. if len(sys.argv) > 1 and sys.argv[1] == "write-password":
  183. wps_write_password_tag(clf)
  184. raise SystemExit
  185. while True:
  186. print "Waiting for a tag or peer to be touched"
  187. tag = find_peer(clf)
  188. if isinstance(tag, nfc.DEP):
  189. wps_handover_init(tag)
  190. continue
  191. if tag.ndef:
  192. wps_tag_read(tag)
  193. continue
  194. print "Not an NDEF tag - remove tag"
  195. while tag.is_present:
  196. time.sleep(0.1)
  197. except KeyboardInterrupt:
  198. raise SystemExit
  199. finally:
  200. clf.close()
  201. raise SystemExit
  202. if __name__ == '__main__':
  203. main()