1 #!/usr/bin/python 2 # 3 # Example nfcpy to wpa_supplicant wrapper for WPS NFC operations 4 # Copyright (c) 2012-2013, Jouni Malinen <j (at] w1.fi> 5 # 6 # This software may be distributed under the terms of the BSD license. 7 # See README for more details. 8 9 import os 10 import sys 11 import time 12 import random 13 import StringIO 14 15 import nfc 16 import nfc.ndef 17 import nfc.llcp 18 import nfc.handover 19 20 import logging 21 logging.basicConfig() 22 23 import wpaspy 24 25 wpas_ctrl = '/var/run/wpa_supplicant' 26 27 def wpas_connect(): 28 ifaces = [] 29 if os.path.isdir(wpas_ctrl): 30 try: 31 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] 32 except OSError, error: 33 print "Could not find wpa_supplicant: ", error 34 return None 35 36 if len(ifaces) < 1: 37 print "No wpa_supplicant control interface found" 38 return None 39 40 for ctrl in ifaces: 41 try: 42 wpas = wpaspy.Ctrl(ctrl) 43 return wpas 44 except Exception, e: 45 pass 46 return None 47 48 49 def wpas_tag_read(message): 50 wpas = wpas_connect() 51 if (wpas == None): 52 return False 53 if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")): 54 return False 55 return True 56 57 def wpas_get_config_token(id=None): 58 wpas = wpas_connect() 59 if (wpas == None): 60 return None 61 if id: 62 ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id) 63 else: 64 ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF") 65 if "FAIL" in ret: 66 return None 67 return ret.rstrip().decode("hex") 68 69 70 def wpas_get_er_config_token(uuid): 71 wpas = wpas_connect() 72 if (wpas == None): 73 return None 74 return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex") 75 76 77 def wpas_get_password_token(): 78 wpas = wpas_connect() 79 if (wpas == None): 80 return None 81 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex") 82 83 84 def wpas_get_handover_req(): 85 wpas = wpas_connect() 86 if (wpas == None): 87 return None 88 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex") 89 90 91 def wpas_get_handover_sel(uuid): 92 wpas = wpas_connect() 93 if (wpas == None): 94 return None 95 if uuid is None: 96 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex") 97 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex") 98 99 100 def wpas_report_handover(req, sel, type): 101 wpas = wpas_connect() 102 if (wpas == None): 103 return None 104 return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " + 105 str(req).encode("hex") + " " + 106 str(sel).encode("hex")) 107 108 109 class HandoverServer(nfc.handover.HandoverServer): 110 def __init__(self): 111 super(HandoverServer, self).__init__() 112 113 def process_request(self, request): 114 print "HandoverServer - request received" 115 print "Parsed handover request: " + request.pretty() 116 117 sel = nfc.ndef.HandoverSelectMessage(version="1.2") 118 119 for carrier in request.carriers: 120 print "Remote carrier type: " + carrier.type 121 if carrier.type == "application/vnd.wfa.wsc": 122 print "WPS carrier type match - add WPS carrier record" 123 self.received_carrier = carrier.record 124 data = wpas_get_handover_sel(self.uuid) 125 if data is None: 126 print "Could not get handover select carrier record from wpa_supplicant" 127 continue 128 print "Handover select carrier record from wpa_supplicant:" 129 print data.encode("hex") 130 self.sent_carrier = data 131 132 message = nfc.ndef.Message(data); 133 sel.add_carrier(message[0], "active", message[1:]) 134 135 print "Handover select:" 136 print sel.pretty() 137 print str(sel).encode("hex") 138 139 print "Sending handover select" 140 return sel 141 142 143 def wps_handover_resp(peer, uuid): 144 if uuid is None: 145 print "Trying to handle WPS handover" 146 else: 147 print "Trying to handle WPS handover with AP " + uuid 148 149 srv = HandoverServer() 150 srv.sent_carrier = None 151 srv.uuid = uuid 152 153 nfc.llcp.activate(peer); 154 155 try: 156 print "Trying handover"; 157 srv.start() 158 print "Wait for disconnect" 159 while nfc.llcp.connected(): 160 time.sleep(0.1) 161 print "Disconnected after handover" 162 except nfc.llcp.ConnectRefused: 163 print "Handover connection refused" 164 nfc.llcp.shutdown() 165 return 166 167 if srv.sent_carrier: 168 wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP") 169 170 print "Remove peer" 171 nfc.llcp.shutdown() 172 print "Done with handover" 173 time.sleep(1) 174 175 176 def wps_handover_init(peer): 177 print "Trying to initiate WPS handover" 178 179 data = wpas_get_handover_req() 180 if (data == None): 181 print "Could not get handover request carrier record from wpa_supplicant" 182 return 183 print "Handover request carrier record from wpa_supplicant: " + data.encode("hex") 184 record = nfc.ndef.Record() 185 f = StringIO.StringIO(data) 186 record._read(f) 187 record = nfc.ndef.HandoverCarrierRecord(record) 188 print "Parsed handover request carrier record:" 189 print record.pretty() 190 191 message = nfc.ndef.HandoverRequestMessage(version="1.2") 192 message.nonce = random.randint(0, 0xffff) 193 message.add_carrier(record, "active") 194 195 print "Handover request:" 196 print message.pretty() 197 198 nfc.llcp.activate(peer); 199 200 client = nfc.handover.HandoverClient() 201 try: 202 print "Trying handover"; 203 client.connect() 204 print "Connected for handover" 205 except nfc.llcp.ConnectRefused: 206 print "Handover connection refused" 207 nfc.llcp.shutdown() 208 client.close() 209 return 210 211 print "Sending handover request" 212 213 if not client.send(message): 214 print "Failed to send handover request" 215 216 print "Receiving handover response" 217 message = client._recv() 218 if message is None: 219 print "No response received" 220 nfc.llcp.shutdown() 221 client.close() 222 return 223 if message.type != "urn:nfc:wkt:Hs": 224 print "Response was not Hs - received: " + message.type 225 nfc.llcp.shutdown() 226 client.close() 227 return 228 229 print "Received message" 230 print message.pretty() 231 message = nfc.ndef.HandoverSelectMessage(message) 232 print "Handover select received" 233 print message.pretty() 234 235 for carrier in message.carriers: 236 print "Remote carrier type: " + carrier.type 237 if carrier.type == "application/vnd.wfa.wsc": 238 print "WPS carrier type match - send to wpa_supplicant" 239 wpas_report_handover(data, carrier.record, "INIT") 240 wifi = nfc.ndef.WifiConfigRecord(carrier.record) 241 print wifi.pretty() 242 243 print "Remove peer" 244 nfc.llcp.shutdown() 245 client.close() 246 print "Done with handover" 247 248 249 def wps_tag_read(tag, wait_remove=True): 250 success = False 251 if len(tag.ndef.message): 252 message = nfc.ndef.Message(tag.ndef.message) 253 print "message type " + message.type 254 255 for record in message: 256 print "record type " + record.type 257 if record.type == "application/vnd.wfa.wsc": 258 print "WPS tag - send to wpa_supplicant" 259 success = wpas_tag_read(tag.ndef.message) 260 break 261 else: 262 print "Empty tag" 263 264 if wait_remove: 265 print "Remove tag" 266 while tag.is_present: 267 time.sleep(0.1) 268 269 return success 270 271 272 def wps_write_config_tag(clf, id=None, wait_remove=True): 273 print "Write WPS config token" 274 data = wpas_get_config_token(id) 275 if (data == None): 276 print "Could not get WPS config token from wpa_supplicant" 277 sys.exit(1) 278 return 279 280 print "Touch an NFC tag" 281 while True: 282 tag = clf.poll() 283 if tag == None: 284 time.sleep(0.1) 285 continue 286 break 287 288 print "Tag found - writing" 289 tag.ndef.message = data 290 print "Done - remove tag" 291 while wait_remove and tag.is_present: 292 time.sleep(0.1) 293 294 295 def wps_write_er_config_tag(clf, uuid): 296 print "Write WPS ER config token" 297 data = wpas_get_er_config_token(uuid) 298 if (data == None): 299 print "Could not get WPS config token from wpa_supplicant" 300 return 301 302 print "Touch an NFC tag" 303 while True: 304 tag = clf.poll() 305 if tag == None: 306 time.sleep(0.1) 307 continue 308 break 309 310 print "Tag found - writing" 311 tag.ndef.message = data 312 print "Done - remove tag" 313 while tag.is_present: 314 time.sleep(0.1) 315 316 317 def wps_write_password_tag(clf, wait_remove=True): 318 print "Write WPS password token" 319 data = wpas_get_password_token() 320 if (data == None): 321 print "Could not get WPS password token from wpa_supplicant" 322 return 323 324 print "Touch an NFC tag" 325 while True: 326 tag = clf.poll() 327 if tag == None: 328 time.sleep(0.1) 329 continue 330 break 331 332 print "Tag found - writing" 333 tag.ndef.message = data 334 print "Done - remove tag" 335 while wait_remove and tag.is_present: 336 time.sleep(0.1) 337 338 339 def find_peer(clf): 340 while True: 341 if nfc.llcp.connected(): 342 print "LLCP connected" 343 general_bytes = nfc.llcp.startup({}) 344 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes) 345 if isinstance(peer, nfc.DEP): 346 print "listen -> DEP"; 347 if peer.general_bytes.startswith("Ffm"): 348 print "Found DEP" 349 return peer 350 print "mismatch in general_bytes" 351 print peer.general_bytes 352 353 peer = clf.poll(general_bytes) 354 if isinstance(peer, nfc.DEP): 355 print "poll -> DEP"; 356 if peer.general_bytes.startswith("Ffm"): 357 print "Found DEP" 358 return peer 359 print "mismatch in general_bytes" 360 print peer.general_bytes 361 362 if peer: 363 print "Found tag" 364 return peer 365 366 367 def main(): 368 clf = nfc.ContactlessFrontend() 369 370 try: 371 arg_uuid = None 372 if len(sys.argv) > 1 and sys.argv[1] != '-1': 373 arg_uuid = sys.argv[1] 374 375 if len(sys.argv) > 1 and sys.argv[1] == '-1': 376 only_one = True 377 else: 378 only_one = False 379 380 if len(sys.argv) > 1 and sys.argv[1] == "write-config": 381 wps_write_config_tag(clf) 382 raise SystemExit 383 384 if len(sys.argv) > 1 and sys.argv[1] == "write-config-no-wait": 385 wps_write_config_tag(clf, wait_remove=False) 386 raise SystemExit 387 388 if len(sys.argv) > 2 and sys.argv[1] == "write-config-id": 389 wps_write_config_tag(clf, sys.argv[2]) 390 raise SystemExit 391 392 if len(sys.argv) > 2 and sys.argv[1] == "write-er-config": 393 wps_write_er_config_tag(clf, sys.argv[2]) 394 raise SystemExit 395 396 if len(sys.argv) > 1 and sys.argv[1] == "write-password": 397 wps_write_password_tag(clf) 398 raise SystemExit 399 400 if len(sys.argv) > 1 and sys.argv[1] == "write-password-no-wait": 401 wps_write_password_tag(clf, wait_remove=False) 402 raise SystemExit 403 404 while True: 405 print "Waiting for a tag or peer to be touched" 406 407 tag = find_peer(clf) 408 if isinstance(tag, nfc.DEP): 409 if arg_uuid is None: 410 wps_handover_init(tag) 411 elif arg_uuid is "ap": 412 wps_handover_resp(tag, None) 413 else: 414 wps_handover_resp(tag, arg_uuid) 415 if only_one: 416 break 417 continue 418 419 if tag.ndef: 420 success = wps_tag_read(tag, not only_one) 421 if only_one: 422 if not success: 423 sys.exit(1) 424 break 425 continue 426 427 print "Not an NDEF tag - remove tag" 428 if only_one: 429 sys.exit(1) 430 while tag.is_present: 431 time.sleep(0.1) 432 433 except KeyboardInterrupt: 434 raise SystemExit 435 finally: 436 clf.close() 437 438 raise SystemExit 439 440 if __name__ == '__main__': 441 main() 442