/src/hostap/src/wps/wps_enrollee.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Wi-Fi Protected Setup - Enrollee |
3 | | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> |
4 | | * |
5 | | * This software may be distributed under the terms of the BSD license. |
6 | | * See README for more details. |
7 | | */ |
8 | | |
9 | | #include "includes.h" |
10 | | |
11 | | #include "common.h" |
12 | | #include "crypto/crypto.h" |
13 | | #include "crypto/sha256.h" |
14 | | #include "crypto/random.h" |
15 | | #include "wps_i.h" |
16 | | #include "wps_dev_attr.h" |
17 | | |
18 | | |
19 | | static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg) |
20 | 0 | { |
21 | 0 | u8 state; |
22 | 0 | if (wps->wps->ap) |
23 | 0 | state = wps->wps->wps_state; |
24 | 0 | else |
25 | 0 | state = WPS_STATE_NOT_CONFIGURED; |
26 | 0 | wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", |
27 | 0 | state); |
28 | 0 | wpabuf_put_be16(msg, ATTR_WPS_STATE); |
29 | 0 | wpabuf_put_be16(msg, 1); |
30 | 0 | wpabuf_put_u8(msg, state); |
31 | 0 | return 0; |
32 | 0 | } |
33 | | |
34 | | |
35 | | static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) |
36 | 0 | { |
37 | 0 | u8 *hash; |
38 | 0 | const u8 *addr[4]; |
39 | 0 | size_t len[4]; |
40 | |
|
41 | 0 | if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) |
42 | 0 | return -1; |
43 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN); |
44 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: E-S2", |
45 | 0 | wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); |
46 | |
|
47 | 0 | if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { |
48 | 0 | wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " |
49 | 0 | "E-Hash derivation"); |
50 | 0 | return -1; |
51 | 0 | } |
52 | | |
53 | 0 | wpa_printf(MSG_DEBUG, "WPS: * E-Hash1"); |
54 | 0 | wpabuf_put_be16(msg, ATTR_E_HASH1); |
55 | 0 | wpabuf_put_be16(msg, SHA256_MAC_LEN); |
56 | 0 | hash = wpabuf_put(msg, SHA256_MAC_LEN); |
57 | | /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ |
58 | 0 | addr[0] = wps->snonce; |
59 | 0 | len[0] = WPS_SECRET_NONCE_LEN; |
60 | 0 | addr[1] = wps->psk1; |
61 | 0 | len[1] = WPS_PSK_LEN; |
62 | 0 | addr[2] = wpabuf_head(wps->dh_pubkey_e); |
63 | 0 | len[2] = wpabuf_len(wps->dh_pubkey_e); |
64 | 0 | addr[3] = wpabuf_head(wps->dh_pubkey_r); |
65 | 0 | len[3] = wpabuf_len(wps->dh_pubkey_r); |
66 | 0 | hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); |
67 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); |
68 | |
|
69 | 0 | wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); |
70 | 0 | wpabuf_put_be16(msg, ATTR_E_HASH2); |
71 | 0 | wpabuf_put_be16(msg, SHA256_MAC_LEN); |
72 | 0 | hash = wpabuf_put(msg, SHA256_MAC_LEN); |
73 | | /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ |
74 | 0 | addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; |
75 | 0 | addr[1] = wps->psk2; |
76 | 0 | hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); |
77 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); |
78 | |
|
79 | 0 | return 0; |
80 | 0 | } |
81 | | |
82 | | |
83 | | static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg) |
84 | 0 | { |
85 | 0 | wpa_printf(MSG_DEBUG, "WPS: * E-SNonce1"); |
86 | 0 | wpabuf_put_be16(msg, ATTR_E_SNONCE1); |
87 | 0 | wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); |
88 | 0 | wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); |
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | | |
93 | | static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg) |
94 | 0 | { |
95 | 0 | wpa_printf(MSG_DEBUG, "WPS: * E-SNonce2"); |
96 | 0 | wpabuf_put_be16(msg, ATTR_E_SNONCE2); |
97 | 0 | wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); |
98 | 0 | wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, |
99 | 0 | WPS_SECRET_NONCE_LEN); |
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | | |
104 | | static struct wpabuf * wps_build_m1(struct wps_data *wps) |
105 | 0 | { |
106 | 0 | struct wpabuf *msg; |
107 | 0 | u16 config_methods; |
108 | 0 | u8 multi_ap_backhaul_sta = 0; |
109 | |
|
110 | 0 | if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) |
111 | 0 | return NULL; |
112 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", |
113 | 0 | wps->nonce_e, WPS_NONCE_LEN); |
114 | |
|
115 | 0 | wpa_printf(MSG_DEBUG, "WPS: Building Message M1"); |
116 | 0 | msg = wpabuf_alloc(1000); |
117 | 0 | if (msg == NULL) |
118 | 0 | return NULL; |
119 | | |
120 | 0 | config_methods = wps->wps->config_methods; |
121 | 0 | if (wps->wps->ap && !wps->pbc_in_m1 && |
122 | 0 | (wps->dev_password_len != 0 || |
123 | 0 | (config_methods & WPS_CONFIG_DISPLAY))) { |
124 | | /* |
125 | | * These are the methods that the AP supports as an Enrollee |
126 | | * for adding external Registrars, so remove PushButton. |
127 | | * |
128 | | * As a workaround for Windows 7 mechanism for probing WPS |
129 | | * capabilities from M1, leave PushButton option if no PIN |
130 | | * method is available or if WPS configuration enables PBC |
131 | | * workaround. |
132 | | */ |
133 | 0 | config_methods &= ~WPS_CONFIG_PUSHBUTTON; |
134 | 0 | config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | |
135 | 0 | WPS_CONFIG_PHY_PUSHBUTTON); |
136 | 0 | } |
137 | |
|
138 | 0 | if (wps->multi_ap_backhaul_sta) |
139 | 0 | multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA; |
140 | |
|
141 | 0 | if (wps_build_version(msg) || |
142 | 0 | wps_build_msg_type(msg, WPS_M1) || |
143 | 0 | wps_build_uuid_e(msg, wps->uuid_e) || |
144 | 0 | wps_build_mac_addr(msg, wps->mac_addr_e) || |
145 | 0 | wps_build_enrollee_nonce(wps, msg) || |
146 | 0 | wps_build_public_key(wps, msg) || |
147 | 0 | wps_build_auth_type_flags(wps, msg) || |
148 | 0 | wps_build_encr_type_flags(wps, msg) || |
149 | 0 | wps_build_conn_type_flags(wps, msg) || |
150 | 0 | wps_build_config_methods(msg, config_methods) || |
151 | 0 | wps_build_wps_state(wps, msg) || |
152 | 0 | wps_build_device_attrs(&wps->wps->dev, msg) || |
153 | 0 | wps_build_rf_bands(&wps->wps->dev, msg, |
154 | 0 | wps->wps->rf_band_cb(wps->wps->cb_ctx)) || |
155 | 0 | wps_build_assoc_state(wps, msg) || |
156 | 0 | wps_build_dev_password_id(msg, wps->dev_pw_id) || |
157 | 0 | wps_build_config_error(msg, WPS_CFG_NO_ERROR) || |
158 | 0 | wps_build_os_version(&wps->wps->dev, msg) || |
159 | 0 | wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) || |
160 | 0 | wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { |
161 | 0 | wpabuf_free(msg); |
162 | 0 | return NULL; |
163 | 0 | } |
164 | | |
165 | 0 | wps->state = RECV_M2; |
166 | 0 | return msg; |
167 | 0 | } |
168 | | |
169 | | |
170 | | static struct wpabuf * wps_build_m3(struct wps_data *wps) |
171 | 0 | { |
172 | 0 | struct wpabuf *msg; |
173 | |
|
174 | 0 | wpa_printf(MSG_DEBUG, "WPS: Building Message M3"); |
175 | |
|
176 | 0 | if (wps->dev_password == NULL) { |
177 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Device Password available"); |
178 | 0 | return NULL; |
179 | 0 | } |
180 | 0 | if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0) |
181 | 0 | return NULL; |
182 | | |
183 | 0 | if (wps->wps->ap && random_pool_ready() != 1) { |
184 | 0 | wpa_printf(MSG_INFO, |
185 | 0 | "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used"); |
186 | 0 | return NULL; |
187 | 0 | } |
188 | | |
189 | 0 | msg = wpabuf_alloc(1000); |
190 | 0 | if (msg == NULL) |
191 | 0 | return NULL; |
192 | | |
193 | 0 | if (wps_build_version(msg) || |
194 | 0 | wps_build_msg_type(msg, WPS_M3) || |
195 | 0 | wps_build_registrar_nonce(wps, msg) || |
196 | 0 | wps_build_e_hash(wps, msg) || |
197 | 0 | wps_build_wfa_ext(msg, 0, NULL, 0, 0) || |
198 | 0 | wps_build_authenticator(wps, msg)) { |
199 | 0 | wpabuf_free(msg); |
200 | 0 | return NULL; |
201 | 0 | } |
202 | | |
203 | 0 | wps->state = RECV_M4; |
204 | 0 | return msg; |
205 | 0 | } |
206 | | |
207 | | |
208 | | static struct wpabuf * wps_build_m5(struct wps_data *wps) |
209 | 0 | { |
210 | 0 | struct wpabuf *msg, *plain; |
211 | |
|
212 | 0 | wpa_printf(MSG_DEBUG, "WPS: Building Message M5"); |
213 | |
|
214 | 0 | plain = wpabuf_alloc(200); |
215 | 0 | if (plain == NULL) |
216 | 0 | return NULL; |
217 | | |
218 | 0 | msg = wpabuf_alloc(1000); |
219 | 0 | if (msg == NULL) { |
220 | 0 | wpabuf_free(plain); |
221 | 0 | return NULL; |
222 | 0 | } |
223 | | |
224 | 0 | if (wps_build_version(msg) || |
225 | 0 | wps_build_msg_type(msg, WPS_M5) || |
226 | 0 | wps_build_registrar_nonce(wps, msg) || |
227 | 0 | wps_build_e_snonce1(wps, plain) || |
228 | 0 | wps_build_key_wrap_auth(wps, plain) || |
229 | 0 | wps_build_encr_settings(wps, msg, plain) || |
230 | 0 | wps_build_wfa_ext(msg, 0, NULL, 0, 0) || |
231 | 0 | wps_build_authenticator(wps, msg)) { |
232 | 0 | wpabuf_clear_free(plain); |
233 | 0 | wpabuf_free(msg); |
234 | 0 | return NULL; |
235 | 0 | } |
236 | 0 | wpabuf_clear_free(plain); |
237 | |
|
238 | 0 | wps->state = RECV_M6; |
239 | 0 | return msg; |
240 | 0 | } |
241 | | |
242 | | |
243 | | static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg) |
244 | 0 | { |
245 | 0 | wpa_printf(MSG_DEBUG, "WPS: * SSID"); |
246 | 0 | wpabuf_put_be16(msg, ATTR_SSID); |
247 | 0 | wpabuf_put_be16(msg, wps->wps->ssid_len); |
248 | 0 | wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len); |
249 | 0 | return 0; |
250 | 0 | } |
251 | | |
252 | | |
253 | | static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg) |
254 | 0 | { |
255 | 0 | u16 auth_type = wps->wps->ap_auth_type; |
256 | | |
257 | | /* |
258 | | * Work around issues with Windows 7 WPS implementation not liking |
259 | | * multiple Authentication Type bits in M7 AP Settings attribute by |
260 | | * showing only the most secure option from current configuration. |
261 | | */ |
262 | 0 | if (auth_type & WPS_AUTH_WPA2PSK) |
263 | 0 | auth_type = WPS_AUTH_WPA2PSK; |
264 | 0 | else if (auth_type & WPS_AUTH_WPAPSK) |
265 | 0 | auth_type = WPS_AUTH_WPAPSK; |
266 | 0 | else if (auth_type & WPS_AUTH_OPEN) |
267 | 0 | auth_type = WPS_AUTH_OPEN; |
268 | |
|
269 | 0 | wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type); |
270 | 0 | wpabuf_put_be16(msg, ATTR_AUTH_TYPE); |
271 | 0 | wpabuf_put_be16(msg, 2); |
272 | 0 | wpabuf_put_be16(msg, auth_type); |
273 | 0 | return 0; |
274 | 0 | } |
275 | | |
276 | | |
277 | | static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg) |
278 | 0 | { |
279 | 0 | u16 encr_type = wps->wps->ap_encr_type; |
280 | | |
281 | | /* |
282 | | * Work around issues with Windows 7 WPS implementation not liking |
283 | | * multiple Encryption Type bits in M7 AP Settings attribute by |
284 | | * showing only the most secure option from current configuration. |
285 | | */ |
286 | 0 | if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) { |
287 | 0 | if (encr_type & WPS_ENCR_AES) |
288 | 0 | encr_type = WPS_ENCR_AES; |
289 | 0 | else if (encr_type & WPS_ENCR_TKIP) |
290 | 0 | encr_type = WPS_ENCR_TKIP; |
291 | 0 | } |
292 | |
|
293 | 0 | wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type); |
294 | 0 | wpabuf_put_be16(msg, ATTR_ENCR_TYPE); |
295 | 0 | wpabuf_put_be16(msg, 2); |
296 | 0 | wpabuf_put_be16(msg, encr_type); |
297 | 0 | return 0; |
298 | 0 | } |
299 | | |
300 | | |
301 | | static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg) |
302 | 0 | { |
303 | 0 | if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) && |
304 | 0 | wps->wps->network_key_len == 0) { |
305 | 0 | char hex[65]; |
306 | 0 | u8 psk[32]; |
307 | | /* Generate a random per-device PSK */ |
308 | 0 | if (random_pool_ready() != 1 || |
309 | 0 | random_get_bytes(psk, sizeof(psk)) < 0) { |
310 | 0 | wpa_printf(MSG_INFO, |
311 | 0 | "WPS: Could not generate random PSK"); |
312 | 0 | return -1; |
313 | 0 | } |
314 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", |
315 | 0 | psk, sizeof(psk)); |
316 | 0 | wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", |
317 | 0 | (unsigned int) wps->new_psk_len * 2); |
318 | 0 | wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk)); |
319 | 0 | wpabuf_put_be16(msg, ATTR_NETWORK_KEY); |
320 | 0 | wpabuf_put_be16(msg, sizeof(psk) * 2); |
321 | 0 | wpabuf_put_data(msg, hex, sizeof(psk) * 2); |
322 | 0 | if (wps->wps->registrar) { |
323 | 0 | wps_cb_new_psk(wps->wps->registrar, |
324 | 0 | wps->peer_dev.mac_addr, |
325 | 0 | wps->p2p_dev_addr, psk, sizeof(psk)); |
326 | 0 | } |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | 0 | wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", |
331 | 0 | (unsigned int) wps->wps->network_key_len); |
332 | 0 | wpabuf_put_be16(msg, ATTR_NETWORK_KEY); |
333 | 0 | wpabuf_put_be16(msg, wps->wps->network_key_len); |
334 | 0 | wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len); |
335 | 0 | return 0; |
336 | 0 | } |
337 | | |
338 | | |
339 | | static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg) |
340 | 0 | { |
341 | 0 | wpa_printf(MSG_DEBUG, "WPS: * MAC Address (AP BSSID)"); |
342 | 0 | wpabuf_put_be16(msg, ATTR_MAC_ADDR); |
343 | 0 | wpabuf_put_be16(msg, ETH_ALEN); |
344 | 0 | wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN); |
345 | 0 | return 0; |
346 | 0 | } |
347 | | |
348 | | |
349 | | static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain) |
350 | 0 | { |
351 | 0 | const u8 *start, *end; |
352 | 0 | int ret; |
353 | |
|
354 | 0 | if (wps->wps->ap_settings) { |
355 | 0 | wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)"); |
356 | 0 | wpabuf_put_data(plain, wps->wps->ap_settings, |
357 | 0 | wps->wps->ap_settings_len); |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | 0 | wpa_printf(MSG_DEBUG, "WPS: * AP Settings based on current configuration"); |
362 | 0 | start = wpabuf_put(plain, 0); |
363 | 0 | ret = wps_build_cred_ssid(wps, plain) || |
364 | 0 | wps_build_cred_mac_addr(wps, plain) || |
365 | 0 | wps_build_cred_auth_type(wps, plain) || |
366 | 0 | wps_build_cred_encr_type(wps, plain) || |
367 | 0 | wps_build_cred_network_key(wps, plain); |
368 | 0 | end = wpabuf_put(plain, 0); |
369 | |
|
370 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings", |
371 | 0 | start, end - start); |
372 | |
|
373 | 0 | return ret; |
374 | 0 | } |
375 | | |
376 | | |
377 | | static struct wpabuf * wps_build_m7(struct wps_data *wps) |
378 | 0 | { |
379 | 0 | struct wpabuf *msg, *plain; |
380 | |
|
381 | 0 | wpa_printf(MSG_DEBUG, "WPS: Building Message M7"); |
382 | |
|
383 | 0 | plain = wpabuf_alloc(500 + wps->wps->ap_settings_len); |
384 | 0 | if (plain == NULL) |
385 | 0 | return NULL; |
386 | | |
387 | 0 | msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len); |
388 | 0 | if (msg == NULL) { |
389 | 0 | wpabuf_free(plain); |
390 | 0 | return NULL; |
391 | 0 | } |
392 | | |
393 | 0 | if (wps_build_version(msg) || |
394 | 0 | wps_build_msg_type(msg, WPS_M7) || |
395 | 0 | wps_build_registrar_nonce(wps, msg) || |
396 | 0 | wps_build_e_snonce2(wps, plain) || |
397 | 0 | (wps->wps->ap && wps_build_ap_settings(wps, plain)) || |
398 | 0 | wps_build_key_wrap_auth(wps, plain) || |
399 | 0 | wps_build_encr_settings(wps, msg, plain) || |
400 | 0 | wps_build_wfa_ext(msg, 0, NULL, 0, 0) || |
401 | 0 | wps_build_authenticator(wps, msg)) { |
402 | 0 | wpabuf_clear_free(plain); |
403 | 0 | wpabuf_free(msg); |
404 | 0 | return NULL; |
405 | 0 | } |
406 | 0 | wpabuf_clear_free(plain); |
407 | |
|
408 | 0 | if (wps->wps->ap && wps->wps->registrar) { |
409 | | /* |
410 | | * If the Registrar is only learning our current configuration, |
411 | | * it may not continue protocol run to successful completion. |
412 | | * Store information here to make sure it remains available. |
413 | | */ |
414 | 0 | wps_device_store(wps->wps->registrar, &wps->peer_dev, |
415 | 0 | wps->uuid_r); |
416 | 0 | } |
417 | |
|
418 | 0 | wps->state = RECV_M8; |
419 | 0 | return msg; |
420 | 0 | } |
421 | | |
422 | | |
423 | | static struct wpabuf * wps_build_wsc_done(struct wps_data *wps) |
424 | 0 | { |
425 | 0 | struct wpabuf *msg; |
426 | |
|
427 | 0 | wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done"); |
428 | |
|
429 | 0 | msg = wpabuf_alloc(1000); |
430 | 0 | if (msg == NULL) |
431 | 0 | return NULL; |
432 | | |
433 | 0 | if (wps_build_version(msg) || |
434 | 0 | wps_build_msg_type(msg, WPS_WSC_DONE) || |
435 | 0 | wps_build_enrollee_nonce(wps, msg) || |
436 | 0 | wps_build_registrar_nonce(wps, msg) || |
437 | 0 | wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { |
438 | 0 | wpabuf_free(msg); |
439 | 0 | return NULL; |
440 | 0 | } |
441 | | |
442 | 0 | if (wps->wps->ap) |
443 | 0 | wps->state = RECV_ACK; |
444 | 0 | else { |
445 | 0 | wps_success_event(wps->wps, wps->peer_dev.mac_addr); |
446 | 0 | wps->state = WPS_FINISHED; |
447 | 0 | } |
448 | 0 | return msg; |
449 | 0 | } |
450 | | |
451 | | |
452 | | struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps, |
453 | | enum wsc_op_code *op_code) |
454 | 0 | { |
455 | 0 | struct wpabuf *msg; |
456 | |
|
457 | 0 | switch (wps->state) { |
458 | 0 | case SEND_M1: |
459 | 0 | msg = wps_build_m1(wps); |
460 | 0 | *op_code = WSC_MSG; |
461 | 0 | break; |
462 | 0 | case SEND_M3: |
463 | 0 | msg = wps_build_m3(wps); |
464 | 0 | *op_code = WSC_MSG; |
465 | 0 | break; |
466 | 0 | case SEND_M5: |
467 | 0 | msg = wps_build_m5(wps); |
468 | 0 | *op_code = WSC_MSG; |
469 | 0 | break; |
470 | 0 | case SEND_M7: |
471 | 0 | msg = wps_build_m7(wps); |
472 | 0 | *op_code = WSC_MSG; |
473 | 0 | break; |
474 | 0 | case RECEIVED_M2D: |
475 | 0 | if (wps->wps->ap) { |
476 | 0 | msg = wps_build_wsc_nack(wps); |
477 | 0 | *op_code = WSC_NACK; |
478 | 0 | break; |
479 | 0 | } |
480 | 0 | msg = wps_build_wsc_ack(wps); |
481 | 0 | *op_code = WSC_ACK; |
482 | 0 | if (msg) { |
483 | | /* Another M2/M2D may be received */ |
484 | 0 | wps->state = RECV_M2; |
485 | 0 | } |
486 | 0 | break; |
487 | 0 | case SEND_WSC_NACK: |
488 | 0 | msg = wps_build_wsc_nack(wps); |
489 | 0 | *op_code = WSC_NACK; |
490 | 0 | break; |
491 | 0 | case WPS_MSG_DONE: |
492 | 0 | msg = wps_build_wsc_done(wps); |
493 | 0 | *op_code = WSC_Done; |
494 | 0 | break; |
495 | 0 | default: |
496 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " |
497 | 0 | "a message", wps->state); |
498 | 0 | msg = NULL; |
499 | 0 | break; |
500 | 0 | } |
501 | | |
502 | 0 | if (*op_code == WSC_MSG && msg) { |
503 | | /* Save a copy of the last message for Authenticator derivation |
504 | | */ |
505 | 0 | wpabuf_free(wps->last_msg); |
506 | 0 | wps->last_msg = wpabuf_dup(msg); |
507 | 0 | } |
508 | |
|
509 | 0 | return msg; |
510 | 0 | } |
511 | | |
512 | | |
513 | | static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce) |
514 | 0 | { |
515 | 0 | if (r_nonce == NULL) { |
516 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); |
517 | 0 | return -1; |
518 | 0 | } |
519 | | |
520 | 0 | os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN); |
521 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", |
522 | 0 | wps->nonce_r, WPS_NONCE_LEN); |
523 | |
|
524 | 0 | return 0; |
525 | 0 | } |
526 | | |
527 | | |
528 | | static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce) |
529 | 0 | { |
530 | 0 | if (e_nonce == NULL) { |
531 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); |
532 | 0 | return -1; |
533 | 0 | } |
534 | | |
535 | 0 | if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) { |
536 | 0 | wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received"); |
537 | 0 | return -1; |
538 | 0 | } |
539 | | |
540 | 0 | return 0; |
541 | 0 | } |
542 | | |
543 | | |
544 | | static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r) |
545 | 0 | { |
546 | 0 | if (uuid_r == NULL) { |
547 | 0 | wpa_printf(MSG_DEBUG, "WPS: No UUID-R received"); |
548 | 0 | return -1; |
549 | 0 | } |
550 | | |
551 | 0 | os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN); |
552 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); |
553 | |
|
554 | 0 | return 0; |
555 | 0 | } |
556 | | |
557 | | |
558 | | static int wps_process_pubkey(struct wps_data *wps, const u8 *pk, |
559 | | size_t pk_len) |
560 | 0 | { |
561 | 0 | if (pk == NULL || pk_len == 0) { |
562 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); |
563 | 0 | return -1; |
564 | 0 | } |
565 | | |
566 | 0 | if (wps->peer_pubkey_hash_set) { |
567 | 0 | u8 hash[WPS_HASH_LEN]; |
568 | 0 | sha256_vector(1, &pk, &pk_len, hash); |
569 | 0 | if (os_memcmp_const(hash, wps->peer_pubkey_hash, |
570 | 0 | WPS_OOB_PUBKEY_HASH_LEN) != 0) { |
571 | 0 | wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch"); |
572 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Received public key", |
573 | 0 | pk, pk_len); |
574 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key " |
575 | 0 | "hash", hash, WPS_OOB_PUBKEY_HASH_LEN); |
576 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash", |
577 | 0 | wps->peer_pubkey_hash, |
578 | 0 | WPS_OOB_PUBKEY_HASH_LEN); |
579 | 0 | wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH; |
580 | 0 | return -1; |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | 0 | wpabuf_free(wps->dh_pubkey_r); |
585 | 0 | wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len); |
586 | 0 | if (wps->dh_pubkey_r == NULL) |
587 | 0 | return -1; |
588 | | |
589 | 0 | if (wps_derive_keys(wps) < 0) |
590 | 0 | return -1; |
591 | | |
592 | 0 | return 0; |
593 | 0 | } |
594 | | |
595 | | |
596 | | static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1) |
597 | 0 | { |
598 | 0 | if (r_hash1 == NULL) { |
599 | 0 | wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received"); |
600 | 0 | return -1; |
601 | 0 | } |
602 | | |
603 | 0 | os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN); |
604 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN); |
605 | |
|
606 | 0 | return 0; |
607 | 0 | } |
608 | | |
609 | | |
610 | | static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2) |
611 | 0 | { |
612 | 0 | if (r_hash2 == NULL) { |
613 | 0 | wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received"); |
614 | 0 | return -1; |
615 | 0 | } |
616 | | |
617 | 0 | os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN); |
618 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN); |
619 | |
|
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | | |
624 | | static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) |
625 | 0 | { |
626 | 0 | u8 hash[SHA256_MAC_LEN]; |
627 | 0 | const u8 *addr[4]; |
628 | 0 | size_t len[4]; |
629 | |
|
630 | 0 | if (r_snonce1 == NULL) { |
631 | 0 | wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received"); |
632 | 0 | return -1; |
633 | 0 | } |
634 | | |
635 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1, |
636 | 0 | WPS_SECRET_NONCE_LEN); |
637 | | |
638 | | /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ |
639 | 0 | addr[0] = r_snonce1; |
640 | 0 | len[0] = WPS_SECRET_NONCE_LEN; |
641 | 0 | addr[1] = wps->psk1; |
642 | 0 | len[1] = WPS_PSK_LEN; |
643 | 0 | addr[2] = wpabuf_head(wps->dh_pubkey_e); |
644 | 0 | len[2] = wpabuf_len(wps->dh_pubkey_e); |
645 | 0 | addr[3] = wpabuf_head(wps->dh_pubkey_r); |
646 | 0 | len[3] = wpabuf_len(wps->dh_pubkey_r); |
647 | 0 | hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); |
648 | |
|
649 | 0 | if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { |
650 | 0 | wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " |
651 | 0 | "not match with the pre-committed value"); |
652 | 0 | wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; |
653 | 0 | wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr); |
654 | 0 | return -1; |
655 | 0 | } |
656 | | |
657 | 0 | wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first " |
658 | 0 | "half of the device password"); |
659 | |
|
660 | 0 | return 0; |
661 | 0 | } |
662 | | |
663 | | |
664 | | static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) |
665 | 0 | { |
666 | 0 | u8 hash[SHA256_MAC_LEN]; |
667 | 0 | const u8 *addr[4]; |
668 | 0 | size_t len[4]; |
669 | |
|
670 | 0 | if (r_snonce2 == NULL) { |
671 | 0 | wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received"); |
672 | 0 | return -1; |
673 | 0 | } |
674 | | |
675 | 0 | wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2, |
676 | 0 | WPS_SECRET_NONCE_LEN); |
677 | | |
678 | | /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ |
679 | 0 | addr[0] = r_snonce2; |
680 | 0 | len[0] = WPS_SECRET_NONCE_LEN; |
681 | 0 | addr[1] = wps->psk2; |
682 | 0 | len[1] = WPS_PSK_LEN; |
683 | 0 | addr[2] = wpabuf_head(wps->dh_pubkey_e); |
684 | 0 | len[2] = wpabuf_len(wps->dh_pubkey_e); |
685 | 0 | addr[3] = wpabuf_head(wps->dh_pubkey_r); |
686 | 0 | len[3] = wpabuf_len(wps->dh_pubkey_r); |
687 | 0 | hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); |
688 | |
|
689 | 0 | if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { |
690 | 0 | wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " |
691 | 0 | "not match with the pre-committed value"); |
692 | 0 | wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; |
693 | 0 | wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr); |
694 | 0 | return -1; |
695 | 0 | } |
696 | | |
697 | 0 | wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second " |
698 | 0 | "half of the device password"); |
699 | |
|
700 | 0 | return 0; |
701 | 0 | } |
702 | | |
703 | | |
704 | | static int wps_process_cred_e(struct wps_data *wps, const u8 *cred, |
705 | | size_t cred_len, int wps2) |
706 | 0 | { |
707 | 0 | struct wps_parse_attr attr; |
708 | 0 | struct wpabuf msg; |
709 | 0 | int ret = 0; |
710 | |
|
711 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received Credential"); |
712 | 0 | os_memset(&wps->cred, 0, sizeof(wps->cred)); |
713 | 0 | wpabuf_set(&msg, cred, cred_len); |
714 | 0 | if (wps_parse_msg(&msg, &attr) < 0 || |
715 | 0 | wps_process_cred(&attr, &wps->cred)) |
716 | 0 | return -1; |
717 | | |
718 | 0 | if (!ether_addr_equal(wps->cred.mac_addr, wps->wps->dev.mac_addr)) { |
719 | 0 | wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential (" |
720 | 0 | MACSTR ") does not match with own address (" MACSTR |
721 | 0 | ")", MAC2STR(wps->cred.mac_addr), |
722 | 0 | MAC2STR(wps->wps->dev.mac_addr)); |
723 | | /* |
724 | | * In theory, this could be consider fatal error, but there are |
725 | | * number of deployed implementations using other address here |
726 | | * due to unclarity in the specification. For interoperability |
727 | | * reasons, allow this to be processed since we do not really |
728 | | * use the MAC Address information for anything. |
729 | | */ |
730 | | #ifdef CONFIG_WPS_STRICT |
731 | | if (wps2) { |
732 | | wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " |
733 | | "MAC Address in AP Settings"); |
734 | | return -1; |
735 | | } |
736 | | #endif /* CONFIG_WPS_STRICT */ |
737 | 0 | } |
738 | |
|
739 | 0 | if (!(wps->cred.encr_type & |
740 | 0 | (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { |
741 | 0 | if (wps->cred.encr_type & WPS_ENCR_WEP) { |
742 | 0 | wpa_printf(MSG_INFO, "WPS: Reject Credential " |
743 | 0 | "due to WEP configuration"); |
744 | 0 | wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; |
745 | 0 | return -2; |
746 | 0 | } |
747 | | |
748 | 0 | wpa_printf(MSG_INFO, "WPS: Reject Credential due to " |
749 | 0 | "invalid encr_type 0x%x", wps->cred.encr_type); |
750 | 0 | return -1; |
751 | 0 | } |
752 | | |
753 | 0 | if (wps->wps->cred_cb) { |
754 | 0 | wps->cred.cred_attr = cred - 4; |
755 | 0 | wps->cred.cred_attr_len = cred_len + 4; |
756 | 0 | ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); |
757 | 0 | wps->cred.cred_attr = NULL; |
758 | 0 | wps->cred.cred_attr_len = 0; |
759 | 0 | } |
760 | |
|
761 | 0 | return ret; |
762 | 0 | } |
763 | | |
764 | | |
765 | | static int wps_process_creds(struct wps_data *wps, const u8 *cred[], |
766 | | u16 cred_len[], unsigned int num_cred, int wps2) |
767 | 0 | { |
768 | 0 | size_t i; |
769 | 0 | int ok = 0; |
770 | |
|
771 | 0 | if (wps->wps->ap) |
772 | 0 | return 0; |
773 | | |
774 | 0 | if (num_cred == 0) { |
775 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Credential attributes " |
776 | 0 | "received"); |
777 | 0 | return -1; |
778 | 0 | } |
779 | | |
780 | 0 | for (i = 0; i < num_cred; i++) { |
781 | 0 | int res; |
782 | 0 | res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2); |
783 | 0 | if (res == 0) |
784 | 0 | ok++; |
785 | 0 | else if (res == -2) |
786 | 0 | wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped"); |
787 | 0 | else |
788 | 0 | return -1; |
789 | 0 | } |
790 | | |
791 | 0 | if (ok == 0) { |
792 | 0 | wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute " |
793 | 0 | "received"); |
794 | 0 | return -1; |
795 | 0 | } |
796 | | |
797 | 0 | return 0; |
798 | 0 | } |
799 | | |
800 | | |
801 | | static int wps_process_ap_settings_e(struct wps_data *wps, |
802 | | struct wps_parse_attr *attr, |
803 | | struct wpabuf *attrs, int wps2) |
804 | 0 | { |
805 | 0 | struct wps_credential cred; |
806 | 0 | int ret = 0; |
807 | |
|
808 | 0 | if (!wps->wps->ap) |
809 | 0 | return 0; |
810 | | |
811 | 0 | if (wps_process_ap_settings(attr, &cred) < 0) |
812 | 0 | return -1; |
813 | | |
814 | 0 | wpa_printf(MSG_INFO, "WPS: Received new AP configuration from " |
815 | 0 | "Registrar"); |
816 | |
|
817 | 0 | if (!ether_addr_equal(cred.mac_addr, wps->wps->dev.mac_addr)) { |
818 | 0 | wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings (" |
819 | 0 | MACSTR ") does not match with own address (" MACSTR |
820 | 0 | ")", MAC2STR(cred.mac_addr), |
821 | 0 | MAC2STR(wps->wps->dev.mac_addr)); |
822 | | /* |
823 | | * In theory, this could be consider fatal error, but there are |
824 | | * number of deployed implementations using other address here |
825 | | * due to unclarity in the specification. For interoperability |
826 | | * reasons, allow this to be processed since we do not really |
827 | | * use the MAC Address information for anything. |
828 | | */ |
829 | | #ifdef CONFIG_WPS_STRICT |
830 | | if (wps2) { |
831 | | wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " |
832 | | "MAC Address in AP Settings"); |
833 | | return -1; |
834 | | } |
835 | | #endif /* CONFIG_WPS_STRICT */ |
836 | 0 | } |
837 | |
|
838 | 0 | if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) |
839 | 0 | { |
840 | 0 | if (cred.encr_type & WPS_ENCR_WEP) { |
841 | 0 | wpa_printf(MSG_INFO, "WPS: Reject new AP settings " |
842 | 0 | "due to WEP configuration"); |
843 | 0 | wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; |
844 | 0 | return -1; |
845 | 0 | } |
846 | | |
847 | 0 | wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " |
848 | 0 | "invalid encr_type 0x%x", cred.encr_type); |
849 | 0 | return -1; |
850 | 0 | } |
851 | | |
852 | | #ifdef CONFIG_WPS_STRICT |
853 | | if (wps2) { |
854 | | if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == |
855 | | WPS_ENCR_TKIP || |
856 | | (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == |
857 | | WPS_AUTH_WPAPSK) { |
858 | | wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 " |
859 | | "AP Settings: WPA-Personal/TKIP only"); |
860 | | wps->error_indication = |
861 | | WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED; |
862 | | return -1; |
863 | | } |
864 | | } |
865 | | #endif /* CONFIG_WPS_STRICT */ |
866 | | |
867 | 0 | if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP) |
868 | 0 | { |
869 | 0 | wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " |
870 | 0 | "TKIP+AES"); |
871 | 0 | cred.encr_type |= WPS_ENCR_AES; |
872 | 0 | } |
873 | |
|
874 | 0 | if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == |
875 | 0 | WPS_AUTH_WPAPSK) { |
876 | 0 | wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " |
877 | 0 | "WPAPSK+WPA2PSK"); |
878 | 0 | cred.auth_type |= WPS_AUTH_WPA2PSK; |
879 | 0 | } |
880 | |
|
881 | | #ifdef CONFIG_NO_TKIP |
882 | | if (cred.encr_type & WPS_ENCR_TKIP) { |
883 | | wpa_printf(MSG_DEBUG, "WPS: Disable encr_type TKIP"); |
884 | | cred.encr_type &= ~WPS_ENCR_TKIP; |
885 | | } |
886 | | if (cred.auth_type & WPS_AUTH_WPAPSK) { |
887 | | wpa_printf(MSG_DEBUG, "WPS: Disable auth_type WPAPSK"); |
888 | | cred.auth_type &= ~WPS_AUTH_WPAPSK; |
889 | | } |
890 | | #endif /* CONFIG_NO_TKIP */ |
891 | |
|
892 | 0 | if (wps->wps->cred_cb) { |
893 | 0 | cred.cred_attr = wpabuf_head(attrs); |
894 | 0 | cred.cred_attr_len = wpabuf_len(attrs); |
895 | 0 | ret = wps->wps->cred_cb(wps->wps->cb_ctx, &cred); |
896 | 0 | } |
897 | |
|
898 | 0 | return ret; |
899 | 0 | } |
900 | | |
901 | | |
902 | | static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id) |
903 | 0 | { |
904 | 0 | u16 id; |
905 | |
|
906 | 0 | if (dev_pw_id == NULL) { |
907 | 0 | wpa_printf(MSG_DEBUG, "WPS: Device Password ID"); |
908 | 0 | return -1; |
909 | 0 | } |
910 | | |
911 | 0 | id = WPA_GET_BE16(dev_pw_id); |
912 | 0 | if (wps->dev_pw_id == id) { |
913 | 0 | wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id); |
914 | 0 | return 0; |
915 | 0 | } |
916 | | |
917 | 0 | #ifdef CONFIG_P2P |
918 | 0 | if ((id == DEV_PW_DEFAULT && |
919 | 0 | wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) || |
920 | 0 | (id == DEV_PW_REGISTRAR_SPECIFIED && |
921 | 0 | wps->dev_pw_id == DEV_PW_DEFAULT)) { |
922 | | /* |
923 | | * Common P2P use cases indicate whether the PIN is from the |
924 | | * client or GO using Device Password Id in M1/M2 in a way that |
925 | | * does not look fully compliant with WSC specification. Anyway, |
926 | | * this is deployed and needs to be allowed, so ignore changes |
927 | | * between Registrar-Specified and Default PIN. |
928 | | */ |
929 | 0 | wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID " |
930 | 0 | "change"); |
931 | 0 | return 0; |
932 | 0 | } |
933 | 0 | #endif /* CONFIG_P2P */ |
934 | | |
935 | 0 | wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password " |
936 | 0 | "ID from %u to %u", wps->dev_pw_id, id); |
937 | |
|
938 | 0 | if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) { |
939 | 0 | wpa_printf(MSG_DEBUG, |
940 | 0 | "WPS: Workaround - ignore PBC-to-PIN change"); |
941 | 0 | return 0; |
942 | 0 | } |
943 | | |
944 | 0 | if (wps->alt_dev_password && wps->alt_dev_pw_id == id) { |
945 | 0 | wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password"); |
946 | 0 | bin_clear_free(wps->dev_password, wps->dev_password_len); |
947 | 0 | wps->dev_pw_id = wps->alt_dev_pw_id; |
948 | 0 | wps->dev_password = wps->alt_dev_password; |
949 | 0 | wps->dev_password_len = wps->alt_dev_password_len; |
950 | 0 | wps->alt_dev_password = NULL; |
951 | 0 | wps->alt_dev_password_len = 0; |
952 | 0 | return 0; |
953 | 0 | } |
954 | | |
955 | 0 | return -1; |
956 | 0 | } |
957 | | |
958 | | |
959 | | static enum wps_process_res wps_process_m2(struct wps_data *wps, |
960 | | const struct wpabuf *msg, |
961 | | struct wps_parse_attr *attr) |
962 | 0 | { |
963 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received M2"); |
964 | |
|
965 | 0 | if (wps->state != RECV_M2) { |
966 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " |
967 | 0 | "receiving M2", wps->state); |
968 | 0 | wps->state = SEND_WSC_NACK; |
969 | 0 | return WPS_CONTINUE; |
970 | 0 | } |
971 | | |
972 | 0 | if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || |
973 | 0 | wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || |
974 | 0 | wps_process_uuid_r(wps, attr->uuid_r) || |
975 | 0 | wps_process_dev_pw_id(wps, attr->dev_password_id)) { |
976 | 0 | wps->state = SEND_WSC_NACK; |
977 | 0 | return WPS_CONTINUE; |
978 | 0 | } |
979 | | |
980 | | /* |
981 | | * Stop here on an AP as an Enrollee if AP Setup is locked unless the |
982 | | * special locked mode is used to allow protocol run up to M7 in order |
983 | | * to support external Registrars that only learn the current AP |
984 | | * configuration without changing it. |
985 | | */ |
986 | 0 | if (wps->wps->ap && |
987 | 0 | ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) || |
988 | 0 | wps->dev_password == NULL)) { |
989 | 0 | wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " |
990 | 0 | "registration of a new Registrar"); |
991 | 0 | wps->config_error = WPS_CFG_SETUP_LOCKED; |
992 | 0 | wps->state = SEND_WSC_NACK; |
993 | 0 | return WPS_CONTINUE; |
994 | 0 | } |
995 | | |
996 | 0 | if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || |
997 | 0 | wps_process_authenticator(wps, attr->authenticator, msg) || |
998 | 0 | wps_process_device_attrs(&wps->peer_dev, attr)) { |
999 | 0 | wps->state = SEND_WSC_NACK; |
1000 | 0 | return WPS_CONTINUE; |
1001 | 0 | } |
1002 | | |
1003 | 0 | #ifdef CONFIG_WPS_NFC |
1004 | 0 | if (wps->peer_pubkey_hash_set) { |
1005 | 0 | struct wpabuf *decrypted; |
1006 | 0 | struct wps_parse_attr eattr; |
1007 | |
|
1008 | 0 | decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, |
1009 | 0 | attr->encr_settings_len); |
1010 | 0 | if (decrypted == NULL) { |
1011 | 0 | wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt " |
1012 | 0 | "Encrypted Settings attribute"); |
1013 | 0 | wps->state = SEND_WSC_NACK; |
1014 | 0 | return WPS_CONTINUE; |
1015 | 0 | } |
1016 | | |
1017 | 0 | wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted " |
1018 | 0 | "Settings attribute"); |
1019 | 0 | if (wps_parse_msg(decrypted, &eattr) < 0 || |
1020 | 0 | wps_process_key_wrap_auth(wps, decrypted, |
1021 | 0 | eattr.key_wrap_auth) || |
1022 | 0 | wps_process_creds(wps, eattr.cred, eattr.cred_len, |
1023 | 0 | eattr.num_cred, attr->version2 != NULL)) { |
1024 | 0 | wpabuf_clear_free(decrypted); |
1025 | 0 | wps->state = SEND_WSC_NACK; |
1026 | 0 | return WPS_CONTINUE; |
1027 | 0 | } |
1028 | 0 | wpabuf_clear_free(decrypted); |
1029 | |
|
1030 | 0 | wps->state = WPS_MSG_DONE; |
1031 | 0 | return WPS_CONTINUE; |
1032 | 0 | } |
1033 | 0 | #endif /* CONFIG_WPS_NFC */ |
1034 | | |
1035 | 0 | wps->state = SEND_M3; |
1036 | 0 | return WPS_CONTINUE; |
1037 | 0 | } |
1038 | | |
1039 | | |
1040 | | static enum wps_process_res wps_process_m2d(struct wps_data *wps, |
1041 | | struct wps_parse_attr *attr) |
1042 | 0 | { |
1043 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received M2D"); |
1044 | |
|
1045 | 0 | if (wps->state != RECV_M2) { |
1046 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " |
1047 | 0 | "receiving M2D", wps->state); |
1048 | 0 | wps->state = SEND_WSC_NACK; |
1049 | 0 | return WPS_CONTINUE; |
1050 | 0 | } |
1051 | | |
1052 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", |
1053 | 0 | attr->manufacturer, attr->manufacturer_len); |
1054 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", |
1055 | 0 | attr->model_name, attr->model_name_len); |
1056 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", |
1057 | 0 | attr->model_number, attr->model_number_len); |
1058 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", |
1059 | 0 | attr->serial_number, attr->serial_number_len); |
1060 | 0 | wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", |
1061 | 0 | attr->dev_name, attr->dev_name_len); |
1062 | |
|
1063 | 0 | if (wps->wps->event_cb) { |
1064 | 0 | union wps_event_data data; |
1065 | 0 | struct wps_event_m2d *m2d = &data.m2d; |
1066 | 0 | os_memset(&data, 0, sizeof(data)); |
1067 | 0 | if (attr->config_methods) |
1068 | 0 | m2d->config_methods = |
1069 | 0 | WPA_GET_BE16(attr->config_methods); |
1070 | 0 | m2d->manufacturer = attr->manufacturer; |
1071 | 0 | m2d->manufacturer_len = attr->manufacturer_len; |
1072 | 0 | m2d->model_name = attr->model_name; |
1073 | 0 | m2d->model_name_len = attr->model_name_len; |
1074 | 0 | m2d->model_number = attr->model_number; |
1075 | 0 | m2d->model_number_len = attr->model_number_len; |
1076 | 0 | m2d->serial_number = attr->serial_number; |
1077 | 0 | m2d->serial_number_len = attr->serial_number_len; |
1078 | 0 | m2d->dev_name = attr->dev_name; |
1079 | 0 | m2d->dev_name_len = attr->dev_name_len; |
1080 | 0 | m2d->primary_dev_type = attr->primary_dev_type; |
1081 | 0 | if (attr->config_error) |
1082 | 0 | m2d->config_error = |
1083 | 0 | WPA_GET_BE16(attr->config_error); |
1084 | 0 | if (attr->dev_password_id) |
1085 | 0 | m2d->dev_password_id = |
1086 | 0 | WPA_GET_BE16(attr->dev_password_id); |
1087 | 0 | wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data); |
1088 | 0 | } |
1089 | |
|
1090 | 0 | wps->state = RECEIVED_M2D; |
1091 | 0 | return WPS_CONTINUE; |
1092 | 0 | } |
1093 | | |
1094 | | |
1095 | | static enum wps_process_res wps_process_m4(struct wps_data *wps, |
1096 | | const struct wpabuf *msg, |
1097 | | struct wps_parse_attr *attr) |
1098 | 0 | { |
1099 | 0 | struct wpabuf *decrypted; |
1100 | 0 | struct wps_parse_attr eattr; |
1101 | |
|
1102 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received M4"); |
1103 | |
|
1104 | 0 | if (wps->state != RECV_M4) { |
1105 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " |
1106 | 0 | "receiving M4", wps->state); |
1107 | 0 | wps->state = SEND_WSC_NACK; |
1108 | 0 | return WPS_CONTINUE; |
1109 | 0 | } |
1110 | | |
1111 | 0 | if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || |
1112 | 0 | wps_process_authenticator(wps, attr->authenticator, msg) || |
1113 | 0 | wps_process_r_hash1(wps, attr->r_hash1) || |
1114 | 0 | wps_process_r_hash2(wps, attr->r_hash2)) { |
1115 | 0 | wps->state = SEND_WSC_NACK; |
1116 | 0 | return WPS_CONTINUE; |
1117 | 0 | } |
1118 | | |
1119 | 0 | decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, |
1120 | 0 | attr->encr_settings_len); |
1121 | 0 | if (decrypted == NULL) { |
1122 | 0 | wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " |
1123 | 0 | "Settings attribute"); |
1124 | 0 | wps->state = SEND_WSC_NACK; |
1125 | 0 | return WPS_CONTINUE; |
1126 | 0 | } |
1127 | | |
1128 | 0 | if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { |
1129 | 0 | wpabuf_clear_free(decrypted); |
1130 | 0 | wps->state = SEND_WSC_NACK; |
1131 | 0 | return WPS_CONTINUE; |
1132 | 0 | } |
1133 | | |
1134 | 0 | wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " |
1135 | 0 | "attribute"); |
1136 | 0 | if (wps_parse_msg(decrypted, &eattr) < 0 || |
1137 | 0 | wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || |
1138 | 0 | wps_process_r_snonce1(wps, eattr.r_snonce1)) { |
1139 | 0 | wpabuf_clear_free(decrypted); |
1140 | 0 | wps->state = SEND_WSC_NACK; |
1141 | 0 | return WPS_CONTINUE; |
1142 | 0 | } |
1143 | 0 | wpabuf_clear_free(decrypted); |
1144 | |
|
1145 | 0 | wps->state = SEND_M5; |
1146 | 0 | return WPS_CONTINUE; |
1147 | 0 | } |
1148 | | |
1149 | | |
1150 | | static enum wps_process_res wps_process_m6(struct wps_data *wps, |
1151 | | const struct wpabuf *msg, |
1152 | | struct wps_parse_attr *attr) |
1153 | 0 | { |
1154 | 0 | struct wpabuf *decrypted; |
1155 | 0 | struct wps_parse_attr eattr; |
1156 | |
|
1157 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received M6"); |
1158 | |
|
1159 | 0 | if (wps->state != RECV_M6) { |
1160 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " |
1161 | 0 | "receiving M6", wps->state); |
1162 | 0 | wps->state = SEND_WSC_NACK; |
1163 | 0 | return WPS_CONTINUE; |
1164 | 0 | } |
1165 | | |
1166 | 0 | if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || |
1167 | 0 | wps_process_authenticator(wps, attr->authenticator, msg)) { |
1168 | 0 | wps->state = SEND_WSC_NACK; |
1169 | 0 | return WPS_CONTINUE; |
1170 | 0 | } |
1171 | | |
1172 | 0 | decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, |
1173 | 0 | attr->encr_settings_len); |
1174 | 0 | if (decrypted == NULL) { |
1175 | 0 | wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " |
1176 | 0 | "Settings attribute"); |
1177 | 0 | wps->state = SEND_WSC_NACK; |
1178 | 0 | return WPS_CONTINUE; |
1179 | 0 | } |
1180 | | |
1181 | 0 | if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { |
1182 | 0 | wpabuf_clear_free(decrypted); |
1183 | 0 | wps->state = SEND_WSC_NACK; |
1184 | 0 | return WPS_CONTINUE; |
1185 | 0 | } |
1186 | | |
1187 | 0 | wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " |
1188 | 0 | "attribute"); |
1189 | 0 | if (wps_parse_msg(decrypted, &eattr) < 0 || |
1190 | 0 | wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || |
1191 | 0 | wps_process_r_snonce2(wps, eattr.r_snonce2)) { |
1192 | 0 | wpabuf_clear_free(decrypted); |
1193 | 0 | wps->state = SEND_WSC_NACK; |
1194 | 0 | return WPS_CONTINUE; |
1195 | 0 | } |
1196 | 0 | wpabuf_clear_free(decrypted); |
1197 | |
|
1198 | 0 | if (wps->wps->ap) |
1199 | 0 | wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS, |
1200 | 0 | NULL); |
1201 | |
|
1202 | 0 | wps->state = SEND_M7; |
1203 | 0 | return WPS_CONTINUE; |
1204 | 0 | } |
1205 | | |
1206 | | |
1207 | | static enum wps_process_res wps_process_m8(struct wps_data *wps, |
1208 | | const struct wpabuf *msg, |
1209 | | struct wps_parse_attr *attr) |
1210 | 0 | { |
1211 | 0 | struct wpabuf *decrypted; |
1212 | 0 | struct wps_parse_attr eattr; |
1213 | |
|
1214 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received M8"); |
1215 | |
|
1216 | 0 | if (wps->state != RECV_M8) { |
1217 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " |
1218 | 0 | "receiving M8", wps->state); |
1219 | 0 | wps->state = SEND_WSC_NACK; |
1220 | 0 | return WPS_CONTINUE; |
1221 | 0 | } |
1222 | | |
1223 | 0 | if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || |
1224 | 0 | wps_process_authenticator(wps, attr->authenticator, msg)) { |
1225 | 0 | wps->state = SEND_WSC_NACK; |
1226 | 0 | return WPS_CONTINUE; |
1227 | 0 | } |
1228 | | |
1229 | 0 | if (wps->wps->ap && wps->wps->ap_setup_locked) { |
1230 | | /* |
1231 | | * Stop here if special ap_setup_locked == 2 mode allowed the |
1232 | | * protocol to continue beyond M2. This allows ER to learn the |
1233 | | * current AP settings without changing them. |
1234 | | */ |
1235 | 0 | wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " |
1236 | 0 | "registration of a new Registrar"); |
1237 | 0 | wps->config_error = WPS_CFG_SETUP_LOCKED; |
1238 | 0 | wps->state = SEND_WSC_NACK; |
1239 | 0 | return WPS_CONTINUE; |
1240 | 0 | } |
1241 | | |
1242 | 0 | decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, |
1243 | 0 | attr->encr_settings_len); |
1244 | 0 | if (decrypted == NULL) { |
1245 | 0 | wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " |
1246 | 0 | "Settings attribute"); |
1247 | 0 | wps->state = SEND_WSC_NACK; |
1248 | 0 | return WPS_CONTINUE; |
1249 | 0 | } |
1250 | | |
1251 | 0 | if (wps_validate_m8_encr(decrypted, wps->wps->ap, |
1252 | 0 | attr->version2 != NULL) < 0) { |
1253 | 0 | wpabuf_clear_free(decrypted); |
1254 | 0 | wps->state = SEND_WSC_NACK; |
1255 | 0 | return WPS_CONTINUE; |
1256 | 0 | } |
1257 | | |
1258 | 0 | wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " |
1259 | 0 | "attribute"); |
1260 | 0 | if (wps_parse_msg(decrypted, &eattr) < 0 || |
1261 | 0 | wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || |
1262 | 0 | wps_process_creds(wps, eattr.cred, eattr.cred_len, |
1263 | 0 | eattr.num_cred, attr->version2 != NULL) || |
1264 | 0 | wps_process_ap_settings_e(wps, &eattr, decrypted, |
1265 | 0 | attr->version2 != NULL)) { |
1266 | 0 | wpabuf_clear_free(decrypted); |
1267 | 0 | wps->state = SEND_WSC_NACK; |
1268 | 0 | return WPS_CONTINUE; |
1269 | 0 | } |
1270 | 0 | wpabuf_clear_free(decrypted); |
1271 | |
|
1272 | 0 | wps->state = WPS_MSG_DONE; |
1273 | 0 | return WPS_CONTINUE; |
1274 | 0 | } |
1275 | | |
1276 | | |
1277 | | static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, |
1278 | | const struct wpabuf *msg) |
1279 | 0 | { |
1280 | 0 | struct wps_parse_attr attr; |
1281 | 0 | enum wps_process_res ret = WPS_CONTINUE; |
1282 | |
|
1283 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); |
1284 | |
|
1285 | 0 | if (wps_parse_msg(msg, &attr) < 0) |
1286 | 0 | return WPS_FAILURE; |
1287 | | |
1288 | 0 | if (attr.enrollee_nonce == NULL || |
1289 | 0 | os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { |
1290 | 0 | wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); |
1291 | 0 | return WPS_FAILURE; |
1292 | 0 | } |
1293 | | |
1294 | 0 | if (attr.msg_type == NULL) { |
1295 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); |
1296 | 0 | wps->state = SEND_WSC_NACK; |
1297 | 0 | return WPS_CONTINUE; |
1298 | 0 | } |
1299 | | |
1300 | 0 | switch (*attr.msg_type) { |
1301 | 0 | case WPS_M2: |
1302 | 0 | if (wps_validate_m2(msg) < 0) |
1303 | 0 | return WPS_FAILURE; |
1304 | 0 | ret = wps_process_m2(wps, msg, &attr); |
1305 | 0 | break; |
1306 | 0 | case WPS_M2D: |
1307 | 0 | if (wps_validate_m2d(msg) < 0) |
1308 | 0 | return WPS_FAILURE; |
1309 | 0 | ret = wps_process_m2d(wps, &attr); |
1310 | 0 | break; |
1311 | 0 | case WPS_M4: |
1312 | 0 | if (wps_validate_m4(msg) < 0) |
1313 | 0 | return WPS_FAILURE; |
1314 | 0 | ret = wps_process_m4(wps, msg, &attr); |
1315 | 0 | if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) |
1316 | 0 | wps_fail_event(wps->wps, WPS_M4, wps->config_error, |
1317 | 0 | wps->error_indication, |
1318 | 0 | wps->peer_dev.mac_addr); |
1319 | 0 | break; |
1320 | 0 | case WPS_M6: |
1321 | 0 | if (wps_validate_m6(msg) < 0) |
1322 | 0 | return WPS_FAILURE; |
1323 | 0 | ret = wps_process_m6(wps, msg, &attr); |
1324 | 0 | if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) |
1325 | 0 | wps_fail_event(wps->wps, WPS_M6, wps->config_error, |
1326 | 0 | wps->error_indication, |
1327 | 0 | wps->peer_dev.mac_addr); |
1328 | 0 | break; |
1329 | 0 | case WPS_M8: |
1330 | 0 | if (wps_validate_m8(msg) < 0) |
1331 | 0 | return WPS_FAILURE; |
1332 | 0 | ret = wps_process_m8(wps, msg, &attr); |
1333 | 0 | if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) |
1334 | 0 | wps_fail_event(wps->wps, WPS_M8, wps->config_error, |
1335 | 0 | wps->error_indication, |
1336 | 0 | wps->peer_dev.mac_addr); |
1337 | 0 | break; |
1338 | 0 | default: |
1339 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", |
1340 | 0 | *attr.msg_type); |
1341 | 0 | return WPS_FAILURE; |
1342 | 0 | } |
1343 | | |
1344 | | /* |
1345 | | * Save a copy of the last message for Authenticator derivation if we |
1346 | | * are continuing. However, skip M2D since it is not authenticated and |
1347 | | * neither is the ACK/NACK response frame. This allows the possibly |
1348 | | * following M2 to be processed correctly by using the previously sent |
1349 | | * M1 in Authenticator derivation. |
1350 | | */ |
1351 | 0 | if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) { |
1352 | | /* Save a copy of the last message for Authenticator derivation |
1353 | | */ |
1354 | 0 | wpabuf_free(wps->last_msg); |
1355 | 0 | wps->last_msg = wpabuf_dup(msg); |
1356 | 0 | } |
1357 | |
|
1358 | 0 | return ret; |
1359 | 0 | } |
1360 | | |
1361 | | |
1362 | | static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, |
1363 | | const struct wpabuf *msg) |
1364 | 0 | { |
1365 | 0 | struct wps_parse_attr attr; |
1366 | |
|
1367 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); |
1368 | |
|
1369 | 0 | if (wps_parse_msg(msg, &attr) < 0) |
1370 | 0 | return WPS_FAILURE; |
1371 | | |
1372 | 0 | if (attr.msg_type == NULL) { |
1373 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); |
1374 | 0 | return WPS_FAILURE; |
1375 | 0 | } |
1376 | | |
1377 | 0 | if (*attr.msg_type != WPS_WSC_ACK) { |
1378 | 0 | wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", |
1379 | 0 | *attr.msg_type); |
1380 | 0 | return WPS_FAILURE; |
1381 | 0 | } |
1382 | | |
1383 | 0 | if (attr.registrar_nonce == NULL || |
1384 | 0 | os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) |
1385 | 0 | { |
1386 | 0 | wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); |
1387 | 0 | return WPS_FAILURE; |
1388 | 0 | } |
1389 | | |
1390 | 0 | if (attr.enrollee_nonce == NULL || |
1391 | 0 | os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { |
1392 | 0 | wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); |
1393 | 0 | return WPS_FAILURE; |
1394 | 0 | } |
1395 | | |
1396 | 0 | if (wps->state == RECV_ACK && wps->wps->ap) { |
1397 | 0 | wpa_printf(MSG_DEBUG, "WPS: External Registrar registration " |
1398 | 0 | "completed successfully"); |
1399 | 0 | wps_success_event(wps->wps, wps->peer_dev.mac_addr); |
1400 | 0 | wps->state = WPS_FINISHED; |
1401 | 0 | return WPS_DONE; |
1402 | 0 | } |
1403 | | |
1404 | 0 | return WPS_FAILURE; |
1405 | 0 | } |
1406 | | |
1407 | | |
1408 | | static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, |
1409 | | const struct wpabuf *msg) |
1410 | 0 | { |
1411 | 0 | struct wps_parse_attr attr; |
1412 | 0 | u16 config_error; |
1413 | |
|
1414 | 0 | wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); |
1415 | |
|
1416 | 0 | if (wps_parse_msg(msg, &attr) < 0) |
1417 | 0 | return WPS_FAILURE; |
1418 | | |
1419 | 0 | if (attr.msg_type == NULL) { |
1420 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); |
1421 | 0 | return WPS_FAILURE; |
1422 | 0 | } |
1423 | | |
1424 | 0 | if (*attr.msg_type != WPS_WSC_NACK) { |
1425 | 0 | wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", |
1426 | 0 | *attr.msg_type); |
1427 | 0 | return WPS_FAILURE; |
1428 | 0 | } |
1429 | | |
1430 | 0 | if (attr.registrar_nonce == NULL || |
1431 | 0 | os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) |
1432 | 0 | { |
1433 | 0 | wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); |
1434 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce", |
1435 | 0 | attr.registrar_nonce, WPS_NONCE_LEN); |
1436 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce", |
1437 | 0 | wps->nonce_r, WPS_NONCE_LEN); |
1438 | 0 | return WPS_FAILURE; |
1439 | 0 | } |
1440 | | |
1441 | 0 | if (attr.enrollee_nonce == NULL || |
1442 | 0 | os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { |
1443 | 0 | wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); |
1444 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce", |
1445 | 0 | attr.enrollee_nonce, WPS_NONCE_LEN); |
1446 | 0 | wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce", |
1447 | 0 | wps->nonce_e, WPS_NONCE_LEN); |
1448 | 0 | return WPS_FAILURE; |
1449 | 0 | } |
1450 | | |
1451 | 0 | if (attr.config_error == NULL) { |
1452 | 0 | wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " |
1453 | 0 | "in WSC_NACK"); |
1454 | 0 | return WPS_FAILURE; |
1455 | 0 | } |
1456 | | |
1457 | 0 | config_error = WPA_GET_BE16(attr.config_error); |
1458 | 0 | wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with " |
1459 | 0 | "Configuration Error %d", config_error); |
1460 | |
|
1461 | 0 | switch (wps->state) { |
1462 | 0 | case RECV_M4: |
1463 | 0 | wps_fail_event(wps->wps, WPS_M3, config_error, |
1464 | 0 | wps->error_indication, wps->peer_dev.mac_addr); |
1465 | 0 | break; |
1466 | 0 | case RECV_M6: |
1467 | 0 | wps_fail_event(wps->wps, WPS_M5, config_error, |
1468 | 0 | wps->error_indication, wps->peer_dev.mac_addr); |
1469 | 0 | break; |
1470 | 0 | case RECV_M8: |
1471 | 0 | wps_fail_event(wps->wps, WPS_M7, config_error, |
1472 | 0 | wps->error_indication, wps->peer_dev.mac_addr); |
1473 | 0 | break; |
1474 | 0 | default: |
1475 | 0 | break; |
1476 | 0 | } |
1477 | | |
1478 | | /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if |
1479 | | * Enrollee is Authenticator */ |
1480 | 0 | wps->state = SEND_WSC_NACK; |
1481 | |
|
1482 | 0 | return WPS_FAILURE; |
1483 | 0 | } |
1484 | | |
1485 | | |
1486 | | enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps, |
1487 | | enum wsc_op_code op_code, |
1488 | | const struct wpabuf *msg) |
1489 | 0 | { |
1490 | |
|
1491 | 0 | wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " |
1492 | 0 | "op_code=%d)", |
1493 | 0 | (unsigned long) wpabuf_len(msg), op_code); |
1494 | |
|
1495 | 0 | if (op_code == WSC_UPnP) { |
1496 | | /* Determine the OpCode based on message type attribute */ |
1497 | 0 | struct wps_parse_attr attr; |
1498 | 0 | if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { |
1499 | 0 | if (*attr.msg_type == WPS_WSC_ACK) |
1500 | 0 | op_code = WSC_ACK; |
1501 | 0 | else if (*attr.msg_type == WPS_WSC_NACK) |
1502 | 0 | op_code = WSC_NACK; |
1503 | 0 | } |
1504 | 0 | } |
1505 | |
|
1506 | 0 | switch (op_code) { |
1507 | 0 | case WSC_MSG: |
1508 | 0 | case WSC_UPnP: |
1509 | 0 | return wps_process_wsc_msg(wps, msg); |
1510 | 0 | case WSC_ACK: |
1511 | 0 | if (wps_validate_wsc_ack(msg) < 0) |
1512 | 0 | return WPS_FAILURE; |
1513 | 0 | return wps_process_wsc_ack(wps, msg); |
1514 | 0 | case WSC_NACK: |
1515 | 0 | if (wps_validate_wsc_nack(msg) < 0) |
1516 | 0 | return WPS_FAILURE; |
1517 | 0 | return wps_process_wsc_nack(wps, msg); |
1518 | 0 | default: |
1519 | 0 | wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); |
1520 | 0 | return WPS_FAILURE; |
1521 | 0 | } |
1522 | 0 | } |