]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/wpa/src/wps/wps_attr_parse.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / wpa / src / wps / wps_attr_parse.c
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 }