wps_common.c revision 209158
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
26void 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
64int 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
131void 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
151struct 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 */
208unsigned 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 */
227unsigned 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 */
237unsigned 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
254void 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
267void 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
276void 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
290void 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
299void 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