wps_attr_build.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
1965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang/*
2965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang * Wi-Fi Protected Setup - attribute building
3965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang *
53b573f7bf1c5736d500e39013b8d32478a1429e6Gloria Wang * This software may be distributed under the terms of the BSD license.
66655174826330afe66ef766258181ae8c11f3f6cInsun Kang * See README for more details.
725eefbedf4b0ba6aea38605f4ba19c75a40810d1Insun Kang */
86655174826330afe66ef766258181ae8c11f3f6cInsun Kang
96655174826330afe66ef766258181ae8c11f3f6cInsun Kang#include "includes.h"
10965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang
11965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang#include "common.h"
123b5ec66c3623647fc4dfd1a446c4f25a2c7f1ba0Mark Salyzyn#include "crypto/aes_wrap.h"
13d411b4ca2945cd8974a3a78199fce94646950128Andreas Huber#include "crypto/crypto.h"
14965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang#include "crypto/dh_group5.h"
15559bf2836f5da25b75bfb229fec0d20d540ee426James Dong#include "crypto/sha256.h"
16559bf2836f5da25b75bfb229fec0d20d540ee426James Dong#include "crypto/random.h"
17965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang#include "common/ieee802_11_defs.h"
18965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang#include "wps_i.h"
19965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang
20965d08ba16ee82bc85f69546360c18e7da907406Gloria Wang
21int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
22{
23	struct wpabuf *pubkey;
24
25	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
26	wpabuf_free(wps->dh_privkey);
27	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
28		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
29		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
30		wps->dh_ctx = wps->wps->dh_ctx;
31		wps->wps->dh_ctx = NULL;
32		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
33	} else {
34		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
35		wps->dh_privkey = NULL;
36		dh5_free(wps->dh_ctx);
37		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
38		pubkey = wpabuf_zeropad(pubkey, 192);
39	}
40	if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
41		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
42			   "Diffie-Hellman handshake");
43		wpabuf_free(pubkey);
44		return -1;
45	}
46	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
47	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
48
49	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
50	wpabuf_put_be16(msg, wpabuf_len(pubkey));
51	wpabuf_put_buf(msg, pubkey);
52
53	if (wps->registrar) {
54		wpabuf_free(wps->dh_pubkey_r);
55		wps->dh_pubkey_r = pubkey;
56	} else {
57		wpabuf_free(wps->dh_pubkey_e);
58		wps->dh_pubkey_e = pubkey;
59	}
60
61	return 0;
62}
63
64
65int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
66{
67	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
68	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
69	wpabuf_put_be16(msg, 1);
70	wpabuf_put_u8(msg, type);
71	return 0;
72}
73
74
75int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
76{
77	wpa_printf(MSG_DEBUG, "WPS:  * Response Type (%d)", type);
78	wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
79	wpabuf_put_be16(msg, 1);
80	wpabuf_put_u8(msg, type);
81	return 0;
82}
83
84
85int wps_build_config_methods(struct wpabuf *msg, u16 methods)
86{
87	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
88	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
89	wpabuf_put_be16(msg, 2);
90	wpabuf_put_be16(msg, methods);
91	return 0;
92}
93
94
95int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
96{
97	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
98	wpabuf_put_be16(msg, ATTR_UUID_E);
99	wpabuf_put_be16(msg, WPS_UUID_LEN);
100	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
101	return 0;
102}
103
104
105int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
106{
107	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
108	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
109	wpabuf_put_be16(msg, 2);
110	wpabuf_put_be16(msg, id);
111	return 0;
112}
113
114
115int wps_build_config_error(struct wpabuf *msg, u16 err)
116{
117	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
118	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
119	wpabuf_put_be16(msg, 2);
120	wpabuf_put_be16(msg, err);
121	return 0;
122}
123
124
125int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
126{
127	u8 hash[SHA256_MAC_LEN];
128	const u8 *addr[2];
129	size_t len[2];
130
131	if (wps->last_msg == NULL) {
132		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
133			   "building authenticator");
134		return -1;
135	}
136
137	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
138	 * (M_curr* is M_curr without the Authenticator attribute)
139	 */
140	addr[0] = wpabuf_head(wps->last_msg);
141	len[0] = wpabuf_len(wps->last_msg);
142	addr[1] = wpabuf_head(msg);
143	len[1] = wpabuf_len(msg);
144	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
145
146	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
147	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
148	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
149	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
150
151	return 0;
152}
153
154
155int wps_build_version(struct wpabuf *msg)
156{
157	/*
158	 * Note: This attribute is deprecated and set to hardcoded 0x10 for
159	 * backwards compatibility reasons. The real version negotiation is
160	 * done with Version2.
161	 */
162	wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
163	wpabuf_put_be16(msg, ATTR_VERSION);
164	wpabuf_put_be16(msg, 1);
165	wpabuf_put_u8(msg, 0x10);
166	return 0;
167}
168
169
170int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
171		      const u8 *auth_macs, size_t auth_macs_count)
172{
173#ifdef CONFIG_WPS2
174	u8 *len;
175
176	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
177	len = wpabuf_put(msg, 2); /* to be filled */
178	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
179
180	wpa_printf(MSG_DEBUG, "WPS:  * Version2 (0x%x)", WPS_VERSION);
181	wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
182	wpabuf_put_u8(msg, 1);
183	wpabuf_put_u8(msg, WPS_VERSION);
184
185	if (req_to_enroll) {
186		wpa_printf(MSG_DEBUG, "WPS:  * Request to Enroll (1)");
187		wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
188		wpabuf_put_u8(msg, 1);
189		wpabuf_put_u8(msg, 1);
190	}
191
192	if (auth_macs && auth_macs_count) {
193		size_t i;
194		wpa_printf(MSG_DEBUG, "WPS:  * AuthorizedMACs (count=%d)",
195			   (int) auth_macs_count);
196		wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
197		wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
198		wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
199		for (i = 0; i < auth_macs_count; i++)
200			wpa_printf(MSG_DEBUG, "WPS:    AuthorizedMAC: " MACSTR,
201				   MAC2STR(&auth_macs[i * ETH_ALEN]));
202	}
203
204	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
205#endif /* CONFIG_WPS2 */
206
207#ifdef CONFIG_WPS_TESTING
208	if (WPS_VERSION > 0x20) {
209		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
210			   "attribute");
211		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
212		wpabuf_put_be16(msg, 1);
213		wpabuf_put_u8(msg, 42);
214	}
215#endif /* CONFIG_WPS_TESTING */
216	return 0;
217}
218
219
220int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
221{
222	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
223	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
224	wpabuf_put_be16(msg, 1);
225	wpabuf_put_u8(msg, msg_type);
226	return 0;
227}
228
229
230int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
231{
232	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
233	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
234	wpabuf_put_be16(msg, WPS_NONCE_LEN);
235	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
236	return 0;
237}
238
239
240int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
241{
242	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
243	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
244	wpabuf_put_be16(msg, WPS_NONCE_LEN);
245	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
246	return 0;
247}
248
249
250int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
251{
252	u16 auth_types = WPS_AUTH_TYPES;
253#ifdef CONFIG_WPS2
254	auth_types &= ~WPS_AUTH_SHARED;
255#endif /* CONFIG_WPS2 */
256	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
257	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
258	wpabuf_put_be16(msg, 2);
259	wpabuf_put_be16(msg, auth_types);
260	return 0;
261}
262
263
264int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
265{
266	u16 encr_types = WPS_ENCR_TYPES;
267#ifdef CONFIG_WPS2
268	encr_types &= ~WPS_ENCR_WEP;
269#endif /* CONFIG_WPS2 */
270	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
271	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
272	wpabuf_put_be16(msg, 2);
273	wpabuf_put_be16(msg, encr_types);
274	return 0;
275}
276
277
278int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
279{
280	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
281	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
282	wpabuf_put_be16(msg, 1);
283	wpabuf_put_u8(msg, WPS_CONN_ESS);
284	return 0;
285}
286
287
288int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
289{
290	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
291	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
292	wpabuf_put_be16(msg, 2);
293	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
294	return 0;
295}
296
297
298int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
299{
300	u8 hash[SHA256_MAC_LEN];
301
302	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
303	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
304		    wpabuf_len(msg), hash);
305
306	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
307	wpabuf_put_be16(msg, WPS_KWA_LEN);
308	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
309	return 0;
310}
311
312
313int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
314			    struct wpabuf *plain)
315{
316	size_t pad_len;
317	const size_t block_size = 16;
318	u8 *iv, *data;
319
320	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
321
322	/* PKCS#5 v2.0 pad */
323	pad_len = block_size - wpabuf_len(plain) % block_size;
324	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
325
326	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
327	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
328
329	iv = wpabuf_put(msg, block_size);
330	if (random_get_bytes(iv, block_size) < 0)
331		return -1;
332
333	data = wpabuf_put(msg, 0);
334	wpabuf_put_buf(msg, plain);
335	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
336		return -1;
337
338	return 0;
339}
340
341
342#ifdef CONFIG_WPS_OOB
343int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
344{
345	size_t hash_len;
346	const u8 *addr[1];
347	u8 pubkey_hash[WPS_HASH_LEN];
348	u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
349
350	wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password");
351
352	addr[0] = wpabuf_head(wps->dh_pubkey);
353	hash_len = wpabuf_len(wps->dh_pubkey);
354	sha256_vector(1, addr, &hash_len, pubkey_hash);
355
356	if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
357		wpa_printf(MSG_ERROR, "WPS: device password id "
358			   "generation error");
359		return -1;
360	}
361	wps->oob_dev_pw_id |= 0x0010;
362
363	if (random_get_bytes(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) <
364	    0) {
365		wpa_printf(MSG_ERROR, "WPS: OOB device password "
366			   "generation error");
367		return -1;
368	}
369
370	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
371	wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
372	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
373	wpabuf_put_be16(msg, wps->oob_dev_pw_id);
374	wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
375
376	wpa_snprintf_hex_uppercase(
377		wpabuf_put(wps->oob_conf.dev_password,
378			   wpabuf_size(wps->oob_conf.dev_password)),
379		wpabuf_size(wps->oob_conf.dev_password),
380		dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
381
382	return 0;
383}
384#endif /* CONFIG_WPS_OOB */
385
386
387/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
388struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
389{
390	struct wpabuf *ie;
391	const u8 *pos, *end;
392
393	ie = wpabuf_alloc(wpabuf_len(data) + 100);
394	if (ie == NULL) {
395		wpabuf_free(data);
396		return NULL;
397	}
398
399	pos = wpabuf_head(data);
400	end = pos + wpabuf_len(data);
401
402	while (end > pos) {
403		size_t frag_len = end - pos;
404		if (frag_len > 251)
405			frag_len = 251;
406		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
407		wpabuf_put_u8(ie, 4 + frag_len);
408		wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
409		wpabuf_put_data(ie, pos, frag_len);
410		pos += frag_len;
411	}
412
413	wpabuf_free(data);
414
415	return ie;
416}
417