xref: /freebsd/contrib/wpa/src/wps/wps_attr_parse.c (revision aa0a1e58)
1 /*
2  * Wi-Fi Protected Setup - attribute parsing
3  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
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"
18 #include "wps_i.h"
19 
20 #define WPS_WORKAROUNDS
21 
22 
23 static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
24 			const u8 *pos, u16 len)
25 {
26 	switch (type) {
27 	case ATTR_VERSION:
28 		if (len != 1) {
29 			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
30 				   len);
31 			return -1;
32 		}
33 		attr->version = pos;
34 		break;
35 	case ATTR_MSG_TYPE:
36 		if (len != 1) {
37 			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
38 				   "length %u", len);
39 			return -1;
40 		}
41 		attr->msg_type = pos;
42 		break;
43 	case ATTR_ENROLLEE_NONCE:
44 		if (len != WPS_NONCE_LEN) {
45 			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
46 				   "length %u", len);
47 			return -1;
48 		}
49 		attr->enrollee_nonce = pos;
50 		break;
51 	case ATTR_REGISTRAR_NONCE:
52 		if (len != WPS_NONCE_LEN) {
53 			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
54 				   "length %u", len);
55 			return -1;
56 		}
57 		attr->registrar_nonce = pos;
58 		break;
59 	case ATTR_UUID_E:
60 		if (len != WPS_UUID_LEN) {
61 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
62 				   len);
63 			return -1;
64 		}
65 		attr->uuid_e = pos;
66 		break;
67 	case ATTR_UUID_R:
68 		if (len != WPS_UUID_LEN) {
69 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
70 				   len);
71 			return -1;
72 		}
73 		attr->uuid_r = pos;
74 		break;
75 	case ATTR_AUTH_TYPE_FLAGS:
76 		if (len != 2) {
77 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
78 				   "Type Flags length %u", len);
79 			return -1;
80 		}
81 		attr->auth_type_flags = pos;
82 		break;
83 	case ATTR_ENCR_TYPE_FLAGS:
84 		if (len != 2) {
85 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
86 				   "Flags length %u", len);
87 			return -1;
88 		}
89 		attr->encr_type_flags = pos;
90 		break;
91 	case ATTR_CONN_TYPE_FLAGS:
92 		if (len != 1) {
93 			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
94 				   "Flags length %u", len);
95 			return -1;
96 		}
97 		attr->conn_type_flags = pos;
98 		break;
99 	case ATTR_CONFIG_METHODS:
100 		if (len != 2) {
101 			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
102 				   "length %u", len);
103 			return -1;
104 		}
105 		attr->config_methods = pos;
106 		break;
107 	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
108 		if (len != 2) {
109 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
110 				   "Registrar Config Methods length %u", len);
111 			return -1;
112 		}
113 		attr->sel_reg_config_methods = pos;
114 		break;
115 	case ATTR_PRIMARY_DEV_TYPE:
116 		if (len != WPS_DEV_TYPE_LEN) {
117 			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
118 				   "Type length %u", len);
119 			return -1;
120 		}
121 		attr->primary_dev_type = pos;
122 		break;
123 	case ATTR_RF_BANDS:
124 		if (len != 1) {
125 			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
126 				   "%u", len);
127 			return -1;
128 		}
129 		attr->rf_bands = pos;
130 		break;
131 	case ATTR_ASSOC_STATE:
132 		if (len != 2) {
133 			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
134 				   "length %u", len);
135 			return -1;
136 		}
137 		attr->assoc_state = pos;
138 		break;
139 	case ATTR_CONFIG_ERROR:
140 		if (len != 2) {
141 			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
142 				   "Error length %u", len);
143 			return -1;
144 		}
145 		attr->config_error = pos;
146 		break;
147 	case ATTR_DEV_PASSWORD_ID:
148 		if (len != 2) {
149 			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
150 				   "ID length %u", len);
151 			return -1;
152 		}
153 		attr->dev_password_id = pos;
154 		break;
155 	case ATTR_OOB_DEVICE_PASSWORD:
156 		if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
157 			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
158 				   "Password length %u", len);
159 			return -1;
160 		}
161 		attr->oob_dev_password = pos;
162 		break;
163 	case ATTR_OS_VERSION:
164 		if (len != 4) {
165 			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
166 				   "%u", len);
167 			return -1;
168 		}
169 		attr->os_version = pos;
170 		break;
171 	case ATTR_WPS_STATE:
172 		if (len != 1) {
173 			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
174 				   "Setup State length %u", len);
175 			return -1;
176 		}
177 		attr->wps_state = pos;
178 		break;
179 	case ATTR_AUTHENTICATOR:
180 		if (len != WPS_AUTHENTICATOR_LEN) {
181 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
182 				   "length %u", len);
183 			return -1;
184 		}
185 		attr->authenticator = pos;
186 		break;
187 	case ATTR_R_HASH1:
188 		if (len != WPS_HASH_LEN) {
189 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
190 				   len);
191 			return -1;
192 		}
193 		attr->r_hash1 = pos;
194 		break;
195 	case ATTR_R_HASH2:
196 		if (len != WPS_HASH_LEN) {
197 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
198 				   len);
199 			return -1;
200 		}
201 		attr->r_hash2 = pos;
202 		break;
203 	case ATTR_E_HASH1:
204 		if (len != WPS_HASH_LEN) {
205 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
206 				   len);
207 			return -1;
208 		}
209 		attr->e_hash1 = pos;
210 		break;
211 	case ATTR_E_HASH2:
212 		if (len != WPS_HASH_LEN) {
213 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
214 				   len);
215 			return -1;
216 		}
217 		attr->e_hash2 = pos;
218 		break;
219 	case ATTR_R_SNONCE1:
220 		if (len != WPS_SECRET_NONCE_LEN) {
221 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
222 				   "%u", len);
223 			return -1;
224 		}
225 		attr->r_snonce1 = pos;
226 		break;
227 	case ATTR_R_SNONCE2:
228 		if (len != WPS_SECRET_NONCE_LEN) {
229 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
230 				   "%u", len);
231 			return -1;
232 		}
233 		attr->r_snonce2 = pos;
234 		break;
235 	case ATTR_E_SNONCE1:
236 		if (len != WPS_SECRET_NONCE_LEN) {
237 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
238 				   "%u", len);
239 			return -1;
240 		}
241 		attr->e_snonce1 = pos;
242 		break;
243 	case ATTR_E_SNONCE2:
244 		if (len != WPS_SECRET_NONCE_LEN) {
245 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
246 				   "%u", len);
247 			return -1;
248 		}
249 		attr->e_snonce2 = pos;
250 		break;
251 	case ATTR_KEY_WRAP_AUTH:
252 		if (len != WPS_KWA_LEN) {
253 			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
254 				   "Authenticator length %u", len);
255 			return -1;
256 		}
257 		attr->key_wrap_auth = pos;
258 		break;
259 	case ATTR_AUTH_TYPE:
260 		if (len != 2) {
261 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
262 				   "Type length %u", len);
263 			return -1;
264 		}
265 		attr->auth_type = pos;
266 		break;
267 	case ATTR_ENCR_TYPE:
268 		if (len != 2) {
269 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
270 				   "Type length %u", len);
271 			return -1;
272 		}
273 		attr->encr_type = pos;
274 		break;
275 	case ATTR_NETWORK_INDEX:
276 		if (len != 1) {
277 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
278 				   "length %u", len);
279 			return -1;
280 		}
281 		attr->network_idx = pos;
282 		break;
283 	case ATTR_NETWORK_KEY_INDEX:
284 		if (len != 1) {
285 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
286 				   "length %u", len);
287 			return -1;
288 		}
289 		attr->network_key_idx = pos;
290 		break;
291 	case ATTR_MAC_ADDR:
292 		if (len != ETH_ALEN) {
293 			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
294 				   "length %u", len);
295 			return -1;
296 		}
297 		attr->mac_addr = pos;
298 		break;
299 	case ATTR_KEY_PROVIDED_AUTO:
300 		if (len != 1) {
301 			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
302 				   "Automatically length %u", len);
303 			return -1;
304 		}
305 		attr->key_prov_auto = pos;
306 		break;
307 	case ATTR_802_1X_ENABLED:
308 		if (len != 1) {
309 			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
310 				   "length %u", len);
311 			return -1;
312 		}
313 		attr->dot1x_enabled = pos;
314 		break;
315 	case ATTR_SELECTED_REGISTRAR:
316 		if (len != 1) {
317 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
318 				   " length %u", len);
319 			return -1;
320 		}
321 		attr->selected_registrar = pos;
322 		break;
323 	case ATTR_REQUEST_TYPE:
324 		if (len != 1) {
325 			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
326 				   "length %u", len);
327 			return -1;
328 		}
329 		attr->request_type = pos;
330 		break;
331 	case ATTR_RESPONSE_TYPE:
332 		if (len != 1) {
333 			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
334 				   "length %u", len);
335 			return -1;
336 		}
337 		attr->response_type = pos;
338 		break;
339 	case ATTR_MANUFACTURER:
340 		attr->manufacturer = pos;
341 		attr->manufacturer_len = len;
342 		break;
343 	case ATTR_MODEL_NAME:
344 		attr->model_name = pos;
345 		attr->model_name_len = len;
346 		break;
347 	case ATTR_MODEL_NUMBER:
348 		attr->model_number = pos;
349 		attr->model_number_len = len;
350 		break;
351 	case ATTR_SERIAL_NUMBER:
352 		attr->serial_number = pos;
353 		attr->serial_number_len = len;
354 		break;
355 	case ATTR_DEV_NAME:
356 		attr->dev_name = pos;
357 		attr->dev_name_len = len;
358 		break;
359 	case ATTR_PUBLIC_KEY:
360 		attr->public_key = pos;
361 		attr->public_key_len = len;
362 		break;
363 	case ATTR_ENCR_SETTINGS:
364 		attr->encr_settings = pos;
365 		attr->encr_settings_len = len;
366 		break;
367 	case ATTR_CRED:
368 		if (attr->num_cred >= MAX_CRED_COUNT) {
369 			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
370 				   "attribute (max %d credentials)",
371 				   MAX_CRED_COUNT);
372 			break;
373 		}
374 		attr->cred[attr->num_cred] = pos;
375 		attr->cred_len[attr->num_cred] = len;
376 		attr->num_cred++;
377 		break;
378 	case ATTR_SSID:
379 		attr->ssid = pos;
380 		attr->ssid_len = len;
381 		break;
382 	case ATTR_NETWORK_KEY:
383 		attr->network_key = pos;
384 		attr->network_key_len = len;
385 		break;
386 	case ATTR_EAP_TYPE:
387 		attr->eap_type = pos;
388 		attr->eap_type_len = len;
389 		break;
390 	case ATTR_EAP_IDENTITY:
391 		attr->eap_identity = pos;
392 		attr->eap_identity_len = len;
393 		break;
394 	case ATTR_AP_SETUP_LOCKED:
395 		if (len != 1) {
396 			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
397 				   "length %u", len);
398 			return -1;
399 		}
400 		attr->ap_setup_locked = pos;
401 		break;
402 	default:
403 		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
404 			   "len=%u", type, len);
405 		break;
406 	}
407 
408 	return 0;
409 }
410 
411 
412 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
413 {
414 	const u8 *pos, *end;
415 	u16 type, len;
416 
417 	os_memset(attr, 0, sizeof(*attr));
418 	pos = wpabuf_head(msg);
419 	end = pos + wpabuf_len(msg);
420 
421 	while (pos < end) {
422 		if (end - pos < 4) {
423 			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
424 				   "%lu bytes remaining",
425 				   (unsigned long) (end - pos));
426 			return -1;
427 		}
428 
429 		type = WPA_GET_BE16(pos);
430 		pos += 2;
431 		len = WPA_GET_BE16(pos);
432 		pos += 2;
433 		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
434 			   type, len);
435 		if (len > end - pos) {
436 			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
437 			return -1;
438 		}
439 
440 #ifdef WPS_WORKAROUNDS
441 		if (type == 0 && len == 0) {
442 			/*
443 			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
444 			 * end of M1. Skip those to avoid interop issues.
445 			 */
446 			int i;
447 			for (i = 0; i < end - pos; i++) {
448 				if (pos[i])
449 					break;
450 			}
451 			if (i == end - pos) {
452 				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
453 					   "unexpected message padding");
454 				break;
455 			}
456 		}
457 #endif /* WPS_WORKAROUNDS */
458 
459 		if (wps_set_attr(attr, type, pos, len) < 0)
460 			return -1;
461 
462 		pos += len;
463 	}
464 
465 	return 0;
466 }
467