wps_attr_process.c revision 302408
1251876Speter/* 2251876Speter * Wi-Fi Protected Setup - attribute processing 3251876Speter * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4251876Speter * 5251876Speter * This software may be distributed under the terms of the BSD license. 6251876Speter * See README for more details. 7251876Speter */ 8251876Speter 9251876Speter#include "includes.h" 10251876Speter 11251876Speter#include "common.h" 12251876Speter#include "crypto/sha256.h" 13251876Speter#include "wps_i.h" 14251876Speter 15251876Speter 16251876Speterint wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, 17251876Speter const struct wpabuf *msg) 18251876Speter{ 19251876Speter u8 hash[SHA256_MAC_LEN]; 20251876Speter const u8 *addr[2]; 21251876Speter size_t len[2]; 22251876Speter 23251876Speter if (authenticator == NULL) { 24251876Speter wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute " 25251876Speter "included"); 26251876Speter return -1; 27251876Speter } 28251876Speter 29251876Speter if (wps->last_msg == NULL) { 30251876Speter wpa_printf(MSG_DEBUG, "WPS: Last message not available for " 31251876Speter "validating authenticator"); 32251876Speter return -1; 33251876Speter } 34251876Speter 35251876Speter /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) 36251876Speter * (M_curr* is M_curr without the Authenticator attribute) 37251876Speter */ 38251876Speter addr[0] = wpabuf_head(wps->last_msg); 39251876Speter len[0] = wpabuf_len(wps->last_msg); 40251876Speter addr[1] = wpabuf_head(msg); 41251876Speter len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; 42251876Speter hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); 43251876Speter 44251876Speter if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { 45251876Speter wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); 46251876Speter return -1; 47251876Speter } 48251876Speter 49251876Speter return 0; 50251876Speter} 51251876Speter 52251876Speter 53251876Speterint wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, 54251876Speter const u8 *key_wrap_auth) 55251876Speter{ 56251876Speter u8 hash[SHA256_MAC_LEN]; 57251876Speter const u8 *head; 58251876Speter size_t len; 59251876Speter 60251876Speter if (key_wrap_auth == NULL) { 61251876Speter wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute"); 62251876Speter return -1; 63251876Speter } 64251876Speter 65251876Speter head = wpabuf_head(msg); 66251876Speter len = wpabuf_len(msg) - 4 - WPS_KWA_LEN; 67251876Speter if (head + len != key_wrap_auth - 4) { 68251876Speter wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the " 69251876Speter "decrypted attribute"); 70251876Speter return -1; 71251876Speter } 72251876Speter 73251876Speter hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); 74251876Speter if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { 75251876Speter wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); 76251876Speter return -1; 77251876Speter } 78251876Speter 79251876Speter return 0; 80251876Speter} 81251876Speter 82251876Speter 83251876Speterstatic int wps_process_cred_network_idx(struct wps_credential *cred, 84251876Speter const u8 *idx) 85251876Speter{ 86251876Speter if (idx == NULL) { 87251876Speter wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 88251876Speter "Network Index"); 89251876Speter return -1; 90251876Speter } 91251876Speter 92251876Speter wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx); 93251876Speter 94251876Speter return 0; 95251876Speter} 96251876Speter 97251876Speter 98251876Speterstatic int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid, 99251876Speter size_t ssid_len) 100251876Speter{ 101251876Speter if (ssid == NULL) { 102251876Speter wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID"); 103251876Speter return -1; 104251876Speter } 105251876Speter 106251876Speter /* Remove zero-padding since some Registrar implementations seem to use 107251876Speter * hardcoded 32-octet length for this attribute */ 108251876Speter while (ssid_len > 0 && ssid[ssid_len - 1] == 0) 109251876Speter ssid_len--; 110251876Speter 111251876Speter wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len); 112251876Speter if (ssid_len <= sizeof(cred->ssid)) { 113251876Speter os_memcpy(cred->ssid, ssid, ssid_len); 114251876Speter cred->ssid_len = ssid_len; 115251876Speter } 116251876Speter 117251876Speter return 0; 118251876Speter} 119251876Speter 120251876Speter 121251876Speterstatic int wps_process_cred_auth_type(struct wps_credential *cred, 122251876Speter const u8 *auth_type) 123251876Speter{ 124251876Speter if (auth_type == NULL) { 125251876Speter wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 126251876Speter "Authentication Type"); 127251876Speter return -1; 128251876Speter } 129251876Speter 130251876Speter cred->auth_type = WPA_GET_BE16(auth_type); 131251876Speter wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x", 132251876Speter cred->auth_type); 133251876Speter 134251876Speter return 0; 135251876Speter} 136251876Speter 137251876Speter 138251876Speterstatic int wps_process_cred_encr_type(struct wps_credential *cred, 139251876Speter const u8 *encr_type) 140251876Speter{ 141251876Speter if (encr_type == NULL) { 142251876Speter wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 143251876Speter "Encryption Type"); 144251876Speter return -1; 145251876Speter } 146251876Speter 147251876Speter cred->encr_type = WPA_GET_BE16(encr_type); 148251876Speter wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x", 149251876Speter cred->encr_type); 150251876Speter 151251876Speter return 0; 152251876Speter} 153251876Speter 154251876Speter 155251876Speterstatic int wps_process_cred_network_key_idx(struct wps_credential *cred, 156251876Speter const u8 *key_idx) 157251876Speter{ 158251876Speter if (key_idx == NULL) 159251876Speter return 0; /* optional attribute */ 160251876Speter 161251876Speter wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx); 162251876Speter cred->key_idx = *key_idx; 163251876Speter 164251876Speter return 0; 165251876Speter} 166251876Speter 167251876Speter 168251876Speterstatic int wps_process_cred_network_key(struct wps_credential *cred, 169251876Speter const u8 *key, size_t key_len) 170251876Speter{ 171251876Speter if (key == NULL) { 172251876Speter wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 173251876Speter "Network Key"); 174251876Speter if (cred->auth_type == WPS_AUTH_OPEN && 175251876Speter cred->encr_type == WPS_ENCR_NONE) { 176251876Speter 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 194static 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 210static int wps_workaround_cred_key(struct wps_credential *cred) 211{ 212 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) && 213 cred->key_len > 8 && cred->key_len < 64 && 214 cred->key[cred->key_len - 1] == 0) { 215#ifdef CONFIG_WPS_STRICT 216 wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses " 217 "forbidden NULL termination"); 218 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", 219 cred->key, cred->key_len); 220 return -1; 221#else /* CONFIG_WPS_STRICT */ 222 /* 223 * A deployed external registrar is known to encode ASCII 224 * passphrases incorrectly. Remove the extra NULL termination 225 * to fix the encoding. 226 */ 227 wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL " 228 "termination from ASCII passphrase"); 229 cred->key_len--; 230#endif /* CONFIG_WPS_STRICT */ 231 } 232 return 0; 233} 234 235 236int wps_process_cred(struct wps_parse_attr *attr, 237 struct wps_credential *cred) 238{ 239 wpa_printf(MSG_DEBUG, "WPS: Process Credential"); 240 241 /* TODO: support multiple Network Keys */ 242 if (wps_process_cred_network_idx(cred, attr->network_idx) || 243 wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 244 wps_process_cred_auth_type(cred, attr->auth_type) || 245 wps_process_cred_encr_type(cred, attr->encr_type) || 246 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 247 wps_process_cred_network_key(cred, attr->network_key, 248 attr->network_key_len) || 249 wps_process_cred_mac_addr(cred, attr->mac_addr)) 250 return -1; 251 252 return wps_workaround_cred_key(cred); 253} 254 255 256int wps_process_ap_settings(struct wps_parse_attr *attr, 257 struct wps_credential *cred) 258{ 259 wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings"); 260 os_memset(cred, 0, sizeof(*cred)); 261 /* TODO: optional attributes New Password and Device Password ID */ 262 if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 263 wps_process_cred_auth_type(cred, attr->auth_type) || 264 wps_process_cred_encr_type(cred, attr->encr_type) || 265 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 266 wps_process_cred_network_key(cred, attr->network_key, 267 attr->network_key_len) || 268 wps_process_cred_mac_addr(cred, attr->mac_addr)) 269 return -1; 270 271 return wps_workaround_cred_key(cred); 272} 273