wps-ap-nfc.py revision 700a137ab366edc72e371da68ba187b4717ee660
1#!/usr/bin/python 2# 3# Example nfcpy to hostapd 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 12 13import nfc 14import nfc.ndef 15import nfc.llcp 16import nfc.handover 17 18import logging 19logging.basicConfig() 20 21import wpaspy 22 23wpas_ctrl = '/var/run/hostapd' 24 25def wpas_connect(): 26 ifaces = [] 27 if os.path.isdir(wpas_ctrl): 28 try: 29 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] 30 except OSError, error: 31 print "Could not find hostapd: ", error 32 return None 33 34 if len(ifaces) < 1: 35 print "No hostapd control interface found" 36 return None 37 38 for ctrl in ifaces: 39 try: 40 wpas = wpaspy.Ctrl(ctrl) 41 return wpas 42 except Exception, e: 43 pass 44 return None 45 46 47def wpas_tag_read(message): 48 wpas = wpas_connect() 49 if (wpas == None): 50 return 51 print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")) 52 53 54def wpas_get_config_token(): 55 wpas = wpas_connect() 56 if (wpas == None): 57 return None 58 return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex") 59 60 61def wpas_get_password_token(): 62 wpas = wpas_connect() 63 if (wpas == None): 64 return None 65 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex") 66 67 68def wpas_get_handover_sel(): 69 wpas = wpas_connect() 70 if (wpas == None): 71 return None 72 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex") 73 74 75def wpas_report_handover(req, sel): 76 wpas = wpas_connect() 77 if (wpas == None): 78 return None 79 return wpas.request("NFC_REPORT_HANDOVER RESP WPS " + 80 str(req).encode("hex") + " " + 81 str(sel).encode("hex")) 82 83 84class HandoverServer(nfc.handover.HandoverServer): 85 def __init__(self): 86 super(HandoverServer, self).__init__() 87 88 def process_request(self, request): 89 print "HandoverServer - request received" 90 print "Parsed handover request: " + request.pretty() 91 92 sel = nfc.ndef.HandoverSelectMessage(version="1.2") 93 94 for carrier in request.carriers: 95 print "Remote carrier type: " + carrier.type 96 if carrier.type == "application/vnd.wfa.wsc": 97 print "WPS carrier type match - add WPS carrier record" 98 self.received_carrier = carrier.record 99 data = wpas_get_handover_sel() 100 if data is None: 101 print "Could not get handover select carrier record from hostapd" 102 continue 103 print "Handover select carrier record from hostapd:" 104 print data.encode("hex") 105 self.sent_carrier = data 106 107 message = nfc.ndef.Message(data); 108 sel.add_carrier(message[0], "active", message[1:]) 109 110 print "Handover select:" 111 print sel.pretty() 112 print str(sel).encode("hex") 113 114 print "Sending handover select" 115 return sel 116 117 118def wps_handover_resp(peer): 119 print "Trying to handle WPS handover" 120 121 srv = HandoverServer() 122 srv.sent_carrier = None 123 124 nfc.llcp.activate(peer); 125 126 try: 127 print "Trying handover"; 128 srv.start() 129 print "Wait for disconnect" 130 while nfc.llcp.connected(): 131 time.sleep(0.1) 132 print "Disconnected after handover" 133 except nfc.llcp.ConnectRefused: 134 print "Handover connection refused" 135 nfc.llcp.shutdown() 136 return 137 138 if srv.sent_carrier: 139 wpas_report_handover(srv.received_carrier, srv.sent_carrier) 140 141 print "Remove peer" 142 nfc.llcp.shutdown() 143 print "Done with handover" 144 145 146def wps_tag_read(tag): 147 if len(tag.ndef.message): 148 message = nfc.ndef.Message(tag.ndef.message) 149 print "message type " + message.type 150 151 for record in message: 152 print "record type " + record.type 153 if record.type == "application/vnd.wfa.wsc": 154 print "WPS tag - send to hostapd" 155 wpas_tag_read(tag.ndef.message) 156 break 157 else: 158 print "Empty tag" 159 160 print "Remove tag" 161 while tag.is_present: 162 time.sleep(0.1) 163 164 165def wps_write_config_tag(clf): 166 print "Write WPS config token" 167 data = wpas_get_config_token() 168 if (data == None): 169 print "Could not get WPS config token from hostapd" 170 return 171 172 print "Touch an NFC tag" 173 while True: 174 tag = clf.poll() 175 if tag == None: 176 time.sleep(0.1) 177 continue 178 break 179 180 print "Tag found - writing" 181 tag.ndef.message = data 182 print "Done - remove tag" 183 while tag.is_present: 184 time.sleep(0.1) 185 186 187def wps_write_password_tag(clf): 188 print "Write WPS password token" 189 data = wpas_get_password_token() 190 if (data == None): 191 print "Could not get WPS password token from hostapd" 192 return 193 194 print "Touch an NFC tag" 195 while True: 196 tag = clf.poll() 197 if tag == None: 198 time.sleep(0.1) 199 continue 200 break 201 202 print "Tag found - writing" 203 tag.ndef.message = data 204 print "Done - remove tag" 205 while tag.is_present: 206 time.sleep(0.1) 207 208 209def find_peer(clf): 210 while True: 211 if nfc.llcp.connected(): 212 print "LLCP connected" 213 general_bytes = nfc.llcp.startup({}) 214 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes) 215 if isinstance(peer, nfc.DEP): 216 print "listen -> DEP"; 217 if peer.general_bytes.startswith("Ffm"): 218 print "Found DEP" 219 return peer 220 print "mismatch in general_bytes" 221 print peer.general_bytes 222 223 peer = clf.poll(general_bytes) 224 if isinstance(peer, nfc.DEP): 225 print "poll -> DEP"; 226 if peer.general_bytes.startswith("Ffm"): 227 print "Found DEP" 228 return peer 229 print "mismatch in general_bytes" 230 print peer.general_bytes 231 232 if peer: 233 print "Found tag" 234 return peer 235 236 237def main(): 238 clf = nfc.ContactlessFrontend() 239 240 try: 241 if len(sys.argv) > 1 and sys.argv[1] == "write-config": 242 wps_write_config_tag(clf) 243 raise SystemExit 244 245 if len(sys.argv) > 1 and sys.argv[1] == "write-password": 246 wps_write_password_tag(clf) 247 raise SystemExit 248 249 while True: 250 print "Waiting for a tag or peer to be touched" 251 252 tag = find_peer(clf) 253 if isinstance(tag, nfc.DEP): 254 wps_handover_resp(tag) 255 continue 256 257 if tag.ndef: 258 wps_tag_read(tag) 259 continue 260 261 print "Not an NDEF tag - remove tag" 262 while tag.is_present: 263 time.sleep(0.1) 264 265 except KeyboardInterrupt: 266 raise SystemExit 267 finally: 268 clf.close() 269 270 raise SystemExit 271 272if __name__ == '__main__': 273 main() 274