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 void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, 132 size_t dev_passwd_len) 133 { 134 u8 hash[SHA256_MAC_LEN]; 135 136 hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, 137 (dev_passwd_len + 1) / 2, hash); 138 os_memcpy(wps->psk1, hash, WPS_PSK_LEN); 139 hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, 140 dev_passwd + (dev_passwd_len + 1) / 2, 141 dev_passwd_len / 2, hash); 142 os_memcpy(wps->psk2, hash, WPS_PSK_LEN); 143 144 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", 145 dev_passwd, dev_passwd_len); 146 wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); 147 wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); 148 } 149 150 151 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 152 size_t encr_len) 153 { 154 struct wpabuf *decrypted; 155 const size_t block_size = 16; 156 size_t i; 157 u8 pad; 158 const u8 *pos; 159 160 /* AES-128-CBC */ 161 if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) 162 { 163 wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); 164 return NULL; 165 } 166 167 decrypted = wpabuf_alloc(encr_len - block_size); 168 if (decrypted == NULL) 169 return NULL; 170 171 wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); 172 wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); 173 if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), 174 wpabuf_len(decrypted))) { 175 wpabuf_free(decrypted); 176 return NULL; 177 } 178 179 wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", 180 decrypted); 181 182 pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; 183 pad = *pos; 184 if (pad > wpabuf_len(decrypted)) { 185 wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); 186 wpabuf_free(decrypted); 187 return NULL; 188 } 189 for (i = 0; i < pad; i++) { 190 if (*pos-- != pad) { 191 wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " 192 "string"); 193 wpabuf_free(decrypted); 194 return NULL; 195 } 196 } 197 decrypted->used -= pad; 198 199 return decrypted; 200 } 201 202 203 /** 204 * wps_pin_checksum - Compute PIN checksum 205 * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) 206 * Returns: Checksum digit 207 */ 208 unsigned int wps_pin_checksum(unsigned int pin) 209 { 210 unsigned int accum = 0; 211 while (pin) { 212 accum += 3 * (pin % 10); 213 pin /= 10; 214 accum += pin % 10; 215 pin /= 10; 216 } 217 218 return (10 - accum % 10) % 10; 219 } 220 221 222 /** 223 * wps_pin_valid - Check whether a PIN has a valid checksum 224 * @pin: Eight digit PIN (i.e., including the checksum digit) 225 * Returns: 1 if checksum digit is valid, or 0 if not 226 */ 227 unsigned int wps_pin_valid(unsigned int pin) 228 { 229 return wps_pin_checksum(pin / 10) == (pin % 10); 230 } 231 232 233 /** 234 * wps_generate_pin - Generate a random PIN 235 * Returns: Eight digit PIN (i.e., including the checksum digit) 236 */ 237 unsigned int wps_generate_pin(void) 238 { 239 unsigned int val; 240 241 /* Generate seven random digits for the PIN */ 242 if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) { 243 struct os_time now; 244 os_get_time(&now); 245 val = os_random() ^ now.sec ^ now.usec; 246 } 247 val %= 10000000; 248 249 /* Append checksum digit */ 250 return val * 10 + wps_pin_checksum(val); 251 } 252 253 254 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg) 255 { 256 union wps_event_data data; 257 258 if (wps->event_cb == NULL) 259 return; 260 261 os_memset(&data, 0, sizeof(data)); 262 data.fail.msg = msg; 263 wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); 264 } 265 266 267 void wps_success_event(struct wps_context *wps) 268 { 269 if (wps->event_cb == NULL) 270 return; 271 272 wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL); 273 } 274 275 276 void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part) 277 { 278 union wps_event_data data; 279 280 if (wps->event_cb == NULL) 281 return; 282 283 os_memset(&data, 0, sizeof(data)); 284 data.pwd_auth_fail.enrollee = enrollee; 285 data.pwd_auth_fail.part = part; 286 wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); 287 } 288 289 290 void wps_pbc_overlap_event(struct wps_context *wps) 291 { 292 if (wps->event_cb == NULL) 293 return; 294 295 wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); 296 } 297 298 299 void wps_pbc_timeout_event(struct wps_context *wps) 300 { 301 if (wps->event_cb == NULL) 302 return; 303 304 wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); 305 } 306