blob: d6dec85c8c27c6b1f6bbc6bd759b22276d5cb02e [file] [log] [blame]
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001#!/usr/bin/python
2#
3# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005#
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
Dmitry Shmidtf8623282013-02-20 14:34:59 -080012import random
13import StringIO
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080014
15import nfc
16import nfc.ndef
17import nfc.llcp
18import nfc.handover
19
Dmitry Shmidtf8623282013-02-20 14:34:59 -080020import logging
21logging.basicConfig()
22
Dmitry Shmidt700a1372013-03-15 14:14:44 -070023import wpaspy
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080024
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:
Dmitry Shmidt700a1372013-03-15 14:14:44 -070042 wpas = wpaspy.Ctrl(ctrl)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080043 return wpas
Dmitry Shmidt700a1372013-03-15 14:14:44 -070044 except Exception, e:
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080045 pass
46 return None
47
48
49def wpas_tag_read(message):
50 wpas = wpas_connect()
51 if (wpas == None):
Dmitry Shmidt4b060592013-04-29 16:42:49 -070052 return False
53 if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + message.encode("hex")):
54 return False
55 return True
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080056
Dmitry Shmidt1e78e762013-04-02 11:05:36 -070057def wpas_get_config_token(id=None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080058 wpas = wpas_connect()
59 if (wpas == None):
60 return None
Dmitry Shmidt1e78e762013-04-02 11:05:36 -070061 if id:
Dmitry Shmidt4b060592013-04-29 16:42:49 -070062 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")
Dmitry Shmidtf8623282013-02-20 14:34:59 -080068
69
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080070def 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
Dmitry Shmidtf8623282013-02-20 14:34:59 -080077def 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
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080084def wpas_get_handover_req():
85 wpas = wpas_connect()
86 if (wpas == None):
87 return None
Dmitry Shmidtf8623282013-02-20 14:34:59 -080088 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080089
90
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080091def wpas_get_handover_sel(uuid):
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080092 wpas = wpas_connect()
93 if (wpas == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080094 return None
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080095 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 " +
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800105 str(req).encode("hex") + " " +
106 str(sel).encode("hex"))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800107
108
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800109class 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
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800176def wps_handover_init(peer):
177 print "Trying to initiate WPS handover"
178
179 data = wpas_get_handover_req()
180 if (data == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800181 print "Could not get handover request carrier record from wpa_supplicant"
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800182 return
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800183 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()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800197
198 nfc.llcp.activate(peer);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800199
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()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800218 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)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800232 print "Handover select received"
233 print message.pretty()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800234
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"
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800239 wpas_report_handover(data, carrier.record, "INIT")
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800240 wifi = nfc.ndef.WifiConfigRecord(carrier.record)
241 print wifi.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800242
243 print "Remove peer"
244 nfc.llcp.shutdown()
245 client.close()
246 print "Done with handover"
247
248
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700249def wps_tag_read(tag, wait_remove=True):
250 success = False
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800251 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"
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700259 success = wpas_tag_read(tag.ndef.message)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800260 break
261 else:
262 print "Empty tag"
263
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700264 if wait_remove:
265 print "Remove tag"
266 while tag.is_present:
267 time.sleep(0.1)
268
269 return success
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800270
271
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700272def wps_write_config_tag(clf, id=None, wait_remove=True):
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800273 print "Write WPS config token"
Dmitry Shmidt1e78e762013-04-02 11:05:36 -0700274 data = wpas_get_config_token(id)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800275 if (data == None):
276 print "Could not get WPS config token from wpa_supplicant"
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700277 sys.exit(1)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800278 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"
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700291 while wait_remove and tag.is_present:
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800292 time.sleep(0.1)
293
294
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800295def 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
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700317def wps_write_password_tag(clf, wait_remove=True):
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800318 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"
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700335 while wait_remove and tag.is_present:
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800336 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
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800367def main():
368 clf = nfc.ContactlessFrontend()
369
370 try:
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800371 arg_uuid = None
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700372 if len(sys.argv) > 1 and sys.argv[1] != '-1':
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800373 arg_uuid = sys.argv[1]
374
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700375 if len(sys.argv) > 1 and sys.argv[1] == '-1':
376 only_one = True
377 else:
378 only_one = False
379
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800380 if len(sys.argv) > 1 and sys.argv[1] == "write-config":
381 wps_write_config_tag(clf)
382 raise SystemExit
383
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700384 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
Dmitry Shmidt1e78e762013-04-02 11:05:36 -0700388 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
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800392 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
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800396 if len(sys.argv) > 1 and sys.argv[1] == "write-password":
397 wps_write_password_tag(clf)
398 raise SystemExit
399
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700400 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
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800404 while True:
405 print "Waiting for a tag or peer to be touched"
406
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800407 tag = find_peer(clf)
408 if isinstance(tag, nfc.DEP):
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800409 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)
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700415 if only_one:
416 break
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800417 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800418
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800419 if tag.ndef:
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700420 success = wps_tag_read(tag, not only_one)
421 if only_one:
422 if not success:
423 sys.exit(1)
424 break
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800425 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800426
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800427 print "Not an NDEF tag - remove tag"
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700428 if only_one:
429 sys.exit(1)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800430 while tag.is_present:
431 time.sleep(0.1)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800432
433 except KeyboardInterrupt:
434 raise SystemExit
435 finally:
436 clf.close()
437
438 raise SystemExit
439
440if __name__ == '__main__':
441 main()