#!/usr/bin/python # # Example nfcpy to wpa_supplicant wrapper for WPS NFC operations # Copyright (c) 2012-2013, Jouni Malinen # # This software may be distributed under the terms of the BSD license. # See README for more details. import os import sys import time import random import StringIO import nfc import nfc.ndef import nfc.llcp import nfc.handover import logging logging.basicConfig() import wpactrl wpas_ctrl = '/var/run/wpa_supplicant' def wpas_connect(): ifaces = [] if os.path.isdir(wpas_ctrl): try: ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] except OSError, error: print "Could not find wpa_supplicant: ", error return None if len(ifaces) < 1: print "No wpa_supplicant control interface found" return None for ctrl in ifaces: try: wpas = wpactrl.WPACtrl(ctrl) return wpas except wpactrl.error, error: print "Error: ", error pass return None def wpas_tag_read(message): wpas = wpas_connect() if (wpas == None): return print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")) def wpas_get_config_token(): wpas = wpas_connect() if (wpas == None): return None return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex") def wpas_get_er_config_token(uuid): wpas = wpas_connect() if (wpas == None): return None return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex") def wpas_get_password_token(): wpas = wpas_connect() if (wpas == None): return None return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex") def wpas_get_handover_req(): wpas = wpas_connect() if (wpas == None): return None return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex") def wpas_get_handover_sel(uuid): wpas = wpas_connect() if (wpas == None): return None return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex") def wpas_report_handover(req, sel, type): wpas = wpas_connect() if (wpas == None): return None return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")) class HandoverServer(nfc.handover.HandoverServer): def __init__(self): super(HandoverServer, self).__init__() def process_request(self, request): print "HandoverServer - request received" print "Parsed handover request: " + request.pretty() sel = nfc.ndef.HandoverSelectMessage(version="1.2") for carrier in request.carriers: print "Remote carrier type: " + carrier.type if carrier.type == "application/vnd.wfa.wsc": print "WPS carrier type match - add WPS carrier record" self.received_carrier = carrier.record data = wpas_get_handover_sel(self.uuid) if data is None: print "Could not get handover select carrier record from wpa_supplicant" continue print "Handover select carrier record from wpa_supplicant:" print data.encode("hex") self.sent_carrier = data message = nfc.ndef.Message(data); sel.add_carrier(message[0], "active", message[1:]) print "Handover select:" print sel.pretty() print str(sel).encode("hex") print "Sending handover select" return sel def wps_handover_resp(peer, uuid): print "Trying to handle WPS handover with AP " + uuid srv = HandoverServer() srv.sent_carrier = None srv.uuid = uuid nfc.llcp.activate(peer); try: print "Trying handover"; srv.start() print "Wait for disconnect" while nfc.llcp.connected(): time.sleep(0.1) print "Disconnected after handover" except nfc.llcp.ConnectRefused: print "Handover connection refused" nfc.llcp.shutdown() return if srv.sent_carrier: wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP") print "Remove peer" nfc.llcp.shutdown() print "Done with handover" time.sleep(1) def wps_handover_init(peer): print "Trying to initiate WPS handover" data = wpas_get_handover_req() if (data == None): print "Could not get handover request carrier record from wpa_supplicant" return print "Handover request carrier record from wpa_supplicant: " + data.encode("hex") record = nfc.ndef.Record() f = StringIO.StringIO(data) record._read(f) record = nfc.ndef.HandoverCarrierRecord(record) print "Parsed handover request carrier record:" print record.pretty() message = nfc.ndef.HandoverRequestMessage(version="1.2") message.nonce = random.randint(0, 0xffff) message.add_carrier(record, "active") print "Handover request:" print message.pretty() nfc.llcp.activate(peer); client = nfc.handover.HandoverClient() try: print "Trying handover"; client.connect() print "Connected for handover" except nfc.llcp.ConnectRefused: print "Handover connection refused" nfc.llcp.shutdown() client.close() return print "Sending handover request" if not client.send(message): print "Failed to send handover request" print "Receiving handover response" message = client._recv() if message is None: print "No response received" nfc.llcp.shutdown() client.close() return if message.type != "urn:nfc:wkt:Hs": print "Response was not Hs - received: " + message.type nfc.llcp.shutdown() client.close() return print "Received message" print message.pretty() message = nfc.ndef.HandoverSelectMessage(message) print "Handover select received" print message.pretty() for carrier in message.carriers: print "Remote carrier type: " + carrier.type if carrier.type == "application/vnd.wfa.wsc": print "WPS carrier type match - send to wpa_supplicant" wpas_report_handover(data, carrier.record, "INIT") wifi = nfc.ndef.WifiConfigRecord(carrier.record) print wifi.pretty() print "Remove peer" nfc.llcp.shutdown() client.close() print "Done with handover" def wps_tag_read(tag): if len(tag.ndef.message): message = nfc.ndef.Message(tag.ndef.message) print "message type " + message.type for record in message: print "record type " + record.type if record.type == "application/vnd.wfa.wsc": print "WPS tag - send to wpa_supplicant" wpas_tag_read(tag.ndef.message) break else: print "Empty tag" print "Remove tag" while tag.is_present: time.sleep(0.1) def wps_write_config_tag(clf): print "Write WPS config token" data = wpas_get_config_token() if (data == None): print "Could not get WPS config token from wpa_supplicant" return print "Touch an NFC tag" while True: tag = clf.poll() if tag == None: time.sleep(0.1) continue break print "Tag found - writing" tag.ndef.message = data print "Done - remove tag" while tag.is_present: time.sleep(0.1) def wps_write_er_config_tag(clf, uuid): print "Write WPS ER config token" data = wpas_get_er_config_token(uuid) if (data == None): print "Could not get WPS config token from wpa_supplicant" return print "Touch an NFC tag" while True: tag = clf.poll() if tag == None: time.sleep(0.1) continue break print "Tag found - writing" tag.ndef.message = data print "Done - remove tag" while tag.is_present: time.sleep(0.1) def wps_write_password_tag(clf): print "Write WPS password token" data = wpas_get_password_token() if (data == None): print "Could not get WPS password token from wpa_supplicant" return print "Touch an NFC tag" while True: tag = clf.poll() if tag == None: time.sleep(0.1) continue break print "Tag found - writing" tag.ndef.message = data print "Done - remove tag" while tag.is_present: time.sleep(0.1) def find_peer(clf): while True: if nfc.llcp.connected(): print "LLCP connected" general_bytes = nfc.llcp.startup({}) peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes) if isinstance(peer, nfc.DEP): print "listen -> DEP"; if peer.general_bytes.startswith("Ffm"): print "Found DEP" return peer print "mismatch in general_bytes" print peer.general_bytes peer = clf.poll(general_bytes) if isinstance(peer, nfc.DEP): print "poll -> DEP"; if peer.general_bytes.startswith("Ffm"): print "Found DEP" return peer print "mismatch in general_bytes" print peer.general_bytes if peer: print "Found tag" return peer def main(): clf = nfc.ContactlessFrontend() try: arg_uuid = None if len(sys.argv) > 1: arg_uuid = sys.argv[1] if len(sys.argv) > 1 and sys.argv[1] == "write-config": wps_write_config_tag(clf) raise SystemExit if len(sys.argv) > 2 and sys.argv[1] == "write-er-config": wps_write_er_config_tag(clf, sys.argv[2]) raise SystemExit if len(sys.argv) > 1 and sys.argv[1] == "write-password": wps_write_password_tag(clf) raise SystemExit while True: print "Waiting for a tag or peer to be touched" tag = find_peer(clf) if isinstance(tag, nfc.DEP): if arg_uuid is None: wps_handover_init(tag) else: wps_handover_resp(tag, arg_uuid) continue if tag.ndef: wps_tag_read(tag) continue print "Not an NDEF tag - remove tag" while tag.is_present: time.sleep(0.1) except KeyboardInterrupt: raise SystemExit finally: clf.close() raise SystemExit if __name__ == '__main__': main()