wps-nfc.py 5.7 KB

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