Home | History | Annotate | Download | only in wps
      1 /*
      2  * Wi-Fi Protected Setup - common functionality
      3  * Copyright (c) 2008, Jouni Malinen <j (at) 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 "crypto/dh_groups.h"
     19 #include "crypto/sha256.h"
     20 #include "crypto/aes_wrap.h"
     21 #include "crypto/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