2 * Wi-Fi Protected Setup - attribute processing
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "crypto/sha256.h"
22 int wps_process_authenticator(struct wps_data
*wps
, const u8
*authenticator
,
23 const struct wpabuf
*msg
)
25 u8 hash
[SHA256_MAC_LEN
];
29 if (authenticator
== NULL
) {
30 wpa_printf(MSG_DEBUG
, "WPS: No Authenticator attribute "
35 if (wps
->last_msg
== NULL
) {
36 wpa_printf(MSG_DEBUG
, "WPS: Last message not available for "
37 "validating authenticator");
41 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
42 * (M_curr* is M_curr without the Authenticator attribute)
44 addr
[0] = wpabuf_head(wps
->last_msg
);
45 len
[0] = wpabuf_len(wps
->last_msg
);
46 addr
[1] = wpabuf_head(msg
);
47 len
[1] = wpabuf_len(msg
) - 4 - WPS_AUTHENTICATOR_LEN
;
48 hmac_sha256_vector(wps
->authkey
, WPS_AUTHKEY_LEN
, 2, addr
, len
, hash
);
50 if (os_memcmp(hash
, authenticator
, WPS_AUTHENTICATOR_LEN
) != 0) {
51 wpa_printf(MSG_DEBUG
, "WPS: Incorrect Authenticator");
59 int wps_process_key_wrap_auth(struct wps_data
*wps
, struct wpabuf
*msg
,
60 const u8
*key_wrap_auth
)
62 u8 hash
[SHA256_MAC_LEN
];
66 if (key_wrap_auth
== NULL
) {
67 wpa_printf(MSG_DEBUG
, "WPS: No KWA in decrypted attribute");
71 head
= wpabuf_head(msg
);
72 len
= wpabuf_len(msg
) - 4 - WPS_KWA_LEN
;
73 if (head
+ len
!= key_wrap_auth
- 4) {
74 wpa_printf(MSG_DEBUG
, "WPS: KWA not in the end of the "
75 "decrypted attribute");
79 hmac_sha256(wps
->authkey
, WPS_AUTHKEY_LEN
, head
, len
, hash
);
80 if (os_memcmp(hash
, key_wrap_auth
, WPS_KWA_LEN
) != 0) {
81 wpa_printf(MSG_DEBUG
, "WPS: Invalid KWA");
89 static int wps_process_cred_network_idx(struct wps_credential
*cred
,
93 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
98 wpa_printf(MSG_DEBUG
, "WPS: Network Index: %d", *idx
);
104 static int wps_process_cred_ssid(struct wps_credential
*cred
, const u8
*ssid
,
108 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include SSID");
112 /* Remove zero-padding since some Registrar implementations seem to use
113 * hardcoded 32-octet length for this attribute */
114 while (ssid_len
> 0 && ssid
[ssid_len
- 1] == 0)
117 wpa_hexdump_ascii(MSG_DEBUG
, "WPS: SSID", ssid
, ssid_len
);
118 if (ssid_len
<= sizeof(cred
->ssid
)) {
119 os_memcpy(cred
->ssid
, ssid
, ssid_len
);
120 cred
->ssid_len
= ssid_len
;
127 static int wps_process_cred_auth_type(struct wps_credential
*cred
,
130 if (auth_type
== NULL
) {
131 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
132 "Authentication Type");
136 cred
->auth_type
= WPA_GET_BE16(auth_type
);
137 wpa_printf(MSG_DEBUG
, "WPS: Authentication Type: 0x%x",
144 static int wps_process_cred_encr_type(struct wps_credential
*cred
,
147 if (encr_type
== NULL
) {
148 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
153 cred
->encr_type
= WPA_GET_BE16(encr_type
);
154 wpa_printf(MSG_DEBUG
, "WPS: Encryption Type: 0x%x",
161 static int wps_process_cred_network_key_idx(struct wps_credential
*cred
,
165 return 0; /* optional attribute */
167 wpa_printf(MSG_DEBUG
, "WPS: Network Key Index: %d", *key_idx
);
168 cred
->key_idx
= *key_idx
;
174 static int wps_process_cred_network_key(struct wps_credential
*cred
,
175 const u8
*key
, size_t key_len
)
178 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
180 if (cred
->auth_type
== WPS_AUTH_OPEN
&&
181 cred
->encr_type
== WPS_ENCR_NONE
) {
182 wpa_printf(MSG_DEBUG
, "WPS: Workaround - Allow "
183 "missing mandatory Network Key attribute "
190 wpa_hexdump_key(MSG_DEBUG
, "WPS: Network Key", key
, key_len
);
191 if (key_len
<= sizeof(cred
->key
)) {
192 os_memcpy(cred
->key
, key
, key_len
);
193 cred
->key_len
= key_len
;
200 static int wps_process_cred_mac_addr(struct wps_credential
*cred
,
203 if (mac_addr
== NULL
) {
204 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
209 wpa_printf(MSG_DEBUG
, "WPS: MAC Address " MACSTR
, MAC2STR(mac_addr
));
210 os_memcpy(cred
->mac_addr
, mac_addr
, ETH_ALEN
);
216 static int wps_process_cred_eap_type(struct wps_credential
*cred
,
217 const u8
*eap_type
, size_t eap_type_len
)
219 if (eap_type
== NULL
)
220 return 0; /* optional attribute */
222 wpa_hexdump(MSG_DEBUG
, "WPS: EAP Type", eap_type
, eap_type_len
);
228 static int wps_process_cred_eap_identity(struct wps_credential
*cred
,
232 if (identity
== NULL
)
233 return 0; /* optional attribute */
235 wpa_hexdump_ascii(MSG_DEBUG
, "WPS: EAP Identity",
236 identity
, identity_len
);
242 static int wps_process_cred_key_prov_auto(struct wps_credential
*cred
,
243 const u8
*key_prov_auto
)
245 if (key_prov_auto
== NULL
)
246 return 0; /* optional attribute */
248 wpa_printf(MSG_DEBUG
, "WPS: Key Provided Automatically: %d",
255 static int wps_process_cred_802_1x_enabled(struct wps_credential
*cred
,
256 const u8
*dot1x_enabled
)
258 if (dot1x_enabled
== NULL
)
259 return 0; /* optional attribute */
261 wpa_printf(MSG_DEBUG
, "WPS: 802.1X Enabled: %d", *dot1x_enabled
);
267 static void wps_workaround_cred_key(struct wps_credential
*cred
)
269 if (cred
->auth_type
& (WPS_AUTH_WPAPSK
| WPS_AUTH_WPA2PSK
) &&
270 cred
->key_len
> 8 && cred
->key_len
< 64 &&
271 cred
->key
[cred
->key_len
- 1] == 0) {
273 * A deployed external registrar is known to encode ASCII
274 * passphrases incorrectly. Remove the extra NULL termination
275 * to fix the encoding.
277 wpa_printf(MSG_DEBUG
, "WPS: Workaround - remove NULL "
278 "termination from ASCII passphrase");
284 int wps_process_cred(struct wps_parse_attr
*attr
,
285 struct wps_credential
*cred
)
287 wpa_printf(MSG_DEBUG
, "WPS: Process Credential");
289 /* TODO: support multiple Network Keys */
290 if (wps_process_cred_network_idx(cred
, attr
->network_idx
) ||
291 wps_process_cred_ssid(cred
, attr
->ssid
, attr
->ssid_len
) ||
292 wps_process_cred_auth_type(cred
, attr
->auth_type
) ||
293 wps_process_cred_encr_type(cred
, attr
->encr_type
) ||
294 wps_process_cred_network_key_idx(cred
, attr
->network_key_idx
) ||
295 wps_process_cred_network_key(cred
, attr
->network_key
,
296 attr
->network_key_len
) ||
297 wps_process_cred_mac_addr(cred
, attr
->mac_addr
) ||
298 wps_process_cred_eap_type(cred
, attr
->eap_type
,
299 attr
->eap_type_len
) ||
300 wps_process_cred_eap_identity(cred
, attr
->eap_identity
,
301 attr
->eap_identity_len
) ||
302 wps_process_cred_key_prov_auto(cred
, attr
->key_prov_auto
) ||
303 wps_process_cred_802_1x_enabled(cred
, attr
->dot1x_enabled
))
306 wps_workaround_cred_key(cred
);
312 int wps_process_ap_settings(struct wps_parse_attr
*attr
,
313 struct wps_credential
*cred
)
315 wpa_printf(MSG_DEBUG
, "WPS: Processing AP Settings");
316 os_memset(cred
, 0, sizeof(*cred
));
317 /* TODO: optional attributes New Password and Device Password ID */
318 if (wps_process_cred_ssid(cred
, attr
->ssid
, attr
->ssid_len
) ||
319 wps_process_cred_auth_type(cred
, attr
->auth_type
) ||
320 wps_process_cred_encr_type(cred
, attr
->encr_type
) ||
321 wps_process_cred_network_key_idx(cred
, attr
->network_key_idx
) ||
322 wps_process_cred_network_key(cred
, attr
->network_key
,
323 attr
->network_key_len
) ||
324 wps_process_cred_mac_addr(cred
, attr
->mac_addr
))
327 wps_workaround_cred_key(cred
);