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 "
183 wpa_hexdump_key(MSG_DEBUG
, "WPS: Network Key", key
, key_len
);
184 if (key_len
<= sizeof(cred
->key
)) {
185 os_memcpy(cred
->key
, key
, key_len
);
186 cred
->key_len
= key_len
;
193 static int wps_process_cred_mac_addr(struct wps_credential
*cred
,
196 if (mac_addr
== NULL
) {
197 wpa_printf(MSG_DEBUG
, "WPS: Credential did not include "
202 wpa_printf(MSG_DEBUG
, "WPS: MAC Address " MACSTR
, MAC2STR(mac_addr
));
203 os_memcpy(cred
->mac_addr
, mac_addr
, ETH_ALEN
);
209 static int wps_process_cred_eap_type(struct wps_credential
*cred
,
210 const u8
*eap_type
, size_t eap_type_len
)
212 if (eap_type
== NULL
)
213 return 0; /* optional attribute */
215 wpa_hexdump(MSG_DEBUG
, "WPS: EAP Type", eap_type
, eap_type_len
);
221 static int wps_process_cred_eap_identity(struct wps_credential
*cred
,
225 if (identity
== NULL
)
226 return 0; /* optional attribute */
228 wpa_hexdump_ascii(MSG_DEBUG
, "WPS: EAP Identity",
229 identity
, identity_len
);
235 static int wps_process_cred_key_prov_auto(struct wps_credential
*cred
,
236 const u8
*key_prov_auto
)
238 if (key_prov_auto
== NULL
)
239 return 0; /* optional attribute */
241 wpa_printf(MSG_DEBUG
, "WPS: Key Provided Automatically: %d",
248 static int wps_process_cred_802_1x_enabled(struct wps_credential
*cred
,
249 const u8
*dot1x_enabled
)
251 if (dot1x_enabled
== NULL
)
252 return 0; /* optional attribute */
254 wpa_printf(MSG_DEBUG
, "WPS: 802.1X Enabled: %d", *dot1x_enabled
);
260 static void wps_workaround_cred_key(struct wps_credential
*cred
)
262 if (cred
->auth_type
& (WPS_AUTH_WPAPSK
| WPS_AUTH_WPA2PSK
) &&
263 cred
->key_len
> 8 && cred
->key_len
< 64 &&
264 cred
->key
[cred
->key_len
- 1] == 0) {
266 * A deployed external registrar is known to encode ASCII
267 * passphrases incorrectly. Remove the extra NULL termination
268 * to fix the encoding.
270 wpa_printf(MSG_DEBUG
, "WPS: Workaround - remove NULL "
271 "termination from ASCII passphrase");
277 int wps_process_cred(struct wps_parse_attr
*attr
,
278 struct wps_credential
*cred
)
280 wpa_printf(MSG_DEBUG
, "WPS: Process Credential");
282 /* TODO: support multiple Network Keys */
283 if (wps_process_cred_network_idx(cred
, attr
->network_idx
) ||
284 wps_process_cred_ssid(cred
, attr
->ssid
, attr
->ssid_len
) ||
285 wps_process_cred_auth_type(cred
, attr
->auth_type
) ||
286 wps_process_cred_encr_type(cred
, attr
->encr_type
) ||
287 wps_process_cred_network_key_idx(cred
, attr
->network_key_idx
) ||
288 wps_process_cred_network_key(cred
, attr
->network_key
,
289 attr
->network_key_len
) ||
290 wps_process_cred_mac_addr(cred
, attr
->mac_addr
) ||
291 wps_process_cred_eap_type(cred
, attr
->eap_type
,
292 attr
->eap_type_len
) ||
293 wps_process_cred_eap_identity(cred
, attr
->eap_identity
,
294 attr
->eap_identity_len
) ||
295 wps_process_cred_key_prov_auto(cred
, attr
->key_prov_auto
) ||
296 wps_process_cred_802_1x_enabled(cred
, attr
->dot1x_enabled
))
299 wps_workaround_cred_key(cred
);
305 int wps_process_ap_settings(struct wps_parse_attr
*attr
,
306 struct wps_credential
*cred
)
308 wpa_printf(MSG_DEBUG
, "WPS: Processing AP Settings");
309 os_memset(cred
, 0, sizeof(*cred
));
310 /* TODO: optional attributes New Password and Device Password ID */
311 if (wps_process_cred_ssid(cred
, attr
->ssid
, attr
->ssid_len
) ||
312 wps_process_cred_auth_type(cred
, attr
->auth_type
) ||
313 wps_process_cred_encr_type(cred
, attr
->encr_type
) ||
314 wps_process_cred_network_key_idx(cred
, attr
->network_key_idx
) ||
315 wps_process_cred_network_key(cred
, attr
->network_key
,
316 attr
->network_key_len
) ||
317 wps_process_cred_mac_addr(cred
, attr
->mac_addr
))
320 wps_workaround_cred_key(cred
);