wps_attr_parse.c revision 189251
1189251Ssam/*
2189251Ssam * Wi-Fi Protected Setup - attribute parsing
3189251Ssam * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "common.h"
18189251Ssam#include "wps_i.h"
19189251Ssam
20189251Ssam
21189251Ssamstatic int wps_set_attr(struct wps_parse_attr *attr, u16 type,
22189251Ssam			const u8 *pos, u16 len)
23189251Ssam{
24189251Ssam	switch (type) {
25189251Ssam	case ATTR_VERSION:
26189251Ssam		if (len != 1) {
27189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
28189251Ssam				   len);
29189251Ssam			return -1;
30189251Ssam		}
31189251Ssam		attr->version = pos;
32189251Ssam		break;
33189251Ssam	case ATTR_MSG_TYPE:
34189251Ssam		if (len != 1) {
35189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
36189251Ssam				   "length %u", len);
37189251Ssam			return -1;
38189251Ssam		}
39189251Ssam		attr->msg_type = pos;
40189251Ssam		break;
41189251Ssam	case ATTR_ENROLLEE_NONCE:
42189251Ssam		if (len != WPS_NONCE_LEN) {
43189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
44189251Ssam				   "length %u", len);
45189251Ssam			return -1;
46189251Ssam		}
47189251Ssam		attr->enrollee_nonce = pos;
48189251Ssam		break;
49189251Ssam	case ATTR_REGISTRAR_NONCE:
50189251Ssam		if (len != WPS_NONCE_LEN) {
51189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
52189251Ssam				   "length %u", len);
53189251Ssam			return -1;
54189251Ssam		}
55189251Ssam		attr->registrar_nonce = pos;
56189251Ssam		break;
57189251Ssam	case ATTR_UUID_E:
58189251Ssam		if (len != WPS_UUID_LEN) {
59189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
60189251Ssam				   len);
61189251Ssam			return -1;
62189251Ssam		}
63189251Ssam		attr->uuid_e = pos;
64189251Ssam		break;
65189251Ssam	case ATTR_UUID_R:
66189251Ssam		if (len != WPS_UUID_LEN) {
67189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
68189251Ssam				   len);
69189251Ssam			return -1;
70189251Ssam		}
71189251Ssam		attr->uuid_r = pos;
72189251Ssam		break;
73189251Ssam	case ATTR_AUTH_TYPE_FLAGS:
74189251Ssam		if (len != 2) {
75189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
76189251Ssam				   "Type Flags length %u", len);
77189251Ssam			return -1;
78189251Ssam		}
79189251Ssam		attr->auth_type_flags = pos;
80189251Ssam		break;
81189251Ssam	case ATTR_ENCR_TYPE_FLAGS:
82189251Ssam		if (len != 2) {
83189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
84189251Ssam				   "Flags length %u", len);
85189251Ssam			return -1;
86189251Ssam		}
87189251Ssam		attr->encr_type_flags = pos;
88189251Ssam		break;
89189251Ssam	case ATTR_CONN_TYPE_FLAGS:
90189251Ssam		if (len != 1) {
91189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
92189251Ssam				   "Flags length %u", len);
93189251Ssam			return -1;
94189251Ssam		}
95189251Ssam		attr->conn_type_flags = pos;
96189251Ssam		break;
97189251Ssam	case ATTR_CONFIG_METHODS:
98189251Ssam		if (len != 2) {
99189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
100189251Ssam				   "length %u", len);
101189251Ssam			return -1;
102189251Ssam		}
103189251Ssam		attr->config_methods = pos;
104189251Ssam		break;
105189251Ssam	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
106189251Ssam		if (len != 2) {
107189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
108189251Ssam				   "Registrar Config Methods length %u", len);
109189251Ssam			return -1;
110189251Ssam		}
111189251Ssam		attr->sel_reg_config_methods = pos;
112189251Ssam		break;
113189251Ssam	case ATTR_PRIMARY_DEV_TYPE:
114189251Ssam		if (len != sizeof(struct wps_dev_type)) {
115189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
116189251Ssam				   "Type length %u", len);
117189251Ssam			return -1;
118189251Ssam		}
119189251Ssam		attr->primary_dev_type = pos;
120189251Ssam		break;
121189251Ssam	case ATTR_RF_BANDS:
122189251Ssam		if (len != 1) {
123189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
124189251Ssam				   "%u", len);
125189251Ssam			return -1;
126189251Ssam		}
127189251Ssam		attr->rf_bands = pos;
128189251Ssam		break;
129189251Ssam	case ATTR_ASSOC_STATE:
130189251Ssam		if (len != 2) {
131189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
132189251Ssam				   "length %u", len);
133189251Ssam			return -1;
134189251Ssam		}
135189251Ssam		attr->assoc_state = pos;
136189251Ssam		break;
137189251Ssam	case ATTR_CONFIG_ERROR:
138189251Ssam		if (len != 2) {
139189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
140189251Ssam				   "Error length %u", len);
141189251Ssam			return -1;
142189251Ssam		}
143189251Ssam		attr->config_error = pos;
144189251Ssam		break;
145189251Ssam	case ATTR_DEV_PASSWORD_ID:
146189251Ssam		if (len != 2) {
147189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
148189251Ssam				   "ID length %u", len);
149189251Ssam			return -1;
150189251Ssam		}
151189251Ssam		attr->dev_password_id = pos;
152189251Ssam		break;
153189251Ssam	case ATTR_OS_VERSION:
154189251Ssam		if (len != 4) {
155189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
156189251Ssam				   "%u", len);
157189251Ssam			return -1;
158189251Ssam		}
159189251Ssam		attr->os_version = pos;
160189251Ssam		break;
161189251Ssam	case ATTR_WPS_STATE:
162189251Ssam		if (len != 1) {
163189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
164189251Ssam				   "Setup State length %u", len);
165189251Ssam			return -1;
166189251Ssam		}
167189251Ssam		attr->wps_state = pos;
168189251Ssam		break;
169189251Ssam	case ATTR_AUTHENTICATOR:
170189251Ssam		if (len != WPS_AUTHENTICATOR_LEN) {
171189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
172189251Ssam				   "length %u", len);
173189251Ssam			return -1;
174189251Ssam		}
175189251Ssam		attr->authenticator = pos;
176189251Ssam		break;
177189251Ssam	case ATTR_R_HASH1:
178189251Ssam		if (len != WPS_HASH_LEN) {
179189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
180189251Ssam				   len);
181189251Ssam			return -1;
182189251Ssam		}
183189251Ssam		attr->r_hash1 = pos;
184189251Ssam		break;
185189251Ssam	case ATTR_R_HASH2:
186189251Ssam		if (len != WPS_HASH_LEN) {
187189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
188189251Ssam				   len);
189189251Ssam			return -1;
190189251Ssam		}
191189251Ssam		attr->r_hash2 = pos;
192189251Ssam		break;
193189251Ssam	case ATTR_E_HASH1:
194189251Ssam		if (len != WPS_HASH_LEN) {
195189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
196189251Ssam				   len);
197189251Ssam			return -1;
198189251Ssam		}
199189251Ssam		attr->e_hash1 = pos;
200189251Ssam		break;
201189251Ssam	case ATTR_E_HASH2:
202189251Ssam		if (len != WPS_HASH_LEN) {
203189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
204189251Ssam				   len);
205189251Ssam			return -1;
206189251Ssam		}
207189251Ssam		attr->e_hash2 = pos;
208189251Ssam		break;
209189251Ssam	case ATTR_R_SNONCE1:
210189251Ssam		if (len != WPS_SECRET_NONCE_LEN) {
211189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
212189251Ssam				   "%u", len);
213189251Ssam			return -1;
214189251Ssam		}
215189251Ssam		attr->r_snonce1 = pos;
216189251Ssam		break;
217189251Ssam	case ATTR_R_SNONCE2:
218189251Ssam		if (len != WPS_SECRET_NONCE_LEN) {
219189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
220189251Ssam				   "%u", len);
221189251Ssam			return -1;
222189251Ssam		}
223189251Ssam		attr->r_snonce2 = pos;
224189251Ssam		break;
225189251Ssam	case ATTR_E_SNONCE1:
226189251Ssam		if (len != WPS_SECRET_NONCE_LEN) {
227189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
228189251Ssam				   "%u", len);
229189251Ssam			return -1;
230189251Ssam		}
231189251Ssam		attr->e_snonce1 = pos;
232189251Ssam		break;
233189251Ssam	case ATTR_E_SNONCE2:
234189251Ssam		if (len != WPS_SECRET_NONCE_LEN) {
235189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
236189251Ssam				   "%u", len);
237189251Ssam			return -1;
238189251Ssam		}
239189251Ssam		attr->e_snonce2 = pos;
240189251Ssam		break;
241189251Ssam	case ATTR_KEY_WRAP_AUTH:
242189251Ssam		if (len != WPS_KWA_LEN) {
243189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
244189251Ssam				   "Authenticator length %u", len);
245189251Ssam			return -1;
246189251Ssam		}
247189251Ssam		attr->key_wrap_auth = pos;
248189251Ssam		break;
249189251Ssam	case ATTR_AUTH_TYPE:
250189251Ssam		if (len != 2) {
251189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
252189251Ssam				   "Type length %u", len);
253189251Ssam			return -1;
254189251Ssam		}
255189251Ssam		attr->auth_type = pos;
256189251Ssam		break;
257189251Ssam	case ATTR_ENCR_TYPE:
258189251Ssam		if (len != 2) {
259189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
260189251Ssam				   "Type length %u", len);
261189251Ssam			return -1;
262189251Ssam		}
263189251Ssam		attr->encr_type = pos;
264189251Ssam		break;
265189251Ssam	case ATTR_NETWORK_INDEX:
266189251Ssam		if (len != 1) {
267189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
268189251Ssam				   "length %u", len);
269189251Ssam			return -1;
270189251Ssam		}
271189251Ssam		attr->network_idx = pos;
272189251Ssam		break;
273189251Ssam	case ATTR_NETWORK_KEY_INDEX:
274189251Ssam		if (len != 1) {
275189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
276189251Ssam				   "length %u", len);
277189251Ssam			return -1;
278189251Ssam		}
279189251Ssam		attr->network_key_idx = pos;
280189251Ssam		break;
281189251Ssam	case ATTR_MAC_ADDR:
282189251Ssam		if (len != ETH_ALEN) {
283189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
284189251Ssam				   "length %u", len);
285189251Ssam			return -1;
286189251Ssam		}
287189251Ssam		attr->mac_addr = pos;
288189251Ssam		break;
289189251Ssam	case ATTR_KEY_PROVIDED_AUTO:
290189251Ssam		if (len != 1) {
291189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
292189251Ssam				   "Automatically length %u", len);
293189251Ssam			return -1;
294189251Ssam		}
295189251Ssam		attr->key_prov_auto = pos;
296189251Ssam		break;
297189251Ssam	case ATTR_802_1X_ENABLED:
298189251Ssam		if (len != 1) {
299189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
300189251Ssam				   "length %u", len);
301189251Ssam			return -1;
302189251Ssam		}
303189251Ssam		attr->dot1x_enabled = pos;
304189251Ssam		break;
305189251Ssam	case ATTR_SELECTED_REGISTRAR:
306189251Ssam		if (len != 1) {
307189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
308189251Ssam				   " length %u", len);
309189251Ssam			return -1;
310189251Ssam		}
311189251Ssam		attr->selected_registrar = pos;
312189251Ssam		break;
313189251Ssam	case ATTR_REQUEST_TYPE:
314189251Ssam		if (len != 1) {
315189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
316189251Ssam				   "length %u", len);
317189251Ssam			return -1;
318189251Ssam		}
319189251Ssam		attr->request_type = pos;
320189251Ssam		break;
321189251Ssam	case ATTR_RESPONSE_TYPE:
322189251Ssam		if (len != 1) {
323189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
324189251Ssam				   "length %u", len);
325189251Ssam			return -1;
326189251Ssam		}
327189251Ssam		attr->request_type = pos;
328189251Ssam		break;
329189251Ssam	case ATTR_MANUFACTURER:
330189251Ssam		attr->manufacturer = pos;
331189251Ssam		attr->manufacturer_len = len;
332189251Ssam		break;
333189251Ssam	case ATTR_MODEL_NAME:
334189251Ssam		attr->model_name = pos;
335189251Ssam		attr->model_name_len = len;
336189251Ssam		break;
337189251Ssam	case ATTR_MODEL_NUMBER:
338189251Ssam		attr->model_number = pos;
339189251Ssam		attr->model_number_len = len;
340189251Ssam		break;
341189251Ssam	case ATTR_SERIAL_NUMBER:
342189251Ssam		attr->serial_number = pos;
343189251Ssam		attr->serial_number_len = len;
344189251Ssam		break;
345189251Ssam	case ATTR_DEV_NAME:
346189251Ssam		attr->dev_name = pos;
347189251Ssam		attr->dev_name_len = len;
348189251Ssam		break;
349189251Ssam	case ATTR_PUBLIC_KEY:
350189251Ssam		attr->public_key = pos;
351189251Ssam		attr->public_key_len = len;
352189251Ssam		break;
353189251Ssam	case ATTR_ENCR_SETTINGS:
354189251Ssam		attr->encr_settings = pos;
355189251Ssam		attr->encr_settings_len = len;
356189251Ssam		break;
357189251Ssam	case ATTR_CRED:
358189251Ssam		if (attr->num_cred >= MAX_CRED_COUNT) {
359189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
360189251Ssam				   "attribute (max %d credentials)",
361189251Ssam				   MAX_CRED_COUNT);
362189251Ssam			break;
363189251Ssam		}
364189251Ssam		attr->cred[attr->num_cred] = pos;
365189251Ssam		attr->cred_len[attr->num_cred] = len;
366189251Ssam		attr->num_cred++;
367189251Ssam		break;
368189251Ssam	case ATTR_SSID:
369189251Ssam		attr->ssid = pos;
370189251Ssam		attr->ssid_len = len;
371189251Ssam		break;
372189251Ssam	case ATTR_NETWORK_KEY:
373189251Ssam		attr->network_key = pos;
374189251Ssam		attr->network_key_len = len;
375189251Ssam		break;
376189251Ssam	case ATTR_EAP_TYPE:
377189251Ssam		attr->eap_type = pos;
378189251Ssam		attr->eap_type_len = len;
379189251Ssam		break;
380189251Ssam	case ATTR_EAP_IDENTITY:
381189251Ssam		attr->eap_identity = pos;
382189251Ssam		attr->eap_identity_len = len;
383189251Ssam		break;
384189251Ssam	default:
385189251Ssam		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
386189251Ssam			   "len=%u", type, len);
387189251Ssam		break;
388189251Ssam	}
389189251Ssam
390189251Ssam	return 0;
391189251Ssam}
392189251Ssam
393189251Ssam
394189251Ssamint wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
395189251Ssam{
396189251Ssam	const u8 *pos, *end;
397189251Ssam	u16 type, len;
398189251Ssam
399189251Ssam	os_memset(attr, 0, sizeof(*attr));
400189251Ssam	pos = wpabuf_head(msg);
401189251Ssam	end = pos + wpabuf_len(msg);
402189251Ssam
403189251Ssam	while (pos < end) {
404189251Ssam		if (end - pos < 4) {
405189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
406189251Ssam				   "%lu bytes remaining",
407189251Ssam				   (unsigned long) (end - pos));
408189251Ssam			return -1;
409189251Ssam		}
410189251Ssam
411189251Ssam		type = WPA_GET_BE16(pos);
412189251Ssam		pos += 2;
413189251Ssam		len = WPA_GET_BE16(pos);
414189251Ssam		pos += 2;
415189251Ssam		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
416189251Ssam			   type, len);
417189251Ssam		if (len > end - pos) {
418189251Ssam			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
419189251Ssam			return -1;
420189251Ssam		}
421189251Ssam
422189251Ssam		if (wps_set_attr(attr, type, pos, len) < 0)
423189251Ssam			return -1;
424189251Ssam
425189251Ssam		pos += len;
426189251Ssam	}
427189251Ssam
428189251Ssam	return 0;
429189251Ssam}
430