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 43 if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, 44 hash) < 0 || 45 os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { 46 wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); 47 return -1; 48 } 49 50 return 0; 51 } 52 53 54 int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, 55 const u8 *key_wrap_auth) 56 { 57 u8 hash[SHA256_MAC_LEN]; 58 const u8 *head; 59 size_t len; 60 61 if (key_wrap_auth == NULL) { 62 wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute"); 63 return -1; 64 } 65 66 head = wpabuf_head(msg); 67 len = wpabuf_len(msg) - 4 - WPS_KWA_LEN; 68 if (head + len != key_wrap_auth - 4) { 69 wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the " 70 "decrypted attribute"); 71 return -1; 72 } 73 74 if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 || 75 os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { 76 wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); 77 return -1; 78 } 79 80 return 0; 81 } 82 83 84 static int wps_process_cred_network_idx(struct wps_credential *cred, 85 const u8 *idx) 86 { 87 if (idx == NULL) { 88 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 89 "Network Index"); 90 return -1; 91 } 92 93 wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx); 94 95 return 0; 96 } 97 98 99 static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid, 100 size_t ssid_len) 101 { 102 if (ssid == NULL) { 103 wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID"); 104 return -1; 105 } 106 107 /* Remove zero-padding since some Registrar implementations seem to use 108 * hardcoded 32-octet length for this attribute */ 109 while (ssid_len > 0 && ssid[ssid_len - 1] == 0) 110 ssid_len--; 111 112 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len); 113 if (ssid_len <= sizeof(cred->ssid)) { 114 os_memcpy(cred->ssid, ssid, ssid_len); 115 cred->ssid_len = ssid_len; 116 } 117 118 return 0; 119 } 120 121 122 static int wps_process_cred_auth_type(struct wps_credential *cred, 123 const u8 *auth_type) 124 { 125 if (auth_type == NULL) { 126 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 127 "Authentication Type"); 128 return -1; 129 } 130 131 cred->auth_type = WPA_GET_BE16(auth_type); 132 wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x", 133 cred->auth_type); 134 135 return 0; 136 } 137 138 139 static int wps_process_cred_encr_type(struct wps_credential *cred, 140 const u8 *encr_type) 141 { 142 if (encr_type == NULL) { 143 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 144 "Encryption Type"); 145 return -1; 146 } 147 148 cred->encr_type = WPA_GET_BE16(encr_type); 149 wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x", 150 cred->encr_type); 151 152 return 0; 153 } 154 155 156 static int wps_process_cred_network_key_idx(struct wps_credential *cred, 157 const u8 *key_idx) 158 { 159 if (key_idx == NULL) 160 return 0; /* optional attribute */ 161 162 wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx); 163 cred->key_idx = *key_idx; 164 165 return 0; 166 } 167 168 169 static int wps_process_cred_network_key(struct wps_credential *cred, 170 const u8 *key, size_t key_len) 171 { 172 if (key == NULL) { 173 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 174 "Network Key"); 175 if (cred->auth_type == WPS_AUTH_OPEN && 176 cred->encr_type == WPS_ENCR_NONE) { 177 wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow " 178 "missing mandatory Network Key attribute " 179 "for open network"); 180 return 0; 181 } 182 return -1; 183 } 184 185 wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len); 186 if (key_len <= sizeof(cred->key)) { 187 os_memcpy(cred->key, key, key_len); 188 cred->key_len = key_len; 189 } 190 191 return 0; 192 } 193 194 195 static int wps_process_cred_mac_addr(struct wps_credential *cred, 196 const u8 *mac_addr) 197 { 198 if (mac_addr == NULL) { 199 wpa_printf(MSG_DEBUG, "WPS: Credential did not include " 200 "MAC Address"); 201 return -1; 202 } 203 204 wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr)); 205 os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN); 206 207 return 0; 208 } 209 210 211 static int wps_workaround_cred_key(struct wps_credential *cred) 212 { 213 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) && 214 cred->key_len > 8 && cred->key_len < 64 && 215 cred->key[cred->key_len - 1] == 0) { 216 #ifdef CONFIG_WPS_STRICT 217 wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses " 218 "forbidden NULL termination"); 219 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", 220 cred->key, cred->key_len); 221 return -1; 222 #else /* CONFIG_WPS_STRICT */ 223 /* 224 * A deployed external registrar is known to encode ASCII 225 * passphrases incorrectly. Remove the extra NULL termination 226 * to fix the encoding. 227 */ 228 wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL " 229 "termination from ASCII passphrase"); 230 cred->key_len--; 231 #endif /* CONFIG_WPS_STRICT */ 232 } 233 234 235 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) && 236 (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) { 237 wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase"); 238 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key", 239 cred->key, cred->key_len); 240 return -1; 241 } 242 243 return 0; 244 } 245 246 247 int wps_process_cred(struct wps_parse_attr *attr, 248 struct wps_credential *cred) 249 { 250 wpa_printf(MSG_DEBUG, "WPS: Process Credential"); 251 252 /* TODO: support multiple Network Keys */ 253 if (wps_process_cred_network_idx(cred, attr->network_idx) || 254 wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 255 wps_process_cred_auth_type(cred, attr->auth_type) || 256 wps_process_cred_encr_type(cred, attr->encr_type) || 257 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 258 wps_process_cred_network_key(cred, attr->network_key, 259 attr->network_key_len) || 260 wps_process_cred_mac_addr(cred, attr->mac_addr)) 261 return -1; 262 263 return wps_workaround_cred_key(cred); 264 } 265 266 267 int wps_process_ap_settings(struct wps_parse_attr *attr, 268 struct wps_credential *cred) 269 { 270 wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings"); 271 os_memset(cred, 0, sizeof(*cred)); 272 /* TODO: optional attributes New Password and Device Password ID */ 273 if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) || 274 wps_process_cred_auth_type(cred, attr->auth_type) || 275 wps_process_cred_encr_type(cred, attr->encr_type) || 276 wps_process_cred_network_key_idx(cred, attr->network_key_idx) || 277 wps_process_cred_network_key(cred, attr->network_key, 278 attr->network_key_len) || 279 wps_process_cred_mac_addr(cred, attr->mac_addr)) 280 return -1; 281 282 return wps_workaround_cred_key(cred); 283 } 284