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"
25 int wps_build_public_key(struct wps_data
*wps
, struct wpabuf
*msg
)
27 struct wpabuf
*pubkey
;
29 wpa_printf(MSG_DEBUG
, "WPS: * Public Key");
30 wpabuf_free(wps
->dh_privkey
);
31 if (wps
->dev_pw_id
!= DEV_PW_DEFAULT
&& wps
->wps
->dh_privkey
) {
32 wpa_printf(MSG_DEBUG
, "WPS: Using pre-configured DH keys");
33 wps
->dh_privkey
= wpabuf_dup(wps
->wps
->dh_privkey
);
34 wps
->dh_ctx
= wps
->wps
->dh_ctx
;
35 wps
->wps
->dh_ctx
= NULL
;
36 pubkey
= wpabuf_dup(wps
->wps
->dh_pubkey
);
38 wpa_printf(MSG_DEBUG
, "WPS: Generate new DH keys");
39 wps
->dh_privkey
= NULL
;
40 dh5_free(wps
->dh_ctx
);
41 wps
->dh_ctx
= dh5_init(&wps
->dh_privkey
, &pubkey
);
42 pubkey
= wpabuf_zeropad(pubkey
, 192);
44 if (wps
->dh_ctx
== NULL
|| wps
->dh_privkey
== NULL
|| pubkey
== NULL
) {
45 wpa_printf(MSG_DEBUG
, "WPS: Failed to initialize "
46 "Diffie-Hellman handshake");
51 wpabuf_put_be16(msg
, ATTR_PUBLIC_KEY
);
52 wpabuf_put_be16(msg
, wpabuf_len(pubkey
));
53 wpabuf_put_buf(msg
, pubkey
);
56 wpabuf_free(wps
->dh_pubkey_r
);
57 wps
->dh_pubkey_r
= pubkey
;
59 wpabuf_free(wps
->dh_pubkey_e
);
60 wps
->dh_pubkey_e
= pubkey
;
67 int wps_build_req_type(struct wpabuf
*msg
, enum wps_request_type type
)
69 wpa_printf(MSG_DEBUG
, "WPS: * Request Type");
70 wpabuf_put_be16(msg
, ATTR_REQUEST_TYPE
);
71 wpabuf_put_be16(msg
, 1);
72 wpabuf_put_u8(msg
, type
);
77 int wps_build_resp_type(struct wpabuf
*msg
, enum wps_response_type type
)
79 wpa_printf(MSG_DEBUG
, "WPS: * Response Type (%d)", type
);
80 wpabuf_put_be16(msg
, ATTR_RESPONSE_TYPE
);
81 wpabuf_put_be16(msg
, 1);
82 wpabuf_put_u8(msg
, type
);
87 int wps_build_config_methods(struct wpabuf
*msg
, u16 methods
)
89 wpa_printf(MSG_DEBUG
, "WPS: * Config Methods (%x)", methods
);
90 wpabuf_put_be16(msg
, ATTR_CONFIG_METHODS
);
91 wpabuf_put_be16(msg
, 2);
92 wpabuf_put_be16(msg
, methods
);
97 int wps_build_uuid_e(struct wpabuf
*msg
, const u8
*uuid
)
99 wpa_printf(MSG_DEBUG
, "WPS: * UUID-E");
100 wpabuf_put_be16(msg
, ATTR_UUID_E
);
101 wpabuf_put_be16(msg
, WPS_UUID_LEN
);
102 wpabuf_put_data(msg
, uuid
, WPS_UUID_LEN
);
107 int wps_build_dev_password_id(struct wpabuf
*msg
, u16 id
)
109 wpa_printf(MSG_DEBUG
, "WPS: * Device Password ID (%d)", id
);
110 wpabuf_put_be16(msg
, ATTR_DEV_PASSWORD_ID
);
111 wpabuf_put_be16(msg
, 2);
112 wpabuf_put_be16(msg
, id
);
117 int wps_build_config_error(struct wpabuf
*msg
, u16 err
)
119 wpa_printf(MSG_DEBUG
, "WPS: * Configuration Error (%d)", err
);
120 wpabuf_put_be16(msg
, ATTR_CONFIG_ERROR
);
121 wpabuf_put_be16(msg
, 2);
122 wpabuf_put_be16(msg
, err
);
127 int wps_build_authenticator(struct wps_data
*wps
, struct wpabuf
*msg
)
129 u8 hash
[SHA256_MAC_LEN
];
133 if (wps
->last_msg
== NULL
) {
134 wpa_printf(MSG_DEBUG
, "WPS: Last message not available for "
135 "building authenticator");
139 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
140 * (M_curr* is M_curr without the Authenticator attribute)
142 addr
[0] = wpabuf_head(wps
->last_msg
);
143 len
[0] = wpabuf_len(wps
->last_msg
);
144 addr
[1] = wpabuf_head(msg
);
145 len
[1] = wpabuf_len(msg
);
146 hmac_sha256_vector(wps
->authkey
, WPS_AUTHKEY_LEN
, 2, addr
, len
, hash
);
148 wpa_printf(MSG_DEBUG
, "WPS: * Authenticator");
149 wpabuf_put_be16(msg
, ATTR_AUTHENTICATOR
);
150 wpabuf_put_be16(msg
, WPS_AUTHENTICATOR_LEN
);
151 wpabuf_put_data(msg
, hash
, WPS_AUTHENTICATOR_LEN
);
157 int wps_build_version(struct wpabuf
*msg
)
159 wpa_printf(MSG_DEBUG
, "WPS: * Version");
160 wpabuf_put_be16(msg
, ATTR_VERSION
);
161 wpabuf_put_be16(msg
, 1);
162 wpabuf_put_u8(msg
, WPS_VERSION
);
167 int wps_build_msg_type(struct wpabuf
*msg
, enum wps_msg_type msg_type
)
169 wpa_printf(MSG_DEBUG
, "WPS: * Message Type (%d)", msg_type
);
170 wpabuf_put_be16(msg
, ATTR_MSG_TYPE
);
171 wpabuf_put_be16(msg
, 1);
172 wpabuf_put_u8(msg
, msg_type
);
177 int wps_build_enrollee_nonce(struct wps_data
*wps
, struct wpabuf
*msg
)
179 wpa_printf(MSG_DEBUG
, "WPS: * Enrollee Nonce");
180 wpabuf_put_be16(msg
, ATTR_ENROLLEE_NONCE
);
181 wpabuf_put_be16(msg
, WPS_NONCE_LEN
);
182 wpabuf_put_data(msg
, wps
->nonce_e
, WPS_NONCE_LEN
);
187 int wps_build_registrar_nonce(struct wps_data
*wps
, struct wpabuf
*msg
)
189 wpa_printf(MSG_DEBUG
, "WPS: * Registrar Nonce");
190 wpabuf_put_be16(msg
, ATTR_REGISTRAR_NONCE
);
191 wpabuf_put_be16(msg
, WPS_NONCE_LEN
);
192 wpabuf_put_data(msg
, wps
->nonce_r
, WPS_NONCE_LEN
);
197 int wps_build_auth_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
199 wpa_printf(MSG_DEBUG
, "WPS: * Authentication Type Flags");
200 wpabuf_put_be16(msg
, ATTR_AUTH_TYPE_FLAGS
);
201 wpabuf_put_be16(msg
, 2);
202 wpabuf_put_be16(msg
, WPS_AUTH_TYPES
);
207 int wps_build_encr_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
209 wpa_printf(MSG_DEBUG
, "WPS: * Encryption Type Flags");
210 wpabuf_put_be16(msg
, ATTR_ENCR_TYPE_FLAGS
);
211 wpabuf_put_be16(msg
, 2);
212 wpabuf_put_be16(msg
, WPS_ENCR_TYPES
);
217 int wps_build_conn_type_flags(struct wps_data
*wps
, struct wpabuf
*msg
)
219 wpa_printf(MSG_DEBUG
, "WPS: * Connection Type Flags");
220 wpabuf_put_be16(msg
, ATTR_CONN_TYPE_FLAGS
);
221 wpabuf_put_be16(msg
, 1);
222 wpabuf_put_u8(msg
, WPS_CONN_ESS
);
227 int wps_build_assoc_state(struct wps_data
*wps
, struct wpabuf
*msg
)
229 wpa_printf(MSG_DEBUG
, "WPS: * Association State");
230 wpabuf_put_be16(msg
, ATTR_ASSOC_STATE
);
231 wpabuf_put_be16(msg
, 2);
232 wpabuf_put_be16(msg
, WPS_ASSOC_NOT_ASSOC
);
237 int wps_build_key_wrap_auth(struct wps_data
*wps
, struct wpabuf
*msg
)
239 u8 hash
[SHA256_MAC_LEN
];
241 wpa_printf(MSG_DEBUG
, "WPS: * Key Wrap Authenticator");
242 hmac_sha256(wps
->authkey
, WPS_AUTHKEY_LEN
, wpabuf_head(msg
),
243 wpabuf_len(msg
), hash
);
245 wpabuf_put_be16(msg
, ATTR_KEY_WRAP_AUTH
);
246 wpabuf_put_be16(msg
, WPS_KWA_LEN
);
247 wpabuf_put_data(msg
, hash
, WPS_KWA_LEN
);
252 int wps_build_encr_settings(struct wps_data
*wps
, struct wpabuf
*msg
,
253 struct wpabuf
*plain
)
256 const size_t block_size
= 16;
259 wpa_printf(MSG_DEBUG
, "WPS: * Encrypted Settings");
261 /* PKCS#5 v2.0 pad */
262 pad_len
= block_size
- wpabuf_len(plain
) % block_size
;
263 os_memset(wpabuf_put(plain
, pad_len
), pad_len
, pad_len
);
265 wpabuf_put_be16(msg
, ATTR_ENCR_SETTINGS
);
266 wpabuf_put_be16(msg
, block_size
+ wpabuf_len(plain
));
268 iv
= wpabuf_put(msg
, block_size
);
269 if (os_get_random(iv
, block_size
) < 0)
272 data
= wpabuf_put(msg
, 0);
273 wpabuf_put_buf(msg
, plain
);
274 if (aes_128_cbc_encrypt(wps
->keywrapkey
, iv
, data
, wpabuf_len(plain
)))
281 #ifdef CONFIG_WPS_OOB
282 int wps_build_oob_dev_password(struct wpabuf
*msg
, struct wps_context
*wps
)
286 u8 pubkey_hash
[WPS_HASH_LEN
];
287 u8 dev_password_bin
[WPS_OOB_DEVICE_PASSWORD_LEN
];
289 wpa_printf(MSG_DEBUG
, "WPS: * OOB Device Password");
291 addr
[0] = wpabuf_head(wps
->dh_pubkey
);
292 hash_len
= wpabuf_len(wps
->dh_pubkey
);
293 sha256_vector(1, addr
, &hash_len
, pubkey_hash
);
295 if (os_get_random((u8
*) &wps
->oob_dev_pw_id
, sizeof(u16
)) < 0) {
296 wpa_printf(MSG_ERROR
, "WPS: device password id "
300 wps
->oob_dev_pw_id
|= 0x0010;
302 if (os_get_random(dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
) < 0) {
303 wpa_printf(MSG_ERROR
, "WPS: OOB device password "
308 wpabuf_put_be16(msg
, ATTR_OOB_DEVICE_PASSWORD
);
309 wpabuf_put_be16(msg
, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN
);
310 wpabuf_put_data(msg
, pubkey_hash
, WPS_OOB_PUBKEY_HASH_LEN
);
311 wpabuf_put_be16(msg
, wps
->oob_dev_pw_id
);
312 wpabuf_put_data(msg
, dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
);
314 wpa_snprintf_hex_uppercase(
315 wpabuf_put(wps
->oob_conf
.dev_password
,
316 wpabuf_size(wps
->oob_conf
.dev_password
)),
317 wpabuf_size(wps
->oob_conf
.dev_password
),
318 dev_password_bin
, WPS_OOB_DEVICE_PASSWORD_LEN
);
322 #endif /* CONFIG_WPS_OOB */