1 /* 2 * Wi-Fi Protected Setup - attribute processing 3 * Copyright (c) 2008, Jouni Malinen <j (at) 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 "crypto/sha256.h" 19 #include "wps_i.h" 20 21 22 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, 23 const struct wpabuf *msg) 24 { 25 u8 hash[SHA256_MAC_LEN]; 26 const u8 *addr[2]; 27 size_t len[2]; 28 29 if (authenticator == NULL) { 30 wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute " 31 "included"); 32 return -1; 33 } 34 35 if (wps->last_msg == NULL) { 36 wpa_printf(MSG_DEBUG, "WPS: Last message not available for " 37 "validating authenticator"); 38 return -1; 39 } 40 41 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) 42 * (M_curr* is M_curr without the Authenticator attribute) 43 */ 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); 49 50 if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { 51 wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); 52 return -1; 53 } 54 55 return 0; 56 } 57 58 59 int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, 60 const u8 *key_wrap_auth) 61 { 62 u8 hash[SHA256_MAC_LEN]; 63 const u8 *head; 64 size_t len; 65 66 if (key_wrap_auth == NULL) { 67 wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute"); 68 return -1; 69 } 70 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"); 76 return -1; 77 } 78 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"); 82 return -1; 83 } 84 85 return 0; 86 } 87 88 89 static int wps_process_cred_network_idx(struct wps_credential *cred, 90 const u8 *idx) 91 { 92 if (idx == NULL) { 93 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 94 "Network Index"); 95 return -1; 96 } 97 98 wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx); 99 100 return 0; 101 } 102 103 104 static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid, 105 size_t ssid_len) 106 { 107 if (ssid == NULL) { 108 wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID"); 109 return -1; 110 } 111 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) 115 ssid_len--; 116 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; 121 } 122 123 return 0; 124 } 125 126 127 static int wps_process_cred_auth_type(struct wps_credential *cred, 128 const u8 *auth_type) 129 { 130 if (auth_type == NULL) { 131 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 132 "Authentication Type"); 133 return -1; 134 } 135 136 cred->auth_type = WPA_GET_BE16(auth_type); 137 wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x", 138 cred->auth_type); 139 140 return 0; 141 } 142 143 144 static int wps_process_cred_encr_type(struct wps_credential *cred, 145 const u8 *encr_type) 146 { 147 if (encr_type == NULL) { 148 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 149 "Encryption Type"); 150 return -1; 151 } 152 153 cred->encr_type = WPA_GET_BE16(encr_type); 154 wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x", 155 cred->encr_type); 156 157 return 0; 158 } 159 160 161 static int wps_process_cred_network_key_idx(struct wps_credential *cred, 162 const u8 *key_idx) 163 { 164 if (key_idx == NULL) 165 return 0; /* optional attribute */ 166 167 wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx); 168 cred->key_idx = *key_idx; 169 170 return 0; 171 } 172 173 174 static int wps_process_cred_network_key(struct wps_credential *cred, 175 const u8 *key, size_t key_len) 176 { 177 if (key == NULL) { 178 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 179 "Network Key"); 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 " 184 "for open network"); 185 return 0; 186 } 187 return -1; 188 } 189 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; 194 } 195 196 return 0; 197 } 198 199 200 static int wps_process_cred_mac_addr(struct wps_credential *cred, 201 const u8 *mac_addr) 202 { 203 if (mac_addr == NULL) { 204 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 205 "MAC Address"); 206 return -1; 207 } 208 209 wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr)); 210 os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN); 211 212 return 0; 213 } 214 215 216 static int wps_process_cred_eap_type(struct wps_credential *cred, 217 const u8 *eap_type, size_t eap_type_len) 218 { 219 if (eap_type == NULL) 220 return 0; /* optional attribute */ 221 222 wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len); 223 224 return 0; 225 } 226 227 228 static int wps_process_cred_eap_identity(struct wps_credential *cred, 229 const u8 *identity, 230 size_t identity_len) 231 { 232 if (identity == NULL) 233 return 0; /* optional attribute */ 234 235 wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity", 236 identity, identity_len); 237 238 return 0; 239 } 240 241 242 static int wps_process_cred_key_prov_auto(struct wps_credential *cred, 243 const u8 *key_prov_auto) 244 { 245 if (key_prov_auto == NULL) 246 return 0; /* optional attribute */ 247 248 wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d", 249 *key_prov_auto); 250 251 return 0; 252 } 253 254 255 static int wps_process_cred_802_1x_enabled(struct wps_credential *cred, 256 const u8 *dot1x_enabled) 257 { 258 if (dot1x_enabled == NULL) 259 return 0; /* optional attribute */ 260 261 wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled); 262 263 return 0; 264 } 265 266 267 static int wps_workaround_cred_key(struct wps_credential *cred) 268 { 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) { 272 #ifdef CONFIG_WPS_STRICT 273 wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses " 274 "forbidden NULL termination"); 275 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", 276 cred->key, cred->key_len); 277 return -1; 278 #else /* CONFIG_WPS_STRICT */ 279 /* 280 * A deployed external registrar is known to encode ASCII 281 * passphrases incorrectly. Remove the extra NULL termination 282 * to fix the encoding. 283 */ 284 wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL " 285 "termination from ASCII passphrase"); 286 cred->key_len--; 287 #endif /* CONFIG_WPS_STRICT */ 288 } 289 return 0; 290 } 291 292 293 int wps_process_cred(struct wps_parse_attr *attr, 294 struct wps_credential *cred) 295 { 296 wpa_printf(MSG_DEBUG, "WPS: Process Credential"); 297 298 /* TODO: support multiple Network Keys */ 299 if (wps_process_cred_network_idx(cred, attr->network_idx) || 300 wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 301 wps_process_cred_auth_type(cred, attr->auth_type) || 302 wps_process_cred_encr_type(cred, attr->encr_type) || 303 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 304 wps_process_cred_network_key(cred, attr->network_key, 305 attr->network_key_len) || 306 wps_process_cred_mac_addr(cred, attr->mac_addr) || 307 wps_process_cred_eap_type(cred, attr->eap_type, 308 attr->eap_type_len) || 309 wps_process_cred_eap_identity(cred, attr->eap_identity, 310 attr->eap_identity_len) || 311 wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) || 312 wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled)) 313 return -1; 314 315 return wps_workaround_cred_key(cred); 316 } 317 318 319 int wps_process_ap_settings(struct wps_parse_attr *attr, 320 struct wps_credential *cred) 321 { 322 wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings"); 323 os_memset(cred, 0, sizeof(*cred)); 324 /* TODO: optional attributes New Password and Device Password ID */ 325 if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 326 wps_process_cred_auth_type(cred, attr->auth_type) || 327 wps_process_cred_encr_type(cred, attr->encr_type) || 328 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 329 wps_process_cred_network_key(cred, attr->network_key, 330 attr->network_key_len) || 331 wps_process_cred_mac_addr(cred, attr->mac_addr)) 332 return -1; 333 334 return wps_workaround_cred_key(cred); 335 } 336