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 9import os 10import sys 11import time 12import random 13import StringIO 14 15import nfc 16import nfc.ndef 17import nfc.llcp 18import nfc.handover 19 20import logging 21logging.basicConfig() 22 23import wpaspy 24 25wpas_ctrl = '/var/run/wpa_supplicant' 26 27def 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 49def 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 57def 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 70def 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 77def 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 84def 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 91def 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 100def 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 109class 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 143def 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 176def 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 249def 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 272def 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 295def 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 317def 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 339def 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 367def 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 440if __name__ == '__main__': 441 main() 442