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
21static 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
402int 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