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