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