WPS: Add UFD support (USBA out-of-band mechanism)
[mech_eap.git] / src / wps / wps_attr_build.c
1 /*
2  * Wi-Fi Protected Setup - attribute building
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 "crypto.h"
19 #include "sha256.h"
20 #include "aes_wrap.h"
21 #include "wps_i.h"
22
23
24 int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
25 {
26         struct wpabuf *pubkey;
27
28         wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
29         wpabuf_free(wps->dh_privkey);
30         wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
31         pubkey = wpabuf_dup(wps->wps->dh_pubkey);
32         if (wps->dh_privkey == NULL || pubkey == NULL) {
33                 wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
34                            "Diffie-Hellman handshake");
35                 wpabuf_free(pubkey);
36                 return -1;
37         }
38
39         wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
40         wpabuf_put_be16(msg, wpabuf_len(pubkey));
41         wpabuf_put_buf(msg, pubkey);
42
43         if (wps->registrar) {
44                 wpabuf_free(wps->dh_pubkey_r);
45                 wps->dh_pubkey_r = pubkey;
46         } else {
47                 wpabuf_free(wps->dh_pubkey_e);
48                 wps->dh_pubkey_e = pubkey;
49         }
50
51         return 0;
52 }
53
54
55 int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
56 {
57         wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
58         wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
59         wpabuf_put_be16(msg, 1);
60         wpabuf_put_u8(msg, type);
61         return 0;
62 }
63
64
65 int wps_build_config_methods(struct wpabuf *msg, u16 methods)
66 {
67         wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
68         wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
69         wpabuf_put_be16(msg, 2);
70         wpabuf_put_be16(msg, methods);
71         return 0;
72 }
73
74
75 int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
76 {
77         wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
78         wpabuf_put_be16(msg, ATTR_UUID_E);
79         wpabuf_put_be16(msg, WPS_UUID_LEN);
80         wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
81         return 0;
82 }
83
84
85 int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
86 {
87         wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
88         wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
89         wpabuf_put_be16(msg, 2);
90         wpabuf_put_be16(msg, id);
91         return 0;
92 }
93
94
95 int wps_build_config_error(struct wpabuf *msg, u16 err)
96 {
97         wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
98         wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
99         wpabuf_put_be16(msg, 2);
100         wpabuf_put_be16(msg, err);
101         return 0;
102 }
103
104
105 int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
106 {
107         u8 hash[SHA256_MAC_LEN];
108         const u8 *addr[2];
109         size_t len[2];
110
111         if (wps->last_msg == NULL) {
112                 wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
113                            "building authenticator");
114                 return -1;
115         }
116
117         /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
118          * (M_curr* is M_curr without the Authenticator attribute)
119          */
120         addr[0] = wpabuf_head(wps->last_msg);
121         len[0] = wpabuf_len(wps->last_msg);
122         addr[1] = wpabuf_head(msg);
123         len[1] = wpabuf_len(msg);
124         hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
125
126         wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
127         wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
128         wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
129         wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
130
131         return 0;
132 }
133
134
135 int wps_build_version(struct wpabuf *msg)
136 {
137         wpa_printf(MSG_DEBUG, "WPS:  * Version");
138         wpabuf_put_be16(msg, ATTR_VERSION);
139         wpabuf_put_be16(msg, 1);
140         wpabuf_put_u8(msg, WPS_VERSION);
141         return 0;
142 }
143
144
145 int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
146 {
147         wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
148         wpabuf_put_be16(msg, ATTR_MSG_TYPE);
149         wpabuf_put_be16(msg, 1);
150         wpabuf_put_u8(msg, msg_type);
151         return 0;
152 }
153
154
155 int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
156 {
157         wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
158         wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
159         wpabuf_put_be16(msg, WPS_NONCE_LEN);
160         wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
161         return 0;
162 }
163
164
165 int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
166 {
167         wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
168         wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
169         wpabuf_put_be16(msg, WPS_NONCE_LEN);
170         wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
171         return 0;
172 }
173
174
175 int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
176 {
177         wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
178         wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
179         wpabuf_put_be16(msg, 2);
180         wpabuf_put_be16(msg, WPS_AUTH_TYPES);
181         return 0;
182 }
183
184
185 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
186 {
187         wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
188         wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
189         wpabuf_put_be16(msg, 2);
190         wpabuf_put_be16(msg, WPS_ENCR_TYPES);
191         return 0;
192 }
193
194
195 int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
196 {
197         wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
198         wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
199         wpabuf_put_be16(msg, 1);
200         wpabuf_put_u8(msg, WPS_CONN_ESS);
201         return 0;
202 }
203
204
205 int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
206 {
207         wpa_printf(MSG_DEBUG, "WPS:  * Association State");
208         wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
209         wpabuf_put_be16(msg, 2);
210         wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
211         return 0;
212 }
213
214
215 int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
216 {
217         u8 hash[SHA256_MAC_LEN];
218
219         wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
220         hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
221                     wpabuf_len(msg), hash);
222
223         wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
224         wpabuf_put_be16(msg, WPS_KWA_LEN);
225         wpabuf_put_data(msg, hash, WPS_KWA_LEN);
226         return 0;
227 }
228
229
230 int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
231                             struct wpabuf *plain)
232 {
233         size_t pad_len;
234         const size_t block_size = 16;
235         u8 *iv, *data;
236
237         wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
238
239         /* PKCS#5 v2.0 pad */
240         pad_len = block_size - wpabuf_len(plain) % block_size;
241         os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
242
243         wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
244         wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
245
246         iv = wpabuf_put(msg, block_size);
247         if (os_get_random(iv, block_size) < 0)
248                 return -1;
249
250         data = wpabuf_put(msg, 0);
251         wpabuf_put_buf(msg, plain);
252         if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
253                 return -1;
254
255         return 0;
256 }
257
258
259 int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
260 {
261         size_t hash_len;
262         const u8 *addr[1];
263         u8 pubkey_hash[WPS_HASH_LEN];
264         u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
265
266         wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password");
267
268         addr[0] = wpabuf_head(wps->dh_pubkey);
269         hash_len = wpabuf_len(wps->dh_pubkey);
270         sha256_vector(1, addr, &hash_len, pubkey_hash);
271
272         if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
273                 wpa_printf(MSG_ERROR, "WPS: device password id "
274                            "generation error");
275                 return -1;
276         }
277         wps->oob_dev_pw_id |= 0x0010;
278
279         if (os_get_random(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) {
280                 wpa_printf(MSG_ERROR, "WPS: OOB device password "
281                            "generation error");
282                 return -1;
283         }
284
285         wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
286         wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
287         wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
288         wpabuf_put_be16(msg, wps->oob_dev_pw_id);
289         wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
290
291         wpa_snprintf_hex_uppercase(
292                 wpabuf_put(wps->oob_conf.dev_password,
293                            wpabuf_size(wps->oob_conf.dev_password)),
294                 wpabuf_size(wps->oob_conf.dev_password),
295                 dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
296
297         return 0;
298 }