1 #!/usr/bin/python 2 # 3 # Example nfcpy to hostapd 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 13 import nfc 14 import nfc.ndef 15 import nfc.llcp 16 import nfc.handover 17 18 import logging 19 logging.basicConfig() 20 21 import wpaspy 22 23 wpas_ctrl = '/var/run/hostapd' 24 25 def 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 47 def 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 54 def 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 61 def 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 68 def 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 75 def 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 84 class 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 118 def 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 146 def 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 165 def 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 187 def 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 209 def 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 237 def 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 272 if __name__ == '__main__': 273 main() 274