]>
Commit | Line | Data |
---|---|---|
ad08c363 JM |
1 | /* |
2 | * Wi-Fi Protected Setup - common functionality | |
120158cc | 3 | * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> |
ad08c363 JM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "common.h" | |
03da66bd JM |
18 | #include "crypto/aes_wrap.h" |
19 | #include "crypto/crypto.h" | |
20 | #include "crypto/dh_group5.h" | |
21 | #include "crypto/sha1.h" | |
22 | #include "crypto/sha256.h" | |
ad08c363 | 23 | #include "wps_i.h" |
c0d041d9 | 24 | #include "wps_dev_attr.h" |
ad08c363 JM |
25 | |
26 | ||
eb76b7e3 JM |
27 | void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, |
28 | const char *label, u8 *res, size_t res_len) | |
ad08c363 JM |
29 | { |
30 | u8 i_buf[4], key_bits[4]; | |
eb76b7e3 JM |
31 | const u8 *addr[4]; |
32 | size_t len[4]; | |
ad08c363 JM |
33 | int i, iter; |
34 | u8 hash[SHA256_MAC_LEN], *opos; | |
35 | size_t left; | |
36 | ||
37 | WPA_PUT_BE32(key_bits, res_len * 8); | |
38 | ||
39 | addr[0] = i_buf; | |
40 | len[0] = sizeof(i_buf); | |
eb76b7e3 JM |
41 | addr[1] = label_prefix; |
42 | len[1] = label_prefix_len; | |
43 | addr[2] = (const u8 *) label; | |
44 | len[2] = os_strlen(label); | |
45 | addr[3] = key_bits; | |
46 | len[3] = sizeof(key_bits); | |
ad08c363 JM |
47 | |
48 | iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; | |
49 | opos = res; | |
50 | left = res_len; | |
51 | ||
52 | for (i = 1; i <= iter; i++) { | |
53 | WPA_PUT_BE32(i_buf, i); | |
eb76b7e3 | 54 | hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); |
ad08c363 JM |
55 | if (i < iter) { |
56 | os_memcpy(opos, hash, SHA256_MAC_LEN); | |
57 | opos += SHA256_MAC_LEN; | |
58 | left -= SHA256_MAC_LEN; | |
59 | } else | |
60 | os_memcpy(opos, hash, left); | |
61 | } | |
62 | } | |
63 | ||
64 | ||
ad08c363 JM |
65 | int wps_derive_keys(struct wps_data *wps) |
66 | { | |
67 | struct wpabuf *pubkey, *dh_shared; | |
68 | u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; | |
69 | const u8 *addr[3]; | |
70 | size_t len[3]; | |
71 | u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; | |
72 | ||
73 | if (wps->dh_privkey == NULL) { | |
74 | wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); | |
75 | return -1; | |
76 | } | |
77 | ||
78 | pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; | |
79 | if (pubkey == NULL) { | |
80 | wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); | |
81 | return -1; | |
82 | } | |
83 | ||
f042122a JM |
84 | dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); |
85 | dh5_free(wps->dh_ctx); | |
86 | wps->dh_ctx = NULL; | |
b3ddab21 | 87 | dh_shared = wpabuf_zeropad(dh_shared, 192); |
ad08c363 JM |
88 | if (dh_shared == NULL) { |
89 | wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); | |
90 | return -1; | |
91 | } | |
92 | ||
93 | /* Own DH private key is not needed anymore */ | |
94 | wpabuf_free(wps->dh_privkey); | |
95 | wps->dh_privkey = NULL; | |
96 | ||
97 | wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); | |
98 | ||
99 | /* DHKey = SHA-256(g^AB mod p) */ | |
100 | addr[0] = wpabuf_head(dh_shared); | |
101 | len[0] = wpabuf_len(dh_shared); | |
102 | sha256_vector(1, addr, len, dhkey); | |
103 | wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); | |
104 | wpabuf_free(dh_shared); | |
105 | ||
106 | /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ | |
107 | addr[0] = wps->nonce_e; | |
108 | len[0] = WPS_NONCE_LEN; | |
109 | addr[1] = wps->mac_addr_e; | |
110 | len[1] = ETH_ALEN; | |
111 | addr[2] = wps->nonce_r; | |
112 | len[2] = WPS_NONCE_LEN; | |
113 | hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); | |
114 | wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); | |
115 | ||
eb76b7e3 | 116 | wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", |
ad08c363 JM |
117 | keys, sizeof(keys)); |
118 | os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); | |
119 | os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); | |
120 | os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, | |
121 | WPS_EMSK_LEN); | |
122 | ||
123 | wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", | |
124 | wps->authkey, WPS_AUTHKEY_LEN); | |
125 | wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", | |
126 | wps->keywrapkey, WPS_KEYWRAPKEY_LEN); | |
127 | wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | ||
ad08c363 JM |
133 | void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, |
134 | size_t dev_passwd_len) | |
135 | { | |
136 | u8 hash[SHA256_MAC_LEN]; | |
137 | ||
138 | hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, | |
139 | (dev_passwd_len + 1) / 2, hash); | |
140 | os_memcpy(wps->psk1, hash, WPS_PSK_LEN); | |
141 | hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, | |
142 | dev_passwd + (dev_passwd_len + 1) / 2, | |
143 | dev_passwd_len / 2, hash); | |
144 | os_memcpy(wps->psk2, hash, WPS_PSK_LEN); | |
145 | ||
146 | wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", | |
147 | dev_passwd, dev_passwd_len); | |
148 | wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); | |
149 | wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); | |
150 | } | |
151 | ||
152 | ||
153 | struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, | |
154 | size_t encr_len) | |
155 | { | |
156 | struct wpabuf *decrypted; | |
157 | const size_t block_size = 16; | |
158 | size_t i; | |
159 | u8 pad; | |
160 | const u8 *pos; | |
161 | ||
162 | /* AES-128-CBC */ | |
163 | if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) | |
164 | { | |
165 | wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); | |
166 | return NULL; | |
167 | } | |
168 | ||
169 | decrypted = wpabuf_alloc(encr_len - block_size); | |
170 | if (decrypted == NULL) | |
171 | return NULL; | |
172 | ||
173 | wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); | |
174 | wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); | |
175 | if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), | |
176 | wpabuf_len(decrypted))) { | |
177 | wpabuf_free(decrypted); | |
178 | return NULL; | |
179 | } | |
180 | ||
181 | wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", | |
182 | decrypted); | |
183 | ||
184 | pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; | |
185 | pad = *pos; | |
186 | if (pad > wpabuf_len(decrypted)) { | |
187 | wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); | |
188 | wpabuf_free(decrypted); | |
189 | return NULL; | |
190 | } | |
191 | for (i = 0; i < pad; i++) { | |
192 | if (*pos-- != pad) { | |
193 | wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " | |
194 | "string"); | |
195 | wpabuf_free(decrypted); | |
196 | return NULL; | |
197 | } | |
198 | } | |
199 | decrypted->used -= pad; | |
200 | ||
201 | return decrypted; | |
202 | } | |
e05716d0 JM |
203 | |
204 | ||
205 | /** | |
206 | * wps_pin_checksum - Compute PIN checksum | |
207 | * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) | |
208 | * Returns: Checksum digit | |
209 | */ | |
210 | unsigned int wps_pin_checksum(unsigned int pin) | |
211 | { | |
212 | unsigned int accum = 0; | |
213 | while (pin) { | |
214 | accum += 3 * (pin % 10); | |
215 | pin /= 10; | |
216 | accum += pin % 10; | |
217 | pin /= 10; | |
218 | } | |
219 | ||
220 | return (10 - accum % 10) % 10; | |
221 | } | |
222 | ||
223 | ||
224 | /** | |
225 | * wps_pin_valid - Check whether a PIN has a valid checksum | |
226 | * @pin: Eight digit PIN (i.e., including the checksum digit) | |
227 | * Returns: 1 if checksum digit is valid, or 0 if not | |
228 | */ | |
229 | unsigned int wps_pin_valid(unsigned int pin) | |
230 | { | |
231 | return wps_pin_checksum(pin / 10) == (pin % 10); | |
232 | } | |
233 | ||
234 | ||
235 | /** | |
236 | * wps_generate_pin - Generate a random PIN | |
237 | * Returns: Eight digit PIN (i.e., including the checksum digit) | |
238 | */ | |
239 | unsigned int wps_generate_pin(void) | |
240 | { | |
241 | unsigned int val; | |
242 | ||
243 | /* Generate seven random digits for the PIN */ | |
244 | if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) { | |
245 | struct os_time now; | |
246 | os_get_time(&now); | |
247 | val = os_random() ^ now.sec ^ now.usec; | |
248 | } | |
249 | val %= 10000000; | |
250 | ||
251 | /* Append checksum digit */ | |
252 | return val * 10 + wps_pin_checksum(val); | |
253 | } | |
469fc3a4 JM |
254 | |
255 | ||
256 | void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg) | |
257 | { | |
258 | union wps_event_data data; | |
259 | ||
260 | if (wps->event_cb == NULL) | |
261 | return; | |
262 | ||
263 | os_memset(&data, 0, sizeof(data)); | |
264 | data.fail.msg = msg; | |
265 | wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); | |
266 | } | |
ad5302a1 JM |
267 | |
268 | ||
269 | void wps_success_event(struct wps_context *wps) | |
270 | { | |
271 | if (wps->event_cb == NULL) | |
272 | return; | |
273 | ||
274 | wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); | |
275 | } | |
3b2cf800 JM |
276 | |
277 | ||
278 | void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part) | |
279 | { | |
280 | union wps_event_data data; | |
281 | ||
282 | if (wps->event_cb == NULL) | |
283 | return; | |
284 | ||
285 | os_memset(&data, 0, sizeof(data)); | |
286 | data.pwd_auth_fail.enrollee = enrollee; | |
287 | data.pwd_auth_fail.part = part; | |
288 | wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); | |
289 | } | |
46bdb83a MH |
290 | |
291 | ||
63330c68 OK |
292 | void wps_pbc_overlap_event(struct wps_context *wps) |
293 | { | |
294 | if (wps->event_cb == NULL) | |
295 | return; | |
296 | ||
297 | wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); | |
298 | } | |
299 | ||
300 | ||
301 | void wps_pbc_timeout_event(struct wps_context *wps) | |
302 | { | |
303 | if (wps->event_cb == NULL) | |
304 | return; | |
305 | ||
306 | wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); | |
307 | } | |
308 | ||
309 | ||
116f7bb0 JM |
310 | #ifdef CONFIG_WPS_OOB |
311 | ||
46bdb83a MH |
312 | static struct wpabuf * wps_get_oob_cred(struct wps_context *wps) |
313 | { | |
314 | struct wps_data data; | |
315 | struct wpabuf *plain; | |
316 | ||
317 | plain = wpabuf_alloc(500); | |
318 | if (plain == NULL) { | |
319 | wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " | |
320 | "credential"); | |
321 | return NULL; | |
322 | } | |
323 | ||
324 | os_memset(&data, 0, sizeof(data)); | |
325 | data.wps = wps; | |
326 | data.auth_type = wps->auth_types; | |
327 | data.encr_type = wps->encr_types; | |
328 | if (wps_build_version(plain) || wps_build_cred(&data, plain)) { | |
329 | wpabuf_free(plain); | |
330 | return NULL; | |
331 | } | |
332 | ||
333 | return plain; | |
334 | } | |
335 | ||
336 | ||
337 | static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps) | |
338 | { | |
339 | struct wpabuf *data; | |
340 | ||
341 | data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); | |
342 | if (data == NULL) { | |
343 | wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " | |
344 | "device password attribute"); | |
345 | return NULL; | |
346 | } | |
347 | ||
348 | wpabuf_free(wps->oob_conf.dev_password); | |
349 | wps->oob_conf.dev_password = | |
350 | wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); | |
351 | if (wps->oob_conf.dev_password == NULL) { | |
352 | wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " | |
353 | "device password"); | |
354 | wpabuf_free(data); | |
355 | return NULL; | |
356 | } | |
357 | ||
358 | if (wps_build_version(data) || | |
359 | wps_build_oob_dev_password(data, wps)) { | |
360 | wpa_printf(MSG_ERROR, "WPS: Build OOB device password " | |
361 | "attribute error"); | |
362 | wpabuf_free(data); | |
363 | return NULL; | |
364 | } | |
365 | ||
366 | return data; | |
367 | } | |
368 | ||
369 | ||
370 | static int wps_parse_oob_dev_pwd(struct wps_context *wps, | |
371 | struct wpabuf *data) | |
372 | { | |
373 | struct oob_conf_data *oob_conf = &wps->oob_conf; | |
374 | struct wps_parse_attr attr; | |
375 | const u8 *pos; | |
376 | ||
377 | if (wps_parse_msg(data, &attr) < 0 || | |
378 | attr.oob_dev_password == NULL) { | |
379 | wpa_printf(MSG_ERROR, "WPS: OOB device password not found"); | |
380 | return -1; | |
381 | } | |
382 | ||
383 | pos = attr.oob_dev_password; | |
384 | ||
385 | oob_conf->pubkey_hash = | |
386 | wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN); | |
387 | if (oob_conf->pubkey_hash == NULL) { | |
388 | wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " | |
389 | "public key hash"); | |
390 | return -1; | |
391 | } | |
392 | pos += WPS_OOB_PUBKEY_HASH_LEN; | |
393 | ||
394 | wps->oob_dev_pw_id = WPA_GET_BE16(pos); | |
395 | pos += sizeof(wps->oob_dev_pw_id); | |
396 | ||
397 | oob_conf->dev_password = | |
398 | wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); | |
399 | if (oob_conf->dev_password == NULL) { | |
400 | wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " | |
401 | "device password"); | |
402 | return -1; | |
403 | } | |
404 | wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password, | |
405 | wpabuf_size(oob_conf->dev_password)), | |
406 | wpabuf_size(oob_conf->dev_password), pos, | |
407 | WPS_OOB_DEVICE_PASSWORD_LEN); | |
408 | ||
409 | return 0; | |
410 | } | |
411 | ||
412 | ||
413 | static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) | |
414 | { | |
415 | struct wpabuf msg; | |
416 | struct wps_parse_attr attr; | |
417 | size_t i; | |
418 | ||
419 | if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { | |
420 | wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); | |
421 | return -1; | |
422 | } | |
423 | ||
424 | for (i = 0; i < attr.num_cred; i++) { | |
425 | struct wps_credential local_cred; | |
426 | struct wps_parse_attr cattr; | |
427 | ||
428 | os_memset(&local_cred, 0, sizeof(local_cred)); | |
429 | wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]); | |
430 | if (wps_parse_msg(&msg, &cattr) < 0 || | |
431 | wps_process_cred(&cattr, &local_cred)) { | |
432 | wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " | |
433 | "credential"); | |
434 | return -1; | |
435 | } | |
436 | wps->cred_cb(wps->cb_ctx, &local_cred); | |
437 | } | |
438 | ||
439 | return 0; | |
440 | } | |
441 | ||
442 | ||
7cbf51bb JM |
443 | int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, |
444 | int registrar) | |
46bdb83a | 445 | { |
46bdb83a MH |
446 | struct wpabuf *data; |
447 | int ret, write_f, oob_method = wps->oob_conf.oob_method; | |
70e07046 | 448 | void *oob_priv; |
46bdb83a MH |
449 | |
450 | write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar; | |
451 | ||
7cbf51bb | 452 | oob_priv = oob_dev->init_func(wps, oob_dev, registrar); |
70e07046 | 453 | if (oob_priv == NULL) { |
46bdb83a MH |
454 | wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device"); |
455 | return -1; | |
456 | } | |
457 | ||
458 | if (write_f) { | |
459 | if (oob_method == OOB_METHOD_CRED) | |
460 | data = wps_get_oob_cred(wps); | |
461 | else | |
462 | data = wps_get_oob_dev_pwd(wps); | |
463 | ||
464 | ret = 0; | |
7cbf51bb | 465 | if (data == NULL || oob_dev->write_func(oob_priv, data) < 0) |
46bdb83a MH |
466 | ret = -1; |
467 | } else { | |
70e07046 | 468 | data = oob_dev->read_func(oob_priv); |
fe23eb56 MH |
469 | if (data == NULL) |
470 | ret = -1; | |
471 | else { | |
472 | if (oob_method == OOB_METHOD_CRED) | |
473 | ret = wps_parse_oob_cred(wps, data); | |
474 | else | |
475 | ret = wps_parse_oob_dev_pwd(wps, data); | |
70e07046 | 476 | } |
46bdb83a MH |
477 | } |
478 | wpabuf_free(data); | |
fe23eb56 MH |
479 | oob_dev->deinit_func(oob_priv); |
480 | ||
46bdb83a MH |
481 | if (ret < 0) { |
482 | wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data"); | |
483 | return -1; | |
484 | } | |
485 | ||
46bdb83a MH |
486 | return 0; |
487 | } | |
488 | ||
489 | ||
490 | struct oob_device_data * wps_get_oob_device(char *device_type) | |
491 | { | |
390cd310 | 492 | #ifdef CONFIG_WPS_UFD |
46bdb83a MH |
493 | if (os_strstr(device_type, "ufd") != NULL) |
494 | return &oob_ufd_device_data; | |
390cd310 | 495 | #endif /* CONFIG_WPS_UFD */ |
e1ee6b60 MH |
496 | #ifdef CONFIG_WPS_NFC |
497 | if (os_strstr(device_type, "nfc") != NULL) | |
498 | return &oob_nfc_device_data; | |
499 | #endif /* CONFIG_WPS_NFC */ | |
46bdb83a MH |
500 | |
501 | return NULL; | |
502 | } | |
503 | ||
504 | ||
e1ee6b60 MH |
505 | #ifdef CONFIG_WPS_NFC |
506 | struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name) | |
507 | { | |
508 | if (device_name == NULL) | |
509 | return NULL; | |
510 | #ifdef CONFIG_WPS_NFC_PN531 | |
511 | if (os_strstr(device_name, "pn531") != NULL) | |
512 | return &oob_nfc_pn531_device_data; | |
513 | #endif /* CONFIG_WPS_NFC_PN531 */ | |
514 | ||
515 | return NULL; | |
516 | } | |
517 | #endif /* CONFIG_WPS_NFC */ | |
518 | ||
519 | ||
46bdb83a MH |
520 | int wps_get_oob_method(char *method) |
521 | { | |
522 | if (os_strstr(method, "pin-e") != NULL) | |
523 | return OOB_METHOD_DEV_PWD_E; | |
524 | if (os_strstr(method, "pin-r") != NULL) | |
525 | return OOB_METHOD_DEV_PWD_R; | |
526 | if (os_strstr(method, "cred") != NULL) | |
527 | return OOB_METHOD_CRED; | |
528 | return OOB_METHOD_UNKNOWN; | |
529 | } | |
116f7bb0 JM |
530 | |
531 | #endif /* CONFIG_WPS_OOB */ | |
96750ea5 JM |
532 | |
533 | ||
534 | int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]) | |
535 | { | |
536 | const char *pos; | |
537 | ||
538 | /* <categ>-<OUI>-<subcateg> */ | |
539 | WPA_PUT_BE16(dev_type, atoi(str)); | |
540 | pos = os_strchr(str, '-'); | |
541 | if (pos == NULL) | |
542 | return -1; | |
543 | pos++; | |
544 | if (hexstr2bin(pos, &dev_type[2], 4)) | |
545 | return -1; | |
546 | pos = os_strchr(pos, '-'); | |
547 | if (pos == NULL) | |
548 | return -1; | |
549 | pos++; | |
550 | WPA_PUT_BE16(&dev_type[6], atoi(pos)); | |
551 | ||
552 | ||
553 | return 0; | |
554 | } | |
555 | ||
556 | ||
557 | char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, | |
558 | size_t buf_len) | |
559 | { | |
560 | int ret; | |
561 | ||
562 | ret = os_snprintf(buf, buf_len, "%u-%08X-%u", | |
563 | WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), | |
564 | WPA_GET_BE16(&dev_type[6])); | |
565 | if (ret < 0 || (unsigned int) ret >= buf_len) | |
566 | return NULL; | |
567 | ||
568 | return buf; | |
569 | } | |
120158cc JM |
570 | |
571 | ||
572 | void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) | |
573 | { | |
574 | const u8 *addr[2]; | |
575 | size_t len[2]; | |
576 | u8 hash[SHA1_MAC_LEN]; | |
577 | u8 nsid[16] = { | |
578 | 0x52, 0x64, 0x80, 0xf8, | |
579 | 0xc9, 0x9b, | |
580 | 0x4b, 0xe5, | |
581 | 0xa6, 0x55, | |
582 | 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 | |
583 | }; | |
584 | ||
585 | addr[0] = nsid; | |
586 | len[0] = sizeof(nsid); | |
587 | addr[1] = mac_addr; | |
588 | len[1] = 6; | |
589 | sha1_vector(2, addr, len, hash); | |
590 | os_memcpy(uuid, hash, 16); | |
591 | ||
592 | /* Version: 5 = named-based version using SHA-1 */ | |
593 | uuid[6] = (5 << 4) | (uuid[6] & 0x0f); | |
594 | ||
595 | /* Variant specified in RFC 4122 */ | |
596 | uuid[8] = 0x80 | (uuid[8] & 0x3f); | |
597 | } |