2 * Wi-Fi Protected Setup - attribute building
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "crypto/aes_wrap.h"
19 #include "crypto/crypto.h"
20 #include "crypto/dh_group5.h"
21 #include "crypto/sha256.h"
22 #include "common/ieee802_11_defs.h"
26 int wps_build_public_key(struct wps_data
*wps
, struct wpabuf
*msg
)
28 struct wpabuf
*pubkey
;
30 wpa_printf(MSG_DEBUG
, "WPS: * Public Key");
31 wpabuf_free(wps
->dh_privkey
);
32 if (wps
->dev_pw_id
!= DEV_PW_DEFAULT
&& wps
->wps
->dh_privkey
) {
33 wpa_printf(MSG_DEBUG
, "WPS: Using pre-configured DH keys");
34 wps
->dh_privkey
= wpabuf_dup(wps
->wps
->dh_privkey
);
35 wps
->dh_ctx
= wps
->wps
->dh_ctx
;
36 wps
->wps
->dh_ctx
= NULL
;
37 pubkey
= wpabuf_dup(wps
->wps
->dh_pubkey
);
39 wpa_printf(MSG_DEBUG
, "WPS: Generate new DH keys");
40 wps
->dh_privkey
= NULL
;
41 dh5_free(wps
->dh_ctx
);
42 wps
->dh_ctx
= dh5_init(&wps
->dh_privkey
, &pubkey
);
43 pubkey
= wpabuf_zeropad(pubkey
, 192);
45 if (wps
->dh_ctx
== NULL
|| wps
->dh_privkey
== NULL
|| pubkey
== NULL
) {
46 wpa_printf(MSG_DEBUG
, "WPS: Failed to initialize "
47 "Diffie-Hellman handshake");
51 wpa_hexdump_buf_key(MSG_DEBUG
, "WPS: DH Private Key", wps
->dh_privkey
);
52 wpa_hexdump_buf(MSG_DEBUG
, "WPS: DH own Public Key", pubkey
);
54 wpabuf_put_be16(msg
, ATTR_PUBLIC_KEY
);
55 wpabuf_put_be16(msg
, wpabuf_len(pubkey
));
56 wpabuf_put_buf(msg
, pubkey
);
59 wpabuf_free(wps
->dh_pubkey_r
);
60 wps
->dh_pubkey_r
= pubkey
;
62 wpabuf_free(wps
->dh_pubkey_e
);
63 wps
->dh_pubkey_e
= pubkey
;
70 int wps_build_req_type(struct wpabuf
*msg
, enum wps_request_type type
)
72 wpa_printf(MSG_DEBUG
, "WPS: * Request Type");
73 wpabuf_put_be16(msg
, ATTR_REQUEST_TYPE
);
74 wpabuf_put_be16(msg
, 1);
75 wpabuf_put_u8(msg
, type
);
80 int wps_build_resp_type(struct wpabuf
*msg
, enum wps_response_type type
)
82 wpa_printf(MSG_DEBUG
, "WPS: * Response Type (%d)", type
);
83 wpabuf_put_be16(msg
, ATTR_RESPONSE_TYPE
);
84 wpabuf_put_be16(msg
, 1);
85 wpabuf_put_u8(msg
, type
);
90 int wps_build_config_methods(struct wpabuf
*msg
, u16 methods
)
92 wpa_printf(MSG_DEBUG
, "WPS: * Config Methods (%x)", methods
);
93 wpabuf_put_be16(msg
, ATTR_CONFIG_METHODS
);
94 wpabuf_put_be16(msg
, 2);
95 wpabuf_put_be16(msg
, methods
);
100 int wps_build_uuid_e(struct wpabuf
*msg
, const u8
*uuid
)
102 wpa_printf(MSG_DEBUG
, "WPS: * UUID-E");
103 wpabuf_put_be16(msg
, ATTR_UUID_E
);
104 wpabuf_put_be16(msg
, WPS_UUID_LEN
);
105 wpabuf_put_data(msg
, uuid
, WPS_UUID_LEN
);
110 int wps_build_dev_password_id(struct wpabuf
*msg
, u16 id
)
112 wpa_printf(MSG_DEBUG
, "WPS: * Device Password ID (%d)", id
);
113 wpabuf_put_be16(msg
, ATTR_DEV_PASSWORD_ID
);
114 wpabuf_put_be16(msg
, 2);
115 wpabuf_put_be16(msg
, id
);
120 int wps_build_config_error(struct wpabuf
*msg
, u16 err
)
122 wpa_printf(MSG_DEBUG
, "WPS: * Configuration Error (%d)", err
);
123 wpabuf_put_be16(msg
, ATTR_CONFIG_ERROR
);
124 wpabuf_put_be16(msg
, 2);
125 wpabuf_put_be16(msg
, err
);
130 int wps_build_authenticator(struct wps_data
*wps
, struct wpabuf
*msg
)
132 u8 hash
[SHA256_MAC_LEN
];
136 if (wps
->last_msg
== NULL
) {
137 wpa_printf(MSG_DEBUG
, "WPS: Last message not available for "
138 "building authenticator");
142 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
143 * (M_curr* is M_curr without the Authenticator attribute)
145 addr
[0] = wpabuf_head(wps
->last_msg
);
146 len
[0] = wpabuf_len(wps
->last_msg
);
147 addr
[1] = wpabuf_head(msg
);
148 len
[1] = wpabuf_len(msg
);
149 hmac_sha256_vector(wps
->authkey
, WPS_AUTHKEY_LEN
, 2, addr
, len
, hash
);
151 wpa_printf(MSG_DEBUG
, "WPS: * Authenticator");
152 wpabuf_put_be16(msg
, ATTR_AUTHENTICATOR
);
153 wpabuf_put_be16(msg
, WPS_AUTHENTICATOR_LEN
);
154 wpabuf_put_data(msg
, hash
, WPS_AUTHENTICATOR_LEN
);
160 int wps_build_version(struct wpabuf
*msg
)
163 * Note: This attribute is deprecated and set to hardcoded 0x10 for
164 * backwards compatibility reasons. The real version negotiation is
165 * done with Version2.
167 wpa_printf(MSG_DEBUG
, "WPS: * Version (hardcoded 0x10)");
168 wpabuf_put_be16(msg
, ATTR_VERSION
);
169 wpabuf_put_be16(msg
, 1);
170 wpabuf_put_u8(msg
, 0x10);
175 int wps_build_version2(struct wpabuf
*msg
)
178 wpa_printf(MSG_DEBUG
, "WPS: * Version2 (0x%x)", WPS_VERSION
);
179 wpabuf_put_be16(msg
, ATTR_VERSION2
);
180 wpabuf_put_be16(msg
, 1);
181 wpabuf_put_u8(msg
, WPS_VERSION
);
182 #ifdef CONFIG_WPS_EXTENSIBILITY_TESTING
183 wpa_printf(MSG_DEBUG
, "WPS: * Extensibility Testing - extra "
185 wpabuf_put_be16(msg
, ATTR_EXTENSIBILITY_TEST
);
186 wpabuf_put_be16(msg
, 1);
187 wpabuf_put_u8(msg
, 42);
188 #endif /* CONFIG_WPS_EXTENSIBILITY_TESTING */
189 #endif /* CONFIG_WPS2 */
194 int wps_build_msg_type(struct wpabuf
*msg
, enum wps_msg_type msg_type
)
196 wpa_printf(MSG_DEBUG
, "WPS: * Message Type (%d)", msg_type
);
197 wpabuf_put_be16(msg
, ATTR_MSG_TYPE
);
198 wpabuf_put_be16(msg
, 1);
199 wpabuf_put_u8(msg
, msg_type
);
204 int wps_build_enrollee_nonce(struct wps_data
*wps
, struct wpabuf
*msg
)
206 wpa_printf(MSG_DEBUG
, "WPS: * Enrollee Nonce");
207 wpabuf_put_be16(msg
, ATTR_ENROLLEE_NONCE
);
208 wpabuf_put_be16(msg
, WPS_NONCE_LEN
);
209 wpabuf_put_data(msg
, wps
->nonce_e
, WPS_NONCE_LEN
);
214 int wps_build_registrar_nonce(struct wps_data
*wps
, struct wpabuf
*msg
)
216 wpa_printf(MSG_DEBUG
, "WPS: * Registrar Nonce");
217 wpabuf_put_be16(msg
, ATTR_REGISTRAR_NONCE
);
218 wpabuf_put_be16(msg
, WPS_NONCE_LEN
);
219 wpabuf_put_data(msg
, wps
->nonce_r
, WPS_NONCE_LEN
);
224 int wps_build_auth_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
226 wpa_printf(MSG_DEBUG
, "WPS: * Authentication Type Flags");
227 wpabuf_put_be16(msg
, ATTR_AUTH_TYPE_FLAGS
);
228 wpabuf_put_be16(msg
, 2);
229 wpabuf_put_be16(msg
, WPS_AUTH_TYPES
);
234 int wps_build_encr_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
236 wpa_printf(MSG_DEBUG
, "WPS: * Encryption Type Flags");
237 wpabuf_put_be16(msg
, ATTR_ENCR_TYPE_FLAGS
);
238 wpabuf_put_be16(msg
, 2);
239 wpabuf_put_be16(msg
, WPS_ENCR_TYPES
);
244 int wps_build_conn_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
246 wpa_printf(MSG_DEBUG
, "WPS: * Connection Type Flags");
247 wpabuf_put_be16(msg
, ATTR_CONN_TYPE_FLAGS
);
248 wpabuf_put_be16(msg
, 1);
249 wpabuf_put_u8(msg
, WPS_CONN_ESS
);
254 int wps_build_assoc_state(struct wps_data
*wps
, struct wpabuf
*msg
)
256 wpa_printf(MSG_DEBUG
, "WPS: * Association State");
257 wpabuf_put_be16(msg
, ATTR_ASSOC_STATE
);
258 wpabuf_put_be16(msg
, 2);
259 wpabuf_put_be16(msg
, WPS_ASSOC_NOT_ASSOC
);
264 int wps_build_key_wrap_auth(struct wps_data
*wps
, struct wpabuf
*msg
)
266 u8 hash
[SHA256_MAC_LEN
];
268 wpa_printf(MSG_DEBUG
, "WPS: * Key Wrap Authenticator");
269 hmac_sha256(wps
->authkey
, WPS_AUTHKEY_LEN
, wpabuf_head(msg
),
270 wpabuf_len(msg
), hash
);
272 wpabuf_put_be16(msg
, ATTR_KEY_WRAP_AUTH
);
273 wpabuf_put_be16(msg
, WPS_KWA_LEN
);
274 wpabuf_put_data(msg
, hash
, WPS_KWA_LEN
);
279 int wps_build_encr_settings(struct wps_data
*wps
, struct wpabuf
*msg
,
280 struct wpabuf
*plain
)
283 const size_t block_size
= 16;
286 wpa_printf(MSG_DEBUG
, "WPS: * Encrypted Settings");
288 /* PKCS#5 v2.0 pad */
289 pad_len
= block_size
- wpabuf_len(plain
) % block_size
;
290 os_memset(wpabuf_put(plain
, pad_len
), pad_len
, pad_len
);
292 wpabuf_put_be16(msg
, ATTR_ENCR_SETTINGS
);
293 wpabuf_put_be16(msg
, block_size
+ wpabuf_len(plain
));
295 iv
= wpabuf_put(msg
, block_size
);
296 if (os_get_random(iv
, block_size
) < 0)
299 data
= wpabuf_put(msg
, 0);
300 wpabuf_put_buf(msg
, plain
);
301 if (aes_128_cbc_encrypt(wps
->keywrapkey
, iv
, data
, wpabuf_len(plain
)))
308 #ifdef CONFIG_WPS_OOB
309 int wps_build_oob_dev_password(struct wpabuf
*msg
, struct wps_context
*wps
)
313 u8 pubkey_hash
[WPS_HASH_LEN
];
314 u8 dev_password_bin
[WPS_OOB_DEVICE_PASSWORD_LEN
];
316 wpa_printf(MSG_DEBUG
, "WPS: * OOB Device Password");
318 addr
[0] = wpabuf_head(wps
->dh_pubkey
);
319 hash_len
= wpabuf_len(wps
->dh_pubkey
);
320 sha256_vector(1, addr
, &hash_len
, pubkey_hash
);
322 if (os_get_random((u8
*) &wps
->oob_dev_pw_id
, sizeof(u16
)) < 0) {
323 wpa_printf(MSG_ERROR
, "WPS: device password id "
327 wps
->oob_dev_pw_id
|= 0x0010;
329 if (os_get_random(dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
) < 0) {
330 wpa_printf(MSG_ERROR
, "WPS: OOB device password "
335 wpabuf_put_be16(msg
, ATTR_OOB_DEVICE_PASSWORD
);
336 wpabuf_put_be16(msg
, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN
);
337 wpabuf_put_data(msg
, pubkey_hash
, WPS_OOB_PUBKEY_HASH_LEN
);
338 wpabuf_put_be16(msg
, wps
->oob_dev_pw_id
);
339 wpabuf_put_data(msg
, dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
);
341 wpa_snprintf_hex_uppercase(
342 wpabuf_put(wps
->oob_conf
.dev_password
,
343 wpabuf_size(wps
->oob_conf
.dev_password
)),
344 wpabuf_size(wps
->oob_conf
.dev_password
),
345 dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
);
349 #endif /* CONFIG_WPS_OOB */
352 int wps_build_req_to_enroll(struct wpabuf
*msg
)
355 wpa_printf(MSG_DEBUG
, "WPS: * Request to Enroll (1)");
356 wpabuf_put_be16(msg
, ATTR_REQUEST_TO_ENROLL
);
357 wpabuf_put_be16(msg
, 1);
358 wpabuf_put_u8(msg
, 1);
359 #endif /* CONFIG_WPS2 */
364 /* Encapsulate WPS IE data with one (or more, if needed) IE headers */
365 struct wpabuf
* wps_ie_encapsulate(struct wpabuf
*data
)
370 ie
= wpabuf_alloc(wpabuf_len(data
) + 100);
376 pos
= wpabuf_head(data
);
377 end
= pos
+ wpabuf_len(data
);
380 size_t frag_len
= end
- pos
;
383 wpabuf_put_u8(ie
, WLAN_EID_VENDOR_SPECIFIC
);
384 wpabuf_put_u8(ie
, 4 + frag_len
);
385 wpabuf_put_be32(ie
, WPS_DEV_OUI_WFA
);
386 wpabuf_put_data(ie
, pos
, frag_len
);