1 /* 2 * Wi-Fi Protected Setup - common functionality 3 * Copyright (c) 2008, Jouni Malinen <j@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 "dh_groups.h" 19 #include "sha256.h" 20 #include "aes_wrap.h" 21 #include "crypto.h" 22 #include "wps_i.h" 23 #include "wps_dev_attr.h" 24 25 26 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, 27 const char *label, u8 *res, size_t res_len) 28 { 29 u8 i_buf[4], key_bits[4]; 30 const u8 *addr[4]; 31 size_t len[4]; 32 int i, iter; 33 u8 hash[SHA256_MAC_LEN], *opos; 34 size_t left; 35 36 WPA_PUT_BE32(key_bits, res_len * 8); 37 38 addr[0] = i_buf; 39 len[0] = sizeof(i_buf); 40 addr[1] = label_prefix; 41 len[1] = label_prefix_len; 42 addr[2] = (const u8 *) label; 43 len[2] = os_strlen(label); 44 addr[3] = key_bits; 45 len[3] = sizeof(key_bits); 46 47 iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; 48 opos = res; 49 left = res_len; 50 51 for (i = 1; i <= iter; i++) { 52 WPA_PUT_BE32(i_buf, i); 53 hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); 54 if (i < iter) { 55 os_memcpy(opos, hash, SHA256_MAC_LEN); 56 opos += SHA256_MAC_LEN; 57 left -= SHA256_MAC_LEN; 58 } else 59 os_memcpy(opos, hash, left); 60 } 61 } 62 63 64 int wps_derive_keys(struct wps_data *wps) 65 { 66 struct wpabuf *pubkey, *dh_shared; 67 u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; 68 const u8 *addr[3]; 69 size_t len[3]; 70 u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; 71 72 if (wps->dh_privkey == NULL) { 73 wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); 74 return -1; 75 } 76 77 pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; 78 if (pubkey == NULL) { 79 wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); 80 return -1; 81 } 82 83 dh_shared = dh_derive_shared(pubkey, wps->dh_privkey, 84 dh_groups_get(WPS_DH_GROUP)); 85 dh_shared = wpabuf_zeropad(dh_shared, 192); 86 if (dh_shared == NULL) { 87 wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); 88 return -1; 89 } 90 91 /* Own DH private key is not needed anymore */ 92 wpabuf_free(wps->dh_privkey); 93 wps->dh_privkey = NULL; 94 95 wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); 96 97 /* DHKey = SHA-256(g^AB mod p) */ 98 addr[0] = wpabuf_head(dh_shared); 99 len[0] = wpabuf_len(dh_shared); 100 sha256_vector(1, addr, len, dhkey); 101 wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); 102 wpabuf_free(dh_shared); 103 104 /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ 105 addr[0] = wps->nonce_e; 106 len[0] = WPS_NONCE_LEN; 107 addr[1] = wps->mac_addr_e; 108 len[1] = ETH_ALEN; 109 addr[2] = wps->nonce_r; 110 len[2] = WPS_NONCE_LEN; 111 hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); 112 wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); 113 114 wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", 115 keys, sizeof(keys)); 116 os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); 117 os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); 118 os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, 119 WPS_EMSK_LEN); 120 121 wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", 122 wps->authkey, WPS_AUTHKEY_LEN); 123 wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", 124 wps->keywrapkey, WPS_KEYWRAPKEY_LEN); 125 wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); 126 127 return 0; 128 } 129 130 131 int wps_derive_mgmt_keys(struct wps_data *wps) 132 { 133 u8 nonces[2 * WPS_NONCE_LEN]; 134 u8 keys[WPS_MGMTAUTHKEY_LEN + WPS_MGMTENCKEY_LEN]; 135 u8 hash[SHA256_MAC_LEN]; 136 const u8 *addr[2]; 137 size_t len[2]; 138 const char *auth_label = "WFA-WLAN-Management-MgmtAuthKey"; 139 const char *enc_label = "WFA-WLAN-Management-MgmtEncKey"; 140 141 /* MgmtAuthKey || MgmtEncKey = 142 * kdf(EMSK, N1 || N2 || "WFA-WLAN-Management-Keys", 384) */ 143 os_memcpy(nonces, wps->nonce_e, WPS_NONCE_LEN); 144 os_memcpy(nonces + WPS_NONCE_LEN, wps->nonce_r, WPS_NONCE_LEN); 145 wps_kdf(wps->emsk, nonces, sizeof(nonces), "WFA-WLAN-Management-Keys", 146 keys, sizeof(keys)); 147 os_memcpy(wps->mgmt_auth_key, keys, WPS_MGMTAUTHKEY_LEN); 148 os_memcpy(wps->mgmt_enc_key, keys + WPS_MGMTAUTHKEY_LEN, 149 WPS_MGMTENCKEY_LEN); 150 151 addr[0] = nonces; 152 len[0] = sizeof(nonces); 153 154 /* MgmtEncKeyID = first 128 bits of 155 * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtAuthKey") */ 156 addr[1] = (const u8 *) auth_label; 157 len[1] = os_strlen(auth_label); 158 sha256_vector(2, addr, len, hash); 159 os_memcpy(wps->mgmt_auth_key_id, hash, WPS_MGMT_KEY_ID_LEN); 160 161 /* MgmtEncKeyID = first 128 bits of 162 * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtEncKey") */ 163 addr[1] = (const u8 *) enc_label; 164 len[1] = os_strlen(enc_label); 165 sha256_vector(2, addr, len, hash); 166 os_memcpy(wps->mgmt_enc_key_id, hash, WPS_MGMT_KEY_ID_LEN); 167 168 wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtAuthKey", 169 wps->mgmt_auth_key, WPS_MGMTAUTHKEY_LEN); 170 wpa_hexdump(MSG_DEBUG, "WPS: MgmtAuthKeyID", 171 wps->mgmt_auth_key_id, WPS_MGMT_KEY_ID_LEN); 172 wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtEncKey", 173 wps->mgmt_enc_key, WPS_MGMTENCKEY_LEN); 174 wpa_hexdump(MSG_DEBUG, "WPS: MgmtEncKeyID", 175 wps->mgmt_enc_key_id, WPS_MGMT_KEY_ID_LEN); 176 177 return 0; 178 } 179 180 181 void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, 182 size_t dev_passwd_len) 183 { 184 u8 hash[SHA256_MAC_LEN]; 185 186 hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, 187 (dev_passwd_len + 1) / 2, hash); 188 os_memcpy(wps->psk1, hash, WPS_PSK_LEN); 189 hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, 190 dev_passwd + (dev_passwd_len + 1) / 2, 191 dev_passwd_len / 2, hash); 192 os_memcpy(wps->psk2, hash, WPS_PSK_LEN); 193 194 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", 195 dev_passwd, dev_passwd_len); 196 wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); 197 wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); 198 } 199 200 201 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 202 size_t encr_len) 203 { 204 struct wpabuf *decrypted; 205 const size_t block_size = 16; 206 size_t i; 207 u8 pad; 208 const u8 *pos; 209 210 /* AES-128-CBC */ 211 if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) 212 { 213 wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); 214 return NULL; 215 } 216 217 decrypted = wpabuf_alloc(encr_len - block_size); 218 if (decrypted == NULL) 219 return NULL; 220 221 wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); 222 wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); 223 if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), 224 wpabuf_len(decrypted))) { 225 wpabuf_free(decrypted); 226 return NULL; 227 } 228 229 wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", 230 decrypted); 231 232 pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; 233 pad = *pos; 234 if (pad > wpabuf_len(decrypted)) { 235 wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); 236 wpabuf_free(decrypted); 237 return NULL; 238 } 239 for (i = 0; i < pad; i++) { 240 if (*pos-- != pad) { 241 wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " 242 "string"); 243 wpabuf_free(decrypted); 244 return NULL; 245 } 246 } 247 decrypted->used -= pad; 248 249 return decrypted; 250 } 251 252 253 /** 254 * wps_pin_checksum - Compute PIN checksum 255 * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) 256 * Returns: Checksum digit 257 */ 258 unsigned int wps_pin_checksum(unsigned int pin) 259 { 260 unsigned int accum = 0; 261 while (pin) { 262 accum += 3 * (pin % 10); 263 pin /= 10; 264 accum += pin % 10; 265 pin /= 10; 266 } 267 268 return (10 - accum % 10) % 10; 269 } 270 271 272 /** 273 * wps_pin_valid - Check whether a PIN has a valid checksum 274 * @pin: Eight digit PIN (i.e., including the checksum digit) 275 * Returns: 1 if checksum digit is valid, or 0 if not 276 */ 277 unsigned int wps_pin_valid(unsigned int pin) 278 { 279 return wps_pin_checksum(pin / 10) == (pin % 10); 280 } 281 282 283 /** 284 * wps_generate_pin - Generate a random PIN 285 * Returns: Eight digit PIN (i.e., including the checksum digit) 286 */ 287 unsigned int wps_generate_pin(void) 288 { 289 unsigned int val; 290 291 /* Generate seven random digits for the PIN */ 292 if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) { 293 struct os_time now; 294 os_get_time(&now); 295 val = os_random() ^ now.sec ^ now.usec; 296 } 297 val %= 10000000; 298 299 /* Append checksum digit */ 300 return val * 10 + wps_pin_checksum(val); 301 } 302 303 304 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg) 305 { 306 union wps_event_data data; 307 308 if (wps->event_cb == NULL) 309 return; 310 311 os_memset(&data, 0, sizeof(data)); 312 data.fail.msg = msg; 313 wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); 314 } 315 316 317 void wps_success_event(struct wps_context *wps) 318 { 319 if (wps->event_cb == NULL) 320 return; 321 322 wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); 323 } 324 325 326 void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part) 327 { 328 union wps_event_data data; 329 330 if (wps->event_cb == NULL) 331 return; 332 333 os_memset(&data, 0, sizeof(data)); 334 data.pwd_auth_fail.enrollee = enrollee; 335 data.pwd_auth_fail.part = part; 336 wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); 337 } 338