blob: 86473cd62a3d61624906563d655959281f68fdda [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 Shmidtf8623282013-02-20 14:34:59 -080056def wpas_get_config_token():
57 wpas = wpas_connect()
58 if (wpas == None):
59 return None
60 return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
61
62
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080063def wpas_get_er_config_token(uuid):
64 wpas = wpas_connect()
65 if (wpas == None):
66 return None
67 return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
68
69
Dmitry Shmidtf8623282013-02-20 14:34:59 -080070def wpas_get_password_token():
71 wpas = wpas_connect()
72 if (wpas == None):
73 return None
74 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
75
76
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080077def wpas_get_handover_req():
78 wpas = wpas_connect()
79 if (wpas == None):
80 return None
Dmitry Shmidtf8623282013-02-20 14:34:59 -080081 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080082
83
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080084def wpas_get_handover_sel(uuid):
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080085 wpas = wpas_connect()
86 if (wpas == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080087 return None
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080088 if uuid is None:
89 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
90 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
91
92
93def wpas_report_handover(req, sel, type):
94 wpas = wpas_connect()
95 if (wpas == None):
96 return None
97 return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
Dmitry Shmidtf8623282013-02-20 14:34:59 -080098 str(req).encode("hex") + " " +
99 str(sel).encode("hex"))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800100
101
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800102class HandoverServer(nfc.handover.HandoverServer):
103 def __init__(self):
104 super(HandoverServer, self).__init__()
105
106 def process_request(self, request):
107 print "HandoverServer - request received"
108 print "Parsed handover request: " + request.pretty()
109
110 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
111
112 for carrier in request.carriers:
113 print "Remote carrier type: " + carrier.type
114 if carrier.type == "application/vnd.wfa.wsc":
115 print "WPS carrier type match - add WPS carrier record"
116 self.received_carrier = carrier.record
117 data = wpas_get_handover_sel(self.uuid)
118 if data is None:
119 print "Could not get handover select carrier record from wpa_supplicant"
120 continue
121 print "Handover select carrier record from wpa_supplicant:"
122 print data.encode("hex")
123 self.sent_carrier = data
124
125 message = nfc.ndef.Message(data);
126 sel.add_carrier(message[0], "active", message[1:])
127
128 print "Handover select:"
129 print sel.pretty()
130 print str(sel).encode("hex")
131
132 print "Sending handover select"
133 return sel
134
135
136def wps_handover_resp(peer, uuid):
137 if uuid is None:
138 print "Trying to handle WPS handover"
139 else:
140 print "Trying to handle WPS handover with AP " + uuid
141
142 srv = HandoverServer()
143 srv.sent_carrier = None
144 srv.uuid = uuid
145
146 nfc.llcp.activate(peer);
147
148 try:
149 print "Trying handover";
150 srv.start()
151 print "Wait for disconnect"
152 while nfc.llcp.connected():
153 time.sleep(0.1)
154 print "Disconnected after handover"
155 except nfc.llcp.ConnectRefused:
156 print "Handover connection refused"
157 nfc.llcp.shutdown()
158 return
159
160 if srv.sent_carrier:
161 wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
162
163 print "Remove peer"
164 nfc.llcp.shutdown()
165 print "Done with handover"
166 time.sleep(1)
167
168
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800169def wps_handover_init(peer):
170 print "Trying to initiate WPS handover"
171
172 data = wpas_get_handover_req()
173 if (data == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800174 print "Could not get handover request carrier record from wpa_supplicant"
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800175 return
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800176 print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
177 record = nfc.ndef.Record()
178 f = StringIO.StringIO(data)
179 record._read(f)
180 record = nfc.ndef.HandoverCarrierRecord(record)
181 print "Parsed handover request carrier record:"
182 print record.pretty()
183
184 message = nfc.ndef.HandoverRequestMessage(version="1.2")
185 message.nonce = random.randint(0, 0xffff)
186 message.add_carrier(record, "active")
187
188 print "Handover request:"
189 print message.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800190
191 nfc.llcp.activate(peer);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800192
193 client = nfc.handover.HandoverClient()
194 try:
195 print "Trying handover";
196 client.connect()
197 print "Connected for handover"
198 except nfc.llcp.ConnectRefused:
199 print "Handover connection refused"
200 nfc.llcp.shutdown()
201 client.close()
202 return
203
204 print "Sending handover request"
205
206 if not client.send(message):
207 print "Failed to send handover request"
208
209 print "Receiving handover response"
210 message = client._recv()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800211 if message is None:
212 print "No response received"
213 nfc.llcp.shutdown()
214 client.close()
215 return
216 if message.type != "urn:nfc:wkt:Hs":
217 print "Response was not Hs - received: " + message.type
218 nfc.llcp.shutdown()
219 client.close()
220 return
221
222 print "Received message"
223 print message.pretty()
224 message = nfc.ndef.HandoverSelectMessage(message)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800225 print "Handover select received"
226 print message.pretty()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800227
228 for carrier in message.carriers:
229 print "Remote carrier type: " + carrier.type
230 if carrier.type == "application/vnd.wfa.wsc":
231 print "WPS carrier type match - send to wpa_supplicant"
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800232 wpas_report_handover(data, carrier.record, "INIT")
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800233 wifi = nfc.ndef.WifiConfigRecord(carrier.record)
234 print wifi.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800235
236 print "Remove peer"
237 nfc.llcp.shutdown()
238 client.close()
239 print "Done with handover"
240
241
242def wps_tag_read(tag):
243 if len(tag.ndef.message):
244 message = nfc.ndef.Message(tag.ndef.message)
245 print "message type " + message.type
246
247 for record in message:
248 print "record type " + record.type
249 if record.type == "application/vnd.wfa.wsc":
250 print "WPS tag - send to wpa_supplicant"
251 wpas_tag_read(tag.ndef.message)
252 break
253 else:
254 print "Empty tag"
255
256 print "Remove tag"
257 while tag.is_present:
258 time.sleep(0.1)
259
260
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800261def wps_write_config_tag(clf):
262 print "Write WPS config token"
263 data = wpas_get_config_token()
264 if (data == None):
265 print "Could not get WPS config token from wpa_supplicant"
266 return
267
268 print "Touch an NFC tag"
269 while True:
270 tag = clf.poll()
271 if tag == None:
272 time.sleep(0.1)
273 continue
274 break
275
276 print "Tag found - writing"
277 tag.ndef.message = data
278 print "Done - remove tag"
279 while tag.is_present:
280 time.sleep(0.1)
281
282
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800283def wps_write_er_config_tag(clf, uuid):
284 print "Write WPS ER config token"
285 data = wpas_get_er_config_token(uuid)
286 if (data == None):
287 print "Could not get WPS config token from wpa_supplicant"
288 return
289
290 print "Touch an NFC tag"
291 while True:
292 tag = clf.poll()
293 if tag == None:
294 time.sleep(0.1)
295 continue
296 break
297
298 print "Tag found - writing"
299 tag.ndef.message = data
300 print "Done - remove tag"
301 while tag.is_present:
302 time.sleep(0.1)
303
304
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800305def wps_write_password_tag(clf):
306 print "Write WPS password token"
307 data = wpas_get_password_token()
308 if (data == None):
309 print "Could not get WPS password token from wpa_supplicant"
310 return
311
312 print "Touch an NFC tag"
313 while True:
314 tag = clf.poll()
315 if tag == None:
316 time.sleep(0.1)
317 continue
318 break
319
320 print "Tag found - writing"
321 tag.ndef.message = data
322 print "Done - remove tag"
323 while tag.is_present:
324 time.sleep(0.1)
325
326
327def find_peer(clf):
328 while True:
329 if nfc.llcp.connected():
330 print "LLCP connected"
331 general_bytes = nfc.llcp.startup({})
332 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
333 if isinstance(peer, nfc.DEP):
334 print "listen -> DEP";
335 if peer.general_bytes.startswith("Ffm"):
336 print "Found DEP"
337 return peer
338 print "mismatch in general_bytes"
339 print peer.general_bytes
340
341 peer = clf.poll(general_bytes)
342 if isinstance(peer, nfc.DEP):
343 print "poll -> DEP";
344 if peer.general_bytes.startswith("Ffm"):
345 print "Found DEP"
346 return peer
347 print "mismatch in general_bytes"
348 print peer.general_bytes
349
350 if peer:
351 print "Found tag"
352 return peer
353
354
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800355def main():
356 clf = nfc.ContactlessFrontend()
357
358 try:
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800359 arg_uuid = None
360 if len(sys.argv) > 1:
361 arg_uuid = sys.argv[1]
362
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800363 if len(sys.argv) > 1 and sys.argv[1] == "write-config":
364 wps_write_config_tag(clf)
365 raise SystemExit
366
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800367 if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
368 wps_write_er_config_tag(clf, sys.argv[2])
369 raise SystemExit
370
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800371 if len(sys.argv) > 1 and sys.argv[1] == "write-password":
372 wps_write_password_tag(clf)
373 raise SystemExit
374
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800375 while True:
376 print "Waiting for a tag or peer to be touched"
377
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800378 tag = find_peer(clf)
379 if isinstance(tag, nfc.DEP):
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800380 if arg_uuid is None:
381 wps_handover_init(tag)
382 elif arg_uuid is "ap":
383 wps_handover_resp(tag, None)
384 else:
385 wps_handover_resp(tag, arg_uuid)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800386 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800387
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800388 if tag.ndef:
389 wps_tag_read(tag)
390 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800391
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800392 print "Not an NDEF tag - remove tag"
393 while tag.is_present:
394 time.sleep(0.1)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800395
396 except KeyboardInterrupt:
397 raise SystemExit
398 finally:
399 clf.close()
400
401 raise SystemExit
402
403if __name__ == '__main__':
404 main()