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