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