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