1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * DPP functionality shared between hostapd and wpa_supplicant 3e5b75505Sopenharmony_ci * Copyright (c) 2017, Qualcomm Atheros, Inc. 4e5b75505Sopenharmony_ci * Copyright (c) 2018-2019, The Linux Foundation 5e5b75505Sopenharmony_ci * 6e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 7e5b75505Sopenharmony_ci * See README for more details. 8e5b75505Sopenharmony_ci */ 9e5b75505Sopenharmony_ci 10e5b75505Sopenharmony_ci#include "utils/includes.h" 11e5b75505Sopenharmony_ci#include <fcntl.h> 12e5b75505Sopenharmony_ci#include <openssl/opensslv.h> 13e5b75505Sopenharmony_ci#include <openssl/err.h> 14e5b75505Sopenharmony_ci#include <openssl/asn1.h> 15e5b75505Sopenharmony_ci#include <openssl/asn1t.h> 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_ci#include "utils/common.h" 18e5b75505Sopenharmony_ci#include "utils/base64.h" 19e5b75505Sopenharmony_ci#include "utils/json.h" 20e5b75505Sopenharmony_ci#include "utils/ip_addr.h" 21e5b75505Sopenharmony_ci#include "utils/eloop.h" 22e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h" 23e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 24e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h" 25e5b75505Sopenharmony_ci#include "common/gas.h" 26e5b75505Sopenharmony_ci#include "crypto/crypto.h" 27e5b75505Sopenharmony_ci#include "crypto/random.h" 28e5b75505Sopenharmony_ci#include "crypto/aes.h" 29e5b75505Sopenharmony_ci#include "crypto/aes_siv.h" 30e5b75505Sopenharmony_ci#include "crypto/sha384.h" 31e5b75505Sopenharmony_ci#include "crypto/sha512.h" 32e5b75505Sopenharmony_ci#include "drivers/driver.h" 33e5b75505Sopenharmony_ci#include "dpp.h" 34e5b75505Sopenharmony_ci 35e5b75505Sopenharmony_ci 36e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 37e5b75505Sopenharmony_cienum dpp_test_behavior dpp_test = DPP_TEST_DISABLED; 38e5b75505Sopenharmony_ciu8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 39e5b75505Sopenharmony_ciu8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 40e5b75505Sopenharmony_ciu8 dpp_pkex_ephemeral_key_override[600]; 41e5b75505Sopenharmony_cisize_t dpp_pkex_ephemeral_key_override_len = 0; 42e5b75505Sopenharmony_ciu8 dpp_protocol_key_override[600]; 43e5b75505Sopenharmony_cisize_t dpp_protocol_key_override_len = 0; 44e5b75505Sopenharmony_ciu8 dpp_nonce_override[DPP_MAX_NONCE_LEN]; 45e5b75505Sopenharmony_cisize_t dpp_nonce_override_len = 0; 46e5b75505Sopenharmony_ci 47e5b75505Sopenharmony_cistatic int dpp_test_gen_invalid_key(struct wpabuf *msg, 48e5b75505Sopenharmony_ci const struct dpp_curve_params *curve); 49e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 50e5b75505Sopenharmony_ci 51e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 52e5b75505Sopenharmony_ci (defined(LIBRESSL_VERSION_NUMBER) && \ 53e5b75505Sopenharmony_ci LIBRESSL_VERSION_NUMBER < 0x20700000L) 54e5b75505Sopenharmony_ci/* Compatibility wrappers for older versions. */ 55e5b75505Sopenharmony_ci 56e5b75505Sopenharmony_cistatic int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) 57e5b75505Sopenharmony_ci{ 58e5b75505Sopenharmony_ci sig->r = r; 59e5b75505Sopenharmony_ci sig->s = s; 60e5b75505Sopenharmony_ci return 1; 61e5b75505Sopenharmony_ci} 62e5b75505Sopenharmony_ci 63e5b75505Sopenharmony_ci 64e5b75505Sopenharmony_cistatic void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, 65e5b75505Sopenharmony_ci const BIGNUM **ps) 66e5b75505Sopenharmony_ci{ 67e5b75505Sopenharmony_ci if (pr) 68e5b75505Sopenharmony_ci *pr = sig->r; 69e5b75505Sopenharmony_ci if (ps) 70e5b75505Sopenharmony_ci *ps = sig->s; 71e5b75505Sopenharmony_ci} 72e5b75505Sopenharmony_ci 73e5b75505Sopenharmony_ci#endif 74e5b75505Sopenharmony_ci 75e5b75505Sopenharmony_ci 76e5b75505Sopenharmony_cistruct dpp_connection { 77e5b75505Sopenharmony_ci struct dl_list list; 78e5b75505Sopenharmony_ci struct dpp_controller *ctrl; 79e5b75505Sopenharmony_ci struct dpp_relay_controller *relay; 80e5b75505Sopenharmony_ci struct dpp_global *global; 81e5b75505Sopenharmony_ci struct dpp_authentication *auth; 82e5b75505Sopenharmony_ci int sock; 83e5b75505Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 84e5b75505Sopenharmony_ci unsigned int freq; 85e5b75505Sopenharmony_ci u8 msg_len[4]; 86e5b75505Sopenharmony_ci size_t msg_len_octets; 87e5b75505Sopenharmony_ci struct wpabuf *msg; 88e5b75505Sopenharmony_ci struct wpabuf *msg_out; 89e5b75505Sopenharmony_ci size_t msg_out_pos; 90e5b75505Sopenharmony_ci unsigned int read_eloop:1; 91e5b75505Sopenharmony_ci unsigned int write_eloop:1; 92e5b75505Sopenharmony_ci unsigned int on_tcp_tx_complete_gas_done:1; 93e5b75505Sopenharmony_ci unsigned int on_tcp_tx_complete_remove:1; 94e5b75505Sopenharmony_ci unsigned int on_tcp_tx_complete_auth_ok:1; 95e5b75505Sopenharmony_ci}; 96e5b75505Sopenharmony_ci 97e5b75505Sopenharmony_ci/* Remote Controller */ 98e5b75505Sopenharmony_cistruct dpp_relay_controller { 99e5b75505Sopenharmony_ci struct dl_list list; 100e5b75505Sopenharmony_ci struct dpp_global *global; 101e5b75505Sopenharmony_ci u8 pkhash[SHA256_MAC_LEN]; 102e5b75505Sopenharmony_ci struct hostapd_ip_addr ipaddr; 103e5b75505Sopenharmony_ci void *cb_ctx; 104e5b75505Sopenharmony_ci void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg, 105e5b75505Sopenharmony_ci size_t len); 106e5b75505Sopenharmony_ci void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, 107e5b75505Sopenharmony_ci int prot, struct wpabuf *buf); 108e5b75505Sopenharmony_ci struct dl_list conn; /* struct dpp_connection */ 109e5b75505Sopenharmony_ci}; 110e5b75505Sopenharmony_ci 111e5b75505Sopenharmony_ci/* Local Controller */ 112e5b75505Sopenharmony_cistruct dpp_controller { 113e5b75505Sopenharmony_ci struct dpp_global *global; 114e5b75505Sopenharmony_ci u8 allowed_roles; 115e5b75505Sopenharmony_ci int qr_mutual; 116e5b75505Sopenharmony_ci int sock; 117e5b75505Sopenharmony_ci struct dl_list conn; /* struct dpp_connection */ 118e5b75505Sopenharmony_ci char *configurator_params; 119e5b75505Sopenharmony_ci}; 120e5b75505Sopenharmony_ci 121e5b75505Sopenharmony_cistruct dpp_global { 122e5b75505Sopenharmony_ci void *msg_ctx; 123e5b75505Sopenharmony_ci struct dl_list bootstrap; /* struct dpp_bootstrap_info */ 124e5b75505Sopenharmony_ci struct dl_list configurator; /* struct dpp_configurator */ 125e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 126e5b75505Sopenharmony_ci struct dl_list controllers; /* struct dpp_relay_controller */ 127e5b75505Sopenharmony_ci struct dpp_controller *controller; 128e5b75505Sopenharmony_ci struct dl_list tcp_init; /* struct dpp_connection */ 129e5b75505Sopenharmony_ci void *cb_ctx; 130e5b75505Sopenharmony_ci int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); 131e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 132e5b75505Sopenharmony_ci}; 133e5b75505Sopenharmony_ci 134e5b75505Sopenharmony_cistatic const struct dpp_curve_params dpp_curves[] = { 135e5b75505Sopenharmony_ci /* The mandatory to support and the default NIST P-256 curve needs to 136e5b75505Sopenharmony_ci * be the first entry on this list. */ 137e5b75505Sopenharmony_ci { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" }, 138e5b75505Sopenharmony_ci { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" }, 139e5b75505Sopenharmony_ci { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" }, 140e5b75505Sopenharmony_ci { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" }, 141e5b75505Sopenharmony_ci { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" }, 142e5b75505Sopenharmony_ci { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" }, 143e5b75505Sopenharmony_ci { NULL, 0, 0, 0, 0, NULL, 0, NULL } 144e5b75505Sopenharmony_ci}; 145e5b75505Sopenharmony_ci 146e5b75505Sopenharmony_ci 147e5b75505Sopenharmony_ci/* Role-specific elements for PKEX */ 148e5b75505Sopenharmony_ci 149e5b75505Sopenharmony_ci/* NIST P-256 */ 150e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p256[32] = { 151e5b75505Sopenharmony_ci 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b, 152e5b75505Sopenharmony_ci 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54, 153e5b75505Sopenharmony_ci 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07, 154e5b75505Sopenharmony_ci 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25 155e5b75505Sopenharmony_ci }; 156e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p256[32] = { 157e5b75505Sopenharmony_ci 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b, 158e5b75505Sopenharmony_ci 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc, 159e5b75505Sopenharmony_ci 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45, 160e5b75505Sopenharmony_ci 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4 161e5b75505Sopenharmony_ci }; 162e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p256[32] = { 163e5b75505Sopenharmony_ci 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39, 164e5b75505Sopenharmony_ci 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f, 165e5b75505Sopenharmony_ci 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f, 166e5b75505Sopenharmony_ci 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76 167e5b75505Sopenharmony_ci}; 168e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p256[32] = { 169e5b75505Sopenharmony_ci 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19, 170e5b75505Sopenharmony_ci 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1, 171e5b75505Sopenharmony_ci 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a, 172e5b75505Sopenharmony_ci 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67 173e5b75505Sopenharmony_ci}; 174e5b75505Sopenharmony_ci 175e5b75505Sopenharmony_ci/* NIST P-384 */ 176e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p384[48] = { 177e5b75505Sopenharmony_ci 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa, 178e5b75505Sopenharmony_ci 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68, 179e5b75505Sopenharmony_ci 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53, 180e5b75505Sopenharmony_ci 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac, 181e5b75505Sopenharmony_ci 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12, 182e5b75505Sopenharmony_ci 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3 183e5b75505Sopenharmony_ci}; 184e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p384[48] = { 185e5b75505Sopenharmony_ci 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29, 186e5b75505Sopenharmony_ci 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56, 187e5b75505Sopenharmony_ci 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7, 188e5b75505Sopenharmony_ci 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6, 189e5b75505Sopenharmony_ci 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94, 190e5b75505Sopenharmony_ci 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18 191e5b75505Sopenharmony_ci}; 192e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p384[48] = { 193e5b75505Sopenharmony_ci 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98, 194e5b75505Sopenharmony_ci 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97, 195e5b75505Sopenharmony_ci 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92, 196e5b75505Sopenharmony_ci 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44, 197e5b75505Sopenharmony_ci 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf, 198e5b75505Sopenharmony_ci 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf 199e5b75505Sopenharmony_ci}; 200e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p384[48] = { 201e5b75505Sopenharmony_ci 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c, 202e5b75505Sopenharmony_ci 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c, 203e5b75505Sopenharmony_ci 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3, 204e5b75505Sopenharmony_ci 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1, 205e5b75505Sopenharmony_ci 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63, 206e5b75505Sopenharmony_ci 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06 207e5b75505Sopenharmony_ci}; 208e5b75505Sopenharmony_ci 209e5b75505Sopenharmony_ci/* NIST P-521 */ 210e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p521[66] = { 211e5b75505Sopenharmony_ci 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23, 212e5b75505Sopenharmony_ci 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0, 213e5b75505Sopenharmony_ci 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76, 214e5b75505Sopenharmony_ci 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5, 215e5b75505Sopenharmony_ci 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38, 216e5b75505Sopenharmony_ci 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01, 217e5b75505Sopenharmony_ci 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e, 218e5b75505Sopenharmony_ci 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d, 219e5b75505Sopenharmony_ci 0x97, 0x76 220e5b75505Sopenharmony_ci}; 221e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p521[66] = { 222e5b75505Sopenharmony_ci 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59, 223e5b75505Sopenharmony_ci 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99, 224e5b75505Sopenharmony_ci 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b, 225e5b75505Sopenharmony_ci 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd, 226e5b75505Sopenharmony_ci 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f, 227e5b75505Sopenharmony_ci 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf, 228e5b75505Sopenharmony_ci 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02, 229e5b75505Sopenharmony_ci 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d, 230e5b75505Sopenharmony_ci 0x03, 0xa8 231e5b75505Sopenharmony_ci}; 232e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p521[66] = { 233e5b75505Sopenharmony_ci 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a, 234e5b75505Sopenharmony_ci 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44, 235e5b75505Sopenharmony_ci 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f, 236e5b75505Sopenharmony_ci 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb, 237e5b75505Sopenharmony_ci 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48, 238e5b75505Sopenharmony_ci 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e, 239e5b75505Sopenharmony_ci 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a, 240e5b75505Sopenharmony_ci 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97, 241e5b75505Sopenharmony_ci 0x84, 0xb4 242e5b75505Sopenharmony_ci}; 243e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p521[66] = { 244e5b75505Sopenharmony_ci 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d, 245e5b75505Sopenharmony_ci 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20, 246e5b75505Sopenharmony_ci 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3, 247e5b75505Sopenharmony_ci 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84, 248e5b75505Sopenharmony_ci 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9, 249e5b75505Sopenharmony_ci 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2, 250e5b75505Sopenharmony_ci 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80, 251e5b75505Sopenharmony_ci 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53, 252e5b75505Sopenharmony_ci 0xce, 0xe1 253e5b75505Sopenharmony_ci}; 254e5b75505Sopenharmony_ci 255e5b75505Sopenharmony_ci/* Brainpool P-256r1 */ 256e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p256r1[32] = { 257e5b75505Sopenharmony_ci 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10, 258e5b75505Sopenharmony_ci 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca, 259e5b75505Sopenharmony_ci 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75, 260e5b75505Sopenharmony_ci 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8 261e5b75505Sopenharmony_ci}; 262e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p256r1[32] = { 263e5b75505Sopenharmony_ci 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd, 264e5b75505Sopenharmony_ci 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30, 265e5b75505Sopenharmony_ci 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe, 266e5b75505Sopenharmony_ci 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b 267e5b75505Sopenharmony_ci}; 268e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p256r1[32] = { 269e5b75505Sopenharmony_ci 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f, 270e5b75505Sopenharmony_ci 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a, 271e5b75505Sopenharmony_ci 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a, 272e5b75505Sopenharmony_ci 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3 273e5b75505Sopenharmony_ci}; 274e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p256r1[32] = { 275e5b75505Sopenharmony_ci 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd, 276e5b75505Sopenharmony_ci 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2, 277e5b75505Sopenharmony_ci 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e, 278e5b75505Sopenharmony_ci 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64 279e5b75505Sopenharmony_ci}; 280e5b75505Sopenharmony_ci 281e5b75505Sopenharmony_ci/* Brainpool P-384r1 */ 282e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p384r1[48] = { 283e5b75505Sopenharmony_ci 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd, 284e5b75505Sopenharmony_ci 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19, 285e5b75505Sopenharmony_ci 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06, 286e5b75505Sopenharmony_ci 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62, 287e5b75505Sopenharmony_ci 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30, 288e5b75505Sopenharmony_ci 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe 289e5b75505Sopenharmony_ci}; 290e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p384r1[48] = { 291e5b75505Sopenharmony_ci 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99, 292e5b75505Sopenharmony_ci 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86, 293e5b75505Sopenharmony_ci 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32, 294e5b75505Sopenharmony_ci 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9, 295e5b75505Sopenharmony_ci 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e, 296e5b75505Sopenharmony_ci 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52 297e5b75505Sopenharmony_ci}; 298e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p384r1[48] = { 299e5b75505Sopenharmony_ci 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0, 300e5b75505Sopenharmony_ci 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25, 301e5b75505Sopenharmony_ci 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b, 302e5b75505Sopenharmony_ci 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71, 303e5b75505Sopenharmony_ci 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce, 304e5b75505Sopenharmony_ci 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c 305e5b75505Sopenharmony_ci}; 306e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p384r1[48] = { 307e5b75505Sopenharmony_ci 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65, 308e5b75505Sopenharmony_ci 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04, 309e5b75505Sopenharmony_ci 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70, 310e5b75505Sopenharmony_ci 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c, 311e5b75505Sopenharmony_ci 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb, 312e5b75505Sopenharmony_ci 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1 313e5b75505Sopenharmony_ci}; 314e5b75505Sopenharmony_ci 315e5b75505Sopenharmony_ci/* Brainpool P-512r1 */ 316e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p512r1[64] = { 317e5b75505Sopenharmony_ci 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c, 318e5b75505Sopenharmony_ci 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51, 319e5b75505Sopenharmony_ci 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc, 320e5b75505Sopenharmony_ci 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95, 321e5b75505Sopenharmony_ci 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d, 322e5b75505Sopenharmony_ci 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff, 323e5b75505Sopenharmony_ci 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc, 324e5b75505Sopenharmony_ci 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f 325e5b75505Sopenharmony_ci}; 326e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p512r1[64] = { 327e5b75505Sopenharmony_ci 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94, 328e5b75505Sopenharmony_ci 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8, 329e5b75505Sopenharmony_ci 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3, 330e5b75505Sopenharmony_ci 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45, 331e5b75505Sopenharmony_ci 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e, 332e5b75505Sopenharmony_ci 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58, 333e5b75505Sopenharmony_ci 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71, 334e5b75505Sopenharmony_ci 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99 335e5b75505Sopenharmony_ci}; 336e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p512r1[64] = { 337e5b75505Sopenharmony_ci 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72, 338e5b75505Sopenharmony_ci 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76, 339e5b75505Sopenharmony_ci 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19, 340e5b75505Sopenharmony_ci 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e, 341e5b75505Sopenharmony_ci 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9, 342e5b75505Sopenharmony_ci 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88, 343e5b75505Sopenharmony_ci 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29, 344e5b75505Sopenharmony_ci 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e 345e5b75505Sopenharmony_ci}; 346e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p512r1[64] = { 347e5b75505Sopenharmony_ci 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81, 348e5b75505Sopenharmony_ci 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68, 349e5b75505Sopenharmony_ci 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa, 350e5b75505Sopenharmony_ci 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d, 351e5b75505Sopenharmony_ci 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c, 352e5b75505Sopenharmony_ci 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09, 353e5b75505Sopenharmony_ci 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56, 354e5b75505Sopenharmony_ci 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7 355e5b75505Sopenharmony_ci}; 356e5b75505Sopenharmony_ci 357e5b75505Sopenharmony_ci 358e5b75505Sopenharmony_cistatic void dpp_debug_print_point(const char *title, const EC_GROUP *group, 359e5b75505Sopenharmony_ci const EC_POINT *point) 360e5b75505Sopenharmony_ci{ 361e5b75505Sopenharmony_ci BIGNUM *x, *y; 362e5b75505Sopenharmony_ci BN_CTX *ctx; 363e5b75505Sopenharmony_ci char *x_str = NULL, *y_str = NULL; 364e5b75505Sopenharmony_ci 365e5b75505Sopenharmony_ci if (!wpa_debug_show_keys) 366e5b75505Sopenharmony_ci return; 367e5b75505Sopenharmony_ci 368e5b75505Sopenharmony_ci ctx = BN_CTX_new(); 369e5b75505Sopenharmony_ci x = BN_new(); 370e5b75505Sopenharmony_ci y = BN_new(); 371e5b75505Sopenharmony_ci if (!ctx || !x || !y || 372e5b75505Sopenharmony_ci EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1) 373e5b75505Sopenharmony_ci goto fail; 374e5b75505Sopenharmony_ci 375e5b75505Sopenharmony_ci x_str = BN_bn2hex(x); 376e5b75505Sopenharmony_ci y_str = BN_bn2hex(y); 377e5b75505Sopenharmony_ci if (!x_str || !y_str) 378e5b75505Sopenharmony_ci goto fail; 379e5b75505Sopenharmony_ci 380e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str); 381e5b75505Sopenharmony_ci 382e5b75505Sopenharmony_cifail: 383e5b75505Sopenharmony_ci OPENSSL_free(x_str); 384e5b75505Sopenharmony_ci OPENSSL_free(y_str); 385e5b75505Sopenharmony_ci BN_free(x); 386e5b75505Sopenharmony_ci BN_free(y); 387e5b75505Sopenharmony_ci BN_CTX_free(ctx); 388e5b75505Sopenharmony_ci} 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_ci 391e5b75505Sopenharmony_cistatic int dpp_hash_vector(const struct dpp_curve_params *curve, 392e5b75505Sopenharmony_ci size_t num_elem, const u8 *addr[], const size_t *len, 393e5b75505Sopenharmony_ci u8 *mac) 394e5b75505Sopenharmony_ci{ 395e5b75505Sopenharmony_ci if (curve->hash_len == 32) 396e5b75505Sopenharmony_ci return sha256_vector(num_elem, addr, len, mac); 397e5b75505Sopenharmony_ci if (curve->hash_len == 48) 398e5b75505Sopenharmony_ci return sha384_vector(num_elem, addr, len, mac); 399e5b75505Sopenharmony_ci if (curve->hash_len == 64) 400e5b75505Sopenharmony_ci return sha512_vector(num_elem, addr, len, mac); 401e5b75505Sopenharmony_ci return -1; 402e5b75505Sopenharmony_ci} 403e5b75505Sopenharmony_ci 404e5b75505Sopenharmony_ci 405e5b75505Sopenharmony_cistatic int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len, 406e5b75505Sopenharmony_ci const char *label, u8 *out, size_t outlen) 407e5b75505Sopenharmony_ci{ 408e5b75505Sopenharmony_ci if (hash_len == 32) 409e5b75505Sopenharmony_ci return hmac_sha256_kdf(secret, secret_len, NULL, 410e5b75505Sopenharmony_ci (const u8 *) label, os_strlen(label), 411e5b75505Sopenharmony_ci out, outlen); 412e5b75505Sopenharmony_ci if (hash_len == 48) 413e5b75505Sopenharmony_ci return hmac_sha384_kdf(secret, secret_len, NULL, 414e5b75505Sopenharmony_ci (const u8 *) label, os_strlen(label), 415e5b75505Sopenharmony_ci out, outlen); 416e5b75505Sopenharmony_ci if (hash_len == 64) 417e5b75505Sopenharmony_ci return hmac_sha512_kdf(secret, secret_len, NULL, 418e5b75505Sopenharmony_ci (const u8 *) label, os_strlen(label), 419e5b75505Sopenharmony_ci out, outlen); 420e5b75505Sopenharmony_ci return -1; 421e5b75505Sopenharmony_ci} 422e5b75505Sopenharmony_ci 423e5b75505Sopenharmony_ci 424e5b75505Sopenharmony_cistatic int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len, 425e5b75505Sopenharmony_ci size_t num_elem, const u8 *addr[], 426e5b75505Sopenharmony_ci const size_t *len, u8 *mac) 427e5b75505Sopenharmony_ci{ 428e5b75505Sopenharmony_ci if (hash_len == 32) 429e5b75505Sopenharmony_ci return hmac_sha256_vector(key, key_len, num_elem, addr, len, 430e5b75505Sopenharmony_ci mac); 431e5b75505Sopenharmony_ci if (hash_len == 48) 432e5b75505Sopenharmony_ci return hmac_sha384_vector(key, key_len, num_elem, addr, len, 433e5b75505Sopenharmony_ci mac); 434e5b75505Sopenharmony_ci if (hash_len == 64) 435e5b75505Sopenharmony_ci return hmac_sha512_vector(key, key_len, num_elem, addr, len, 436e5b75505Sopenharmony_ci mac); 437e5b75505Sopenharmony_ci return -1; 438e5b75505Sopenharmony_ci} 439e5b75505Sopenharmony_ci 440e5b75505Sopenharmony_ci 441e5b75505Sopenharmony_cistatic int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, 442e5b75505Sopenharmony_ci const u8 *data, size_t data_len, u8 *mac) 443e5b75505Sopenharmony_ci{ 444e5b75505Sopenharmony_ci if (hash_len == 32) 445e5b75505Sopenharmony_ci return hmac_sha256(key, key_len, data, data_len, mac); 446e5b75505Sopenharmony_ci if (hash_len == 48) 447e5b75505Sopenharmony_ci return hmac_sha384(key, key_len, data, data_len, mac); 448e5b75505Sopenharmony_ci if (hash_len == 64) 449e5b75505Sopenharmony_ci return hmac_sha512(key, key_len, data, data_len, mac); 450e5b75505Sopenharmony_ci return -1; 451e5b75505Sopenharmony_ci} 452e5b75505Sopenharmony_ci 453e5b75505Sopenharmony_ci 454e5b75505Sopenharmony_cistatic int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len) 455e5b75505Sopenharmony_ci{ 456e5b75505Sopenharmony_ci int num_bytes, offset; 457e5b75505Sopenharmony_ci 458e5b75505Sopenharmony_ci num_bytes = BN_num_bytes(bn); 459e5b75505Sopenharmony_ci if ((size_t) num_bytes > len) 460e5b75505Sopenharmony_ci return -1; 461e5b75505Sopenharmony_ci offset = len - num_bytes; 462e5b75505Sopenharmony_ci os_memset(pos, 0, offset); 463e5b75505Sopenharmony_ci BN_bn2bin(bn, pos + offset); 464e5b75505Sopenharmony_ci return 0; 465e5b75505Sopenharmony_ci} 466e5b75505Sopenharmony_ci 467e5b75505Sopenharmony_ci 468e5b75505Sopenharmony_cistatic struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix) 469e5b75505Sopenharmony_ci{ 470e5b75505Sopenharmony_ci int len, res; 471e5b75505Sopenharmony_ci EC_KEY *eckey; 472e5b75505Sopenharmony_ci struct wpabuf *buf; 473e5b75505Sopenharmony_ci unsigned char *pos; 474e5b75505Sopenharmony_ci 475e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(pkey); 476e5b75505Sopenharmony_ci if (!eckey) 477e5b75505Sopenharmony_ci return NULL; 478e5b75505Sopenharmony_ci EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED); 479e5b75505Sopenharmony_ci len = i2o_ECPublicKey(eckey, NULL); 480e5b75505Sopenharmony_ci if (len <= 0) { 481e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 482e5b75505Sopenharmony_ci "DDP: Failed to determine public key encoding length"); 483e5b75505Sopenharmony_ci EC_KEY_free(eckey); 484e5b75505Sopenharmony_ci return NULL; 485e5b75505Sopenharmony_ci } 486e5b75505Sopenharmony_ci 487e5b75505Sopenharmony_ci buf = wpabuf_alloc(len); 488e5b75505Sopenharmony_ci if (!buf) { 489e5b75505Sopenharmony_ci EC_KEY_free(eckey); 490e5b75505Sopenharmony_ci return NULL; 491e5b75505Sopenharmony_ci } 492e5b75505Sopenharmony_ci 493e5b75505Sopenharmony_ci pos = wpabuf_put(buf, len); 494e5b75505Sopenharmony_ci res = i2o_ECPublicKey(eckey, &pos); 495e5b75505Sopenharmony_ci EC_KEY_free(eckey); 496e5b75505Sopenharmony_ci if (res != len) { 497e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 498e5b75505Sopenharmony_ci "DDP: Failed to encode public key (res=%d/%d)", 499e5b75505Sopenharmony_ci res, len); 500e5b75505Sopenharmony_ci wpabuf_free(buf); 501e5b75505Sopenharmony_ci return NULL; 502e5b75505Sopenharmony_ci } 503e5b75505Sopenharmony_ci 504e5b75505Sopenharmony_ci if (!prefix) { 505e5b75505Sopenharmony_ci /* Remove 0x04 prefix to match DPP definition */ 506e5b75505Sopenharmony_ci pos = wpabuf_mhead(buf); 507e5b75505Sopenharmony_ci os_memmove(pos, pos + 1, len - 1); 508e5b75505Sopenharmony_ci buf->used--; 509e5b75505Sopenharmony_ci } 510e5b75505Sopenharmony_ci 511e5b75505Sopenharmony_ci return buf; 512e5b75505Sopenharmony_ci} 513e5b75505Sopenharmony_ci 514e5b75505Sopenharmony_ci 515e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group, 516e5b75505Sopenharmony_ci const u8 *buf_x, const u8 *buf_y, 517e5b75505Sopenharmony_ci size_t len) 518e5b75505Sopenharmony_ci{ 519e5b75505Sopenharmony_ci EC_KEY *eckey = NULL; 520e5b75505Sopenharmony_ci BN_CTX *ctx; 521e5b75505Sopenharmony_ci EC_POINT *point = NULL; 522e5b75505Sopenharmony_ci BIGNUM *x = NULL, *y = NULL; 523e5b75505Sopenharmony_ci EVP_PKEY *pkey = NULL; 524e5b75505Sopenharmony_ci 525e5b75505Sopenharmony_ci ctx = BN_CTX_new(); 526e5b75505Sopenharmony_ci if (!ctx) { 527e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Out of memory"); 528e5b75505Sopenharmony_ci return NULL; 529e5b75505Sopenharmony_ci } 530e5b75505Sopenharmony_ci 531e5b75505Sopenharmony_ci point = EC_POINT_new(group); 532e5b75505Sopenharmony_ci x = BN_bin2bn(buf_x, len, NULL); 533e5b75505Sopenharmony_ci y = BN_bin2bn(buf_y, len, NULL); 534e5b75505Sopenharmony_ci if (!point || !x || !y) { 535e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Out of memory"); 536e5b75505Sopenharmony_ci goto fail; 537e5b75505Sopenharmony_ci } 538e5b75505Sopenharmony_ci 539e5b75505Sopenharmony_ci if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { 540e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 541e5b75505Sopenharmony_ci "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", 542e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 543e5b75505Sopenharmony_ci goto fail; 544e5b75505Sopenharmony_ci } 545e5b75505Sopenharmony_ci 546e5b75505Sopenharmony_ci if (!EC_POINT_is_on_curve(group, point, ctx) || 547e5b75505Sopenharmony_ci EC_POINT_is_at_infinity(group, point)) { 548e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Invalid point"); 549e5b75505Sopenharmony_ci goto fail; 550e5b75505Sopenharmony_ci } 551e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point); 552e5b75505Sopenharmony_ci 553e5b75505Sopenharmony_ci eckey = EC_KEY_new(); 554e5b75505Sopenharmony_ci if (!eckey || 555e5b75505Sopenharmony_ci EC_KEY_set_group(eckey, group) != 1 || 556e5b75505Sopenharmony_ci EC_KEY_set_public_key(eckey, point) != 1) { 557e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 558e5b75505Sopenharmony_ci "DPP: Failed to set EC_KEY: %s", 559e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 560e5b75505Sopenharmony_ci goto fail; 561e5b75505Sopenharmony_ci } 562e5b75505Sopenharmony_ci EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); 563e5b75505Sopenharmony_ci 564e5b75505Sopenharmony_ci pkey = EVP_PKEY_new(); 565e5b75505Sopenharmony_ci if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { 566e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY"); 567e5b75505Sopenharmony_ci goto fail; 568e5b75505Sopenharmony_ci } 569e5b75505Sopenharmony_ci 570e5b75505Sopenharmony_ciout: 571e5b75505Sopenharmony_ci BN_free(x); 572e5b75505Sopenharmony_ci BN_free(y); 573e5b75505Sopenharmony_ci EC_KEY_free(eckey); 574e5b75505Sopenharmony_ci EC_POINT_free(point); 575e5b75505Sopenharmony_ci BN_CTX_free(ctx); 576e5b75505Sopenharmony_ci return pkey; 577e5b75505Sopenharmony_cifail: 578e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 579e5b75505Sopenharmony_ci pkey = NULL; 580e5b75505Sopenharmony_ci goto out; 581e5b75505Sopenharmony_ci} 582e5b75505Sopenharmony_ci 583e5b75505Sopenharmony_ci 584e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, 585e5b75505Sopenharmony_ci const u8 *buf, size_t len) 586e5b75505Sopenharmony_ci{ 587e5b75505Sopenharmony_ci EC_KEY *eckey; 588e5b75505Sopenharmony_ci const EC_GROUP *group; 589e5b75505Sopenharmony_ci EVP_PKEY *pkey = NULL; 590e5b75505Sopenharmony_ci 591e5b75505Sopenharmony_ci if (len & 1) 592e5b75505Sopenharmony_ci return NULL; 593e5b75505Sopenharmony_ci 594e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(group_key); 595e5b75505Sopenharmony_ci if (!eckey) { 596e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 597e5b75505Sopenharmony_ci "DPP: Could not get EC_KEY from group_key"); 598e5b75505Sopenharmony_ci return NULL; 599e5b75505Sopenharmony_ci } 600e5b75505Sopenharmony_ci 601e5b75505Sopenharmony_ci group = EC_KEY_get0_group(eckey); 602e5b75505Sopenharmony_ci if (group) 603e5b75505Sopenharmony_ci pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2, 604e5b75505Sopenharmony_ci len / 2); 605e5b75505Sopenharmony_ci else 606e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Could not get EC group"); 607e5b75505Sopenharmony_ci 608e5b75505Sopenharmony_ci EC_KEY_free(eckey); 609e5b75505Sopenharmony_ci return pkey; 610e5b75505Sopenharmony_ci} 611e5b75505Sopenharmony_ci 612e5b75505Sopenharmony_ci 613e5b75505Sopenharmony_cistatic int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, 614e5b75505Sopenharmony_ci u8 *secret, size_t *secret_len) 615e5b75505Sopenharmony_ci{ 616e5b75505Sopenharmony_ci EVP_PKEY_CTX *ctx; 617e5b75505Sopenharmony_ci int ret = -1; 618e5b75505Sopenharmony_ci 619e5b75505Sopenharmony_ci ERR_clear_error(); 620e5b75505Sopenharmony_ci *secret_len = 0; 621e5b75505Sopenharmony_ci 622e5b75505Sopenharmony_ci ctx = EVP_PKEY_CTX_new(own, NULL); 623e5b75505Sopenharmony_ci if (!ctx) { 624e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s", 625e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 626e5b75505Sopenharmony_ci return -1; 627e5b75505Sopenharmony_ci } 628e5b75505Sopenharmony_ci 629e5b75505Sopenharmony_ci if (EVP_PKEY_derive_init(ctx) != 1) { 630e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s", 631e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 632e5b75505Sopenharmony_ci goto fail; 633e5b75505Sopenharmony_ci } 634e5b75505Sopenharmony_ci 635e5b75505Sopenharmony_ci if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) { 636e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 637e5b75505Sopenharmony_ci "DPP: EVP_PKEY_derive_set_peet failed: %s", 638e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 639e5b75505Sopenharmony_ci goto fail; 640e5b75505Sopenharmony_ci } 641e5b75505Sopenharmony_ci 642e5b75505Sopenharmony_ci if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) { 643e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s", 644e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 645e5b75505Sopenharmony_ci goto fail; 646e5b75505Sopenharmony_ci } 647e5b75505Sopenharmony_ci 648e5b75505Sopenharmony_ci if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) { 649e5b75505Sopenharmony_ci u8 buf[200]; 650e5b75505Sopenharmony_ci int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG; 651e5b75505Sopenharmony_ci 652e5b75505Sopenharmony_ci /* It looks like OpenSSL can return unexpectedly large buffer 653e5b75505Sopenharmony_ci * need for shared secret from EVP_PKEY_derive(NULL) in some 654e5b75505Sopenharmony_ci * cases. For example, group 19 has shown cases where secret_len 655e5b75505Sopenharmony_ci * is set to 72 even though the actual length ends up being 656e5b75505Sopenharmony_ci * updated to 32 when EVP_PKEY_derive() is called with a buffer 657e5b75505Sopenharmony_ci * for the value. Work around this by trying to fetch the value 658e5b75505Sopenharmony_ci * and continue if it is within supported range even when the 659e5b75505Sopenharmony_ci * initial buffer need is claimed to be larger. */ 660e5b75505Sopenharmony_ci wpa_printf(level, 661e5b75505Sopenharmony_ci "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()", 662e5b75505Sopenharmony_ci (int) *secret_len); 663e5b75505Sopenharmony_ci if (*secret_len > 200) 664e5b75505Sopenharmony_ci goto fail; 665e5b75505Sopenharmony_ci if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) { 666e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s", 667e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 668e5b75505Sopenharmony_ci goto fail; 669e5b75505Sopenharmony_ci } 670e5b75505Sopenharmony_ci if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) { 671e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 672e5b75505Sopenharmony_ci "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()", 673e5b75505Sopenharmony_ci (int) *secret_len); 674e5b75505Sopenharmony_ci goto fail; 675e5b75505Sopenharmony_ci } 676e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change", 677e5b75505Sopenharmony_ci buf, *secret_len); 678e5b75505Sopenharmony_ci os_memcpy(secret, buf, *secret_len); 679e5b75505Sopenharmony_ci forced_memzero(buf, sizeof(buf)); 680e5b75505Sopenharmony_ci goto done; 681e5b75505Sopenharmony_ci } 682e5b75505Sopenharmony_ci 683e5b75505Sopenharmony_ci if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) { 684e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s", 685e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 686e5b75505Sopenharmony_ci goto fail; 687e5b75505Sopenharmony_ci } 688e5b75505Sopenharmony_ci 689e5b75505Sopenharmony_cidone: 690e5b75505Sopenharmony_ci ret = 0; 691e5b75505Sopenharmony_ci 692e5b75505Sopenharmony_cifail: 693e5b75505Sopenharmony_ci EVP_PKEY_CTX_free(ctx); 694e5b75505Sopenharmony_ci return ret; 695e5b75505Sopenharmony_ci} 696e5b75505Sopenharmony_ci 697e5b75505Sopenharmony_ci 698e5b75505Sopenharmony_cistatic void dpp_auth_fail(struct dpp_authentication *auth, const char *txt) 699e5b75505Sopenharmony_ci{ 700e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); 701e5b75505Sopenharmony_ci} 702e5b75505Sopenharmony_ci 703e5b75505Sopenharmony_ci 704e5b75505Sopenharmony_cistruct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, 705e5b75505Sopenharmony_ci size_t len) 706e5b75505Sopenharmony_ci{ 707e5b75505Sopenharmony_ci struct wpabuf *msg; 708e5b75505Sopenharmony_ci 709e5b75505Sopenharmony_ci msg = wpabuf_alloc(8 + len); 710e5b75505Sopenharmony_ci if (!msg) 711e5b75505Sopenharmony_ci return NULL; 712e5b75505Sopenharmony_ci wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC); 713e5b75505Sopenharmony_ci wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC); 714e5b75505Sopenharmony_ci wpabuf_put_be24(msg, OUI_WFA); 715e5b75505Sopenharmony_ci wpabuf_put_u8(msg, DPP_OUI_TYPE); 716e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 1); /* Crypto Suite */ 717e5b75505Sopenharmony_ci wpabuf_put_u8(msg, type); 718e5b75505Sopenharmony_ci return msg; 719e5b75505Sopenharmony_ci} 720e5b75505Sopenharmony_ci 721e5b75505Sopenharmony_ci 722e5b75505Sopenharmony_ciconst u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len) 723e5b75505Sopenharmony_ci{ 724e5b75505Sopenharmony_ci u16 id, alen; 725e5b75505Sopenharmony_ci const u8 *pos = buf, *end = buf + len; 726e5b75505Sopenharmony_ci 727e5b75505Sopenharmony_ci while (end - pos >= 4) { 728e5b75505Sopenharmony_ci id = WPA_GET_LE16(pos); 729e5b75505Sopenharmony_ci pos += 2; 730e5b75505Sopenharmony_ci alen = WPA_GET_LE16(pos); 731e5b75505Sopenharmony_ci pos += 2; 732e5b75505Sopenharmony_ci if (alen > end - pos) 733e5b75505Sopenharmony_ci return NULL; 734e5b75505Sopenharmony_ci if (id == req_id) { 735e5b75505Sopenharmony_ci *ret_len = alen; 736e5b75505Sopenharmony_ci return pos; 737e5b75505Sopenharmony_ci } 738e5b75505Sopenharmony_ci pos += alen; 739e5b75505Sopenharmony_ci } 740e5b75505Sopenharmony_ci 741e5b75505Sopenharmony_ci return NULL; 742e5b75505Sopenharmony_ci} 743e5b75505Sopenharmony_ci 744e5b75505Sopenharmony_ci 745e5b75505Sopenharmony_ciint dpp_check_attrs(const u8 *buf, size_t len) 746e5b75505Sopenharmony_ci{ 747e5b75505Sopenharmony_ci const u8 *pos, *end; 748e5b75505Sopenharmony_ci int wrapped_data = 0; 749e5b75505Sopenharmony_ci 750e5b75505Sopenharmony_ci pos = buf; 751e5b75505Sopenharmony_ci end = buf + len; 752e5b75505Sopenharmony_ci while (end - pos >= 4) { 753e5b75505Sopenharmony_ci u16 id, alen; 754e5b75505Sopenharmony_ci 755e5b75505Sopenharmony_ci id = WPA_GET_LE16(pos); 756e5b75505Sopenharmony_ci pos += 2; 757e5b75505Sopenharmony_ci alen = WPA_GET_LE16(pos); 758e5b75505Sopenharmony_ci pos += 2; 759e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u", 760e5b75505Sopenharmony_ci id, alen); 761e5b75505Sopenharmony_ci if (alen > end - pos) { 762e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 763e5b75505Sopenharmony_ci "DPP: Truncated message - not enough room for the attribute - dropped"); 764e5b75505Sopenharmony_ci return -1; 765e5b75505Sopenharmony_ci } 766e5b75505Sopenharmony_ci if (wrapped_data) { 767e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 768e5b75505Sopenharmony_ci "DPP: An unexpected attribute included after the Wrapped Data attribute"); 769e5b75505Sopenharmony_ci return -1; 770e5b75505Sopenharmony_ci } 771e5b75505Sopenharmony_ci if (id == DPP_ATTR_WRAPPED_DATA) 772e5b75505Sopenharmony_ci wrapped_data = 1; 773e5b75505Sopenharmony_ci pos += alen; 774e5b75505Sopenharmony_ci } 775e5b75505Sopenharmony_ci 776e5b75505Sopenharmony_ci if (end != pos) { 777e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 778e5b75505Sopenharmony_ci "DPP: Unexpected octets (%d) after the last attribute", 779e5b75505Sopenharmony_ci (int) (end - pos)); 780e5b75505Sopenharmony_ci return -1; 781e5b75505Sopenharmony_ci } 782e5b75505Sopenharmony_ci 783e5b75505Sopenharmony_ci return 0; 784e5b75505Sopenharmony_ci} 785e5b75505Sopenharmony_ci 786e5b75505Sopenharmony_ci 787e5b75505Sopenharmony_civoid dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) 788e5b75505Sopenharmony_ci{ 789e5b75505Sopenharmony_ci if (!info) 790e5b75505Sopenharmony_ci return; 791e5b75505Sopenharmony_ci os_free(info->uri); 792e5b75505Sopenharmony_ci os_free(info->info); 793e5b75505Sopenharmony_ci EVP_PKEY_free(info->pubkey); 794e5b75505Sopenharmony_ci os_free(info); 795e5b75505Sopenharmony_ci} 796e5b75505Sopenharmony_ci 797e5b75505Sopenharmony_ci 798e5b75505Sopenharmony_ciconst char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type) 799e5b75505Sopenharmony_ci{ 800e5b75505Sopenharmony_ci switch (type) { 801e5b75505Sopenharmony_ci case DPP_BOOTSTRAP_QR_CODE: 802e5b75505Sopenharmony_ci return "QRCODE"; 803e5b75505Sopenharmony_ci case DPP_BOOTSTRAP_PKEX: 804e5b75505Sopenharmony_ci return "PKEX"; 805e5b75505Sopenharmony_ci } 806e5b75505Sopenharmony_ci return "??"; 807e5b75505Sopenharmony_ci} 808e5b75505Sopenharmony_ci 809e5b75505Sopenharmony_ci 810e5b75505Sopenharmony_cistatic int dpp_uri_valid_info(const char *info) 811e5b75505Sopenharmony_ci{ 812e5b75505Sopenharmony_ci while (*info) { 813e5b75505Sopenharmony_ci unsigned char val = *info++; 814e5b75505Sopenharmony_ci 815e5b75505Sopenharmony_ci if (val < 0x20 || val > 0x7e || val == 0x3b) 816e5b75505Sopenharmony_ci return 0; 817e5b75505Sopenharmony_ci } 818e5b75505Sopenharmony_ci 819e5b75505Sopenharmony_ci return 1; 820e5b75505Sopenharmony_ci} 821e5b75505Sopenharmony_ci 822e5b75505Sopenharmony_ci 823e5b75505Sopenharmony_cistatic int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri) 824e5b75505Sopenharmony_ci{ 825e5b75505Sopenharmony_ci bi->uri = os_strdup(uri); 826e5b75505Sopenharmony_ci return bi->uri ? 0 : -1; 827e5b75505Sopenharmony_ci} 828e5b75505Sopenharmony_ci 829e5b75505Sopenharmony_ci 830e5b75505Sopenharmony_ciint dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi, 831e5b75505Sopenharmony_ci const char *chan_list) 832e5b75505Sopenharmony_ci{ 833e5b75505Sopenharmony_ci const char *pos = chan_list, *pos2; 834e5b75505Sopenharmony_ci int opclass = -1, channel, freq; 835e5b75505Sopenharmony_ci 836e5b75505Sopenharmony_ci while (pos && *pos && *pos != ';') { 837e5b75505Sopenharmony_ci pos2 = pos; 838e5b75505Sopenharmony_ci while (*pos2 >= '0' && *pos2 <= '9') 839e5b75505Sopenharmony_ci pos2++; 840e5b75505Sopenharmony_ci if (*pos2 == '/') { 841e5b75505Sopenharmony_ci opclass = atoi(pos); 842e5b75505Sopenharmony_ci pos = pos2 + 1; 843e5b75505Sopenharmony_ci } 844e5b75505Sopenharmony_ci if (opclass <= 0) 845e5b75505Sopenharmony_ci goto fail; 846e5b75505Sopenharmony_ci channel = atoi(pos); 847e5b75505Sopenharmony_ci if (channel <= 0) 848e5b75505Sopenharmony_ci goto fail; 849e5b75505Sopenharmony_ci while (*pos >= '0' && *pos <= '9') 850e5b75505Sopenharmony_ci pos++; 851e5b75505Sopenharmony_ci freq = ieee80211_chan_to_freq(NULL, opclass, channel); 852e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 853e5b75505Sopenharmony_ci "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d", 854e5b75505Sopenharmony_ci opclass, channel, freq); 855e5b75505Sopenharmony_ci if (freq < 0) { 856e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 857e5b75505Sopenharmony_ci "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)", 858e5b75505Sopenharmony_ci opclass, channel); 859e5b75505Sopenharmony_ci } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) { 860e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 861e5b75505Sopenharmony_ci "DPP: Too many channels in URI channel-list - ignore list"); 862e5b75505Sopenharmony_ci bi->num_freq = 0; 863e5b75505Sopenharmony_ci break; 864e5b75505Sopenharmony_ci } else { 865e5b75505Sopenharmony_ci bi->freq[bi->num_freq++] = freq; 866e5b75505Sopenharmony_ci } 867e5b75505Sopenharmony_ci 868e5b75505Sopenharmony_ci if (*pos == ';' || *pos == '\0') 869e5b75505Sopenharmony_ci break; 870e5b75505Sopenharmony_ci if (*pos != ',') 871e5b75505Sopenharmony_ci goto fail; 872e5b75505Sopenharmony_ci pos++; 873e5b75505Sopenharmony_ci } 874e5b75505Sopenharmony_ci 875e5b75505Sopenharmony_ci return 0; 876e5b75505Sopenharmony_cifail: 877e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list"); 878e5b75505Sopenharmony_ci return -1; 879e5b75505Sopenharmony_ci} 880e5b75505Sopenharmony_ci 881e5b75505Sopenharmony_ci 882e5b75505Sopenharmony_ciint dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac) 883e5b75505Sopenharmony_ci{ 884e5b75505Sopenharmony_ci if (!mac) 885e5b75505Sopenharmony_ci return 0; 886e5b75505Sopenharmony_ci 887e5b75505Sopenharmony_ci if (hwaddr_aton2(mac, bi->mac_addr) < 0) { 888e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac"); 889e5b75505Sopenharmony_ci return -1; 890e5b75505Sopenharmony_ci } 891e5b75505Sopenharmony_ci 892e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr)); 893e5b75505Sopenharmony_ci 894e5b75505Sopenharmony_ci return 0; 895e5b75505Sopenharmony_ci} 896e5b75505Sopenharmony_ci 897e5b75505Sopenharmony_ci 898e5b75505Sopenharmony_ciint dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info) 899e5b75505Sopenharmony_ci{ 900e5b75505Sopenharmony_ci const char *end; 901e5b75505Sopenharmony_ci 902e5b75505Sopenharmony_ci if (!info) 903e5b75505Sopenharmony_ci return 0; 904e5b75505Sopenharmony_ci 905e5b75505Sopenharmony_ci end = os_strchr(info, ';'); 906e5b75505Sopenharmony_ci if (!end) 907e5b75505Sopenharmony_ci end = info + os_strlen(info); 908e5b75505Sopenharmony_ci bi->info = os_malloc(end - info + 1); 909e5b75505Sopenharmony_ci if (!bi->info) 910e5b75505Sopenharmony_ci return -1; 911e5b75505Sopenharmony_ci os_memcpy(bi->info, info, end - info); 912e5b75505Sopenharmony_ci bi->info[end - info] = '\0'; 913e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info); 914e5b75505Sopenharmony_ci if (!dpp_uri_valid_info(bi->info)) { 915e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload"); 916e5b75505Sopenharmony_ci return -1; 917e5b75505Sopenharmony_ci } 918e5b75505Sopenharmony_ci 919e5b75505Sopenharmony_ci return 0; 920e5b75505Sopenharmony_ci} 921e5b75505Sopenharmony_ci 922e5b75505Sopenharmony_ci 923e5b75505Sopenharmony_cistatic const struct dpp_curve_params * 924e5b75505Sopenharmony_cidpp_get_curve_oid(const ASN1_OBJECT *poid) 925e5b75505Sopenharmony_ci{ 926e5b75505Sopenharmony_ci ASN1_OBJECT *oid; 927e5b75505Sopenharmony_ci int i; 928e5b75505Sopenharmony_ci 929e5b75505Sopenharmony_ci for (i = 0; dpp_curves[i].name; i++) { 930e5b75505Sopenharmony_ci oid = OBJ_txt2obj(dpp_curves[i].name, 0); 931e5b75505Sopenharmony_ci if (oid && OBJ_cmp(poid, oid) == 0) 932e5b75505Sopenharmony_ci return &dpp_curves[i]; 933e5b75505Sopenharmony_ci } 934e5b75505Sopenharmony_ci return NULL; 935e5b75505Sopenharmony_ci} 936e5b75505Sopenharmony_ci 937e5b75505Sopenharmony_ci 938e5b75505Sopenharmony_cistatic const struct dpp_curve_params * dpp_get_curve_nid(int nid) 939e5b75505Sopenharmony_ci{ 940e5b75505Sopenharmony_ci int i, tmp; 941e5b75505Sopenharmony_ci 942e5b75505Sopenharmony_ci if (!nid) 943e5b75505Sopenharmony_ci return NULL; 944e5b75505Sopenharmony_ci for (i = 0; dpp_curves[i].name; i++) { 945e5b75505Sopenharmony_ci tmp = OBJ_txt2nid(dpp_curves[i].name); 946e5b75505Sopenharmony_ci if (tmp == nid) 947e5b75505Sopenharmony_ci return &dpp_curves[i]; 948e5b75505Sopenharmony_ci } 949e5b75505Sopenharmony_ci return NULL; 950e5b75505Sopenharmony_ci} 951e5b75505Sopenharmony_ci 952e5b75505Sopenharmony_ci 953e5b75505Sopenharmony_cistatic int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) 954e5b75505Sopenharmony_ci{ 955e5b75505Sopenharmony_ci const char *end; 956e5b75505Sopenharmony_ci u8 *data; 957e5b75505Sopenharmony_ci size_t data_len; 958e5b75505Sopenharmony_ci EVP_PKEY *pkey; 959e5b75505Sopenharmony_ci const unsigned char *p; 960e5b75505Sopenharmony_ci int res; 961e5b75505Sopenharmony_ci X509_PUBKEY *pub = NULL; 962e5b75505Sopenharmony_ci ASN1_OBJECT *ppkalg; 963e5b75505Sopenharmony_ci const unsigned char *pk; 964e5b75505Sopenharmony_ci int ppklen; 965e5b75505Sopenharmony_ci X509_ALGOR *pa; 966e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 967e5b75505Sopenharmony_ci (defined(LIBRESSL_VERSION_NUMBER) && \ 968e5b75505Sopenharmony_ci LIBRESSL_VERSION_NUMBER < 0x20800000L) 969e5b75505Sopenharmony_ci ASN1_OBJECT *pa_oid; 970e5b75505Sopenharmony_ci#else 971e5b75505Sopenharmony_ci const ASN1_OBJECT *pa_oid; 972e5b75505Sopenharmony_ci#endif 973e5b75505Sopenharmony_ci const void *pval; 974e5b75505Sopenharmony_ci int ptype; 975e5b75505Sopenharmony_ci const ASN1_OBJECT *poid; 976e5b75505Sopenharmony_ci char buf[100]; 977e5b75505Sopenharmony_ci 978e5b75505Sopenharmony_ci end = os_strchr(info, ';'); 979e5b75505Sopenharmony_ci if (!end) 980e5b75505Sopenharmony_ci return -1; 981e5b75505Sopenharmony_ci 982e5b75505Sopenharmony_ci data = base64_decode((const unsigned char *) info, end - info, 983e5b75505Sopenharmony_ci &data_len); 984e5b75505Sopenharmony_ci if (!data) { 985e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 986e5b75505Sopenharmony_ci "DPP: Invalid base64 encoding on URI public-key"); 987e5b75505Sopenharmony_ci return -1; 988e5b75505Sopenharmony_ci } 989e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key", 990e5b75505Sopenharmony_ci data, data_len); 991e5b75505Sopenharmony_ci 992e5b75505Sopenharmony_ci if (sha256_vector(1, (const u8 **) &data, &data_len, 993e5b75505Sopenharmony_ci bi->pubkey_hash) < 0) { 994e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 995e5b75505Sopenharmony_ci os_free(data); 996e5b75505Sopenharmony_ci return -1; 997e5b75505Sopenharmony_ci } 998e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", 999e5b75505Sopenharmony_ci bi->pubkey_hash, SHA256_MAC_LEN); 1000e5b75505Sopenharmony_ci 1001e5b75505Sopenharmony_ci /* DER encoded ASN.1 SubjectPublicKeyInfo 1002e5b75505Sopenharmony_ci * 1003e5b75505Sopenharmony_ci * SubjectPublicKeyInfo ::= SEQUENCE { 1004e5b75505Sopenharmony_ci * algorithm AlgorithmIdentifier, 1005e5b75505Sopenharmony_ci * subjectPublicKey BIT STRING } 1006e5b75505Sopenharmony_ci * 1007e5b75505Sopenharmony_ci * AlgorithmIdentifier ::= SEQUENCE { 1008e5b75505Sopenharmony_ci * algorithm OBJECT IDENTIFIER, 1009e5b75505Sopenharmony_ci * parameters ANY DEFINED BY algorithm OPTIONAL } 1010e5b75505Sopenharmony_ci * 1011e5b75505Sopenharmony_ci * subjectPublicKey = compressed format public key per ANSI X9.63 1012e5b75505Sopenharmony_ci * algorithm = ecPublicKey (1.2.840.10045.2.1) 1013e5b75505Sopenharmony_ci * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g., 1014e5b75505Sopenharmony_ci * prime256v1 (1.2.840.10045.3.1.7) 1015e5b75505Sopenharmony_ci */ 1016e5b75505Sopenharmony_ci 1017e5b75505Sopenharmony_ci p = data; 1018e5b75505Sopenharmony_ci pkey = d2i_PUBKEY(NULL, &p, data_len); 1019e5b75505Sopenharmony_ci os_free(data); 1020e5b75505Sopenharmony_ci 1021e5b75505Sopenharmony_ci if (!pkey) { 1022e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1023e5b75505Sopenharmony_ci "DPP: Could not parse URI public-key SubjectPublicKeyInfo"); 1024e5b75505Sopenharmony_ci return -1; 1025e5b75505Sopenharmony_ci } 1026e5b75505Sopenharmony_ci 1027e5b75505Sopenharmony_ci if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { 1028e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1029e5b75505Sopenharmony_ci "DPP: SubjectPublicKeyInfo does not describe an EC key"); 1030e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1031e5b75505Sopenharmony_ci return -1; 1032e5b75505Sopenharmony_ci } 1033e5b75505Sopenharmony_ci 1034e5b75505Sopenharmony_ci res = X509_PUBKEY_set(&pub, pkey); 1035e5b75505Sopenharmony_ci if (res != 1) { 1036e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey"); 1037e5b75505Sopenharmony_ci goto fail; 1038e5b75505Sopenharmony_ci } 1039e5b75505Sopenharmony_ci 1040e5b75505Sopenharmony_ci res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub); 1041e5b75505Sopenharmony_ci if (res != 1) { 1042e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1043e5b75505Sopenharmony_ci "DPP: Could not extract SubjectPublicKeyInfo parameters"); 1044e5b75505Sopenharmony_ci goto fail; 1045e5b75505Sopenharmony_ci } 1046e5b75505Sopenharmony_ci res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0); 1047e5b75505Sopenharmony_ci if (res < 0 || (size_t) res >= sizeof(buf)) { 1048e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1049e5b75505Sopenharmony_ci "DPP: Could not extract SubjectPublicKeyInfo algorithm"); 1050e5b75505Sopenharmony_ci goto fail; 1051e5b75505Sopenharmony_ci } 1052e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf); 1053e5b75505Sopenharmony_ci if (os_strcmp(buf, "id-ecPublicKey") != 0) { 1054e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1055e5b75505Sopenharmony_ci "DPP: Unsupported SubjectPublicKeyInfo algorithm"); 1056e5b75505Sopenharmony_ci goto fail; 1057e5b75505Sopenharmony_ci } 1058e5b75505Sopenharmony_ci 1059e5b75505Sopenharmony_ci X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa); 1060e5b75505Sopenharmony_ci if (ptype != V_ASN1_OBJECT) { 1061e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1062e5b75505Sopenharmony_ci "DPP: SubjectPublicKeyInfo parameters did not contain an OID"); 1063e5b75505Sopenharmony_ci goto fail; 1064e5b75505Sopenharmony_ci } 1065e5b75505Sopenharmony_ci poid = pval; 1066e5b75505Sopenharmony_ci res = OBJ_obj2txt(buf, sizeof(buf), poid, 0); 1067e5b75505Sopenharmony_ci if (res < 0 || (size_t) res >= sizeof(buf)) { 1068e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1069e5b75505Sopenharmony_ci "DPP: Could not extract SubjectPublicKeyInfo parameters OID"); 1070e5b75505Sopenharmony_ci goto fail; 1071e5b75505Sopenharmony_ci } 1072e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf); 1073e5b75505Sopenharmony_ci bi->curve = dpp_get_curve_oid(poid); 1074e5b75505Sopenharmony_ci if (!bi->curve) { 1075e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1076e5b75505Sopenharmony_ci "DPP: Unsupported SubjectPublicKeyInfo curve: %s", 1077e5b75505Sopenharmony_ci buf); 1078e5b75505Sopenharmony_ci goto fail; 1079e5b75505Sopenharmony_ci } 1080e5b75505Sopenharmony_ci 1081e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen); 1082e5b75505Sopenharmony_ci 1083e5b75505Sopenharmony_ci X509_PUBKEY_free(pub); 1084e5b75505Sopenharmony_ci bi->pubkey = pkey; 1085e5b75505Sopenharmony_ci return 0; 1086e5b75505Sopenharmony_cifail: 1087e5b75505Sopenharmony_ci X509_PUBKEY_free(pub); 1088e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1089e5b75505Sopenharmony_ci return -1; 1090e5b75505Sopenharmony_ci} 1091e5b75505Sopenharmony_ci 1092e5b75505Sopenharmony_ci 1093e5b75505Sopenharmony_cistatic struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) 1094e5b75505Sopenharmony_ci{ 1095e5b75505Sopenharmony_ci const char *pos = uri; 1096e5b75505Sopenharmony_ci const char *end; 1097e5b75505Sopenharmony_ci const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL; 1098e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 1099e5b75505Sopenharmony_ci 1100e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri)); 1101e5b75505Sopenharmony_ci 1102e5b75505Sopenharmony_ci if (os_strncmp(pos, "DPP:", 4) != 0) { 1103e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Not a DPP URI"); 1104e5b75505Sopenharmony_ci return NULL; 1105e5b75505Sopenharmony_ci } 1106e5b75505Sopenharmony_ci pos += 4; 1107e5b75505Sopenharmony_ci 1108e5b75505Sopenharmony_ci for (;;) { 1109e5b75505Sopenharmony_ci end = os_strchr(pos, ';'); 1110e5b75505Sopenharmony_ci if (!end) 1111e5b75505Sopenharmony_ci break; 1112e5b75505Sopenharmony_ci 1113e5b75505Sopenharmony_ci if (end == pos) { 1114e5b75505Sopenharmony_ci /* Handle terminating ";;" and ignore unexpected ";" 1115e5b75505Sopenharmony_ci * for parsing robustness. */ 1116e5b75505Sopenharmony_ci pos++; 1117e5b75505Sopenharmony_ci continue; 1118e5b75505Sopenharmony_ci } 1119e5b75505Sopenharmony_ci 1120e5b75505Sopenharmony_ci if (pos[0] == 'C' && pos[1] == ':' && !chan_list) 1121e5b75505Sopenharmony_ci chan_list = pos + 2; 1122e5b75505Sopenharmony_ci else if (pos[0] == 'M' && pos[1] == ':' && !mac) 1123e5b75505Sopenharmony_ci mac = pos + 2; 1124e5b75505Sopenharmony_ci else if (pos[0] == 'I' && pos[1] == ':' && !info) 1125e5b75505Sopenharmony_ci info = pos + 2; 1126e5b75505Sopenharmony_ci else if (pos[0] == 'K' && pos[1] == ':' && !pk) 1127e5b75505Sopenharmony_ci pk = pos + 2; 1128e5b75505Sopenharmony_ci else 1129e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, 1130e5b75505Sopenharmony_ci "DPP: Ignore unrecognized URI parameter", 1131e5b75505Sopenharmony_ci pos, end - pos); 1132e5b75505Sopenharmony_ci pos = end + 1; 1133e5b75505Sopenharmony_ci } 1134e5b75505Sopenharmony_ci 1135e5b75505Sopenharmony_ci if (!pk) { 1136e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: URI missing public-key"); 1137e5b75505Sopenharmony_ci return NULL; 1138e5b75505Sopenharmony_ci } 1139e5b75505Sopenharmony_ci 1140e5b75505Sopenharmony_ci bi = os_zalloc(sizeof(*bi)); 1141e5b75505Sopenharmony_ci if (!bi) 1142e5b75505Sopenharmony_ci return NULL; 1143e5b75505Sopenharmony_ci 1144e5b75505Sopenharmony_ci if (dpp_clone_uri(bi, uri) < 0 || 1145e5b75505Sopenharmony_ci dpp_parse_uri_chan_list(bi, chan_list) < 0 || 1146e5b75505Sopenharmony_ci dpp_parse_uri_mac(bi, mac) < 0 || 1147e5b75505Sopenharmony_ci dpp_parse_uri_info(bi, info) < 0 || 1148e5b75505Sopenharmony_ci dpp_parse_uri_pk(bi, pk) < 0) { 1149e5b75505Sopenharmony_ci dpp_bootstrap_info_free(bi); 1150e5b75505Sopenharmony_ci bi = NULL; 1151e5b75505Sopenharmony_ci } 1152e5b75505Sopenharmony_ci 1153e5b75505Sopenharmony_ci return bi; 1154e5b75505Sopenharmony_ci} 1155e5b75505Sopenharmony_ci 1156e5b75505Sopenharmony_ci 1157e5b75505Sopenharmony_cistruct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri) 1158e5b75505Sopenharmony_ci{ 1159e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 1160e5b75505Sopenharmony_ci 1161e5b75505Sopenharmony_ci bi = dpp_parse_uri(uri); 1162e5b75505Sopenharmony_ci if (bi) 1163e5b75505Sopenharmony_ci bi->type = DPP_BOOTSTRAP_QR_CODE; 1164e5b75505Sopenharmony_ci return bi; 1165e5b75505Sopenharmony_ci} 1166e5b75505Sopenharmony_ci 1167e5b75505Sopenharmony_ci 1168e5b75505Sopenharmony_cistatic void dpp_debug_print_key(const char *title, EVP_PKEY *key) 1169e5b75505Sopenharmony_ci{ 1170e5b75505Sopenharmony_ci EC_KEY *eckey; 1171e5b75505Sopenharmony_ci BIO *out; 1172e5b75505Sopenharmony_ci size_t rlen; 1173e5b75505Sopenharmony_ci char *txt; 1174e5b75505Sopenharmony_ci int res; 1175e5b75505Sopenharmony_ci unsigned char *der = NULL; 1176e5b75505Sopenharmony_ci int der_len; 1177e5b75505Sopenharmony_ci const EC_GROUP *group; 1178e5b75505Sopenharmony_ci const EC_POINT *point; 1179e5b75505Sopenharmony_ci 1180e5b75505Sopenharmony_ci out = BIO_new(BIO_s_mem()); 1181e5b75505Sopenharmony_ci if (!out) 1182e5b75505Sopenharmony_ci return; 1183e5b75505Sopenharmony_ci 1184e5b75505Sopenharmony_ci EVP_PKEY_print_private(out, key, 0, NULL); 1185e5b75505Sopenharmony_ci rlen = BIO_ctrl_pending(out); 1186e5b75505Sopenharmony_ci txt = os_malloc(rlen + 1); 1187e5b75505Sopenharmony_ci if (txt) { 1188e5b75505Sopenharmony_ci res = BIO_read(out, txt, rlen); 1189e5b75505Sopenharmony_ci if (res > 0) { 1190e5b75505Sopenharmony_ci txt[res] = '\0'; 1191e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: %s", title, txt); 1192e5b75505Sopenharmony_ci } 1193e5b75505Sopenharmony_ci os_free(txt); 1194e5b75505Sopenharmony_ci } 1195e5b75505Sopenharmony_ci BIO_free(out); 1196e5b75505Sopenharmony_ci 1197e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(key); 1198e5b75505Sopenharmony_ci if (!eckey) 1199e5b75505Sopenharmony_ci return; 1200e5b75505Sopenharmony_ci 1201e5b75505Sopenharmony_ci group = EC_KEY_get0_group(eckey); 1202e5b75505Sopenharmony_ci point = EC_KEY_get0_public_key(eckey); 1203e5b75505Sopenharmony_ci if (group && point) 1204e5b75505Sopenharmony_ci dpp_debug_print_point(title, group, point); 1205e5b75505Sopenharmony_ci 1206e5b75505Sopenharmony_ci der_len = i2d_ECPrivateKey(eckey, &der); 1207e5b75505Sopenharmony_ci if (der_len > 0) 1208e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len); 1209e5b75505Sopenharmony_ci OPENSSL_free(der); 1210e5b75505Sopenharmony_ci if (der_len <= 0) { 1211e5b75505Sopenharmony_ci der = NULL; 1212e5b75505Sopenharmony_ci der_len = i2d_EC_PUBKEY(eckey, &der); 1213e5b75505Sopenharmony_ci if (der_len > 0) 1214e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len); 1215e5b75505Sopenharmony_ci OPENSSL_free(der); 1216e5b75505Sopenharmony_ci } 1217e5b75505Sopenharmony_ci 1218e5b75505Sopenharmony_ci EC_KEY_free(eckey); 1219e5b75505Sopenharmony_ci} 1220e5b75505Sopenharmony_ci 1221e5b75505Sopenharmony_ci 1222e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve) 1223e5b75505Sopenharmony_ci{ 1224e5b75505Sopenharmony_ci EVP_PKEY_CTX *kctx = NULL; 1225e5b75505Sopenharmony_ci EC_KEY *ec_params = NULL; 1226e5b75505Sopenharmony_ci EVP_PKEY *params = NULL, *key = NULL; 1227e5b75505Sopenharmony_ci int nid; 1228e5b75505Sopenharmony_ci 1229e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Generating a keypair"); 1230e5b75505Sopenharmony_ci 1231e5b75505Sopenharmony_ci nid = OBJ_txt2nid(curve->name); 1232e5b75505Sopenharmony_ci if (nid == NID_undef) { 1233e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name); 1234e5b75505Sopenharmony_ci return NULL; 1235e5b75505Sopenharmony_ci } 1236e5b75505Sopenharmony_ci 1237e5b75505Sopenharmony_ci ec_params = EC_KEY_new_by_curve_name(nid); 1238e5b75505Sopenharmony_ci if (!ec_params) { 1239e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1240e5b75505Sopenharmony_ci "DPP: Failed to generate EC_KEY parameters"); 1241e5b75505Sopenharmony_ci goto fail; 1242e5b75505Sopenharmony_ci } 1243e5b75505Sopenharmony_ci EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE); 1244e5b75505Sopenharmony_ci params = EVP_PKEY_new(); 1245e5b75505Sopenharmony_ci if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) { 1246e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1247e5b75505Sopenharmony_ci "DPP: Failed to generate EVP_PKEY parameters"); 1248e5b75505Sopenharmony_ci goto fail; 1249e5b75505Sopenharmony_ci } 1250e5b75505Sopenharmony_ci 1251e5b75505Sopenharmony_ci kctx = EVP_PKEY_CTX_new(params, NULL); 1252e5b75505Sopenharmony_ci if (!kctx || 1253e5b75505Sopenharmony_ci EVP_PKEY_keygen_init(kctx) != 1 || 1254e5b75505Sopenharmony_ci EVP_PKEY_keygen(kctx, &key) != 1) { 1255e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key"); 1256e5b75505Sopenharmony_ci key = NULL; 1257e5b75505Sopenharmony_ci goto fail; 1258e5b75505Sopenharmony_ci } 1259e5b75505Sopenharmony_ci 1260e5b75505Sopenharmony_ci if (wpa_debug_show_keys) 1261e5b75505Sopenharmony_ci dpp_debug_print_key("Own generated key", key); 1262e5b75505Sopenharmony_ci 1263e5b75505Sopenharmony_cifail: 1264e5b75505Sopenharmony_ci EC_KEY_free(ec_params); 1265e5b75505Sopenharmony_ci EVP_PKEY_free(params); 1266e5b75505Sopenharmony_ci EVP_PKEY_CTX_free(kctx); 1267e5b75505Sopenharmony_ci return key; 1268e5b75505Sopenharmony_ci} 1269e5b75505Sopenharmony_ci 1270e5b75505Sopenharmony_ci 1271e5b75505Sopenharmony_cistatic const struct dpp_curve_params * 1272e5b75505Sopenharmony_cidpp_get_curve_name(const char *name) 1273e5b75505Sopenharmony_ci{ 1274e5b75505Sopenharmony_ci int i; 1275e5b75505Sopenharmony_ci 1276e5b75505Sopenharmony_ci for (i = 0; dpp_curves[i].name; i++) { 1277e5b75505Sopenharmony_ci if (os_strcmp(name, dpp_curves[i].name) == 0 || 1278e5b75505Sopenharmony_ci (dpp_curves[i].jwk_crv && 1279e5b75505Sopenharmony_ci os_strcmp(name, dpp_curves[i].jwk_crv) == 0)) 1280e5b75505Sopenharmony_ci return &dpp_curves[i]; 1281e5b75505Sopenharmony_ci } 1282e5b75505Sopenharmony_ci return NULL; 1283e5b75505Sopenharmony_ci} 1284e5b75505Sopenharmony_ci 1285e5b75505Sopenharmony_ci 1286e5b75505Sopenharmony_cistatic const struct dpp_curve_params * 1287e5b75505Sopenharmony_cidpp_get_curve_jwk_crv(const char *name) 1288e5b75505Sopenharmony_ci{ 1289e5b75505Sopenharmony_ci int i; 1290e5b75505Sopenharmony_ci 1291e5b75505Sopenharmony_ci for (i = 0; dpp_curves[i].name; i++) { 1292e5b75505Sopenharmony_ci if (dpp_curves[i].jwk_crv && 1293e5b75505Sopenharmony_ci os_strcmp(name, dpp_curves[i].jwk_crv) == 0) 1294e5b75505Sopenharmony_ci return &dpp_curves[i]; 1295e5b75505Sopenharmony_ci } 1296e5b75505Sopenharmony_ci return NULL; 1297e5b75505Sopenharmony_ci} 1298e5b75505Sopenharmony_ci 1299e5b75505Sopenharmony_ci 1300e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve, 1301e5b75505Sopenharmony_ci const u8 *privkey, size_t privkey_len) 1302e5b75505Sopenharmony_ci{ 1303e5b75505Sopenharmony_ci EVP_PKEY *pkey; 1304e5b75505Sopenharmony_ci EC_KEY *eckey; 1305e5b75505Sopenharmony_ci const EC_GROUP *group; 1306e5b75505Sopenharmony_ci int nid; 1307e5b75505Sopenharmony_ci 1308e5b75505Sopenharmony_ci pkey = EVP_PKEY_new(); 1309e5b75505Sopenharmony_ci if (!pkey) 1310e5b75505Sopenharmony_ci return NULL; 1311e5b75505Sopenharmony_ci eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len); 1312e5b75505Sopenharmony_ci if (!eckey) { 1313e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1314e5b75505Sopenharmony_ci "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s", 1315e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 1316e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1317e5b75505Sopenharmony_ci return NULL; 1318e5b75505Sopenharmony_ci } 1319e5b75505Sopenharmony_ci group = EC_KEY_get0_group(eckey); 1320e5b75505Sopenharmony_ci if (!group) { 1321e5b75505Sopenharmony_ci EC_KEY_free(eckey); 1322e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1323e5b75505Sopenharmony_ci return NULL; 1324e5b75505Sopenharmony_ci } 1325e5b75505Sopenharmony_ci nid = EC_GROUP_get_curve_name(group); 1326e5b75505Sopenharmony_ci *curve = dpp_get_curve_nid(nid); 1327e5b75505Sopenharmony_ci if (!*curve) { 1328e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1329e5b75505Sopenharmony_ci "DPP: Unsupported curve (nid=%d) in pre-assigned key", 1330e5b75505Sopenharmony_ci nid); 1331e5b75505Sopenharmony_ci EC_KEY_free(eckey); 1332e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1333e5b75505Sopenharmony_ci return NULL; 1334e5b75505Sopenharmony_ci } 1335e5b75505Sopenharmony_ci 1336e5b75505Sopenharmony_ci if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) { 1337e5b75505Sopenharmony_ci EC_KEY_free(eckey); 1338e5b75505Sopenharmony_ci EVP_PKEY_free(pkey); 1339e5b75505Sopenharmony_ci return NULL; 1340e5b75505Sopenharmony_ci } 1341e5b75505Sopenharmony_ci return pkey; 1342e5b75505Sopenharmony_ci} 1343e5b75505Sopenharmony_ci 1344e5b75505Sopenharmony_ci 1345e5b75505Sopenharmony_citypedef struct { 1346e5b75505Sopenharmony_ci /* AlgorithmIdentifier ecPublicKey with optional parameters present 1347e5b75505Sopenharmony_ci * as an OID identifying the curve */ 1348e5b75505Sopenharmony_ci X509_ALGOR *alg; 1349e5b75505Sopenharmony_ci /* Compressed format public key per ANSI X9.63 */ 1350e5b75505Sopenharmony_ci ASN1_BIT_STRING *pub_key; 1351e5b75505Sopenharmony_ci} DPP_BOOTSTRAPPING_KEY; 1352e5b75505Sopenharmony_ci 1353e5b75505Sopenharmony_ciASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = { 1354e5b75505Sopenharmony_ci ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR), 1355e5b75505Sopenharmony_ci ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING) 1356e5b75505Sopenharmony_ci} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY); 1357e5b75505Sopenharmony_ci 1358e5b75505Sopenharmony_ciIMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY); 1359e5b75505Sopenharmony_ci 1360e5b75505Sopenharmony_ci 1361e5b75505Sopenharmony_cistatic struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key) 1362e5b75505Sopenharmony_ci{ 1363e5b75505Sopenharmony_ci unsigned char *der = NULL; 1364e5b75505Sopenharmony_ci int der_len; 1365e5b75505Sopenharmony_ci EC_KEY *eckey; 1366e5b75505Sopenharmony_ci struct wpabuf *ret = NULL; 1367e5b75505Sopenharmony_ci size_t len; 1368e5b75505Sopenharmony_ci const EC_GROUP *group; 1369e5b75505Sopenharmony_ci const EC_POINT *point; 1370e5b75505Sopenharmony_ci BN_CTX *ctx; 1371e5b75505Sopenharmony_ci DPP_BOOTSTRAPPING_KEY *bootstrap = NULL; 1372e5b75505Sopenharmony_ci int nid; 1373e5b75505Sopenharmony_ci 1374e5b75505Sopenharmony_ci ctx = BN_CTX_new(); 1375e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(key); 1376e5b75505Sopenharmony_ci if (!ctx || !eckey) 1377e5b75505Sopenharmony_ci goto fail; 1378e5b75505Sopenharmony_ci 1379e5b75505Sopenharmony_ci group = EC_KEY_get0_group(eckey); 1380e5b75505Sopenharmony_ci point = EC_KEY_get0_public_key(eckey); 1381e5b75505Sopenharmony_ci if (!group || !point) 1382e5b75505Sopenharmony_ci goto fail; 1383e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: bootstrap public key", group, point); 1384e5b75505Sopenharmony_ci nid = EC_GROUP_get_curve_name(group); 1385e5b75505Sopenharmony_ci 1386e5b75505Sopenharmony_ci bootstrap = DPP_BOOTSTRAPPING_KEY_new(); 1387e5b75505Sopenharmony_ci if (!bootstrap || 1388e5b75505Sopenharmony_ci X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC), 1389e5b75505Sopenharmony_ci V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1) 1390e5b75505Sopenharmony_ci goto fail; 1391e5b75505Sopenharmony_ci 1392e5b75505Sopenharmony_ci len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, 1393e5b75505Sopenharmony_ci NULL, 0, ctx); 1394e5b75505Sopenharmony_ci if (len == 0) 1395e5b75505Sopenharmony_ci goto fail; 1396e5b75505Sopenharmony_ci 1397e5b75505Sopenharmony_ci der = OPENSSL_malloc(len); 1398e5b75505Sopenharmony_ci if (!der) 1399e5b75505Sopenharmony_ci goto fail; 1400e5b75505Sopenharmony_ci len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, 1401e5b75505Sopenharmony_ci der, len, ctx); 1402e5b75505Sopenharmony_ci 1403e5b75505Sopenharmony_ci OPENSSL_free(bootstrap->pub_key->data); 1404e5b75505Sopenharmony_ci bootstrap->pub_key->data = der; 1405e5b75505Sopenharmony_ci der = NULL; 1406e5b75505Sopenharmony_ci bootstrap->pub_key->length = len; 1407e5b75505Sopenharmony_ci /* No unused bits */ 1408e5b75505Sopenharmony_ci bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); 1409e5b75505Sopenharmony_ci bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT; 1410e5b75505Sopenharmony_ci 1411e5b75505Sopenharmony_ci der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der); 1412e5b75505Sopenharmony_ci if (der_len <= 0) { 1413e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1414e5b75505Sopenharmony_ci "DDP: Failed to build DER encoded public key"); 1415e5b75505Sopenharmony_ci goto fail; 1416e5b75505Sopenharmony_ci } 1417e5b75505Sopenharmony_ci 1418e5b75505Sopenharmony_ci ret = wpabuf_alloc_copy(der, der_len); 1419e5b75505Sopenharmony_cifail: 1420e5b75505Sopenharmony_ci DPP_BOOTSTRAPPING_KEY_free(bootstrap); 1421e5b75505Sopenharmony_ci OPENSSL_free(der); 1422e5b75505Sopenharmony_ci EC_KEY_free(eckey); 1423e5b75505Sopenharmony_ci BN_CTX_free(ctx); 1424e5b75505Sopenharmony_ci return ret; 1425e5b75505Sopenharmony_ci} 1426e5b75505Sopenharmony_ci 1427e5b75505Sopenharmony_ci 1428e5b75505Sopenharmony_ciint dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) 1429e5b75505Sopenharmony_ci{ 1430e5b75505Sopenharmony_ci struct wpabuf *der; 1431e5b75505Sopenharmony_ci int res; 1432e5b75505Sopenharmony_ci const u8 *addr[1]; 1433e5b75505Sopenharmony_ci size_t len[1]; 1434e5b75505Sopenharmony_ci 1435e5b75505Sopenharmony_ci der = dpp_bootstrap_key_der(bi->pubkey); 1436e5b75505Sopenharmony_ci if (!der) 1437e5b75505Sopenharmony_ci return -1; 1438e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", 1439e5b75505Sopenharmony_ci der); 1440e5b75505Sopenharmony_ci 1441e5b75505Sopenharmony_ci addr[0] = wpabuf_head(der); 1442e5b75505Sopenharmony_ci len[0] = wpabuf_len(der); 1443e5b75505Sopenharmony_ci res = sha256_vector(1, addr, len, bi->pubkey_hash); 1444e5b75505Sopenharmony_ci if (res < 0) 1445e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 1446e5b75505Sopenharmony_ci else 1447e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, 1448e5b75505Sopenharmony_ci SHA256_MAC_LEN); 1449e5b75505Sopenharmony_ci wpabuf_free(der); 1450e5b75505Sopenharmony_ci return res; 1451e5b75505Sopenharmony_ci} 1452e5b75505Sopenharmony_ci 1453e5b75505Sopenharmony_ci 1454e5b75505Sopenharmony_cichar * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, 1455e5b75505Sopenharmony_ci const u8 *privkey, size_t privkey_len) 1456e5b75505Sopenharmony_ci{ 1457e5b75505Sopenharmony_ci unsigned char *base64 = NULL; 1458e5b75505Sopenharmony_ci char *pos, *end; 1459e5b75505Sopenharmony_ci size_t len; 1460e5b75505Sopenharmony_ci struct wpabuf *der = NULL; 1461e5b75505Sopenharmony_ci const u8 *addr[1]; 1462e5b75505Sopenharmony_ci int res; 1463e5b75505Sopenharmony_ci 1464e5b75505Sopenharmony_ci if (!curve) { 1465e5b75505Sopenharmony_ci bi->curve = &dpp_curves[0]; 1466e5b75505Sopenharmony_ci } else { 1467e5b75505Sopenharmony_ci bi->curve = dpp_get_curve_name(curve); 1468e5b75505Sopenharmony_ci if (!bi->curve) { 1469e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 1470e5b75505Sopenharmony_ci curve); 1471e5b75505Sopenharmony_ci return NULL; 1472e5b75505Sopenharmony_ci } 1473e5b75505Sopenharmony_ci } 1474e5b75505Sopenharmony_ci if (privkey) 1475e5b75505Sopenharmony_ci bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len); 1476e5b75505Sopenharmony_ci else 1477e5b75505Sopenharmony_ci bi->pubkey = dpp_gen_keypair(bi->curve); 1478e5b75505Sopenharmony_ci if (!bi->pubkey) 1479e5b75505Sopenharmony_ci goto fail; 1480e5b75505Sopenharmony_ci bi->own = 1; 1481e5b75505Sopenharmony_ci 1482e5b75505Sopenharmony_ci der = dpp_bootstrap_key_der(bi->pubkey); 1483e5b75505Sopenharmony_ci if (!der) 1484e5b75505Sopenharmony_ci goto fail; 1485e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", 1486e5b75505Sopenharmony_ci der); 1487e5b75505Sopenharmony_ci 1488e5b75505Sopenharmony_ci addr[0] = wpabuf_head(der); 1489e5b75505Sopenharmony_ci len = wpabuf_len(der); 1490e5b75505Sopenharmony_ci res = sha256_vector(1, addr, &len, bi->pubkey_hash); 1491e5b75505Sopenharmony_ci if (res < 0) { 1492e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 1493e5b75505Sopenharmony_ci goto fail; 1494e5b75505Sopenharmony_ci } 1495e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, 1496e5b75505Sopenharmony_ci SHA256_MAC_LEN); 1497e5b75505Sopenharmony_ci 1498e5b75505Sopenharmony_ci base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len); 1499e5b75505Sopenharmony_ci wpabuf_free(der); 1500e5b75505Sopenharmony_ci der = NULL; 1501e5b75505Sopenharmony_ci if (!base64) 1502e5b75505Sopenharmony_ci goto fail; 1503e5b75505Sopenharmony_ci pos = (char *) base64; 1504e5b75505Sopenharmony_ci end = pos + len; 1505e5b75505Sopenharmony_ci for (;;) { 1506e5b75505Sopenharmony_ci pos = os_strchr(pos, '\n'); 1507e5b75505Sopenharmony_ci if (!pos) 1508e5b75505Sopenharmony_ci break; 1509e5b75505Sopenharmony_ci os_memmove(pos, pos + 1, end - pos); 1510e5b75505Sopenharmony_ci } 1511e5b75505Sopenharmony_ci return (char *) base64; 1512e5b75505Sopenharmony_cifail: 1513e5b75505Sopenharmony_ci os_free(base64); 1514e5b75505Sopenharmony_ci wpabuf_free(der); 1515e5b75505Sopenharmony_ci return NULL; 1516e5b75505Sopenharmony_ci} 1517e5b75505Sopenharmony_ci 1518e5b75505Sopenharmony_ci 1519e5b75505Sopenharmony_cistatic int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, 1520e5b75505Sopenharmony_ci unsigned int hash_len) 1521e5b75505Sopenharmony_ci{ 1522e5b75505Sopenharmony_ci u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 1523e5b75505Sopenharmony_ci const char *info = "first intermediate key"; 1524e5b75505Sopenharmony_ci int res; 1525e5b75505Sopenharmony_ci 1526e5b75505Sopenharmony_ci /* k1 = HKDF(<>, "first intermediate key", M.x) */ 1527e5b75505Sopenharmony_ci 1528e5b75505Sopenharmony_ci /* HKDF-Extract(<>, M.x) */ 1529e5b75505Sopenharmony_ci os_memset(salt, 0, hash_len); 1530e5b75505Sopenharmony_ci if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0) 1531e5b75505Sopenharmony_ci return -1; 1532e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)", 1533e5b75505Sopenharmony_ci prk, hash_len); 1534e5b75505Sopenharmony_ci 1535e5b75505Sopenharmony_ci /* HKDF-Expand(PRK, info, L) */ 1536e5b75505Sopenharmony_ci res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len); 1537e5b75505Sopenharmony_ci os_memset(prk, 0, hash_len); 1538e5b75505Sopenharmony_ci if (res < 0) 1539e5b75505Sopenharmony_ci return -1; 1540e5b75505Sopenharmony_ci 1541e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)", 1542e5b75505Sopenharmony_ci k1, hash_len); 1543e5b75505Sopenharmony_ci return 0; 1544e5b75505Sopenharmony_ci} 1545e5b75505Sopenharmony_ci 1546e5b75505Sopenharmony_ci 1547e5b75505Sopenharmony_cistatic int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, 1548e5b75505Sopenharmony_ci unsigned int hash_len) 1549e5b75505Sopenharmony_ci{ 1550e5b75505Sopenharmony_ci u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 1551e5b75505Sopenharmony_ci const char *info = "second intermediate key"; 1552e5b75505Sopenharmony_ci int res; 1553e5b75505Sopenharmony_ci 1554e5b75505Sopenharmony_ci /* k2 = HKDF(<>, "second intermediate key", N.x) */ 1555e5b75505Sopenharmony_ci 1556e5b75505Sopenharmony_ci /* HKDF-Extract(<>, N.x) */ 1557e5b75505Sopenharmony_ci os_memset(salt, 0, hash_len); 1558e5b75505Sopenharmony_ci res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk); 1559e5b75505Sopenharmony_ci if (res < 0) 1560e5b75505Sopenharmony_ci return -1; 1561e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", 1562e5b75505Sopenharmony_ci prk, hash_len); 1563e5b75505Sopenharmony_ci 1564e5b75505Sopenharmony_ci /* HKDF-Expand(PRK, info, L) */ 1565e5b75505Sopenharmony_ci res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len); 1566e5b75505Sopenharmony_ci os_memset(prk, 0, hash_len); 1567e5b75505Sopenharmony_ci if (res < 0) 1568e5b75505Sopenharmony_ci return -1; 1569e5b75505Sopenharmony_ci 1570e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)", 1571e5b75505Sopenharmony_ci k2, hash_len); 1572e5b75505Sopenharmony_ci return 0; 1573e5b75505Sopenharmony_ci} 1574e5b75505Sopenharmony_ci 1575e5b75505Sopenharmony_ci 1576e5b75505Sopenharmony_cistatic int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke, 1577e5b75505Sopenharmony_ci unsigned int hash_len) 1578e5b75505Sopenharmony_ci{ 1579e5b75505Sopenharmony_ci size_t nonce_len; 1580e5b75505Sopenharmony_ci u8 nonces[2 * DPP_MAX_NONCE_LEN]; 1581e5b75505Sopenharmony_ci const char *info_ke = "DPP Key"; 1582e5b75505Sopenharmony_ci u8 prk[DPP_MAX_HASH_LEN]; 1583e5b75505Sopenharmony_ci int res; 1584e5b75505Sopenharmony_ci const u8 *addr[3]; 1585e5b75505Sopenharmony_ci size_t len[3]; 1586e5b75505Sopenharmony_ci size_t num_elem = 0; 1587e5b75505Sopenharmony_ci 1588e5b75505Sopenharmony_ci if (!auth->Mx_len || !auth->Nx_len) { 1589e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1590e5b75505Sopenharmony_ci "DPP: Mx/Nx not available - cannot derive ke"); 1591e5b75505Sopenharmony_ci return -1; 1592e5b75505Sopenharmony_ci } 1593e5b75505Sopenharmony_ci 1594e5b75505Sopenharmony_ci /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */ 1595e5b75505Sopenharmony_ci 1596e5b75505Sopenharmony_ci /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */ 1597e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 1598e5b75505Sopenharmony_ci os_memcpy(nonces, auth->i_nonce, nonce_len); 1599e5b75505Sopenharmony_ci os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len); 1600e5b75505Sopenharmony_ci addr[num_elem] = auth->Mx; 1601e5b75505Sopenharmony_ci len[num_elem] = auth->Mx_len; 1602e5b75505Sopenharmony_ci num_elem++; 1603e5b75505Sopenharmony_ci addr[num_elem] = auth->Nx; 1604e5b75505Sopenharmony_ci len[num_elem] = auth->Nx_len; 1605e5b75505Sopenharmony_ci num_elem++; 1606e5b75505Sopenharmony_ci if (auth->peer_bi && auth->own_bi) { 1607e5b75505Sopenharmony_ci if (!auth->Lx_len) { 1608e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1609e5b75505Sopenharmony_ci "DPP: Lx not available - cannot derive ke"); 1610e5b75505Sopenharmony_ci return -1; 1611e5b75505Sopenharmony_ci } 1612e5b75505Sopenharmony_ci addr[num_elem] = auth->Lx; 1613e5b75505Sopenharmony_ci len[num_elem] = auth->secret_len; 1614e5b75505Sopenharmony_ci num_elem++; 1615e5b75505Sopenharmony_ci } 1616e5b75505Sopenharmony_ci res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len, 1617e5b75505Sopenharmony_ci num_elem, addr, len, prk); 1618e5b75505Sopenharmony_ci if (res < 0) 1619e5b75505Sopenharmony_ci return -1; 1620e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", 1621e5b75505Sopenharmony_ci prk, hash_len); 1622e5b75505Sopenharmony_ci 1623e5b75505Sopenharmony_ci /* HKDF-Expand(PRK, info, L) */ 1624e5b75505Sopenharmony_ci res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len); 1625e5b75505Sopenharmony_ci os_memset(prk, 0, hash_len); 1626e5b75505Sopenharmony_ci if (res < 0) 1627e5b75505Sopenharmony_ci return -1; 1628e5b75505Sopenharmony_ci 1629e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)", 1630e5b75505Sopenharmony_ci ke, hash_len); 1631e5b75505Sopenharmony_ci return 0; 1632e5b75505Sopenharmony_ci} 1633e5b75505Sopenharmony_ci 1634e5b75505Sopenharmony_ci 1635e5b75505Sopenharmony_cistatic void dpp_build_attr_status(struct wpabuf *msg, 1636e5b75505Sopenharmony_ci enum dpp_status_error status) 1637e5b75505Sopenharmony_ci{ 1638e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %d", status); 1639e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_STATUS); 1640e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 1); 1641e5b75505Sopenharmony_ci wpabuf_put_u8(msg, status); 1642e5b75505Sopenharmony_ci} 1643e5b75505Sopenharmony_ci 1644e5b75505Sopenharmony_ci 1645e5b75505Sopenharmony_cistatic void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, 1646e5b75505Sopenharmony_ci const u8 *hash) 1647e5b75505Sopenharmony_ci{ 1648e5b75505Sopenharmony_ci if (hash) { 1649e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash"); 1650e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 1651e5b75505Sopenharmony_ci wpabuf_put_le16(msg, SHA256_MAC_LEN); 1652e5b75505Sopenharmony_ci wpabuf_put_data(msg, hash, SHA256_MAC_LEN); 1653e5b75505Sopenharmony_ci } 1654e5b75505Sopenharmony_ci} 1655e5b75505Sopenharmony_ci 1656e5b75505Sopenharmony_ci 1657e5b75505Sopenharmony_cistatic void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg, 1658e5b75505Sopenharmony_ci const u8 *hash) 1659e5b75505Sopenharmony_ci{ 1660e5b75505Sopenharmony_ci if (hash) { 1661e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash"); 1662e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); 1663e5b75505Sopenharmony_ci wpabuf_put_le16(msg, SHA256_MAC_LEN); 1664e5b75505Sopenharmony_ci wpabuf_put_data(msg, hash, SHA256_MAC_LEN); 1665e5b75505Sopenharmony_ci } 1666e5b75505Sopenharmony_ci} 1667e5b75505Sopenharmony_ci 1668e5b75505Sopenharmony_ci 1669e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, 1670e5b75505Sopenharmony_ci const struct wpabuf *pi, 1671e5b75505Sopenharmony_ci size_t nonce_len, 1672e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, 1673e5b75505Sopenharmony_ci const u8 *i_pubkey_hash, 1674e5b75505Sopenharmony_ci unsigned int neg_freq) 1675e5b75505Sopenharmony_ci{ 1676e5b75505Sopenharmony_ci struct wpabuf *msg; 1677e5b75505Sopenharmony_ci u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1]; 1678e5b75505Sopenharmony_ci u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE]; 1679e5b75505Sopenharmony_ci u8 *pos; 1680e5b75505Sopenharmony_ci const u8 *addr[2]; 1681e5b75505Sopenharmony_ci size_t len[2], siv_len, attr_len; 1682e5b75505Sopenharmony_ci u8 *attr_start, *attr_end; 1683e5b75505Sopenharmony_ci 1684e5b75505Sopenharmony_ci /* Build DPP Authentication Request frame attributes */ 1685e5b75505Sopenharmony_ci attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) + 1686e5b75505Sopenharmony_ci 4 + sizeof(wrapped_data); 1687e5b75505Sopenharmony_ci if (neg_freq > 0) 1688e5b75505Sopenharmony_ci attr_len += 4 + 2; 1689e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 1690e5b75505Sopenharmony_ci attr_len += 5; 1691e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 1692e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1693e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) 1694e5b75505Sopenharmony_ci attr_len += 5; 1695e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1696e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len); 1697e5b75505Sopenharmony_ci if (!msg) 1698e5b75505Sopenharmony_ci return NULL; 1699e5b75505Sopenharmony_ci 1700e5b75505Sopenharmony_ci attr_start = wpabuf_put(msg, 0); 1701e5b75505Sopenharmony_ci 1702e5b75505Sopenharmony_ci /* Responder Bootstrapping Key Hash */ 1703e5b75505Sopenharmony_ci dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash); 1704e5b75505Sopenharmony_ci 1705e5b75505Sopenharmony_ci /* Initiator Bootstrapping Key Hash */ 1706e5b75505Sopenharmony_ci dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash); 1707e5b75505Sopenharmony_ci 1708e5b75505Sopenharmony_ci /* Initiator Protocol Key */ 1709e5b75505Sopenharmony_ci if (pi) { 1710e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY); 1711e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(pi)); 1712e5b75505Sopenharmony_ci wpabuf_put_buf(msg, pi); 1713e5b75505Sopenharmony_ci } 1714e5b75505Sopenharmony_ci 1715e5b75505Sopenharmony_ci /* Channel */ 1716e5b75505Sopenharmony_ci if (neg_freq > 0) { 1717e5b75505Sopenharmony_ci u8 op_class, channel; 1718e5b75505Sopenharmony_ci 1719e5b75505Sopenharmony_ci if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class, 1720e5b75505Sopenharmony_ci &channel) == 1721e5b75505Sopenharmony_ci NUM_HOSTAPD_MODES) { 1722e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1723e5b75505Sopenharmony_ci "DPP: Unsupported negotiation frequency request: %d", 1724e5b75505Sopenharmony_ci neg_freq); 1725e5b75505Sopenharmony_ci wpabuf_free(msg); 1726e5b75505Sopenharmony_ci return NULL; 1727e5b75505Sopenharmony_ci } 1728e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_CHANNEL); 1729e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 2); 1730e5b75505Sopenharmony_ci wpabuf_put_u8(msg, op_class); 1731e5b75505Sopenharmony_ci wpabuf_put_u8(msg, channel); 1732e5b75505Sopenharmony_ci } 1733e5b75505Sopenharmony_ci 1734e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 1735e5b75505Sopenharmony_ci /* Protocol Version */ 1736e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 1737e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 1); 1738e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 2); 1739e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 1740e5b75505Sopenharmony_ci 1741e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1742e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) { 1743e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 1744e5b75505Sopenharmony_ci goto skip_wrapped_data; 1745e5b75505Sopenharmony_ci } 1746e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1747e5b75505Sopenharmony_ci 1748e5b75505Sopenharmony_ci /* Wrapped data ({I-nonce, I-capabilities}k1) */ 1749e5b75505Sopenharmony_ci pos = clear; 1750e5b75505Sopenharmony_ci 1751e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1752e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) { 1753e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce"); 1754e5b75505Sopenharmony_ci goto skip_i_nonce; 1755e5b75505Sopenharmony_ci } 1756e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) { 1757e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce"); 1758e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 1759e5b75505Sopenharmony_ci pos += 2; 1760e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, nonce_len - 1); 1761e5b75505Sopenharmony_ci pos += 2; 1762e5b75505Sopenharmony_ci os_memcpy(pos, auth->i_nonce, nonce_len - 1); 1763e5b75505Sopenharmony_ci pos += nonce_len - 1; 1764e5b75505Sopenharmony_ci goto skip_i_nonce; 1765e5b75505Sopenharmony_ci } 1766e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1767e5b75505Sopenharmony_ci 1768e5b75505Sopenharmony_ci /* I-nonce */ 1769e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 1770e5b75505Sopenharmony_ci pos += 2; 1771e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, nonce_len); 1772e5b75505Sopenharmony_ci pos += 2; 1773e5b75505Sopenharmony_ci os_memcpy(pos, auth->i_nonce, nonce_len); 1774e5b75505Sopenharmony_ci pos += nonce_len; 1775e5b75505Sopenharmony_ci 1776e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1777e5b75505Sopenharmony_ciskip_i_nonce: 1778e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) { 1779e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab"); 1780e5b75505Sopenharmony_ci goto skip_i_capab; 1781e5b75505Sopenharmony_ci } 1782e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1783e5b75505Sopenharmony_ci 1784e5b75505Sopenharmony_ci /* I-capabilities */ 1785e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES); 1786e5b75505Sopenharmony_ci pos += 2; 1787e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, 1); 1788e5b75505Sopenharmony_ci pos += 2; 1789e5b75505Sopenharmony_ci auth->i_capab = auth->allowed_roles; 1790e5b75505Sopenharmony_ci *pos++ = auth->i_capab; 1791e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1792e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_ZERO_I_CAPAB) { 1793e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities"); 1794e5b75505Sopenharmony_ci pos[-1] = 0; 1795e5b75505Sopenharmony_ci } 1796e5b75505Sopenharmony_ciskip_i_capab: 1797e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1798e5b75505Sopenharmony_ci 1799e5b75505Sopenharmony_ci attr_end = wpabuf_put(msg, 0); 1800e5b75505Sopenharmony_ci 1801e5b75505Sopenharmony_ci /* OUI, OUI type, Crypto Suite, DPP frame type */ 1802e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 1803e5b75505Sopenharmony_ci len[0] = 3 + 1 + 1 + 1; 1804e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1805e5b75505Sopenharmony_ci 1806e5b75505Sopenharmony_ci /* Attributes before Wrapped Data */ 1807e5b75505Sopenharmony_ci addr[1] = attr_start; 1808e5b75505Sopenharmony_ci len[1] = attr_end - attr_start; 1809e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1810e5b75505Sopenharmony_ci 1811e5b75505Sopenharmony_ci siv_len = pos - clear; 1812e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len); 1813e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len, 1814e5b75505Sopenharmony_ci 2, addr, len, wrapped_data) < 0) { 1815e5b75505Sopenharmony_ci wpabuf_free(msg); 1816e5b75505Sopenharmony_ci return NULL; 1817e5b75505Sopenharmony_ci } 1818e5b75505Sopenharmony_ci siv_len += AES_BLOCK_SIZE; 1819e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1820e5b75505Sopenharmony_ci wrapped_data, siv_len); 1821e5b75505Sopenharmony_ci 1822e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 1823e5b75505Sopenharmony_ci wpabuf_put_le16(msg, siv_len); 1824e5b75505Sopenharmony_ci wpabuf_put_data(msg, wrapped_data, siv_len); 1825e5b75505Sopenharmony_ci 1826e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1827e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) { 1828e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 1829e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 1830e5b75505Sopenharmony_ci } 1831e5b75505Sopenharmony_ciskip_wrapped_data: 1832e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1833e5b75505Sopenharmony_ci 1834e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, 1835e5b75505Sopenharmony_ci "DPP: Authentication Request frame attributes", msg); 1836e5b75505Sopenharmony_ci 1837e5b75505Sopenharmony_ci return msg; 1838e5b75505Sopenharmony_ci} 1839e5b75505Sopenharmony_ci 1840e5b75505Sopenharmony_ci 1841e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth, 1842e5b75505Sopenharmony_ci enum dpp_status_error status, 1843e5b75505Sopenharmony_ci const struct wpabuf *pr, 1844e5b75505Sopenharmony_ci size_t nonce_len, 1845e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, 1846e5b75505Sopenharmony_ci const u8 *i_pubkey_hash, 1847e5b75505Sopenharmony_ci const u8 *r_nonce, const u8 *i_nonce, 1848e5b75505Sopenharmony_ci const u8 *wrapped_r_auth, 1849e5b75505Sopenharmony_ci size_t wrapped_r_auth_len, 1850e5b75505Sopenharmony_ci const u8 *siv_key) 1851e5b75505Sopenharmony_ci{ 1852e5b75505Sopenharmony_ci struct wpabuf *msg; 1853e5b75505Sopenharmony_ci#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \ 1854e5b75505Sopenharmony_ci 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE 1855e5b75505Sopenharmony_ci u8 clear[DPP_AUTH_RESP_CLEAR_LEN]; 1856e5b75505Sopenharmony_ci u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE]; 1857e5b75505Sopenharmony_ci const u8 *addr[2]; 1858e5b75505Sopenharmony_ci size_t len[2], siv_len, attr_len; 1859e5b75505Sopenharmony_ci u8 *attr_start, *attr_end, *pos; 1860e5b75505Sopenharmony_ci 1861e5b75505Sopenharmony_ci auth->waiting_auth_conf = 1; 1862e5b75505Sopenharmony_ci auth->auth_resp_tries = 0; 1863e5b75505Sopenharmony_ci 1864e5b75505Sopenharmony_ci /* Build DPP Authentication Response frame attributes */ 1865e5b75505Sopenharmony_ci attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 1866e5b75505Sopenharmony_ci 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data); 1867e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 1868e5b75505Sopenharmony_ci attr_len += 5; 1869e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 1870e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1871e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) 1872e5b75505Sopenharmony_ci attr_len += 5; 1873e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1874e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); 1875e5b75505Sopenharmony_ci if (!msg) 1876e5b75505Sopenharmony_ci return NULL; 1877e5b75505Sopenharmony_ci 1878e5b75505Sopenharmony_ci attr_start = wpabuf_put(msg, 0); 1879e5b75505Sopenharmony_ci 1880e5b75505Sopenharmony_ci /* DPP Status */ 1881e5b75505Sopenharmony_ci if (status != 255) 1882e5b75505Sopenharmony_ci dpp_build_attr_status(msg, status); 1883e5b75505Sopenharmony_ci 1884e5b75505Sopenharmony_ci /* Responder Bootstrapping Key Hash */ 1885e5b75505Sopenharmony_ci dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash); 1886e5b75505Sopenharmony_ci 1887e5b75505Sopenharmony_ci /* Initiator Bootstrapping Key Hash (mutual authentication) */ 1888e5b75505Sopenharmony_ci dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash); 1889e5b75505Sopenharmony_ci 1890e5b75505Sopenharmony_ci /* Responder Protocol Key */ 1891e5b75505Sopenharmony_ci if (pr) { 1892e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY); 1893e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(pr)); 1894e5b75505Sopenharmony_ci wpabuf_put_buf(msg, pr); 1895e5b75505Sopenharmony_ci } 1896e5b75505Sopenharmony_ci 1897e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 1898e5b75505Sopenharmony_ci /* Protocol Version */ 1899e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 1900e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 1); 1901e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 2); 1902e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 1903e5b75505Sopenharmony_ci 1904e5b75505Sopenharmony_ci attr_end = wpabuf_put(msg, 0); 1905e5b75505Sopenharmony_ci 1906e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1907e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) { 1908e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 1909e5b75505Sopenharmony_ci goto skip_wrapped_data; 1910e5b75505Sopenharmony_ci } 1911e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1912e5b75505Sopenharmony_ci 1913e5b75505Sopenharmony_ci /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */ 1914e5b75505Sopenharmony_ci pos = clear; 1915e5b75505Sopenharmony_ci 1916e5b75505Sopenharmony_ci if (r_nonce) { 1917e5b75505Sopenharmony_ci /* R-nonce */ 1918e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE); 1919e5b75505Sopenharmony_ci pos += 2; 1920e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, nonce_len); 1921e5b75505Sopenharmony_ci pos += 2; 1922e5b75505Sopenharmony_ci os_memcpy(pos, r_nonce, nonce_len); 1923e5b75505Sopenharmony_ci pos += nonce_len; 1924e5b75505Sopenharmony_ci } 1925e5b75505Sopenharmony_ci 1926e5b75505Sopenharmony_ci if (i_nonce) { 1927e5b75505Sopenharmony_ci /* I-nonce */ 1928e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 1929e5b75505Sopenharmony_ci pos += 2; 1930e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, nonce_len); 1931e5b75505Sopenharmony_ci pos += 2; 1932e5b75505Sopenharmony_ci os_memcpy(pos, i_nonce, nonce_len); 1933e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1934e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) { 1935e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch"); 1936e5b75505Sopenharmony_ci pos[nonce_len / 2] ^= 0x01; 1937e5b75505Sopenharmony_ci } 1938e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1939e5b75505Sopenharmony_ci pos += nonce_len; 1940e5b75505Sopenharmony_ci } 1941e5b75505Sopenharmony_ci 1942e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1943e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) { 1944e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab"); 1945e5b75505Sopenharmony_ci goto skip_r_capab; 1946e5b75505Sopenharmony_ci } 1947e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1948e5b75505Sopenharmony_ci 1949e5b75505Sopenharmony_ci /* R-capabilities */ 1950e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES); 1951e5b75505Sopenharmony_ci pos += 2; 1952e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, 1); 1953e5b75505Sopenharmony_ci pos += 2; 1954e5b75505Sopenharmony_ci auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR : 1955e5b75505Sopenharmony_ci DPP_CAPAB_ENROLLEE; 1956e5b75505Sopenharmony_ci *pos++ = auth->r_capab; 1957e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1958e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_ZERO_R_CAPAB) { 1959e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities"); 1960e5b75505Sopenharmony_ci pos[-1] = 0; 1961e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) { 1962e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1963e5b75505Sopenharmony_ci "DPP: TESTING - incompatible R-capabilities"); 1964e5b75505Sopenharmony_ci if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) == 1965e5b75505Sopenharmony_ci (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) 1966e5b75505Sopenharmony_ci pos[-1] = 0; 1967e5b75505Sopenharmony_ci else 1968e5b75505Sopenharmony_ci pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE : 1969e5b75505Sopenharmony_ci DPP_CAPAB_CONFIGURATOR; 1970e5b75505Sopenharmony_ci } 1971e5b75505Sopenharmony_ciskip_r_capab: 1972e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1973e5b75505Sopenharmony_ci 1974e5b75505Sopenharmony_ci if (wrapped_r_auth) { 1975e5b75505Sopenharmony_ci /* {R-auth}ke */ 1976e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA); 1977e5b75505Sopenharmony_ci pos += 2; 1978e5b75505Sopenharmony_ci WPA_PUT_LE16(pos, wrapped_r_auth_len); 1979e5b75505Sopenharmony_ci pos += 2; 1980e5b75505Sopenharmony_ci os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len); 1981e5b75505Sopenharmony_ci pos += wrapped_r_auth_len; 1982e5b75505Sopenharmony_ci } 1983e5b75505Sopenharmony_ci 1984e5b75505Sopenharmony_ci /* OUI, OUI type, Crypto Suite, DPP frame type */ 1985e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 1986e5b75505Sopenharmony_ci len[0] = 3 + 1 + 1 + 1; 1987e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1988e5b75505Sopenharmony_ci 1989e5b75505Sopenharmony_ci /* Attributes before Wrapped Data */ 1990e5b75505Sopenharmony_ci addr[1] = attr_start; 1991e5b75505Sopenharmony_ci len[1] = attr_end - attr_start; 1992e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1993e5b75505Sopenharmony_ci 1994e5b75505Sopenharmony_ci siv_len = pos - clear; 1995e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len); 1996e5b75505Sopenharmony_ci if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len, 1997e5b75505Sopenharmony_ci 2, addr, len, wrapped_data) < 0) { 1998e5b75505Sopenharmony_ci wpabuf_free(msg); 1999e5b75505Sopenharmony_ci return NULL; 2000e5b75505Sopenharmony_ci } 2001e5b75505Sopenharmony_ci siv_len += AES_BLOCK_SIZE; 2002e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2003e5b75505Sopenharmony_ci wrapped_data, siv_len); 2004e5b75505Sopenharmony_ci 2005e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 2006e5b75505Sopenharmony_ci wpabuf_put_le16(msg, siv_len); 2007e5b75505Sopenharmony_ci wpabuf_put_data(msg, wrapped_data, siv_len); 2008e5b75505Sopenharmony_ci 2009e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2010e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) { 2011e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 2012e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 2013e5b75505Sopenharmony_ci } 2014e5b75505Sopenharmony_ciskip_wrapped_data: 2015e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2016e5b75505Sopenharmony_ci 2017e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, 2018e5b75505Sopenharmony_ci "DPP: Authentication Response frame attributes", msg); 2019e5b75505Sopenharmony_ci return msg; 2020e5b75505Sopenharmony_ci} 2021e5b75505Sopenharmony_ci 2022e5b75505Sopenharmony_ci 2023e5b75505Sopenharmony_cistatic int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes, 2024e5b75505Sopenharmony_ci u16 num_modes, unsigned int freq) 2025e5b75505Sopenharmony_ci{ 2026e5b75505Sopenharmony_ci u16 m; 2027e5b75505Sopenharmony_ci int c, flag; 2028e5b75505Sopenharmony_ci 2029e5b75505Sopenharmony_ci if (!own_modes || !num_modes) 2030e5b75505Sopenharmony_ci return 1; 2031e5b75505Sopenharmony_ci 2032e5b75505Sopenharmony_ci for (m = 0; m < num_modes; m++) { 2033e5b75505Sopenharmony_ci for (c = 0; c < own_modes[m].num_channels; c++) { 2034e5b75505Sopenharmony_ci if ((unsigned int) own_modes[m].channels[c].freq != 2035e5b75505Sopenharmony_ci freq) 2036e5b75505Sopenharmony_ci continue; 2037e5b75505Sopenharmony_ci flag = own_modes[m].channels[c].flag; 2038e5b75505Sopenharmony_ci if (!(flag & (HOSTAPD_CHAN_DISABLED | 2039e5b75505Sopenharmony_ci HOSTAPD_CHAN_NO_IR | 2040e5b75505Sopenharmony_ci HOSTAPD_CHAN_RADAR))) 2041e5b75505Sopenharmony_ci return 1; 2042e5b75505Sopenharmony_ci } 2043e5b75505Sopenharmony_ci } 2044e5b75505Sopenharmony_ci 2045e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq); 2046e5b75505Sopenharmony_ci return 0; 2047e5b75505Sopenharmony_ci} 2048e5b75505Sopenharmony_ci 2049e5b75505Sopenharmony_ci 2050e5b75505Sopenharmony_cistatic int freq_included(const unsigned int freqs[], unsigned int num, 2051e5b75505Sopenharmony_ci unsigned int freq) 2052e5b75505Sopenharmony_ci{ 2053e5b75505Sopenharmony_ci while (num > 0) { 2054e5b75505Sopenharmony_ci if (freqs[--num] == freq) 2055e5b75505Sopenharmony_ci return 1; 2056e5b75505Sopenharmony_ci } 2057e5b75505Sopenharmony_ci return 0; 2058e5b75505Sopenharmony_ci} 2059e5b75505Sopenharmony_ci 2060e5b75505Sopenharmony_ci 2061e5b75505Sopenharmony_cistatic void freq_to_start(unsigned int freqs[], unsigned int num, 2062e5b75505Sopenharmony_ci unsigned int freq) 2063e5b75505Sopenharmony_ci{ 2064e5b75505Sopenharmony_ci unsigned int i; 2065e5b75505Sopenharmony_ci 2066e5b75505Sopenharmony_ci for (i = 0; i < num; i++) { 2067e5b75505Sopenharmony_ci if (freqs[i] == freq) 2068e5b75505Sopenharmony_ci break; 2069e5b75505Sopenharmony_ci } 2070e5b75505Sopenharmony_ci if (i == 0 || i >= num) 2071e5b75505Sopenharmony_ci return; 2072e5b75505Sopenharmony_ci os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0])); 2073e5b75505Sopenharmony_ci freqs[0] = freq; 2074e5b75505Sopenharmony_ci} 2075e5b75505Sopenharmony_ci 2076e5b75505Sopenharmony_ci 2077e5b75505Sopenharmony_cistatic int dpp_channel_intersect(struct dpp_authentication *auth, 2078e5b75505Sopenharmony_ci struct hostapd_hw_modes *own_modes, 2079e5b75505Sopenharmony_ci u16 num_modes) 2080e5b75505Sopenharmony_ci{ 2081e5b75505Sopenharmony_ci struct dpp_bootstrap_info *peer_bi = auth->peer_bi; 2082e5b75505Sopenharmony_ci unsigned int i, freq; 2083e5b75505Sopenharmony_ci 2084e5b75505Sopenharmony_ci for (i = 0; i < peer_bi->num_freq; i++) { 2085e5b75505Sopenharmony_ci freq = peer_bi->freq[i]; 2086e5b75505Sopenharmony_ci if (freq_included(auth->freq, auth->num_freq, freq)) 2087e5b75505Sopenharmony_ci continue; 2088e5b75505Sopenharmony_ci if (dpp_channel_ok_init(own_modes, num_modes, freq)) 2089e5b75505Sopenharmony_ci auth->freq[auth->num_freq++] = freq; 2090e5b75505Sopenharmony_ci } 2091e5b75505Sopenharmony_ci if (!auth->num_freq) { 2092e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2093e5b75505Sopenharmony_ci "DPP: No available channels for initiating DPP Authentication"); 2094e5b75505Sopenharmony_ci return -1; 2095e5b75505Sopenharmony_ci } 2096e5b75505Sopenharmony_ci auth->curr_freq = auth->freq[0]; 2097e5b75505Sopenharmony_ci return 0; 2098e5b75505Sopenharmony_ci} 2099e5b75505Sopenharmony_ci 2100e5b75505Sopenharmony_ci 2101e5b75505Sopenharmony_cistatic int dpp_channel_local_list(struct dpp_authentication *auth, 2102e5b75505Sopenharmony_ci struct hostapd_hw_modes *own_modes, 2103e5b75505Sopenharmony_ci u16 num_modes) 2104e5b75505Sopenharmony_ci{ 2105e5b75505Sopenharmony_ci u16 m; 2106e5b75505Sopenharmony_ci int c, flag; 2107e5b75505Sopenharmony_ci unsigned int freq; 2108e5b75505Sopenharmony_ci 2109e5b75505Sopenharmony_ci auth->num_freq = 0; 2110e5b75505Sopenharmony_ci 2111e5b75505Sopenharmony_ci if (!own_modes || !num_modes) { 2112e5b75505Sopenharmony_ci auth->freq[0] = 2412; 2113e5b75505Sopenharmony_ci auth->freq[1] = 2437; 2114e5b75505Sopenharmony_ci auth->freq[2] = 2462; 2115e5b75505Sopenharmony_ci auth->num_freq = 3; 2116e5b75505Sopenharmony_ci return 0; 2117e5b75505Sopenharmony_ci } 2118e5b75505Sopenharmony_ci 2119e5b75505Sopenharmony_ci for (m = 0; m < num_modes; m++) { 2120e5b75505Sopenharmony_ci for (c = 0; c < own_modes[m].num_channels; c++) { 2121e5b75505Sopenharmony_ci freq = own_modes[m].channels[c].freq; 2122e5b75505Sopenharmony_ci flag = own_modes[m].channels[c].flag; 2123e5b75505Sopenharmony_ci if (flag & (HOSTAPD_CHAN_DISABLED | 2124e5b75505Sopenharmony_ci HOSTAPD_CHAN_NO_IR | 2125e5b75505Sopenharmony_ci HOSTAPD_CHAN_RADAR)) 2126e5b75505Sopenharmony_ci continue; 2127e5b75505Sopenharmony_ci if (freq_included(auth->freq, auth->num_freq, freq)) 2128e5b75505Sopenharmony_ci continue; 2129e5b75505Sopenharmony_ci auth->freq[auth->num_freq++] = freq; 2130e5b75505Sopenharmony_ci if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) { 2131e5b75505Sopenharmony_ci m = num_modes; 2132e5b75505Sopenharmony_ci break; 2133e5b75505Sopenharmony_ci } 2134e5b75505Sopenharmony_ci } 2135e5b75505Sopenharmony_ci } 2136e5b75505Sopenharmony_ci 2137e5b75505Sopenharmony_ci return auth->num_freq == 0 ? -1 : 0; 2138e5b75505Sopenharmony_ci} 2139e5b75505Sopenharmony_ci 2140e5b75505Sopenharmony_ci 2141e5b75505Sopenharmony_cistatic int dpp_prepare_channel_list(struct dpp_authentication *auth, 2142e5b75505Sopenharmony_ci struct hostapd_hw_modes *own_modes, 2143e5b75505Sopenharmony_ci u16 num_modes) 2144e5b75505Sopenharmony_ci{ 2145e5b75505Sopenharmony_ci int res; 2146e5b75505Sopenharmony_ci char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end; 2147e5b75505Sopenharmony_ci unsigned int i; 2148e5b75505Sopenharmony_ci 2149e5b75505Sopenharmony_ci if (auth->peer_bi->num_freq > 0) 2150e5b75505Sopenharmony_ci res = dpp_channel_intersect(auth, own_modes, num_modes); 2151e5b75505Sopenharmony_ci else 2152e5b75505Sopenharmony_ci res = dpp_channel_local_list(auth, own_modes, num_modes); 2153e5b75505Sopenharmony_ci if (res < 0) 2154e5b75505Sopenharmony_ci return res; 2155e5b75505Sopenharmony_ci 2156e5b75505Sopenharmony_ci /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most 2157e5b75505Sopenharmony_ci * likely channels first. */ 2158e5b75505Sopenharmony_ci freq_to_start(auth->freq, auth->num_freq, 2462); 2159e5b75505Sopenharmony_ci freq_to_start(auth->freq, auth->num_freq, 2412); 2160e5b75505Sopenharmony_ci freq_to_start(auth->freq, auth->num_freq, 2437); 2161e5b75505Sopenharmony_ci 2162e5b75505Sopenharmony_ci auth->freq_idx = 0; 2163e5b75505Sopenharmony_ci auth->curr_freq = auth->freq[0]; 2164e5b75505Sopenharmony_ci 2165e5b75505Sopenharmony_ci pos = freqs; 2166e5b75505Sopenharmony_ci end = pos + sizeof(freqs); 2167e5b75505Sopenharmony_ci for (i = 0; i < auth->num_freq; i++) { 2168e5b75505Sopenharmony_ci res = os_snprintf(pos, end - pos, " %u", auth->freq[i]); 2169e5b75505Sopenharmony_ci if (os_snprintf_error(end - pos, res)) 2170e5b75505Sopenharmony_ci break; 2171e5b75505Sopenharmony_ci pos += res; 2172e5b75505Sopenharmony_ci } 2173e5b75505Sopenharmony_ci *pos = '\0'; 2174e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s", 2175e5b75505Sopenharmony_ci freqs); 2176e5b75505Sopenharmony_ci 2177e5b75505Sopenharmony_ci return 0; 2178e5b75505Sopenharmony_ci} 2179e5b75505Sopenharmony_ci 2180e5b75505Sopenharmony_ci 2181e5b75505Sopenharmony_cistatic int dpp_autogen_bootstrap_key(struct dpp_authentication *auth) 2182e5b75505Sopenharmony_ci{ 2183e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 2184e5b75505Sopenharmony_ci char *pk = NULL; 2185e5b75505Sopenharmony_ci size_t len; 2186e5b75505Sopenharmony_ci 2187e5b75505Sopenharmony_ci if (auth->own_bi) 2188e5b75505Sopenharmony_ci return 0; /* already generated */ 2189e5b75505Sopenharmony_ci 2190e5b75505Sopenharmony_ci bi = os_zalloc(sizeof(*bi)); 2191e5b75505Sopenharmony_ci if (!bi) 2192e5b75505Sopenharmony_ci return -1; 2193e5b75505Sopenharmony_ci bi->type = DPP_BOOTSTRAP_QR_CODE; 2194e5b75505Sopenharmony_ci pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0); 2195e5b75505Sopenharmony_ci if (!pk) 2196e5b75505Sopenharmony_ci goto fail; 2197e5b75505Sopenharmony_ci 2198e5b75505Sopenharmony_ci len = 4; /* "DPP:" */ 2199e5b75505Sopenharmony_ci len += 4 + os_strlen(pk); 2200e5b75505Sopenharmony_ci bi->uri = os_malloc(len + 1); 2201e5b75505Sopenharmony_ci if (!bi->uri) 2202e5b75505Sopenharmony_ci goto fail; 2203e5b75505Sopenharmony_ci os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk); 2204e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2205e5b75505Sopenharmony_ci "DPP: Auto-generated own bootstrapping key info: URI %s", 2206e5b75505Sopenharmony_ci bi->uri); 2207e5b75505Sopenharmony_ci 2208e5b75505Sopenharmony_ci auth->tmp_own_bi = auth->own_bi = bi; 2209e5b75505Sopenharmony_ci 2210e5b75505Sopenharmony_ci os_free(pk); 2211e5b75505Sopenharmony_ci 2212e5b75505Sopenharmony_ci return 0; 2213e5b75505Sopenharmony_cifail: 2214e5b75505Sopenharmony_ci os_free(pk); 2215e5b75505Sopenharmony_ci dpp_bootstrap_info_free(bi); 2216e5b75505Sopenharmony_ci return -1; 2217e5b75505Sopenharmony_ci} 2218e5b75505Sopenharmony_ci 2219e5b75505Sopenharmony_ci 2220e5b75505Sopenharmony_cistruct dpp_authentication * dpp_auth_init(void *msg_ctx, 2221e5b75505Sopenharmony_ci struct dpp_bootstrap_info *peer_bi, 2222e5b75505Sopenharmony_ci struct dpp_bootstrap_info *own_bi, 2223e5b75505Sopenharmony_ci u8 dpp_allowed_roles, 2224e5b75505Sopenharmony_ci unsigned int neg_freq, 2225e5b75505Sopenharmony_ci struct hostapd_hw_modes *own_modes, 2226e5b75505Sopenharmony_ci u16 num_modes) 2227e5b75505Sopenharmony_ci{ 2228e5b75505Sopenharmony_ci struct dpp_authentication *auth; 2229e5b75505Sopenharmony_ci size_t nonce_len; 2230e5b75505Sopenharmony_ci size_t secret_len; 2231e5b75505Sopenharmony_ci struct wpabuf *pi = NULL; 2232e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, *i_pubkey_hash; 2233e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2234e5b75505Sopenharmony_ci u8 test_hash[SHA256_MAC_LEN]; 2235e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2236e5b75505Sopenharmony_ci 2237e5b75505Sopenharmony_ci auth = os_zalloc(sizeof(*auth)); 2238e5b75505Sopenharmony_ci if (!auth) 2239e5b75505Sopenharmony_ci return NULL; 2240e5b75505Sopenharmony_ci auth->msg_ctx = msg_ctx; 2241e5b75505Sopenharmony_ci auth->initiator = 1; 2242e5b75505Sopenharmony_ci auth->waiting_auth_resp = 1; 2243e5b75505Sopenharmony_ci auth->allowed_roles = dpp_allowed_roles; 2244e5b75505Sopenharmony_ci auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR); 2245e5b75505Sopenharmony_ci auth->peer_bi = peer_bi; 2246e5b75505Sopenharmony_ci auth->own_bi = own_bi; 2247e5b75505Sopenharmony_ci auth->curve = peer_bi->curve; 2248e5b75505Sopenharmony_ci 2249e5b75505Sopenharmony_ci if (dpp_autogen_bootstrap_key(auth) < 0 || 2250e5b75505Sopenharmony_ci dpp_prepare_channel_list(auth, own_modes, num_modes) < 0) 2251e5b75505Sopenharmony_ci goto fail; 2252e5b75505Sopenharmony_ci 2253e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2254e5b75505Sopenharmony_ci if (dpp_nonce_override_len > 0) { 2255e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce"); 2256e5b75505Sopenharmony_ci nonce_len = dpp_nonce_override_len; 2257e5b75505Sopenharmony_ci os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len); 2258e5b75505Sopenharmony_ci } else { 2259e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2260e5b75505Sopenharmony_ci if (random_get_bytes(auth->i_nonce, nonce_len)) { 2261e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 2262e5b75505Sopenharmony_ci "DPP: Failed to generate I-nonce"); 2263e5b75505Sopenharmony_ci goto fail; 2264e5b75505Sopenharmony_ci } 2265e5b75505Sopenharmony_ci } 2266e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 2267e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2268e5b75505Sopenharmony_ci if (random_get_bytes(auth->i_nonce, nonce_len)) { 2269e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce"); 2270e5b75505Sopenharmony_ci goto fail; 2271e5b75505Sopenharmony_ci } 2272e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2273e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len); 2274e5b75505Sopenharmony_ci 2275e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2276e5b75505Sopenharmony_ci if (dpp_protocol_key_override_len) { 2277e5b75505Sopenharmony_ci const struct dpp_curve_params *tmp_curve; 2278e5b75505Sopenharmony_ci 2279e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2280e5b75505Sopenharmony_ci "DPP: TESTING - override protocol key"); 2281e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_set_keypair( 2282e5b75505Sopenharmony_ci &tmp_curve, dpp_protocol_key_override, 2283e5b75505Sopenharmony_ci dpp_protocol_key_override_len); 2284e5b75505Sopenharmony_ci } else { 2285e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_gen_keypair(auth->curve); 2286e5b75505Sopenharmony_ci } 2287e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 2288e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_gen_keypair(auth->curve); 2289e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2290e5b75505Sopenharmony_ci if (!auth->own_protocol_key) 2291e5b75505Sopenharmony_ci goto fail; 2292e5b75505Sopenharmony_ci 2293e5b75505Sopenharmony_ci pi = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2294e5b75505Sopenharmony_ci if (!pi) 2295e5b75505Sopenharmony_ci goto fail; 2296e5b75505Sopenharmony_ci 2297e5b75505Sopenharmony_ci /* ECDH: M = pI * BR */ 2298e5b75505Sopenharmony_ci if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey, 2299e5b75505Sopenharmony_ci auth->Mx, &secret_len) < 0) 2300e5b75505Sopenharmony_ci goto fail; 2301e5b75505Sopenharmony_ci auth->secret_len = secret_len; 2302e5b75505Sopenharmony_ci 2303e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)", 2304e5b75505Sopenharmony_ci auth->Mx, auth->secret_len); 2305e5b75505Sopenharmony_ci auth->Mx_len = auth->secret_len; 2306e5b75505Sopenharmony_ci 2307e5b75505Sopenharmony_ci if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1, 2308e5b75505Sopenharmony_ci auth->curve->hash_len) < 0) 2309e5b75505Sopenharmony_ci goto fail; 2310e5b75505Sopenharmony_ci 2311e5b75505Sopenharmony_ci r_pubkey_hash = auth->peer_bi->pubkey_hash; 2312e5b75505Sopenharmony_ci i_pubkey_hash = auth->own_bi->pubkey_hash; 2313e5b75505Sopenharmony_ci 2314e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2315e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) { 2316e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash"); 2317e5b75505Sopenharmony_ci r_pubkey_hash = NULL; 2318e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) { 2319e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2320e5b75505Sopenharmony_ci "DPP: TESTING - invalid R-Bootstrap Key Hash"); 2321e5b75505Sopenharmony_ci os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN); 2322e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 2323e5b75505Sopenharmony_ci r_pubkey_hash = test_hash; 2324e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) { 2325e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash"); 2326e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 2327e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) { 2328e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2329e5b75505Sopenharmony_ci "DPP: TESTING - invalid I-Bootstrap Key Hash"); 2330e5b75505Sopenharmony_ci os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN); 2331e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 2332e5b75505Sopenharmony_ci i_pubkey_hash = test_hash; 2333e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) { 2334e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key"); 2335e5b75505Sopenharmony_ci wpabuf_free(pi); 2336e5b75505Sopenharmony_ci pi = NULL; 2337e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) { 2338e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key"); 2339e5b75505Sopenharmony_ci wpabuf_free(pi); 2340e5b75505Sopenharmony_ci pi = wpabuf_alloc(2 * auth->curve->prime_len); 2341e5b75505Sopenharmony_ci if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0) 2342e5b75505Sopenharmony_ci goto fail; 2343e5b75505Sopenharmony_ci } 2344e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2345e5b75505Sopenharmony_ci 2346e5b75505Sopenharmony_ci auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash, 2347e5b75505Sopenharmony_ci i_pubkey_hash, neg_freq); 2348e5b75505Sopenharmony_ci if (!auth->req_msg) 2349e5b75505Sopenharmony_ci goto fail; 2350e5b75505Sopenharmony_ci 2351e5b75505Sopenharmony_ciout: 2352e5b75505Sopenharmony_ci wpabuf_free(pi); 2353e5b75505Sopenharmony_ci return auth; 2354e5b75505Sopenharmony_cifail: 2355e5b75505Sopenharmony_ci dpp_auth_deinit(auth); 2356e5b75505Sopenharmony_ci auth = NULL; 2357e5b75505Sopenharmony_ci goto out; 2358e5b75505Sopenharmony_ci} 2359e5b75505Sopenharmony_ci 2360e5b75505Sopenharmony_ci 2361e5b75505Sopenharmony_cistatic struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, 2362e5b75505Sopenharmony_ci const char *json) 2363e5b75505Sopenharmony_ci{ 2364e5b75505Sopenharmony_ci size_t nonce_len; 2365e5b75505Sopenharmony_ci size_t json_len, clear_len; 2366e5b75505Sopenharmony_ci struct wpabuf *clear = NULL, *msg = NULL; 2367e5b75505Sopenharmony_ci u8 *wrapped; 2368e5b75505Sopenharmony_ci size_t attr_len; 2369e5b75505Sopenharmony_ci 2370e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); 2371e5b75505Sopenharmony_ci 2372e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2373e5b75505Sopenharmony_ci if (random_get_bytes(auth->e_nonce, nonce_len)) { 2374e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce"); 2375e5b75505Sopenharmony_ci goto fail; 2376e5b75505Sopenharmony_ci } 2377e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len); 2378e5b75505Sopenharmony_ci json_len = os_strlen(json); 2379e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len); 2380e5b75505Sopenharmony_ci 2381e5b75505Sopenharmony_ci /* { E-nonce, configAttrib }ke */ 2382e5b75505Sopenharmony_ci clear_len = 4 + nonce_len + 4 + json_len; 2383e5b75505Sopenharmony_ci clear = wpabuf_alloc(clear_len); 2384e5b75505Sopenharmony_ci attr_len = 4 + clear_len + AES_BLOCK_SIZE; 2385e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2386e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) 2387e5b75505Sopenharmony_ci attr_len += 5; 2388e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2389e5b75505Sopenharmony_ci msg = wpabuf_alloc(attr_len); 2390e5b75505Sopenharmony_ci if (!clear || !msg) 2391e5b75505Sopenharmony_ci goto fail; 2392e5b75505Sopenharmony_ci 2393e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2394e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) { 2395e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce"); 2396e5b75505Sopenharmony_ci goto skip_e_nonce; 2397e5b75505Sopenharmony_ci } 2398e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) { 2399e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce"); 2400e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 2401e5b75505Sopenharmony_ci wpabuf_put_le16(clear, nonce_len - 1); 2402e5b75505Sopenharmony_ci wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1); 2403e5b75505Sopenharmony_ci goto skip_e_nonce; 2404e5b75505Sopenharmony_ci } 2405e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) { 2406e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 2407e5b75505Sopenharmony_ci goto skip_wrapped_data; 2408e5b75505Sopenharmony_ci } 2409e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2410e5b75505Sopenharmony_ci 2411e5b75505Sopenharmony_ci /* E-nonce */ 2412e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 2413e5b75505Sopenharmony_ci wpabuf_put_le16(clear, nonce_len); 2414e5b75505Sopenharmony_ci wpabuf_put_data(clear, auth->e_nonce, nonce_len); 2415e5b75505Sopenharmony_ci 2416e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2417e5b75505Sopenharmony_ciskip_e_nonce: 2418e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) { 2419e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib"); 2420e5b75505Sopenharmony_ci goto skip_conf_attr_obj; 2421e5b75505Sopenharmony_ci } 2422e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2423e5b75505Sopenharmony_ci 2424e5b75505Sopenharmony_ci /* configAttrib */ 2425e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); 2426e5b75505Sopenharmony_ci wpabuf_put_le16(clear, json_len); 2427e5b75505Sopenharmony_ci wpabuf_put_data(clear, json, json_len); 2428e5b75505Sopenharmony_ci 2429e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2430e5b75505Sopenharmony_ciskip_conf_attr_obj: 2431e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2432e5b75505Sopenharmony_ci 2433e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 2434e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 2435e5b75505Sopenharmony_ci wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 2436e5b75505Sopenharmony_ci 2437e5b75505Sopenharmony_ci /* No AES-SIV AD */ 2438e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 2439e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 2440e5b75505Sopenharmony_ci wpabuf_head(clear), wpabuf_len(clear), 2441e5b75505Sopenharmony_ci 0, NULL, NULL, wrapped) < 0) 2442e5b75505Sopenharmony_ci goto fail; 2443e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2444e5b75505Sopenharmony_ci wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 2445e5b75505Sopenharmony_ci 2446e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2447e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) { 2448e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 2449e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 2450e5b75505Sopenharmony_ci } 2451e5b75505Sopenharmony_ciskip_wrapped_data: 2452e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2453e5b75505Sopenharmony_ci 2454e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, 2455e5b75505Sopenharmony_ci "DPP: Configuration Request frame attributes", msg); 2456e5b75505Sopenharmony_ci wpabuf_free(clear); 2457e5b75505Sopenharmony_ci return msg; 2458e5b75505Sopenharmony_ci 2459e5b75505Sopenharmony_cifail: 2460e5b75505Sopenharmony_ci wpabuf_free(clear); 2461e5b75505Sopenharmony_ci wpabuf_free(msg); 2462e5b75505Sopenharmony_ci return NULL; 2463e5b75505Sopenharmony_ci} 2464e5b75505Sopenharmony_ci 2465e5b75505Sopenharmony_ci 2466e5b75505Sopenharmony_cistatic void dpp_write_adv_proto(struct wpabuf *buf) 2467e5b75505Sopenharmony_ci{ 2468e5b75505Sopenharmony_ci /* Advertisement Protocol IE */ 2469e5b75505Sopenharmony_ci wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); 2470e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 8); /* Length */ 2471e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x7f); 2472e5b75505Sopenharmony_ci wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 2473e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 5); 2474e5b75505Sopenharmony_ci wpabuf_put_be24(buf, OUI_WFA); 2475e5b75505Sopenharmony_ci wpabuf_put_u8(buf, DPP_OUI_TYPE); 2476e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x01); 2477e5b75505Sopenharmony_ci} 2478e5b75505Sopenharmony_ci 2479e5b75505Sopenharmony_ci 2480e5b75505Sopenharmony_cistatic void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query) 2481e5b75505Sopenharmony_ci{ 2482e5b75505Sopenharmony_ci /* GAS Query */ 2483e5b75505Sopenharmony_ci wpabuf_put_le16(buf, wpabuf_len(query)); 2484e5b75505Sopenharmony_ci wpabuf_put_buf(buf, query); 2485e5b75505Sopenharmony_ci} 2486e5b75505Sopenharmony_ci 2487e5b75505Sopenharmony_ci 2488e5b75505Sopenharmony_cistruct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, 2489e5b75505Sopenharmony_ci const char *json) 2490e5b75505Sopenharmony_ci{ 2491e5b75505Sopenharmony_ci struct wpabuf *buf, *conf_req; 2492e5b75505Sopenharmony_ci 2493e5b75505Sopenharmony_ci conf_req = dpp_build_conf_req_attr(auth, json); 2494e5b75505Sopenharmony_ci if (!conf_req) { 2495e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2496e5b75505Sopenharmony_ci "DPP: No configuration request data available"); 2497e5b75505Sopenharmony_ci return NULL; 2498e5b75505Sopenharmony_ci } 2499e5b75505Sopenharmony_ci 2500e5b75505Sopenharmony_ci buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req)); 2501e5b75505Sopenharmony_ci if (!buf) { 2502e5b75505Sopenharmony_ci wpabuf_free(conf_req); 2503e5b75505Sopenharmony_ci return NULL; 2504e5b75505Sopenharmony_ci } 2505e5b75505Sopenharmony_ci 2506e5b75505Sopenharmony_ci dpp_write_adv_proto(buf); 2507e5b75505Sopenharmony_ci dpp_write_gas_query(buf, conf_req); 2508e5b75505Sopenharmony_ci wpabuf_free(conf_req); 2509e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf); 2510e5b75505Sopenharmony_ci 2511e5b75505Sopenharmony_ci return buf; 2512e5b75505Sopenharmony_ci} 2513e5b75505Sopenharmony_ci 2514e5b75505Sopenharmony_ci 2515e5b75505Sopenharmony_cistatic void dpp_auth_success(struct dpp_authentication *auth) 2516e5b75505Sopenharmony_ci{ 2517e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2518e5b75505Sopenharmony_ci "DPP: Authentication success - clear temporary keys"); 2519e5b75505Sopenharmony_ci os_memset(auth->Mx, 0, sizeof(auth->Mx)); 2520e5b75505Sopenharmony_ci auth->Mx_len = 0; 2521e5b75505Sopenharmony_ci os_memset(auth->Nx, 0, sizeof(auth->Nx)); 2522e5b75505Sopenharmony_ci auth->Nx_len = 0; 2523e5b75505Sopenharmony_ci os_memset(auth->Lx, 0, sizeof(auth->Lx)); 2524e5b75505Sopenharmony_ci auth->Lx_len = 0; 2525e5b75505Sopenharmony_ci os_memset(auth->k1, 0, sizeof(auth->k1)); 2526e5b75505Sopenharmony_ci os_memset(auth->k2, 0, sizeof(auth->k2)); 2527e5b75505Sopenharmony_ci 2528e5b75505Sopenharmony_ci auth->auth_success = 1; 2529e5b75505Sopenharmony_ci} 2530e5b75505Sopenharmony_ci 2531e5b75505Sopenharmony_ci 2532e5b75505Sopenharmony_cistatic int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth) 2533e5b75505Sopenharmony_ci{ 2534e5b75505Sopenharmony_ci struct wpabuf *pix, *prx, *bix, *brx; 2535e5b75505Sopenharmony_ci const u8 *addr[7]; 2536e5b75505Sopenharmony_ci size_t len[7]; 2537e5b75505Sopenharmony_ci size_t i, num_elem = 0; 2538e5b75505Sopenharmony_ci size_t nonce_len; 2539e5b75505Sopenharmony_ci u8 zero = 0; 2540e5b75505Sopenharmony_ci int res = -1; 2541e5b75505Sopenharmony_ci 2542e5b75505Sopenharmony_ci /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 2543e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2544e5b75505Sopenharmony_ci 2545e5b75505Sopenharmony_ci if (auth->initiator) { 2546e5b75505Sopenharmony_ci pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2547e5b75505Sopenharmony_ci prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 2548e5b75505Sopenharmony_ci if (auth->own_bi) 2549e5b75505Sopenharmony_ci bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 2550e5b75505Sopenharmony_ci else 2551e5b75505Sopenharmony_ci bix = NULL; 2552e5b75505Sopenharmony_ci brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 2553e5b75505Sopenharmony_ci } else { 2554e5b75505Sopenharmony_ci pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 2555e5b75505Sopenharmony_ci prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2556e5b75505Sopenharmony_ci if (auth->peer_bi) 2557e5b75505Sopenharmony_ci bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 2558e5b75505Sopenharmony_ci else 2559e5b75505Sopenharmony_ci bix = NULL; 2560e5b75505Sopenharmony_ci brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 2561e5b75505Sopenharmony_ci } 2562e5b75505Sopenharmony_ci if (!pix || !prx || !brx) 2563e5b75505Sopenharmony_ci goto fail; 2564e5b75505Sopenharmony_ci 2565e5b75505Sopenharmony_ci addr[num_elem] = auth->i_nonce; 2566e5b75505Sopenharmony_ci len[num_elem] = nonce_len; 2567e5b75505Sopenharmony_ci num_elem++; 2568e5b75505Sopenharmony_ci 2569e5b75505Sopenharmony_ci addr[num_elem] = auth->r_nonce; 2570e5b75505Sopenharmony_ci len[num_elem] = nonce_len; 2571e5b75505Sopenharmony_ci num_elem++; 2572e5b75505Sopenharmony_ci 2573e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(pix); 2574e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(pix) / 2; 2575e5b75505Sopenharmony_ci num_elem++; 2576e5b75505Sopenharmony_ci 2577e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(prx); 2578e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(prx) / 2; 2579e5b75505Sopenharmony_ci num_elem++; 2580e5b75505Sopenharmony_ci 2581e5b75505Sopenharmony_ci if (bix) { 2582e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(bix); 2583e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(bix) / 2; 2584e5b75505Sopenharmony_ci num_elem++; 2585e5b75505Sopenharmony_ci } 2586e5b75505Sopenharmony_ci 2587e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(brx); 2588e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(brx) / 2; 2589e5b75505Sopenharmony_ci num_elem++; 2590e5b75505Sopenharmony_ci 2591e5b75505Sopenharmony_ci addr[num_elem] = &zero; 2592e5b75505Sopenharmony_ci len[num_elem] = 1; 2593e5b75505Sopenharmony_ci num_elem++; 2594e5b75505Sopenharmony_ci 2595e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: R-auth hash components"); 2596e5b75505Sopenharmony_ci for (i = 0; i < num_elem; i++) 2597e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); 2598e5b75505Sopenharmony_ci res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth); 2599e5b75505Sopenharmony_ci if (res == 0) 2600e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth, 2601e5b75505Sopenharmony_ci auth->curve->hash_len); 2602e5b75505Sopenharmony_cifail: 2603e5b75505Sopenharmony_ci wpabuf_free(pix); 2604e5b75505Sopenharmony_ci wpabuf_free(prx); 2605e5b75505Sopenharmony_ci wpabuf_free(bix); 2606e5b75505Sopenharmony_ci wpabuf_free(brx); 2607e5b75505Sopenharmony_ci return res; 2608e5b75505Sopenharmony_ci} 2609e5b75505Sopenharmony_ci 2610e5b75505Sopenharmony_ci 2611e5b75505Sopenharmony_cistatic int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth) 2612e5b75505Sopenharmony_ci{ 2613e5b75505Sopenharmony_ci struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL; 2614e5b75505Sopenharmony_ci const u8 *addr[7]; 2615e5b75505Sopenharmony_ci size_t len[7]; 2616e5b75505Sopenharmony_ci size_t i, num_elem = 0; 2617e5b75505Sopenharmony_ci size_t nonce_len; 2618e5b75505Sopenharmony_ci u8 one = 1; 2619e5b75505Sopenharmony_ci int res = -1; 2620e5b75505Sopenharmony_ci 2621e5b75505Sopenharmony_ci /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ 2622e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2623e5b75505Sopenharmony_ci 2624e5b75505Sopenharmony_ci if (auth->initiator) { 2625e5b75505Sopenharmony_ci pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2626e5b75505Sopenharmony_ci prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 2627e5b75505Sopenharmony_ci if (auth->own_bi) 2628e5b75505Sopenharmony_ci bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 2629e5b75505Sopenharmony_ci else 2630e5b75505Sopenharmony_ci bix = NULL; 2631e5b75505Sopenharmony_ci if (!auth->peer_bi) 2632e5b75505Sopenharmony_ci goto fail; 2633e5b75505Sopenharmony_ci brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 2634e5b75505Sopenharmony_ci } else { 2635e5b75505Sopenharmony_ci pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 2636e5b75505Sopenharmony_ci prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2637e5b75505Sopenharmony_ci if (auth->peer_bi) 2638e5b75505Sopenharmony_ci bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 2639e5b75505Sopenharmony_ci else 2640e5b75505Sopenharmony_ci bix = NULL; 2641e5b75505Sopenharmony_ci if (!auth->own_bi) 2642e5b75505Sopenharmony_ci goto fail; 2643e5b75505Sopenharmony_ci brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 2644e5b75505Sopenharmony_ci } 2645e5b75505Sopenharmony_ci if (!pix || !prx || !brx) 2646e5b75505Sopenharmony_ci goto fail; 2647e5b75505Sopenharmony_ci 2648e5b75505Sopenharmony_ci addr[num_elem] = auth->r_nonce; 2649e5b75505Sopenharmony_ci len[num_elem] = nonce_len; 2650e5b75505Sopenharmony_ci num_elem++; 2651e5b75505Sopenharmony_ci 2652e5b75505Sopenharmony_ci addr[num_elem] = auth->i_nonce; 2653e5b75505Sopenharmony_ci len[num_elem] = nonce_len; 2654e5b75505Sopenharmony_ci num_elem++; 2655e5b75505Sopenharmony_ci 2656e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(prx); 2657e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(prx) / 2; 2658e5b75505Sopenharmony_ci num_elem++; 2659e5b75505Sopenharmony_ci 2660e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(pix); 2661e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(pix) / 2; 2662e5b75505Sopenharmony_ci num_elem++; 2663e5b75505Sopenharmony_ci 2664e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(brx); 2665e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(brx) / 2; 2666e5b75505Sopenharmony_ci num_elem++; 2667e5b75505Sopenharmony_ci 2668e5b75505Sopenharmony_ci if (bix) { 2669e5b75505Sopenharmony_ci addr[num_elem] = wpabuf_head(bix); 2670e5b75505Sopenharmony_ci len[num_elem] = wpabuf_len(bix) / 2; 2671e5b75505Sopenharmony_ci num_elem++; 2672e5b75505Sopenharmony_ci } 2673e5b75505Sopenharmony_ci 2674e5b75505Sopenharmony_ci addr[num_elem] = &one; 2675e5b75505Sopenharmony_ci len[num_elem] = 1; 2676e5b75505Sopenharmony_ci num_elem++; 2677e5b75505Sopenharmony_ci 2678e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: I-auth hash components"); 2679e5b75505Sopenharmony_ci for (i = 0; i < num_elem; i++) 2680e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); 2681e5b75505Sopenharmony_ci res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth); 2682e5b75505Sopenharmony_ci if (res == 0) 2683e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth, 2684e5b75505Sopenharmony_ci auth->curve->hash_len); 2685e5b75505Sopenharmony_cifail: 2686e5b75505Sopenharmony_ci wpabuf_free(pix); 2687e5b75505Sopenharmony_ci wpabuf_free(prx); 2688e5b75505Sopenharmony_ci wpabuf_free(bix); 2689e5b75505Sopenharmony_ci wpabuf_free(brx); 2690e5b75505Sopenharmony_ci return res; 2691e5b75505Sopenharmony_ci} 2692e5b75505Sopenharmony_ci 2693e5b75505Sopenharmony_ci 2694e5b75505Sopenharmony_cistatic int dpp_auth_derive_l_responder(struct dpp_authentication *auth) 2695e5b75505Sopenharmony_ci{ 2696e5b75505Sopenharmony_ci const EC_GROUP *group; 2697e5b75505Sopenharmony_ci EC_POINT *l = NULL; 2698e5b75505Sopenharmony_ci EC_KEY *BI = NULL, *bR = NULL, *pR = NULL; 2699e5b75505Sopenharmony_ci const EC_POINT *BI_point; 2700e5b75505Sopenharmony_ci BN_CTX *bnctx; 2701e5b75505Sopenharmony_ci BIGNUM *lx, *sum, *q; 2702e5b75505Sopenharmony_ci const BIGNUM *bR_bn, *pR_bn; 2703e5b75505Sopenharmony_ci int ret = -1; 2704e5b75505Sopenharmony_ci 2705e5b75505Sopenharmony_ci /* L = ((bR + pR) modulo q) * BI */ 2706e5b75505Sopenharmony_ci 2707e5b75505Sopenharmony_ci bnctx = BN_CTX_new(); 2708e5b75505Sopenharmony_ci sum = BN_new(); 2709e5b75505Sopenharmony_ci q = BN_new(); 2710e5b75505Sopenharmony_ci lx = BN_new(); 2711e5b75505Sopenharmony_ci if (!bnctx || !sum || !q || !lx) 2712e5b75505Sopenharmony_ci goto fail; 2713e5b75505Sopenharmony_ci BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey); 2714e5b75505Sopenharmony_ci if (!BI) 2715e5b75505Sopenharmony_ci goto fail; 2716e5b75505Sopenharmony_ci BI_point = EC_KEY_get0_public_key(BI); 2717e5b75505Sopenharmony_ci group = EC_KEY_get0_group(BI); 2718e5b75505Sopenharmony_ci if (!group) 2719e5b75505Sopenharmony_ci goto fail; 2720e5b75505Sopenharmony_ci 2721e5b75505Sopenharmony_ci bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey); 2722e5b75505Sopenharmony_ci pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key); 2723e5b75505Sopenharmony_ci if (!bR || !pR) 2724e5b75505Sopenharmony_ci goto fail; 2725e5b75505Sopenharmony_ci bR_bn = EC_KEY_get0_private_key(bR); 2726e5b75505Sopenharmony_ci pR_bn = EC_KEY_get0_private_key(pR); 2727e5b75505Sopenharmony_ci if (!bR_bn || !pR_bn) 2728e5b75505Sopenharmony_ci goto fail; 2729e5b75505Sopenharmony_ci if (EC_GROUP_get_order(group, q, bnctx) != 1 || 2730e5b75505Sopenharmony_ci BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1) 2731e5b75505Sopenharmony_ci goto fail; 2732e5b75505Sopenharmony_ci l = EC_POINT_new(group); 2733e5b75505Sopenharmony_ci if (!l || 2734e5b75505Sopenharmony_ci EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 || 2735e5b75505Sopenharmony_ci EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL, 2736e5b75505Sopenharmony_ci bnctx) != 1) { 2737e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 2738e5b75505Sopenharmony_ci "OpenSSL: failed: %s", 2739e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 2740e5b75505Sopenharmony_ci goto fail; 2741e5b75505Sopenharmony_ci } 2742e5b75505Sopenharmony_ci 2743e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) 2744e5b75505Sopenharmony_ci goto fail; 2745e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); 2746e5b75505Sopenharmony_ci auth->Lx_len = auth->secret_len; 2747e5b75505Sopenharmony_ci ret = 0; 2748e5b75505Sopenharmony_cifail: 2749e5b75505Sopenharmony_ci EC_POINT_clear_free(l); 2750e5b75505Sopenharmony_ci EC_KEY_free(BI); 2751e5b75505Sopenharmony_ci EC_KEY_free(bR); 2752e5b75505Sopenharmony_ci EC_KEY_free(pR); 2753e5b75505Sopenharmony_ci BN_clear_free(lx); 2754e5b75505Sopenharmony_ci BN_clear_free(sum); 2755e5b75505Sopenharmony_ci BN_free(q); 2756e5b75505Sopenharmony_ci BN_CTX_free(bnctx); 2757e5b75505Sopenharmony_ci return ret; 2758e5b75505Sopenharmony_ci} 2759e5b75505Sopenharmony_ci 2760e5b75505Sopenharmony_ci 2761e5b75505Sopenharmony_cistatic int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) 2762e5b75505Sopenharmony_ci{ 2763e5b75505Sopenharmony_ci const EC_GROUP *group; 2764e5b75505Sopenharmony_ci EC_POINT *l = NULL, *sum = NULL; 2765e5b75505Sopenharmony_ci EC_KEY *bI = NULL, *BR = NULL, *PR = NULL; 2766e5b75505Sopenharmony_ci const EC_POINT *BR_point, *PR_point; 2767e5b75505Sopenharmony_ci BN_CTX *bnctx; 2768e5b75505Sopenharmony_ci BIGNUM *lx; 2769e5b75505Sopenharmony_ci const BIGNUM *bI_bn; 2770e5b75505Sopenharmony_ci int ret = -1; 2771e5b75505Sopenharmony_ci 2772e5b75505Sopenharmony_ci /* L = bI * (BR + PR) */ 2773e5b75505Sopenharmony_ci 2774e5b75505Sopenharmony_ci bnctx = BN_CTX_new(); 2775e5b75505Sopenharmony_ci lx = BN_new(); 2776e5b75505Sopenharmony_ci if (!bnctx || !lx) 2777e5b75505Sopenharmony_ci goto fail; 2778e5b75505Sopenharmony_ci BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey); 2779e5b75505Sopenharmony_ci PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key); 2780e5b75505Sopenharmony_ci if (!BR || !PR) 2781e5b75505Sopenharmony_ci goto fail; 2782e5b75505Sopenharmony_ci BR_point = EC_KEY_get0_public_key(BR); 2783e5b75505Sopenharmony_ci PR_point = EC_KEY_get0_public_key(PR); 2784e5b75505Sopenharmony_ci 2785e5b75505Sopenharmony_ci bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey); 2786e5b75505Sopenharmony_ci if (!bI) 2787e5b75505Sopenharmony_ci goto fail; 2788e5b75505Sopenharmony_ci group = EC_KEY_get0_group(bI); 2789e5b75505Sopenharmony_ci bI_bn = EC_KEY_get0_private_key(bI); 2790e5b75505Sopenharmony_ci if (!group || !bI_bn) 2791e5b75505Sopenharmony_ci goto fail; 2792e5b75505Sopenharmony_ci sum = EC_POINT_new(group); 2793e5b75505Sopenharmony_ci l = EC_POINT_new(group); 2794e5b75505Sopenharmony_ci if (!sum || !l || 2795e5b75505Sopenharmony_ci EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 || 2796e5b75505Sopenharmony_ci EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 || 2797e5b75505Sopenharmony_ci EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL, 2798e5b75505Sopenharmony_ci bnctx) != 1) { 2799e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 2800e5b75505Sopenharmony_ci "OpenSSL: failed: %s", 2801e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 2802e5b75505Sopenharmony_ci goto fail; 2803e5b75505Sopenharmony_ci } 2804e5b75505Sopenharmony_ci 2805e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) 2806e5b75505Sopenharmony_ci goto fail; 2807e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); 2808e5b75505Sopenharmony_ci auth->Lx_len = auth->secret_len; 2809e5b75505Sopenharmony_ci ret = 0; 2810e5b75505Sopenharmony_cifail: 2811e5b75505Sopenharmony_ci EC_POINT_clear_free(l); 2812e5b75505Sopenharmony_ci EC_POINT_clear_free(sum); 2813e5b75505Sopenharmony_ci EC_KEY_free(bI); 2814e5b75505Sopenharmony_ci EC_KEY_free(BR); 2815e5b75505Sopenharmony_ci EC_KEY_free(PR); 2816e5b75505Sopenharmony_ci BN_clear_free(lx); 2817e5b75505Sopenharmony_ci BN_CTX_free(bnctx); 2818e5b75505Sopenharmony_ci return ret; 2819e5b75505Sopenharmony_ci} 2820e5b75505Sopenharmony_ci 2821e5b75505Sopenharmony_ci 2822e5b75505Sopenharmony_cistatic int dpp_auth_build_resp_ok(struct dpp_authentication *auth) 2823e5b75505Sopenharmony_ci{ 2824e5b75505Sopenharmony_ci size_t nonce_len; 2825e5b75505Sopenharmony_ci size_t secret_len; 2826e5b75505Sopenharmony_ci struct wpabuf *msg, *pr = NULL; 2827e5b75505Sopenharmony_ci u8 r_auth[4 + DPP_MAX_HASH_LEN]; 2828e5b75505Sopenharmony_ci u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth; 2829e5b75505Sopenharmony_ci size_t wrapped_r_auth_len; 2830e5b75505Sopenharmony_ci int ret = -1; 2831e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce; 2832e5b75505Sopenharmony_ci enum dpp_status_error status = DPP_STATUS_OK; 2833e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2834e5b75505Sopenharmony_ci u8 test_hash[SHA256_MAC_LEN]; 2835e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2836e5b75505Sopenharmony_ci 2837e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response"); 2838e5b75505Sopenharmony_ci if (!auth->own_bi) 2839e5b75505Sopenharmony_ci return -1; 2840e5b75505Sopenharmony_ci 2841e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2842e5b75505Sopenharmony_ci if (dpp_nonce_override_len > 0) { 2843e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce"); 2844e5b75505Sopenharmony_ci nonce_len = dpp_nonce_override_len; 2845e5b75505Sopenharmony_ci os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len); 2846e5b75505Sopenharmony_ci } else { 2847e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2848e5b75505Sopenharmony_ci if (random_get_bytes(auth->r_nonce, nonce_len)) { 2849e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 2850e5b75505Sopenharmony_ci "DPP: Failed to generate R-nonce"); 2851e5b75505Sopenharmony_ci goto fail; 2852e5b75505Sopenharmony_ci } 2853e5b75505Sopenharmony_ci } 2854e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 2855e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 2856e5b75505Sopenharmony_ci if (random_get_bytes(auth->r_nonce, nonce_len)) { 2857e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce"); 2858e5b75505Sopenharmony_ci goto fail; 2859e5b75505Sopenharmony_ci } 2860e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2861e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len); 2862e5b75505Sopenharmony_ci 2863e5b75505Sopenharmony_ci EVP_PKEY_free(auth->own_protocol_key); 2864e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2865e5b75505Sopenharmony_ci if (dpp_protocol_key_override_len) { 2866e5b75505Sopenharmony_ci const struct dpp_curve_params *tmp_curve; 2867e5b75505Sopenharmony_ci 2868e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2869e5b75505Sopenharmony_ci "DPP: TESTING - override protocol key"); 2870e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_set_keypair( 2871e5b75505Sopenharmony_ci &tmp_curve, dpp_protocol_key_override, 2872e5b75505Sopenharmony_ci dpp_protocol_key_override_len); 2873e5b75505Sopenharmony_ci } else { 2874e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_gen_keypair(auth->curve); 2875e5b75505Sopenharmony_ci } 2876e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 2877e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_gen_keypair(auth->curve); 2878e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2879e5b75505Sopenharmony_ci if (!auth->own_protocol_key) 2880e5b75505Sopenharmony_ci goto fail; 2881e5b75505Sopenharmony_ci 2882e5b75505Sopenharmony_ci pr = dpp_get_pubkey_point(auth->own_protocol_key, 0); 2883e5b75505Sopenharmony_ci if (!pr) 2884e5b75505Sopenharmony_ci goto fail; 2885e5b75505Sopenharmony_ci 2886e5b75505Sopenharmony_ci /* ECDH: N = pR * PI */ 2887e5b75505Sopenharmony_ci if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key, 2888e5b75505Sopenharmony_ci auth->Nx, &secret_len) < 0) 2889e5b75505Sopenharmony_ci goto fail; 2890e5b75505Sopenharmony_ci 2891e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 2892e5b75505Sopenharmony_ci auth->Nx, auth->secret_len); 2893e5b75505Sopenharmony_ci auth->Nx_len = auth->secret_len; 2894e5b75505Sopenharmony_ci 2895e5b75505Sopenharmony_ci if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2, 2896e5b75505Sopenharmony_ci auth->curve->hash_len) < 0) 2897e5b75505Sopenharmony_ci goto fail; 2898e5b75505Sopenharmony_ci 2899e5b75505Sopenharmony_ci if (auth->own_bi && auth->peer_bi) { 2900e5b75505Sopenharmony_ci /* Mutual authentication */ 2901e5b75505Sopenharmony_ci if (dpp_auth_derive_l_responder(auth) < 0) 2902e5b75505Sopenharmony_ci goto fail; 2903e5b75505Sopenharmony_ci } 2904e5b75505Sopenharmony_ci 2905e5b75505Sopenharmony_ci if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) 2906e5b75505Sopenharmony_ci goto fail; 2907e5b75505Sopenharmony_ci 2908e5b75505Sopenharmony_ci /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 2909e5b75505Sopenharmony_ci WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG); 2910e5b75505Sopenharmony_ci WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len); 2911e5b75505Sopenharmony_ci if (dpp_gen_r_auth(auth, r_auth + 4) < 0) 2912e5b75505Sopenharmony_ci goto fail; 2913e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2914e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) { 2915e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch"); 2916e5b75505Sopenharmony_ci r_auth[4 + auth->curve->hash_len / 2] ^= 0x01; 2917e5b75505Sopenharmony_ci } 2918e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2919e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 2920e5b75505Sopenharmony_ci r_auth, 4 + auth->curve->hash_len, 2921e5b75505Sopenharmony_ci 0, NULL, NULL, wrapped_r_auth) < 0) 2922e5b75505Sopenharmony_ci goto fail; 2923e5b75505Sopenharmony_ci wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE; 2924e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke", 2925e5b75505Sopenharmony_ci wrapped_r_auth, wrapped_r_auth_len); 2926e5b75505Sopenharmony_ci w_r_auth = wrapped_r_auth; 2927e5b75505Sopenharmony_ci 2928e5b75505Sopenharmony_ci r_pubkey_hash = auth->own_bi->pubkey_hash; 2929e5b75505Sopenharmony_ci if (auth->peer_bi) 2930e5b75505Sopenharmony_ci i_pubkey_hash = auth->peer_bi->pubkey_hash; 2931e5b75505Sopenharmony_ci else 2932e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 2933e5b75505Sopenharmony_ci 2934e5b75505Sopenharmony_ci i_nonce = auth->i_nonce; 2935e5b75505Sopenharmony_ci r_nonce = auth->r_nonce; 2936e5b75505Sopenharmony_ci 2937e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2938e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 2939e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash"); 2940e5b75505Sopenharmony_ci r_pubkey_hash = NULL; 2941e5b75505Sopenharmony_ci } else if (dpp_test == 2942e5b75505Sopenharmony_ci DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 2943e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2944e5b75505Sopenharmony_ci "DPP: TESTING - invalid R-Bootstrap Key Hash"); 2945e5b75505Sopenharmony_ci os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN); 2946e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 2947e5b75505Sopenharmony_ci r_pubkey_hash = test_hash; 2948e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 2949e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash"); 2950e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 2951e5b75505Sopenharmony_ci } else if (dpp_test == 2952e5b75505Sopenharmony_ci DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 2953e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2954e5b75505Sopenharmony_ci "DPP: TESTING - invalid I-Bootstrap Key Hash"); 2955e5b75505Sopenharmony_ci if (i_pubkey_hash) 2956e5b75505Sopenharmony_ci os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN); 2957e5b75505Sopenharmony_ci else 2958e5b75505Sopenharmony_ci os_memset(test_hash, 0, SHA256_MAC_LEN); 2959e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 2960e5b75505Sopenharmony_ci i_pubkey_hash = test_hash; 2961e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) { 2962e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key"); 2963e5b75505Sopenharmony_ci wpabuf_free(pr); 2964e5b75505Sopenharmony_ci pr = NULL; 2965e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) { 2966e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key"); 2967e5b75505Sopenharmony_ci wpabuf_free(pr); 2968e5b75505Sopenharmony_ci pr = wpabuf_alloc(2 * auth->curve->prime_len); 2969e5b75505Sopenharmony_ci if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0) 2970e5b75505Sopenharmony_ci goto fail; 2971e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) { 2972e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth"); 2973e5b75505Sopenharmony_ci w_r_auth = NULL; 2974e5b75505Sopenharmony_ci wrapped_r_auth_len = 0; 2975e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) { 2976e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 2977e5b75505Sopenharmony_ci status = 255; 2978e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) { 2979e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 2980e5b75505Sopenharmony_ci status = 254; 2981e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) { 2982e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce"); 2983e5b75505Sopenharmony_ci r_nonce = NULL; 2984e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) { 2985e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce"); 2986e5b75505Sopenharmony_ci i_nonce = NULL; 2987e5b75505Sopenharmony_ci } 2988e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2989e5b75505Sopenharmony_ci 2990e5b75505Sopenharmony_ci msg = dpp_auth_build_resp(auth, status, pr, nonce_len, 2991e5b75505Sopenharmony_ci r_pubkey_hash, i_pubkey_hash, 2992e5b75505Sopenharmony_ci r_nonce, i_nonce, 2993e5b75505Sopenharmony_ci w_r_auth, wrapped_r_auth_len, 2994e5b75505Sopenharmony_ci auth->k2); 2995e5b75505Sopenharmony_ci if (!msg) 2996e5b75505Sopenharmony_ci goto fail; 2997e5b75505Sopenharmony_ci wpabuf_free(auth->resp_msg); 2998e5b75505Sopenharmony_ci auth->resp_msg = msg; 2999e5b75505Sopenharmony_ci ret = 0; 3000e5b75505Sopenharmony_cifail: 3001e5b75505Sopenharmony_ci wpabuf_free(pr); 3002e5b75505Sopenharmony_ci return ret; 3003e5b75505Sopenharmony_ci} 3004e5b75505Sopenharmony_ci 3005e5b75505Sopenharmony_ci 3006e5b75505Sopenharmony_cistatic int dpp_auth_build_resp_status(struct dpp_authentication *auth, 3007e5b75505Sopenharmony_ci enum dpp_status_error status) 3008e5b75505Sopenharmony_ci{ 3009e5b75505Sopenharmony_ci struct wpabuf *msg; 3010e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce; 3011e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3012e5b75505Sopenharmony_ci u8 test_hash[SHA256_MAC_LEN]; 3013e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3014e5b75505Sopenharmony_ci 3015e5b75505Sopenharmony_ci if (!auth->own_bi) 3016e5b75505Sopenharmony_ci return -1; 3017e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response"); 3018e5b75505Sopenharmony_ci 3019e5b75505Sopenharmony_ci r_pubkey_hash = auth->own_bi->pubkey_hash; 3020e5b75505Sopenharmony_ci if (auth->peer_bi) 3021e5b75505Sopenharmony_ci i_pubkey_hash = auth->peer_bi->pubkey_hash; 3022e5b75505Sopenharmony_ci else 3023e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 3024e5b75505Sopenharmony_ci 3025e5b75505Sopenharmony_ci i_nonce = auth->i_nonce; 3026e5b75505Sopenharmony_ci 3027e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3028e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 3029e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash"); 3030e5b75505Sopenharmony_ci r_pubkey_hash = NULL; 3031e5b75505Sopenharmony_ci } else if (dpp_test == 3032e5b75505Sopenharmony_ci DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 3033e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3034e5b75505Sopenharmony_ci "DPP: TESTING - invalid R-Bootstrap Key Hash"); 3035e5b75505Sopenharmony_ci os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN); 3036e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 3037e5b75505Sopenharmony_ci r_pubkey_hash = test_hash; 3038e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 3039e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash"); 3040e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 3041e5b75505Sopenharmony_ci } else if (dpp_test == 3042e5b75505Sopenharmony_ci DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) { 3043e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3044e5b75505Sopenharmony_ci "DPP: TESTING - invalid I-Bootstrap Key Hash"); 3045e5b75505Sopenharmony_ci if (i_pubkey_hash) 3046e5b75505Sopenharmony_ci os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN); 3047e5b75505Sopenharmony_ci else 3048e5b75505Sopenharmony_ci os_memset(test_hash, 0, SHA256_MAC_LEN); 3049e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 3050e5b75505Sopenharmony_ci i_pubkey_hash = test_hash; 3051e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) { 3052e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 3053e5b75505Sopenharmony_ci status = 255; 3054e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) { 3055e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce"); 3056e5b75505Sopenharmony_ci i_nonce = NULL; 3057e5b75505Sopenharmony_ci } 3058e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3059e5b75505Sopenharmony_ci 3060e5b75505Sopenharmony_ci msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len, 3061e5b75505Sopenharmony_ci r_pubkey_hash, i_pubkey_hash, 3062e5b75505Sopenharmony_ci NULL, i_nonce, NULL, 0, auth->k1); 3063e5b75505Sopenharmony_ci if (!msg) 3064e5b75505Sopenharmony_ci return -1; 3065e5b75505Sopenharmony_ci wpabuf_free(auth->resp_msg); 3066e5b75505Sopenharmony_ci auth->resp_msg = msg; 3067e5b75505Sopenharmony_ci return 0; 3068e5b75505Sopenharmony_ci} 3069e5b75505Sopenharmony_ci 3070e5b75505Sopenharmony_ci 3071e5b75505Sopenharmony_cistruct dpp_authentication * 3072e5b75505Sopenharmony_cidpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, 3073e5b75505Sopenharmony_ci struct dpp_bootstrap_info *peer_bi, 3074e5b75505Sopenharmony_ci struct dpp_bootstrap_info *own_bi, 3075e5b75505Sopenharmony_ci unsigned int freq, const u8 *hdr, const u8 *attr_start, 3076e5b75505Sopenharmony_ci size_t attr_len) 3077e5b75505Sopenharmony_ci{ 3078e5b75505Sopenharmony_ci EVP_PKEY *pi = NULL; 3079e5b75505Sopenharmony_ci EVP_PKEY_CTX *ctx = NULL; 3080e5b75505Sopenharmony_ci size_t secret_len; 3081e5b75505Sopenharmony_ci const u8 *addr[2]; 3082e5b75505Sopenharmony_ci size_t len[2]; 3083e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 3084e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 3085e5b75505Sopenharmony_ci const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap, 3086e5b75505Sopenharmony_ci *channel; 3087e5b75505Sopenharmony_ci u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len, 3088e5b75505Sopenharmony_ci i_bootstrap_len, channel_len; 3089e5b75505Sopenharmony_ci struct dpp_authentication *auth = NULL; 3090e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3091e5b75505Sopenharmony_ci const u8 *version; 3092e5b75505Sopenharmony_ci u16 version_len; 3093e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3094e5b75505Sopenharmony_ci 3095e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3096e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) { 3097e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3098e5b75505Sopenharmony_ci "DPP: TESTING - stop at Authentication Request"); 3099e5b75505Sopenharmony_ci return NULL; 3100e5b75505Sopenharmony_ci } 3101e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3102e5b75505Sopenharmony_ci 3103e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 3104e5b75505Sopenharmony_ci &wrapped_data_len); 3105e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 3106e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 3107e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 3108e5b75505Sopenharmony_ci return NULL; 3109e5b75505Sopenharmony_ci } 3110e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data", 3111e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3112e5b75505Sopenharmony_ci attr_len = wrapped_data - 4 - attr_start; 3113e5b75505Sopenharmony_ci 3114e5b75505Sopenharmony_ci auth = os_zalloc(sizeof(*auth)); 3115e5b75505Sopenharmony_ci if (!auth) 3116e5b75505Sopenharmony_ci goto fail; 3117e5b75505Sopenharmony_ci auth->msg_ctx = msg_ctx; 3118e5b75505Sopenharmony_ci auth->peer_bi = peer_bi; 3119e5b75505Sopenharmony_ci auth->own_bi = own_bi; 3120e5b75505Sopenharmony_ci auth->curve = own_bi->curve; 3121e5b75505Sopenharmony_ci auth->curr_freq = freq; 3122e5b75505Sopenharmony_ci 3123e5b75505Sopenharmony_ci auth->peer_version = 1; /* default to the first version */ 3124e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3125e5b75505Sopenharmony_ci version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 3126e5b75505Sopenharmony_ci &version_len); 3127e5b75505Sopenharmony_ci if (version) { 3128e5b75505Sopenharmony_ci if (version_len < 1 || version[0] == 0) { 3129e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3130e5b75505Sopenharmony_ci "Invalid Protocol Version attribute"); 3131e5b75505Sopenharmony_ci goto fail; 3132e5b75505Sopenharmony_ci } 3133e5b75505Sopenharmony_ci auth->peer_version = version[0]; 3134e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 3135e5b75505Sopenharmony_ci auth->peer_version); 3136e5b75505Sopenharmony_ci } 3137e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3138e5b75505Sopenharmony_ci 3139e5b75505Sopenharmony_ci channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL, 3140e5b75505Sopenharmony_ci &channel_len); 3141e5b75505Sopenharmony_ci if (channel) { 3142e5b75505Sopenharmony_ci int neg_freq; 3143e5b75505Sopenharmony_ci 3144e5b75505Sopenharmony_ci if (channel_len < 2) { 3145e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Too short Channel attribute"); 3146e5b75505Sopenharmony_ci goto fail; 3147e5b75505Sopenharmony_ci } 3148e5b75505Sopenharmony_ci 3149e5b75505Sopenharmony_ci neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]); 3150e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3151e5b75505Sopenharmony_ci "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d", 3152e5b75505Sopenharmony_ci channel[0], channel[1], neg_freq); 3153e5b75505Sopenharmony_ci if (neg_freq < 0) { 3154e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3155e5b75505Sopenharmony_ci "Unsupported Channel attribute value"); 3156e5b75505Sopenharmony_ci goto fail; 3157e5b75505Sopenharmony_ci } 3158e5b75505Sopenharmony_ci 3159e5b75505Sopenharmony_ci if (auth->curr_freq != (unsigned int) neg_freq) { 3160e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3161e5b75505Sopenharmony_ci "DPP: Changing negotiation channel from %u MHz to %u MHz", 3162e5b75505Sopenharmony_ci freq, neg_freq); 3163e5b75505Sopenharmony_ci auth->curr_freq = neg_freq; 3164e5b75505Sopenharmony_ci } 3165e5b75505Sopenharmony_ci } 3166e5b75505Sopenharmony_ci 3167e5b75505Sopenharmony_ci i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY, 3168e5b75505Sopenharmony_ci &i_proto_len); 3169e5b75505Sopenharmony_ci if (!i_proto) { 3170e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3171e5b75505Sopenharmony_ci "Missing required Initiator Protocol Key attribute"); 3172e5b75505Sopenharmony_ci goto fail; 3173e5b75505Sopenharmony_ci } 3174e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key", 3175e5b75505Sopenharmony_ci i_proto, i_proto_len); 3176e5b75505Sopenharmony_ci 3177e5b75505Sopenharmony_ci /* M = bR * PI */ 3178e5b75505Sopenharmony_ci pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len); 3179e5b75505Sopenharmony_ci if (!pi) { 3180e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid Initiator Protocol Key"); 3181e5b75505Sopenharmony_ci goto fail; 3182e5b75505Sopenharmony_ci } 3183e5b75505Sopenharmony_ci dpp_debug_print_key("Peer (Initiator) Protocol Key", pi); 3184e5b75505Sopenharmony_ci 3185e5b75505Sopenharmony_ci if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0) 3186e5b75505Sopenharmony_ci goto fail; 3187e5b75505Sopenharmony_ci auth->secret_len = secret_len; 3188e5b75505Sopenharmony_ci 3189e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)", 3190e5b75505Sopenharmony_ci auth->Mx, auth->secret_len); 3191e5b75505Sopenharmony_ci auth->Mx_len = auth->secret_len; 3192e5b75505Sopenharmony_ci 3193e5b75505Sopenharmony_ci if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1, 3194e5b75505Sopenharmony_ci auth->curve->hash_len) < 0) 3195e5b75505Sopenharmony_ci goto fail; 3196e5b75505Sopenharmony_ci 3197e5b75505Sopenharmony_ci addr[0] = hdr; 3198e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 3199e5b75505Sopenharmony_ci addr[1] = attr_start; 3200e5b75505Sopenharmony_ci len[1] = attr_len; 3201e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3202e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3203e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3204e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3205e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3206e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 3207e5b75505Sopenharmony_ci if (!unwrapped) 3208e5b75505Sopenharmony_ci goto fail; 3209e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->k1, auth->curve->hash_len, 3210e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 3211e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 3212e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 3213e5b75505Sopenharmony_ci goto fail; 3214e5b75505Sopenharmony_ci } 3215e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3216e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 3217e5b75505Sopenharmony_ci 3218e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3219e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 3220e5b75505Sopenharmony_ci goto fail; 3221e5b75505Sopenharmony_ci } 3222e5b75505Sopenharmony_ci 3223e5b75505Sopenharmony_ci i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 3224e5b75505Sopenharmony_ci &i_nonce_len); 3225e5b75505Sopenharmony_ci if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 3226e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid I-nonce"); 3227e5b75505Sopenharmony_ci goto fail; 3228e5b75505Sopenharmony_ci } 3229e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 3230e5b75505Sopenharmony_ci os_memcpy(auth->i_nonce, i_nonce, i_nonce_len); 3231e5b75505Sopenharmony_ci 3232e5b75505Sopenharmony_ci i_capab = dpp_get_attr(unwrapped, unwrapped_len, 3233e5b75505Sopenharmony_ci DPP_ATTR_I_CAPABILITIES, 3234e5b75505Sopenharmony_ci &i_capab_len); 3235e5b75505Sopenharmony_ci if (!i_capab || i_capab_len < 1) { 3236e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid I-capabilities"); 3237e5b75505Sopenharmony_ci goto fail; 3238e5b75505Sopenharmony_ci } 3239e5b75505Sopenharmony_ci auth->i_capab = i_capab[0]; 3240e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab); 3241e5b75505Sopenharmony_ci 3242e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3243e5b75505Sopenharmony_ci unwrapped = NULL; 3244e5b75505Sopenharmony_ci 3245e5b75505Sopenharmony_ci switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) { 3246e5b75505Sopenharmony_ci case DPP_CAPAB_ENROLLEE: 3247e5b75505Sopenharmony_ci if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) { 3248e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3249e5b75505Sopenharmony_ci "DPP: Local policy does not allow Configurator role"); 3250e5b75505Sopenharmony_ci goto not_compatible; 3251e5b75505Sopenharmony_ci } 3252e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator"); 3253e5b75505Sopenharmony_ci auth->configurator = 1; 3254e5b75505Sopenharmony_ci break; 3255e5b75505Sopenharmony_ci case DPP_CAPAB_CONFIGURATOR: 3256e5b75505Sopenharmony_ci if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) { 3257e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3258e5b75505Sopenharmony_ci "DPP: Local policy does not allow Enrollee role"); 3259e5b75505Sopenharmony_ci goto not_compatible; 3260e5b75505Sopenharmony_ci } 3261e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee"); 3262e5b75505Sopenharmony_ci auth->configurator = 0; 3263e5b75505Sopenharmony_ci break; 3264e5b75505Sopenharmony_ci case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE: 3265e5b75505Sopenharmony_ci if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) { 3266e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee"); 3267e5b75505Sopenharmony_ci auth->configurator = 0; 3268e5b75505Sopenharmony_ci } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) { 3269e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator"); 3270e5b75505Sopenharmony_ci auth->configurator = 1; 3271e5b75505Sopenharmony_ci } else { 3272e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3273e5b75505Sopenharmony_ci "DPP: Local policy does not allow Configurator/Enrollee role"); 3274e5b75505Sopenharmony_ci goto not_compatible; 3275e5b75505Sopenharmony_ci } 3276e5b75505Sopenharmony_ci break; 3277e5b75505Sopenharmony_ci default: 3278e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities"); 3279e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, 3280e5b75505Sopenharmony_ci DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x", 3281e5b75505Sopenharmony_ci auth->i_capab & DPP_CAPAB_ROLE_MASK); 3282e5b75505Sopenharmony_ci goto fail; 3283e5b75505Sopenharmony_ci } 3284e5b75505Sopenharmony_ci 3285e5b75505Sopenharmony_ci auth->peer_protocol_key = pi; 3286e5b75505Sopenharmony_ci pi = NULL; 3287e5b75505Sopenharmony_ci if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) { 3288e5b75505Sopenharmony_ci char hex[SHA256_MAC_LEN * 2 + 1]; 3289e5b75505Sopenharmony_ci 3290e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3291e5b75505Sopenharmony_ci "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time"); 3292e5b75505Sopenharmony_ci if (dpp_auth_build_resp_status(auth, 3293e5b75505Sopenharmony_ci DPP_STATUS_RESPONSE_PENDING) < 0) 3294e5b75505Sopenharmony_ci goto fail; 3295e5b75505Sopenharmony_ci i_bootstrap = dpp_get_attr(attr_start, attr_len, 3296e5b75505Sopenharmony_ci DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 3297e5b75505Sopenharmony_ci &i_bootstrap_len); 3298e5b75505Sopenharmony_ci if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) { 3299e5b75505Sopenharmony_ci auth->response_pending = 1; 3300e5b75505Sopenharmony_ci os_memcpy(auth->waiting_pubkey_hash, 3301e5b75505Sopenharmony_ci i_bootstrap, i_bootstrap_len); 3302e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap, 3303e5b75505Sopenharmony_ci i_bootstrap_len); 3304e5b75505Sopenharmony_ci } else { 3305e5b75505Sopenharmony_ci hex[0] = '\0'; 3306e5b75505Sopenharmony_ci } 3307e5b75505Sopenharmony_ci 3308e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE 3309e5b75505Sopenharmony_ci "%s", hex); 3310e5b75505Sopenharmony_ci return auth; 3311e5b75505Sopenharmony_ci } 3312e5b75505Sopenharmony_ci if (dpp_auth_build_resp_ok(auth) < 0) 3313e5b75505Sopenharmony_ci goto fail; 3314e5b75505Sopenharmony_ci 3315e5b75505Sopenharmony_ci return auth; 3316e5b75505Sopenharmony_ci 3317e5b75505Sopenharmony_cinot_compatible: 3318e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE 3319e5b75505Sopenharmony_ci "i-capab=0x%02x", auth->i_capab); 3320e5b75505Sopenharmony_ci if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) 3321e5b75505Sopenharmony_ci auth->configurator = 1; 3322e5b75505Sopenharmony_ci else 3323e5b75505Sopenharmony_ci auth->configurator = 0; 3324e5b75505Sopenharmony_ci auth->peer_protocol_key = pi; 3325e5b75505Sopenharmony_ci pi = NULL; 3326e5b75505Sopenharmony_ci if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0) 3327e5b75505Sopenharmony_ci goto fail; 3328e5b75505Sopenharmony_ci 3329e5b75505Sopenharmony_ci auth->remove_on_tx_status = 1; 3330e5b75505Sopenharmony_ci return auth; 3331e5b75505Sopenharmony_cifail: 3332e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3333e5b75505Sopenharmony_ci EVP_PKEY_free(pi); 3334e5b75505Sopenharmony_ci EVP_PKEY_CTX_free(ctx); 3335e5b75505Sopenharmony_ci dpp_auth_deinit(auth); 3336e5b75505Sopenharmony_ci return NULL; 3337e5b75505Sopenharmony_ci} 3338e5b75505Sopenharmony_ci 3339e5b75505Sopenharmony_ci 3340e5b75505Sopenharmony_ciint dpp_notify_new_qr_code(struct dpp_authentication *auth, 3341e5b75505Sopenharmony_ci struct dpp_bootstrap_info *peer_bi) 3342e5b75505Sopenharmony_ci{ 3343e5b75505Sopenharmony_ci if (!auth || !auth->response_pending || 3344e5b75505Sopenharmony_ci os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash, 3345e5b75505Sopenharmony_ci SHA256_MAC_LEN) != 0) 3346e5b75505Sopenharmony_ci return 0; 3347e5b75505Sopenharmony_ci 3348e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3349e5b75505Sopenharmony_ci "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with " 3350e5b75505Sopenharmony_ci MACSTR, MAC2STR(auth->peer_mac_addr)); 3351e5b75505Sopenharmony_ci auth->peer_bi = peer_bi; 3352e5b75505Sopenharmony_ci 3353e5b75505Sopenharmony_ci if (dpp_auth_build_resp_ok(auth) < 0) 3354e5b75505Sopenharmony_ci return -1; 3355e5b75505Sopenharmony_ci 3356e5b75505Sopenharmony_ci return 1; 3357e5b75505Sopenharmony_ci} 3358e5b75505Sopenharmony_ci 3359e5b75505Sopenharmony_ci 3360e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth, 3361e5b75505Sopenharmony_ci enum dpp_status_error status) 3362e5b75505Sopenharmony_ci{ 3363e5b75505Sopenharmony_ci struct wpabuf *msg; 3364e5b75505Sopenharmony_ci u8 i_auth[4 + DPP_MAX_HASH_LEN]; 3365e5b75505Sopenharmony_ci size_t i_auth_len; 3366e5b75505Sopenharmony_ci u8 r_nonce[4 + DPP_MAX_NONCE_LEN]; 3367e5b75505Sopenharmony_ci size_t r_nonce_len; 3368e5b75505Sopenharmony_ci const u8 *addr[2]; 3369e5b75505Sopenharmony_ci size_t len[2], attr_len; 3370e5b75505Sopenharmony_ci u8 *wrapped_i_auth; 3371e5b75505Sopenharmony_ci u8 *wrapped_r_nonce; 3372e5b75505Sopenharmony_ci u8 *attr_start, *attr_end; 3373e5b75505Sopenharmony_ci const u8 *r_pubkey_hash, *i_pubkey_hash; 3374e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3375e5b75505Sopenharmony_ci u8 test_hash[SHA256_MAC_LEN]; 3376e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3377e5b75505Sopenharmony_ci 3378e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation"); 3379e5b75505Sopenharmony_ci 3380e5b75505Sopenharmony_ci i_auth_len = 4 + auth->curve->hash_len; 3381e5b75505Sopenharmony_ci r_nonce_len = 4 + auth->curve->nonce_len; 3382e5b75505Sopenharmony_ci /* Build DPP Authentication Confirmation frame attributes */ 3383e5b75505Sopenharmony_ci attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 3384e5b75505Sopenharmony_ci 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE; 3385e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3386e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) 3387e5b75505Sopenharmony_ci attr_len += 5; 3388e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3389e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len); 3390e5b75505Sopenharmony_ci if (!msg) 3391e5b75505Sopenharmony_ci goto fail; 3392e5b75505Sopenharmony_ci 3393e5b75505Sopenharmony_ci attr_start = wpabuf_put(msg, 0); 3394e5b75505Sopenharmony_ci 3395e5b75505Sopenharmony_ci r_pubkey_hash = auth->peer_bi->pubkey_hash; 3396e5b75505Sopenharmony_ci if (auth->own_bi) 3397e5b75505Sopenharmony_ci i_pubkey_hash = auth->own_bi->pubkey_hash; 3398e5b75505Sopenharmony_ci else 3399e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 3400e5b75505Sopenharmony_ci 3401e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3402e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) { 3403e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 3404e5b75505Sopenharmony_ci goto skip_status; 3405e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) { 3406e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 3407e5b75505Sopenharmony_ci status = 254; 3408e5b75505Sopenharmony_ci } 3409e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3410e5b75505Sopenharmony_ci 3411e5b75505Sopenharmony_ci /* DPP Status */ 3412e5b75505Sopenharmony_ci dpp_build_attr_status(msg, status); 3413e5b75505Sopenharmony_ci 3414e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3415e5b75505Sopenharmony_ciskip_status: 3416e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) { 3417e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash"); 3418e5b75505Sopenharmony_ci r_pubkey_hash = NULL; 3419e5b75505Sopenharmony_ci } else if (dpp_test == 3420e5b75505Sopenharmony_ci DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) { 3421e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3422e5b75505Sopenharmony_ci "DPP: TESTING - invalid R-Bootstrap Key Hash"); 3423e5b75505Sopenharmony_ci os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN); 3424e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 3425e5b75505Sopenharmony_ci r_pubkey_hash = test_hash; 3426e5b75505Sopenharmony_ci } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) { 3427e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash"); 3428e5b75505Sopenharmony_ci i_pubkey_hash = NULL; 3429e5b75505Sopenharmony_ci } else if (dpp_test == 3430e5b75505Sopenharmony_ci DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) { 3431e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3432e5b75505Sopenharmony_ci "DPP: TESTING - invalid I-Bootstrap Key Hash"); 3433e5b75505Sopenharmony_ci if (i_pubkey_hash) 3434e5b75505Sopenharmony_ci os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN); 3435e5b75505Sopenharmony_ci else 3436e5b75505Sopenharmony_ci os_memset(test_hash, 0, SHA256_MAC_LEN); 3437e5b75505Sopenharmony_ci test_hash[SHA256_MAC_LEN - 1] ^= 0x01; 3438e5b75505Sopenharmony_ci i_pubkey_hash = test_hash; 3439e5b75505Sopenharmony_ci } 3440e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3441e5b75505Sopenharmony_ci 3442e5b75505Sopenharmony_ci /* Responder Bootstrapping Key Hash */ 3443e5b75505Sopenharmony_ci dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash); 3444e5b75505Sopenharmony_ci 3445e5b75505Sopenharmony_ci /* Initiator Bootstrapping Key Hash (mutual authentication) */ 3446e5b75505Sopenharmony_ci dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash); 3447e5b75505Sopenharmony_ci 3448e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3449e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF) 3450e5b75505Sopenharmony_ci goto skip_wrapped_data; 3451e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF) 3452e5b75505Sopenharmony_ci i_auth_len = 0; 3453e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3454e5b75505Sopenharmony_ci 3455e5b75505Sopenharmony_ci attr_end = wpabuf_put(msg, 0); 3456e5b75505Sopenharmony_ci 3457e5b75505Sopenharmony_ci /* OUI, OUI type, Crypto Suite, DPP frame type */ 3458e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 3459e5b75505Sopenharmony_ci len[0] = 3 + 1 + 1 + 1; 3460e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3461e5b75505Sopenharmony_ci 3462e5b75505Sopenharmony_ci /* Attributes before Wrapped Data */ 3463e5b75505Sopenharmony_ci addr[1] = attr_start; 3464e5b75505Sopenharmony_ci len[1] = attr_end - attr_start; 3465e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3466e5b75505Sopenharmony_ci 3467e5b75505Sopenharmony_ci if (status == DPP_STATUS_OK) { 3468e5b75505Sopenharmony_ci /* I-auth wrapped with ke */ 3469e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 3470e5b75505Sopenharmony_ci wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE); 3471e5b75505Sopenharmony_ci wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE); 3472e5b75505Sopenharmony_ci 3473e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3474e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF) 3475e5b75505Sopenharmony_ci goto skip_i_auth; 3476e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3477e5b75505Sopenharmony_ci 3478e5b75505Sopenharmony_ci /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 3479e5b75505Sopenharmony_ci * 1) */ 3480e5b75505Sopenharmony_ci WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG); 3481e5b75505Sopenharmony_ci WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len); 3482e5b75505Sopenharmony_ci if (dpp_gen_i_auth(auth, i_auth + 4) < 0) 3483e5b75505Sopenharmony_ci goto fail; 3484e5b75505Sopenharmony_ci 3485e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3486e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) { 3487e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch"); 3488e5b75505Sopenharmony_ci i_auth[4 + auth->curve->hash_len / 2] ^= 0x01; 3489e5b75505Sopenharmony_ci } 3490e5b75505Sopenharmony_ciskip_i_auth: 3491e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3492e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 3493e5b75505Sopenharmony_ci i_auth, i_auth_len, 3494e5b75505Sopenharmony_ci 2, addr, len, wrapped_i_auth) < 0) 3495e5b75505Sopenharmony_ci goto fail; 3496e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke", 3497e5b75505Sopenharmony_ci wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE); 3498e5b75505Sopenharmony_ci } else { 3499e5b75505Sopenharmony_ci /* R-nonce wrapped with k2 */ 3500e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 3501e5b75505Sopenharmony_ci wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE); 3502e5b75505Sopenharmony_ci wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE); 3503e5b75505Sopenharmony_ci 3504e5b75505Sopenharmony_ci WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE); 3505e5b75505Sopenharmony_ci WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len); 3506e5b75505Sopenharmony_ci os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len); 3507e5b75505Sopenharmony_ci 3508e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->k2, auth->curve->hash_len, 3509e5b75505Sopenharmony_ci r_nonce, r_nonce_len, 3510e5b75505Sopenharmony_ci 2, addr, len, wrapped_r_nonce) < 0) 3511e5b75505Sopenharmony_ci goto fail; 3512e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2", 3513e5b75505Sopenharmony_ci wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE); 3514e5b75505Sopenharmony_ci } 3515e5b75505Sopenharmony_ci 3516e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3517e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) { 3518e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 3519e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 3520e5b75505Sopenharmony_ci } 3521e5b75505Sopenharmony_ciskip_wrapped_data: 3522e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3523e5b75505Sopenharmony_ci 3524e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, 3525e5b75505Sopenharmony_ci "DPP: Authentication Confirmation frame attributes", 3526e5b75505Sopenharmony_ci msg); 3527e5b75505Sopenharmony_ci if (status == DPP_STATUS_OK) 3528e5b75505Sopenharmony_ci dpp_auth_success(auth); 3529e5b75505Sopenharmony_ci 3530e5b75505Sopenharmony_ci return msg; 3531e5b75505Sopenharmony_ci 3532e5b75505Sopenharmony_cifail: 3533e5b75505Sopenharmony_ci wpabuf_free(msg); 3534e5b75505Sopenharmony_ci return NULL; 3535e5b75505Sopenharmony_ci} 3536e5b75505Sopenharmony_ci 3537e5b75505Sopenharmony_ci 3538e5b75505Sopenharmony_cistatic void 3539e5b75505Sopenharmony_cidpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr, 3540e5b75505Sopenharmony_ci const u8 *attr_start, size_t attr_len, 3541e5b75505Sopenharmony_ci const u8 *wrapped_data, u16 wrapped_data_len, 3542e5b75505Sopenharmony_ci enum dpp_status_error status) 3543e5b75505Sopenharmony_ci{ 3544e5b75505Sopenharmony_ci const u8 *addr[2]; 3545e5b75505Sopenharmony_ci size_t len[2]; 3546e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 3547e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 3548e5b75505Sopenharmony_ci const u8 *i_nonce, *r_capab; 3549e5b75505Sopenharmony_ci u16 i_nonce_len, r_capab_len; 3550e5b75505Sopenharmony_ci 3551e5b75505Sopenharmony_ci if (status == DPP_STATUS_NOT_COMPATIBLE) { 3552e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3553e5b75505Sopenharmony_ci "DPP: Responder reported incompatible roles"); 3554e5b75505Sopenharmony_ci } else if (status == DPP_STATUS_RESPONSE_PENDING) { 3555e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3556e5b75505Sopenharmony_ci "DPP: Responder reported more time needed"); 3557e5b75505Sopenharmony_ci } else { 3558e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3559e5b75505Sopenharmony_ci "DPP: Responder reported failure (status %d)", 3560e5b75505Sopenharmony_ci status); 3561e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Responder reported failure"); 3562e5b75505Sopenharmony_ci return; 3563e5b75505Sopenharmony_ci } 3564e5b75505Sopenharmony_ci 3565e5b75505Sopenharmony_ci addr[0] = hdr; 3566e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 3567e5b75505Sopenharmony_ci addr[1] = attr_start; 3568e5b75505Sopenharmony_ci len[1] = attr_len; 3569e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3570e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3571e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3572e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3573e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3574e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 3575e5b75505Sopenharmony_ci if (!unwrapped) 3576e5b75505Sopenharmony_ci goto fail; 3577e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->k1, auth->curve->hash_len, 3578e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 3579e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 3580e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 3581e5b75505Sopenharmony_ci goto fail; 3582e5b75505Sopenharmony_ci } 3583e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3584e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 3585e5b75505Sopenharmony_ci 3586e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3587e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 3588e5b75505Sopenharmony_ci goto fail; 3589e5b75505Sopenharmony_ci } 3590e5b75505Sopenharmony_ci 3591e5b75505Sopenharmony_ci i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 3592e5b75505Sopenharmony_ci &i_nonce_len); 3593e5b75505Sopenharmony_ci if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 3594e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid I-nonce"); 3595e5b75505Sopenharmony_ci goto fail; 3596e5b75505Sopenharmony_ci } 3597e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 3598e5b75505Sopenharmony_ci if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) { 3599e5b75505Sopenharmony_ci dpp_auth_fail(auth, "I-nonce mismatch"); 3600e5b75505Sopenharmony_ci goto fail; 3601e5b75505Sopenharmony_ci } 3602e5b75505Sopenharmony_ci 3603e5b75505Sopenharmony_ci r_capab = dpp_get_attr(unwrapped, unwrapped_len, 3604e5b75505Sopenharmony_ci DPP_ATTR_R_CAPABILITIES, 3605e5b75505Sopenharmony_ci &r_capab_len); 3606e5b75505Sopenharmony_ci if (!r_capab || r_capab_len < 1) { 3607e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid R-capabilities"); 3608e5b75505Sopenharmony_ci goto fail; 3609e5b75505Sopenharmony_ci } 3610e5b75505Sopenharmony_ci auth->r_capab = r_capab[0]; 3611e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab); 3612e5b75505Sopenharmony_ci if (status == DPP_STATUS_NOT_COMPATIBLE) { 3613e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE 3614e5b75505Sopenharmony_ci "r-capab=0x%02x", auth->r_capab); 3615e5b75505Sopenharmony_ci } else if (status == DPP_STATUS_RESPONSE_PENDING) { 3616e5b75505Sopenharmony_ci u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK; 3617e5b75505Sopenharmony_ci 3618e5b75505Sopenharmony_ci if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) || 3619e5b75505Sopenharmony_ci (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) { 3620e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, 3621e5b75505Sopenharmony_ci DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x", 3622e5b75505Sopenharmony_ci role); 3623e5b75505Sopenharmony_ci } else { 3624e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3625e5b75505Sopenharmony_ci "DPP: Continue waiting for full DPP Authentication Response"); 3626e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, 3627e5b75505Sopenharmony_ci DPP_EVENT_RESPONSE_PENDING "%s", 3628e5b75505Sopenharmony_ci auth->tmp_own_bi ? auth->tmp_own_bi->uri : ""); 3629e5b75505Sopenharmony_ci } 3630e5b75505Sopenharmony_ci } 3631e5b75505Sopenharmony_cifail: 3632e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3633e5b75505Sopenharmony_ci} 3634e5b75505Sopenharmony_ci 3635e5b75505Sopenharmony_ci 3636e5b75505Sopenharmony_cistruct wpabuf * 3637e5b75505Sopenharmony_cidpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, 3638e5b75505Sopenharmony_ci const u8 *attr_start, size_t attr_len) 3639e5b75505Sopenharmony_ci{ 3640e5b75505Sopenharmony_ci EVP_PKEY *pr; 3641e5b75505Sopenharmony_ci size_t secret_len; 3642e5b75505Sopenharmony_ci const u8 *addr[2]; 3643e5b75505Sopenharmony_ci size_t len[2]; 3644e5b75505Sopenharmony_ci u8 *unwrapped = NULL, *unwrapped2 = NULL; 3645e5b75505Sopenharmony_ci size_t unwrapped_len = 0, unwrapped2_len = 0; 3646e5b75505Sopenharmony_ci const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto, 3647e5b75505Sopenharmony_ci *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth; 3648e5b75505Sopenharmony_ci u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len, 3649e5b75505Sopenharmony_ci r_proto_len, r_nonce_len, i_nonce_len, r_capab_len, 3650e5b75505Sopenharmony_ci wrapped2_len, r_auth_len; 3651e5b75505Sopenharmony_ci u8 r_auth2[DPP_MAX_HASH_LEN]; 3652e5b75505Sopenharmony_ci u8 role; 3653e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3654e5b75505Sopenharmony_ci const u8 *version; 3655e5b75505Sopenharmony_ci u16 version_len; 3656e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3657e5b75505Sopenharmony_ci 3658e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3659e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) { 3660e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3661e5b75505Sopenharmony_ci "DPP: TESTING - stop at Authentication Response"); 3662e5b75505Sopenharmony_ci return NULL; 3663e5b75505Sopenharmony_ci } 3664e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3665e5b75505Sopenharmony_ci 3666e5b75505Sopenharmony_ci if (!auth->initiator || !auth->peer_bi) { 3667e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unexpected Authentication Response"); 3668e5b75505Sopenharmony_ci return NULL; 3669e5b75505Sopenharmony_ci } 3670e5b75505Sopenharmony_ci 3671e5b75505Sopenharmony_ci auth->waiting_auth_resp = 0; 3672e5b75505Sopenharmony_ci 3673e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 3674e5b75505Sopenharmony_ci &wrapped_data_len); 3675e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 3676e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3677e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 3678e5b75505Sopenharmony_ci return NULL; 3679e5b75505Sopenharmony_ci } 3680e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 3681e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3682e5b75505Sopenharmony_ci 3683e5b75505Sopenharmony_ci attr_len = wrapped_data - 4 - attr_start; 3684e5b75505Sopenharmony_ci 3685e5b75505Sopenharmony_ci r_bootstrap = dpp_get_attr(attr_start, attr_len, 3686e5b75505Sopenharmony_ci DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 3687e5b75505Sopenharmony_ci &r_bootstrap_len); 3688e5b75505Sopenharmony_ci if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 3689e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3690e5b75505Sopenharmony_ci "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 3691e5b75505Sopenharmony_ci return NULL; 3692e5b75505Sopenharmony_ci } 3693e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash", 3694e5b75505Sopenharmony_ci r_bootstrap, r_bootstrap_len); 3695e5b75505Sopenharmony_ci if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash, 3696e5b75505Sopenharmony_ci SHA256_MAC_LEN) != 0) { 3697e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3698e5b75505Sopenharmony_ci "Unexpected Responder Bootstrapping Key Hash value"); 3699e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, 3700e5b75505Sopenharmony_ci "DPP: Expected Responder Bootstrapping Key Hash", 3701e5b75505Sopenharmony_ci auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 3702e5b75505Sopenharmony_ci return NULL; 3703e5b75505Sopenharmony_ci } 3704e5b75505Sopenharmony_ci 3705e5b75505Sopenharmony_ci i_bootstrap = dpp_get_attr(attr_start, attr_len, 3706e5b75505Sopenharmony_ci DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 3707e5b75505Sopenharmony_ci &i_bootstrap_len); 3708e5b75505Sopenharmony_ci if (i_bootstrap) { 3709e5b75505Sopenharmony_ci if (i_bootstrap_len != SHA256_MAC_LEN) { 3710e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3711e5b75505Sopenharmony_ci "Invalid Initiator Bootstrapping Key Hash attribute"); 3712e5b75505Sopenharmony_ci return NULL; 3713e5b75505Sopenharmony_ci } 3714e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, 3715e5b75505Sopenharmony_ci "DPP: Initiator Bootstrapping Key Hash", 3716e5b75505Sopenharmony_ci i_bootstrap, i_bootstrap_len); 3717e5b75505Sopenharmony_ci if (!auth->own_bi || 3718e5b75505Sopenharmony_ci os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash, 3719e5b75505Sopenharmony_ci SHA256_MAC_LEN) != 0) { 3720e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3721e5b75505Sopenharmony_ci "Initiator Bootstrapping Key Hash attribute did not match"); 3722e5b75505Sopenharmony_ci return NULL; 3723e5b75505Sopenharmony_ci } 3724e5b75505Sopenharmony_ci } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) { 3725e5b75505Sopenharmony_ci /* PKEX bootstrapping mandates use of mutual authentication */ 3726e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3727e5b75505Sopenharmony_ci "Missing Initiator Bootstrapping Key Hash attribute"); 3728e5b75505Sopenharmony_ci return NULL; 3729e5b75505Sopenharmony_ci } 3730e5b75505Sopenharmony_ci 3731e5b75505Sopenharmony_ci auth->peer_version = 1; /* default to the first version */ 3732e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3733e5b75505Sopenharmony_ci version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 3734e5b75505Sopenharmony_ci &version_len); 3735e5b75505Sopenharmony_ci if (version) { 3736e5b75505Sopenharmony_ci if (version_len < 1 || version[0] == 0) { 3737e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3738e5b75505Sopenharmony_ci "Invalid Protocol Version attribute"); 3739e5b75505Sopenharmony_ci return NULL; 3740e5b75505Sopenharmony_ci } 3741e5b75505Sopenharmony_ci auth->peer_version = version[0]; 3742e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 3743e5b75505Sopenharmony_ci auth->peer_version); 3744e5b75505Sopenharmony_ci } 3745e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3746e5b75505Sopenharmony_ci 3747e5b75505Sopenharmony_ci status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 3748e5b75505Sopenharmony_ci &status_len); 3749e5b75505Sopenharmony_ci if (!status || status_len < 1) { 3750e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3751e5b75505Sopenharmony_ci "Missing or invalid required DPP Status attribute"); 3752e5b75505Sopenharmony_ci return NULL; 3753e5b75505Sopenharmony_ci } 3754e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 3755e5b75505Sopenharmony_ci auth->auth_resp_status = status[0]; 3756e5b75505Sopenharmony_ci if (status[0] != DPP_STATUS_OK) { 3757e5b75505Sopenharmony_ci dpp_auth_resp_rx_status(auth, hdr, attr_start, 3758e5b75505Sopenharmony_ci attr_len, wrapped_data, 3759e5b75505Sopenharmony_ci wrapped_data_len, status[0]); 3760e5b75505Sopenharmony_ci return NULL; 3761e5b75505Sopenharmony_ci } 3762e5b75505Sopenharmony_ci 3763e5b75505Sopenharmony_ci if (!i_bootstrap && auth->own_bi) { 3764e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3765e5b75505Sopenharmony_ci "DPP: Responder decided not to use mutual authentication"); 3766e5b75505Sopenharmony_ci auth->own_bi = NULL; 3767e5b75505Sopenharmony_ci } 3768e5b75505Sopenharmony_ci 3769e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d", 3770e5b75505Sopenharmony_ci auth->own_bi != NULL); 3771e5b75505Sopenharmony_ci 3772e5b75505Sopenharmony_ci r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY, 3773e5b75505Sopenharmony_ci &r_proto_len); 3774e5b75505Sopenharmony_ci if (!r_proto) { 3775e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3776e5b75505Sopenharmony_ci "Missing required Responder Protocol Key attribute"); 3777e5b75505Sopenharmony_ci return NULL; 3778e5b75505Sopenharmony_ci } 3779e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key", 3780e5b75505Sopenharmony_ci r_proto, r_proto_len); 3781e5b75505Sopenharmony_ci 3782e5b75505Sopenharmony_ci /* N = pI * PR */ 3783e5b75505Sopenharmony_ci pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len); 3784e5b75505Sopenharmony_ci if (!pr) { 3785e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid Responder Protocol Key"); 3786e5b75505Sopenharmony_ci return NULL; 3787e5b75505Sopenharmony_ci } 3788e5b75505Sopenharmony_ci dpp_debug_print_key("Peer (Responder) Protocol Key", pr); 3789e5b75505Sopenharmony_ci 3790e5b75505Sopenharmony_ci if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) { 3791e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Failed to derive ECDH shared secret"); 3792e5b75505Sopenharmony_ci goto fail; 3793e5b75505Sopenharmony_ci } 3794e5b75505Sopenharmony_ci EVP_PKEY_free(auth->peer_protocol_key); 3795e5b75505Sopenharmony_ci auth->peer_protocol_key = pr; 3796e5b75505Sopenharmony_ci pr = NULL; 3797e5b75505Sopenharmony_ci 3798e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 3799e5b75505Sopenharmony_ci auth->Nx, auth->secret_len); 3800e5b75505Sopenharmony_ci auth->Nx_len = auth->secret_len; 3801e5b75505Sopenharmony_ci 3802e5b75505Sopenharmony_ci if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2, 3803e5b75505Sopenharmony_ci auth->curve->hash_len) < 0) 3804e5b75505Sopenharmony_ci goto fail; 3805e5b75505Sopenharmony_ci 3806e5b75505Sopenharmony_ci addr[0] = hdr; 3807e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 3808e5b75505Sopenharmony_ci addr[1] = attr_start; 3809e5b75505Sopenharmony_ci len[1] = attr_len; 3810e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3811e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3812e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3813e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3814e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3815e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 3816e5b75505Sopenharmony_ci if (!unwrapped) 3817e5b75505Sopenharmony_ci goto fail; 3818e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->k2, auth->curve->hash_len, 3819e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 3820e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 3821e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 3822e5b75505Sopenharmony_ci goto fail; 3823e5b75505Sopenharmony_ci } 3824e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3825e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 3826e5b75505Sopenharmony_ci 3827e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3828e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 3829e5b75505Sopenharmony_ci goto fail; 3830e5b75505Sopenharmony_ci } 3831e5b75505Sopenharmony_ci 3832e5b75505Sopenharmony_ci r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE, 3833e5b75505Sopenharmony_ci &r_nonce_len); 3834e5b75505Sopenharmony_ci if (!r_nonce || r_nonce_len != auth->curve->nonce_len) { 3835e5b75505Sopenharmony_ci dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce"); 3836e5b75505Sopenharmony_ci goto fail; 3837e5b75505Sopenharmony_ci } 3838e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len); 3839e5b75505Sopenharmony_ci os_memcpy(auth->r_nonce, r_nonce, r_nonce_len); 3840e5b75505Sopenharmony_ci 3841e5b75505Sopenharmony_ci i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 3842e5b75505Sopenharmony_ci &i_nonce_len); 3843e5b75505Sopenharmony_ci if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 3844e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid I-nonce"); 3845e5b75505Sopenharmony_ci goto fail; 3846e5b75505Sopenharmony_ci } 3847e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 3848e5b75505Sopenharmony_ci if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) { 3849e5b75505Sopenharmony_ci dpp_auth_fail(auth, "I-nonce mismatch"); 3850e5b75505Sopenharmony_ci goto fail; 3851e5b75505Sopenharmony_ci } 3852e5b75505Sopenharmony_ci 3853e5b75505Sopenharmony_ci if (auth->own_bi) { 3854e5b75505Sopenharmony_ci /* Mutual authentication */ 3855e5b75505Sopenharmony_ci if (dpp_auth_derive_l_initiator(auth) < 0) 3856e5b75505Sopenharmony_ci goto fail; 3857e5b75505Sopenharmony_ci } 3858e5b75505Sopenharmony_ci 3859e5b75505Sopenharmony_ci r_capab = dpp_get_attr(unwrapped, unwrapped_len, 3860e5b75505Sopenharmony_ci DPP_ATTR_R_CAPABILITIES, 3861e5b75505Sopenharmony_ci &r_capab_len); 3862e5b75505Sopenharmony_ci if (!r_capab || r_capab_len < 1) { 3863e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Missing or invalid R-capabilities"); 3864e5b75505Sopenharmony_ci goto fail; 3865e5b75505Sopenharmony_ci } 3866e5b75505Sopenharmony_ci auth->r_capab = r_capab[0]; 3867e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab); 3868e5b75505Sopenharmony_ci role = auth->r_capab & DPP_CAPAB_ROLE_MASK; 3869e5b75505Sopenharmony_ci if ((auth->allowed_roles == 3870e5b75505Sopenharmony_ci (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) && 3871e5b75505Sopenharmony_ci (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) { 3872e5b75505Sopenharmony_ci /* Peer selected its role, so move from "either role" to the 3873e5b75505Sopenharmony_ci * role that is compatible with peer's selection. */ 3874e5b75505Sopenharmony_ci auth->configurator = role == DPP_CAPAB_ENROLLEE; 3875e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Acting as %s", 3876e5b75505Sopenharmony_ci auth->configurator ? "Configurator" : "Enrollee"); 3877e5b75505Sopenharmony_ci } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) || 3878e5b75505Sopenharmony_ci (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) { 3879e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection"); 3880e5b75505Sopenharmony_ci wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 3881e5b75505Sopenharmony_ci "Unexpected role in R-capabilities 0x%02x", 3882e5b75505Sopenharmony_ci role); 3883e5b75505Sopenharmony_ci if (role != DPP_CAPAB_ENROLLEE && 3884e5b75505Sopenharmony_ci role != DPP_CAPAB_CONFIGURATOR) 3885e5b75505Sopenharmony_ci goto fail; 3886e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3887e5b75505Sopenharmony_ci auth->remove_on_tx_status = 1; 3888e5b75505Sopenharmony_ci return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE); 3889e5b75505Sopenharmony_ci } 3890e5b75505Sopenharmony_ci 3891e5b75505Sopenharmony_ci wrapped2 = dpp_get_attr(unwrapped, unwrapped_len, 3892e5b75505Sopenharmony_ci DPP_ATTR_WRAPPED_DATA, &wrapped2_len); 3893e5b75505Sopenharmony_ci if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) { 3894e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3895e5b75505Sopenharmony_ci "Missing or invalid Secondary Wrapped Data"); 3896e5b75505Sopenharmony_ci goto fail; 3897e5b75505Sopenharmony_ci } 3898e5b75505Sopenharmony_ci 3899e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3900e5b75505Sopenharmony_ci wrapped2, wrapped2_len); 3901e5b75505Sopenharmony_ci 3902e5b75505Sopenharmony_ci if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) 3903e5b75505Sopenharmony_ci goto fail; 3904e5b75505Sopenharmony_ci 3905e5b75505Sopenharmony_ci unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE; 3906e5b75505Sopenharmony_ci unwrapped2 = os_malloc(unwrapped2_len); 3907e5b75505Sopenharmony_ci if (!unwrapped2) 3908e5b75505Sopenharmony_ci goto fail; 3909e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 3910e5b75505Sopenharmony_ci wrapped2, wrapped2_len, 3911e5b75505Sopenharmony_ci 0, NULL, NULL, unwrapped2) < 0) { 3912e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 3913e5b75505Sopenharmony_ci goto fail; 3914e5b75505Sopenharmony_ci } 3915e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3916e5b75505Sopenharmony_ci unwrapped2, unwrapped2_len); 3917e5b75505Sopenharmony_ci 3918e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) { 3919e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3920e5b75505Sopenharmony_ci "Invalid attribute in secondary unwrapped data"); 3921e5b75505Sopenharmony_ci goto fail; 3922e5b75505Sopenharmony_ci } 3923e5b75505Sopenharmony_ci 3924e5b75505Sopenharmony_ci r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG, 3925e5b75505Sopenharmony_ci &r_auth_len); 3926e5b75505Sopenharmony_ci if (!r_auth || r_auth_len != auth->curve->hash_len) { 3927e5b75505Sopenharmony_ci dpp_auth_fail(auth, 3928e5b75505Sopenharmony_ci "Missing or invalid Responder Authenticating Tag"); 3929e5b75505Sopenharmony_ci goto fail; 3930e5b75505Sopenharmony_ci } 3931e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag", 3932e5b75505Sopenharmony_ci r_auth, r_auth_len); 3933e5b75505Sopenharmony_ci /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 3934e5b75505Sopenharmony_ci if (dpp_gen_r_auth(auth, r_auth2) < 0) 3935e5b75505Sopenharmony_ci goto fail; 3936e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag", 3937e5b75505Sopenharmony_ci r_auth2, r_auth_len); 3938e5b75505Sopenharmony_ci if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) { 3939e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag"); 3940e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3941e5b75505Sopenharmony_ci bin_clear_free(unwrapped2, unwrapped2_len); 3942e5b75505Sopenharmony_ci auth->remove_on_tx_status = 1; 3943e5b75505Sopenharmony_ci return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE); 3944e5b75505Sopenharmony_ci } 3945e5b75505Sopenharmony_ci 3946e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3947e5b75505Sopenharmony_ci bin_clear_free(unwrapped2, unwrapped2_len); 3948e5b75505Sopenharmony_ci 3949e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3950e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) { 3951e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3952e5b75505Sopenharmony_ci "DPP: TESTING - Authentication Response in place of Confirm"); 3953e5b75505Sopenharmony_ci if (dpp_auth_build_resp_ok(auth) < 0) 3954e5b75505Sopenharmony_ci return NULL; 3955e5b75505Sopenharmony_ci return wpabuf_dup(auth->resp_msg); 3956e5b75505Sopenharmony_ci } 3957e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3958e5b75505Sopenharmony_ci 3959e5b75505Sopenharmony_ci return dpp_auth_build_conf(auth, DPP_STATUS_OK); 3960e5b75505Sopenharmony_ci 3961e5b75505Sopenharmony_cifail: 3962e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 3963e5b75505Sopenharmony_ci bin_clear_free(unwrapped2, unwrapped2_len); 3964e5b75505Sopenharmony_ci EVP_PKEY_free(pr); 3965e5b75505Sopenharmony_ci return NULL; 3966e5b75505Sopenharmony_ci} 3967e5b75505Sopenharmony_ci 3968e5b75505Sopenharmony_ci 3969e5b75505Sopenharmony_cistatic int dpp_auth_conf_rx_failure(struct dpp_authentication *auth, 3970e5b75505Sopenharmony_ci const u8 *hdr, 3971e5b75505Sopenharmony_ci const u8 *attr_start, size_t attr_len, 3972e5b75505Sopenharmony_ci const u8 *wrapped_data, 3973e5b75505Sopenharmony_ci u16 wrapped_data_len, 3974e5b75505Sopenharmony_ci enum dpp_status_error status) 3975e5b75505Sopenharmony_ci{ 3976e5b75505Sopenharmony_ci const u8 *addr[2]; 3977e5b75505Sopenharmony_ci size_t len[2]; 3978e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 3979e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 3980e5b75505Sopenharmony_ci const u8 *r_nonce; 3981e5b75505Sopenharmony_ci u16 r_nonce_len; 3982e5b75505Sopenharmony_ci 3983e5b75505Sopenharmony_ci /* Authentication Confirm failure cases are expected to include 3984e5b75505Sopenharmony_ci * {R-nonce}k2 in the Wrapped Data attribute. */ 3985e5b75505Sopenharmony_ci 3986e5b75505Sopenharmony_ci addr[0] = hdr; 3987e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 3988e5b75505Sopenharmony_ci addr[1] = attr_start; 3989e5b75505Sopenharmony_ci len[1] = attr_len; 3990e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 3991e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 3992e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3993e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 3994e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3995e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 3996e5b75505Sopenharmony_ci if (!unwrapped) { 3997e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Authentication failed"); 3998e5b75505Sopenharmony_ci goto fail; 3999e5b75505Sopenharmony_ci } 4000e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->k2, auth->curve->hash_len, 4001e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 4002e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 4003e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 4004e5b75505Sopenharmony_ci goto fail; 4005e5b75505Sopenharmony_ci } 4006e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 4007e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 4008e5b75505Sopenharmony_ci 4009e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 4010e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 4011e5b75505Sopenharmony_ci goto fail; 4012e5b75505Sopenharmony_ci } 4013e5b75505Sopenharmony_ci 4014e5b75505Sopenharmony_ci r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE, 4015e5b75505Sopenharmony_ci &r_nonce_len); 4016e5b75505Sopenharmony_ci if (!r_nonce || r_nonce_len != auth->curve->nonce_len) { 4017e5b75505Sopenharmony_ci dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce"); 4018e5b75505Sopenharmony_ci goto fail; 4019e5b75505Sopenharmony_ci } 4020e5b75505Sopenharmony_ci if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) { 4021e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce", 4022e5b75505Sopenharmony_ci r_nonce, r_nonce_len); 4023e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce", 4024e5b75505Sopenharmony_ci auth->r_nonce, r_nonce_len); 4025e5b75505Sopenharmony_ci dpp_auth_fail(auth, "R-nonce mismatch"); 4026e5b75505Sopenharmony_ci goto fail; 4027e5b75505Sopenharmony_ci } 4028e5b75505Sopenharmony_ci 4029e5b75505Sopenharmony_ci if (status == DPP_STATUS_NOT_COMPATIBLE) 4030e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Peer reported incompatible R-capab role"); 4031e5b75505Sopenharmony_ci else if (status == DPP_STATUS_AUTH_FAILURE) 4032e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Peer reported authentication failure)"); 4033e5b75505Sopenharmony_ci 4034e5b75505Sopenharmony_cifail: 4035e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 4036e5b75505Sopenharmony_ci return -1; 4037e5b75505Sopenharmony_ci} 4038e5b75505Sopenharmony_ci 4039e5b75505Sopenharmony_ci 4040e5b75505Sopenharmony_ciint dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, 4041e5b75505Sopenharmony_ci const u8 *attr_start, size_t attr_len) 4042e5b75505Sopenharmony_ci{ 4043e5b75505Sopenharmony_ci const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth; 4044e5b75505Sopenharmony_ci u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len, 4045e5b75505Sopenharmony_ci i_auth_len; 4046e5b75505Sopenharmony_ci const u8 *addr[2]; 4047e5b75505Sopenharmony_ci size_t len[2]; 4048e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 4049e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 4050e5b75505Sopenharmony_ci u8 i_auth2[DPP_MAX_HASH_LEN]; 4051e5b75505Sopenharmony_ci 4052e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4053e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { 4054e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 4055e5b75505Sopenharmony_ci "DPP: TESTING - stop at Authentication Confirm"); 4056e5b75505Sopenharmony_ci return -1; 4057e5b75505Sopenharmony_ci } 4058e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4059e5b75505Sopenharmony_ci 4060e5b75505Sopenharmony_ci if (auth->initiator || !auth->own_bi) { 4061e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unexpected Authentication Confirm"); 4062e5b75505Sopenharmony_ci return -1; 4063e5b75505Sopenharmony_ci } 4064e5b75505Sopenharmony_ci 4065e5b75505Sopenharmony_ci auth->waiting_auth_conf = 0; 4066e5b75505Sopenharmony_ci 4067e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 4068e5b75505Sopenharmony_ci &wrapped_data_len); 4069e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 4070e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4071e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 4072e5b75505Sopenharmony_ci return -1; 4073e5b75505Sopenharmony_ci } 4074e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 4075e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 4076e5b75505Sopenharmony_ci 4077e5b75505Sopenharmony_ci attr_len = wrapped_data - 4 - attr_start; 4078e5b75505Sopenharmony_ci 4079e5b75505Sopenharmony_ci r_bootstrap = dpp_get_attr(attr_start, attr_len, 4080e5b75505Sopenharmony_ci DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 4081e5b75505Sopenharmony_ci &r_bootstrap_len); 4082e5b75505Sopenharmony_ci if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 4083e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4084e5b75505Sopenharmony_ci "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 4085e5b75505Sopenharmony_ci return -1; 4086e5b75505Sopenharmony_ci } 4087e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash", 4088e5b75505Sopenharmony_ci r_bootstrap, r_bootstrap_len); 4089e5b75505Sopenharmony_ci if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash, 4090e5b75505Sopenharmony_ci SHA256_MAC_LEN) != 0) { 4091e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, 4092e5b75505Sopenharmony_ci "DPP: Expected Responder Bootstrapping Key Hash", 4093e5b75505Sopenharmony_ci auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 4094e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4095e5b75505Sopenharmony_ci "Responder Bootstrapping Key Hash mismatch"); 4096e5b75505Sopenharmony_ci return -1; 4097e5b75505Sopenharmony_ci } 4098e5b75505Sopenharmony_ci 4099e5b75505Sopenharmony_ci i_bootstrap = dpp_get_attr(attr_start, attr_len, 4100e5b75505Sopenharmony_ci DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 4101e5b75505Sopenharmony_ci &i_bootstrap_len); 4102e5b75505Sopenharmony_ci if (i_bootstrap) { 4103e5b75505Sopenharmony_ci if (i_bootstrap_len != SHA256_MAC_LEN) { 4104e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4105e5b75505Sopenharmony_ci "Invalid Initiator Bootstrapping Key Hash attribute"); 4106e5b75505Sopenharmony_ci return -1; 4107e5b75505Sopenharmony_ci } 4108e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, 4109e5b75505Sopenharmony_ci "DPP: Initiator Bootstrapping Key Hash", 4110e5b75505Sopenharmony_ci i_bootstrap, i_bootstrap_len); 4111e5b75505Sopenharmony_ci if (!auth->peer_bi || 4112e5b75505Sopenharmony_ci os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash, 4113e5b75505Sopenharmony_ci SHA256_MAC_LEN) != 0) { 4114e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4115e5b75505Sopenharmony_ci "Initiator Bootstrapping Key Hash mismatch"); 4116e5b75505Sopenharmony_ci return -1; 4117e5b75505Sopenharmony_ci } 4118e5b75505Sopenharmony_ci } else if (auth->peer_bi) { 4119e5b75505Sopenharmony_ci /* Mutual authentication and peer did not include its 4120e5b75505Sopenharmony_ci * Bootstrapping Key Hash attribute. */ 4121e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4122e5b75505Sopenharmony_ci "Missing Initiator Bootstrapping Key Hash attribute"); 4123e5b75505Sopenharmony_ci return -1; 4124e5b75505Sopenharmony_ci } 4125e5b75505Sopenharmony_ci 4126e5b75505Sopenharmony_ci status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 4127e5b75505Sopenharmony_ci &status_len); 4128e5b75505Sopenharmony_ci if (!status || status_len < 1) { 4129e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4130e5b75505Sopenharmony_ci "Missing or invalid required DPP Status attribute"); 4131e5b75505Sopenharmony_ci return -1; 4132e5b75505Sopenharmony_ci } 4133e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 4134e5b75505Sopenharmony_ci if (status[0] == DPP_STATUS_NOT_COMPATIBLE || 4135e5b75505Sopenharmony_ci status[0] == DPP_STATUS_AUTH_FAILURE) 4136e5b75505Sopenharmony_ci return dpp_auth_conf_rx_failure(auth, hdr, attr_start, 4137e5b75505Sopenharmony_ci attr_len, wrapped_data, 4138e5b75505Sopenharmony_ci wrapped_data_len, status[0]); 4139e5b75505Sopenharmony_ci 4140e5b75505Sopenharmony_ci if (status[0] != DPP_STATUS_OK) { 4141e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Authentication failed"); 4142e5b75505Sopenharmony_ci return -1; 4143e5b75505Sopenharmony_ci } 4144e5b75505Sopenharmony_ci 4145e5b75505Sopenharmony_ci addr[0] = hdr; 4146e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 4147e5b75505Sopenharmony_ci addr[1] = attr_start; 4148e5b75505Sopenharmony_ci len[1] = attr_len; 4149e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 4150e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 4151e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 4152e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 4153e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 4154e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 4155e5b75505Sopenharmony_ci if (!unwrapped) 4156e5b75505Sopenharmony_ci return -1; 4157e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 4158e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 4159e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 4160e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 4161e5b75505Sopenharmony_ci goto fail; 4162e5b75505Sopenharmony_ci } 4163e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 4164e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 4165e5b75505Sopenharmony_ci 4166e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 4167e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 4168e5b75505Sopenharmony_ci goto fail; 4169e5b75505Sopenharmony_ci } 4170e5b75505Sopenharmony_ci 4171e5b75505Sopenharmony_ci i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 4172e5b75505Sopenharmony_ci &i_auth_len); 4173e5b75505Sopenharmony_ci if (!i_auth || i_auth_len != auth->curve->hash_len) { 4174e5b75505Sopenharmony_ci dpp_auth_fail(auth, 4175e5b75505Sopenharmony_ci "Missing or invalid Initiator Authenticating Tag"); 4176e5b75505Sopenharmony_ci goto fail; 4177e5b75505Sopenharmony_ci } 4178e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag", 4179e5b75505Sopenharmony_ci i_auth, i_auth_len); 4180e5b75505Sopenharmony_ci /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ 4181e5b75505Sopenharmony_ci if (dpp_gen_i_auth(auth, i_auth2) < 0) 4182e5b75505Sopenharmony_ci goto fail; 4183e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag", 4184e5b75505Sopenharmony_ci i_auth2, i_auth_len); 4185e5b75505Sopenharmony_ci if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) { 4186e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag"); 4187e5b75505Sopenharmony_ci goto fail; 4188e5b75505Sopenharmony_ci } 4189e5b75505Sopenharmony_ci 4190e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 4191e5b75505Sopenharmony_ci dpp_auth_success(auth); 4192e5b75505Sopenharmony_ci return 0; 4193e5b75505Sopenharmony_cifail: 4194e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 4195e5b75505Sopenharmony_ci return -1; 4196e5b75505Sopenharmony_ci} 4197e5b75505Sopenharmony_ci 4198e5b75505Sopenharmony_ci 4199e5b75505Sopenharmony_cistatic int bin_str_eq(const char *val, size_t len, const char *cmp) 4200e5b75505Sopenharmony_ci{ 4201e5b75505Sopenharmony_ci return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0; 4202e5b75505Sopenharmony_ci} 4203e5b75505Sopenharmony_ci 4204e5b75505Sopenharmony_ci 4205e5b75505Sopenharmony_cistruct dpp_configuration * dpp_configuration_alloc(const char *type) 4206e5b75505Sopenharmony_ci{ 4207e5b75505Sopenharmony_ci struct dpp_configuration *conf; 4208e5b75505Sopenharmony_ci const char *end; 4209e5b75505Sopenharmony_ci size_t len; 4210e5b75505Sopenharmony_ci 4211e5b75505Sopenharmony_ci conf = os_zalloc(sizeof(*conf)); 4212e5b75505Sopenharmony_ci if (!conf) 4213e5b75505Sopenharmony_ci goto fail; 4214e5b75505Sopenharmony_ci 4215e5b75505Sopenharmony_ci end = os_strchr(type, ' '); 4216e5b75505Sopenharmony_ci if (end) 4217e5b75505Sopenharmony_ci len = end - type; 4218e5b75505Sopenharmony_ci else 4219e5b75505Sopenharmony_ci len = os_strlen(type); 4220e5b75505Sopenharmony_ci 4221e5b75505Sopenharmony_ci if (bin_str_eq(type, len, "psk")) 4222e5b75505Sopenharmony_ci conf->akm = DPP_AKM_PSK; 4223e5b75505Sopenharmony_ci else if (bin_str_eq(type, len, "sae")) 4224e5b75505Sopenharmony_ci conf->akm = DPP_AKM_SAE; 4225e5b75505Sopenharmony_ci else if (bin_str_eq(type, len, "psk-sae") || 4226e5b75505Sopenharmony_ci bin_str_eq(type, len, "psk+sae")) 4227e5b75505Sopenharmony_ci conf->akm = DPP_AKM_PSK_SAE; 4228e5b75505Sopenharmony_ci else if (bin_str_eq(type, len, "sae-dpp") || 4229e5b75505Sopenharmony_ci bin_str_eq(type, len, "dpp+sae")) 4230e5b75505Sopenharmony_ci conf->akm = DPP_AKM_SAE_DPP; 4231e5b75505Sopenharmony_ci else if (bin_str_eq(type, len, "psk-sae-dpp") || 4232e5b75505Sopenharmony_ci bin_str_eq(type, len, "dpp+psk+sae")) 4233e5b75505Sopenharmony_ci conf->akm = DPP_AKM_PSK_SAE_DPP; 4234e5b75505Sopenharmony_ci else if (bin_str_eq(type, len, "dpp")) 4235e5b75505Sopenharmony_ci conf->akm = DPP_AKM_DPP; 4236e5b75505Sopenharmony_ci else 4237e5b75505Sopenharmony_ci goto fail; 4238e5b75505Sopenharmony_ci 4239e5b75505Sopenharmony_ci return conf; 4240e5b75505Sopenharmony_cifail: 4241e5b75505Sopenharmony_ci dpp_configuration_free(conf); 4242e5b75505Sopenharmony_ci return NULL; 4243e5b75505Sopenharmony_ci} 4244e5b75505Sopenharmony_ci 4245e5b75505Sopenharmony_ci 4246e5b75505Sopenharmony_ciint dpp_akm_psk(enum dpp_akm akm) 4247e5b75505Sopenharmony_ci{ 4248e5b75505Sopenharmony_ci return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || 4249e5b75505Sopenharmony_ci akm == DPP_AKM_PSK_SAE_DPP; 4250e5b75505Sopenharmony_ci} 4251e5b75505Sopenharmony_ci 4252e5b75505Sopenharmony_ci 4253e5b75505Sopenharmony_ciint dpp_akm_sae(enum dpp_akm akm) 4254e5b75505Sopenharmony_ci{ 4255e5b75505Sopenharmony_ci return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE || 4256e5b75505Sopenharmony_ci akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; 4257e5b75505Sopenharmony_ci} 4258e5b75505Sopenharmony_ci 4259e5b75505Sopenharmony_ci 4260e5b75505Sopenharmony_ciint dpp_akm_legacy(enum dpp_akm akm) 4261e5b75505Sopenharmony_ci{ 4262e5b75505Sopenharmony_ci return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || 4263e5b75505Sopenharmony_ci akm == DPP_AKM_SAE; 4264e5b75505Sopenharmony_ci} 4265e5b75505Sopenharmony_ci 4266e5b75505Sopenharmony_ci 4267e5b75505Sopenharmony_ciint dpp_akm_dpp(enum dpp_akm akm) 4268e5b75505Sopenharmony_ci{ 4269e5b75505Sopenharmony_ci return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP || 4270e5b75505Sopenharmony_ci akm == DPP_AKM_PSK_SAE_DPP; 4271e5b75505Sopenharmony_ci} 4272e5b75505Sopenharmony_ci 4273e5b75505Sopenharmony_ci 4274e5b75505Sopenharmony_ciint dpp_akm_ver2(enum dpp_akm akm) 4275e5b75505Sopenharmony_ci{ 4276e5b75505Sopenharmony_ci return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; 4277e5b75505Sopenharmony_ci} 4278e5b75505Sopenharmony_ci 4279e5b75505Sopenharmony_ci 4280e5b75505Sopenharmony_ciint dpp_configuration_valid(const struct dpp_configuration *conf) 4281e5b75505Sopenharmony_ci{ 4282e5b75505Sopenharmony_ci if (conf->ssid_len == 0) 4283e5b75505Sopenharmony_ci return 0; 4284e5b75505Sopenharmony_ci if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set) 4285e5b75505Sopenharmony_ci return 0; 4286e5b75505Sopenharmony_ci if (dpp_akm_sae(conf->akm) && !conf->passphrase) 4287e5b75505Sopenharmony_ci return 0; 4288e5b75505Sopenharmony_ci return 1; 4289e5b75505Sopenharmony_ci} 4290e5b75505Sopenharmony_ci 4291e5b75505Sopenharmony_ci 4292e5b75505Sopenharmony_civoid dpp_configuration_free(struct dpp_configuration *conf) 4293e5b75505Sopenharmony_ci{ 4294e5b75505Sopenharmony_ci if (!conf) 4295e5b75505Sopenharmony_ci return; 4296e5b75505Sopenharmony_ci str_clear_free(conf->passphrase); 4297e5b75505Sopenharmony_ci os_free(conf->group_id); 4298e5b75505Sopenharmony_ci bin_clear_free(conf, sizeof(*conf)); 4299e5b75505Sopenharmony_ci} 4300e5b75505Sopenharmony_ci 4301e5b75505Sopenharmony_ci 4302e5b75505Sopenharmony_cistatic int dpp_configuration_parse(struct dpp_authentication *auth, 4303e5b75505Sopenharmony_ci const char *cmd) 4304e5b75505Sopenharmony_ci{ 4305e5b75505Sopenharmony_ci const char *pos, *end; 4306e5b75505Sopenharmony_ci struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL; 4307e5b75505Sopenharmony_ci struct dpp_configuration *conf = NULL; 4308e5b75505Sopenharmony_ci 4309e5b75505Sopenharmony_ci pos = os_strstr(cmd, " conf=sta-"); 4310e5b75505Sopenharmony_ci if (pos) { 4311e5b75505Sopenharmony_ci conf_sta = dpp_configuration_alloc(pos + 10); 4312e5b75505Sopenharmony_ci if (!conf_sta) 4313e5b75505Sopenharmony_ci goto fail; 4314e5b75505Sopenharmony_ci conf = conf_sta; 4315e5b75505Sopenharmony_ci } 4316e5b75505Sopenharmony_ci 4317e5b75505Sopenharmony_ci pos = os_strstr(cmd, " conf=ap-"); 4318e5b75505Sopenharmony_ci if (pos) { 4319e5b75505Sopenharmony_ci conf_ap = dpp_configuration_alloc(pos + 9); 4320e5b75505Sopenharmony_ci if (!conf_ap) 4321e5b75505Sopenharmony_ci goto fail; 4322e5b75505Sopenharmony_ci conf = conf_ap; 4323e5b75505Sopenharmony_ci } 4324e5b75505Sopenharmony_ci 4325e5b75505Sopenharmony_ci if (!conf) 4326e5b75505Sopenharmony_ci return 0; 4327e5b75505Sopenharmony_ci 4328e5b75505Sopenharmony_ci pos = os_strstr(cmd, " ssid="); 4329e5b75505Sopenharmony_ci if (pos) { 4330e5b75505Sopenharmony_ci pos += 6; 4331e5b75505Sopenharmony_ci end = os_strchr(pos, ' '); 4332e5b75505Sopenharmony_ci conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos); 4333e5b75505Sopenharmony_ci conf->ssid_len /= 2; 4334e5b75505Sopenharmony_ci if (conf->ssid_len > sizeof(conf->ssid) || 4335e5b75505Sopenharmony_ci hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0) 4336e5b75505Sopenharmony_ci goto fail; 4337e5b75505Sopenharmony_ci } else { 4338e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4339e5b75505Sopenharmony_ci /* use a default SSID for legacy testing reasons */ 4340e5b75505Sopenharmony_ci os_memcpy(conf->ssid, "test", 4); 4341e5b75505Sopenharmony_ci conf->ssid_len = 4; 4342e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 4343e5b75505Sopenharmony_ci goto fail; 4344e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4345e5b75505Sopenharmony_ci } 4346e5b75505Sopenharmony_ci 4347e5b75505Sopenharmony_ci pos = os_strstr(cmd, " pass="); 4348e5b75505Sopenharmony_ci if (pos) { 4349e5b75505Sopenharmony_ci size_t pass_len; 4350e5b75505Sopenharmony_ci 4351e5b75505Sopenharmony_ci pos += 6; 4352e5b75505Sopenharmony_ci end = os_strchr(pos, ' '); 4353e5b75505Sopenharmony_ci pass_len = end ? (size_t) (end - pos) : os_strlen(pos); 4354e5b75505Sopenharmony_ci pass_len /= 2; 4355e5b75505Sopenharmony_ci if (pass_len > 63 || pass_len < 8) 4356e5b75505Sopenharmony_ci goto fail; 4357e5b75505Sopenharmony_ci conf->passphrase = os_zalloc(pass_len + 1); 4358e5b75505Sopenharmony_ci if (!conf->passphrase || 4359e5b75505Sopenharmony_ci hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0) 4360e5b75505Sopenharmony_ci goto fail; 4361e5b75505Sopenharmony_ci } 4362e5b75505Sopenharmony_ci 4363e5b75505Sopenharmony_ci pos = os_strstr(cmd, " psk="); 4364e5b75505Sopenharmony_ci if (pos) { 4365e5b75505Sopenharmony_ci pos += 5; 4366e5b75505Sopenharmony_ci if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0) 4367e5b75505Sopenharmony_ci goto fail; 4368e5b75505Sopenharmony_ci conf->psk_set = 1; 4369e5b75505Sopenharmony_ci } 4370e5b75505Sopenharmony_ci 4371e5b75505Sopenharmony_ci pos = os_strstr(cmd, " group_id="); 4372e5b75505Sopenharmony_ci if (pos) { 4373e5b75505Sopenharmony_ci size_t group_id_len; 4374e5b75505Sopenharmony_ci 4375e5b75505Sopenharmony_ci pos += 10; 4376e5b75505Sopenharmony_ci end = os_strchr(pos, ' '); 4377e5b75505Sopenharmony_ci group_id_len = end ? (size_t) (end - pos) : os_strlen(pos); 4378e5b75505Sopenharmony_ci conf->group_id = os_malloc(group_id_len + 1); 4379e5b75505Sopenharmony_ci if (!conf->group_id) 4380e5b75505Sopenharmony_ci goto fail; 4381e5b75505Sopenharmony_ci os_memcpy(conf->group_id, pos, group_id_len); 4382e5b75505Sopenharmony_ci conf->group_id[group_id_len] = '\0'; 4383e5b75505Sopenharmony_ci } 4384e5b75505Sopenharmony_ci 4385e5b75505Sopenharmony_ci pos = os_strstr(cmd, " expiry="); 4386e5b75505Sopenharmony_ci if (pos) { 4387e5b75505Sopenharmony_ci long int val; 4388e5b75505Sopenharmony_ci 4389e5b75505Sopenharmony_ci pos += 8; 4390e5b75505Sopenharmony_ci val = strtol(pos, NULL, 0); 4391e5b75505Sopenharmony_ci if (val <= 0) 4392e5b75505Sopenharmony_ci goto fail; 4393e5b75505Sopenharmony_ci conf->netaccesskey_expiry = val; 4394e5b75505Sopenharmony_ci } 4395e5b75505Sopenharmony_ci 4396e5b75505Sopenharmony_ci if (!dpp_configuration_valid(conf)) 4397e5b75505Sopenharmony_ci goto fail; 4398e5b75505Sopenharmony_ci 4399e5b75505Sopenharmony_ci auth->conf_sta = conf_sta; 4400e5b75505Sopenharmony_ci auth->conf_ap = conf_ap; 4401e5b75505Sopenharmony_ci return 0; 4402e5b75505Sopenharmony_ci 4403e5b75505Sopenharmony_cifail: 4404e5b75505Sopenharmony_ci dpp_configuration_free(conf_sta); 4405e5b75505Sopenharmony_ci dpp_configuration_free(conf_ap); 4406e5b75505Sopenharmony_ci return -1; 4407e5b75505Sopenharmony_ci} 4408e5b75505Sopenharmony_ci 4409e5b75505Sopenharmony_ci 4410e5b75505Sopenharmony_cistatic struct dpp_configurator * 4411e5b75505Sopenharmony_cidpp_configurator_get_id(struct dpp_global *dpp, unsigned int id) 4412e5b75505Sopenharmony_ci{ 4413e5b75505Sopenharmony_ci struct dpp_configurator *conf; 4414e5b75505Sopenharmony_ci 4415e5b75505Sopenharmony_ci if (!dpp) 4416e5b75505Sopenharmony_ci return NULL; 4417e5b75505Sopenharmony_ci 4418e5b75505Sopenharmony_ci dl_list_for_each(conf, &dpp->configurator, 4419e5b75505Sopenharmony_ci struct dpp_configurator, list) { 4420e5b75505Sopenharmony_ci if (conf->id == id) 4421e5b75505Sopenharmony_ci return conf; 4422e5b75505Sopenharmony_ci } 4423e5b75505Sopenharmony_ci return NULL; 4424e5b75505Sopenharmony_ci} 4425e5b75505Sopenharmony_ci 4426e5b75505Sopenharmony_ci 4427e5b75505Sopenharmony_ciint dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, 4428e5b75505Sopenharmony_ci struct dpp_authentication *auth, 4429e5b75505Sopenharmony_ci const char *cmd) 4430e5b75505Sopenharmony_ci{ 4431e5b75505Sopenharmony_ci const char *pos; 4432e5b75505Sopenharmony_ci 4433e5b75505Sopenharmony_ci if (!cmd) 4434e5b75505Sopenharmony_ci return 0; 4435e5b75505Sopenharmony_ci 4436e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); 4437e5b75505Sopenharmony_ci 4438e5b75505Sopenharmony_ci pos = os_strstr(cmd, " configurator="); 4439e5b75505Sopenharmony_ci if (pos) { 4440e5b75505Sopenharmony_ci pos += 14; 4441e5b75505Sopenharmony_ci auth->conf = dpp_configurator_get_id(dpp, atoi(pos)); 4442e5b75505Sopenharmony_ci if (!auth->conf) { 4443e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 4444e5b75505Sopenharmony_ci "DPP: Could not find the specified configurator"); 4445e5b75505Sopenharmony_ci return -1; 4446e5b75505Sopenharmony_ci } 4447e5b75505Sopenharmony_ci } 4448e5b75505Sopenharmony_ci 4449e5b75505Sopenharmony_ci if (dpp_configuration_parse(auth, cmd) < 0) { 4450e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, 4451e5b75505Sopenharmony_ci "DPP: Failed to set configurator parameters"); 4452e5b75505Sopenharmony_ci return -1; 4453e5b75505Sopenharmony_ci } 4454e5b75505Sopenharmony_ci return 0; 4455e5b75505Sopenharmony_ci} 4456e5b75505Sopenharmony_ci 4457e5b75505Sopenharmony_ci 4458e5b75505Sopenharmony_civoid dpp_auth_deinit(struct dpp_authentication *auth) 4459e5b75505Sopenharmony_ci{ 4460e5b75505Sopenharmony_ci if (!auth) 4461e5b75505Sopenharmony_ci return; 4462e5b75505Sopenharmony_ci dpp_configuration_free(auth->conf_ap); 4463e5b75505Sopenharmony_ci dpp_configuration_free(auth->conf_sta); 4464e5b75505Sopenharmony_ci EVP_PKEY_free(auth->own_protocol_key); 4465e5b75505Sopenharmony_ci EVP_PKEY_free(auth->peer_protocol_key); 4466e5b75505Sopenharmony_ci wpabuf_free(auth->req_msg); 4467e5b75505Sopenharmony_ci wpabuf_free(auth->resp_msg); 4468e5b75505Sopenharmony_ci wpabuf_free(auth->conf_req); 4469e5b75505Sopenharmony_ci os_free(auth->connector); 4470e5b75505Sopenharmony_ci wpabuf_free(auth->net_access_key); 4471e5b75505Sopenharmony_ci wpabuf_free(auth->c_sign_key); 4472e5b75505Sopenharmony_ci dpp_bootstrap_info_free(auth->tmp_own_bi); 4473e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4474e5b75505Sopenharmony_ci os_free(auth->config_obj_override); 4475e5b75505Sopenharmony_ci os_free(auth->discovery_override); 4476e5b75505Sopenharmony_ci os_free(auth->groups_override); 4477e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4478e5b75505Sopenharmony_ci bin_clear_free(auth, sizeof(*auth)); 4479e5b75505Sopenharmony_ci} 4480e5b75505Sopenharmony_ci 4481e5b75505Sopenharmony_ci 4482e5b75505Sopenharmony_cistatic struct wpabuf * 4483e5b75505Sopenharmony_cidpp_build_conf_start(struct dpp_authentication *auth, 4484e5b75505Sopenharmony_ci struct dpp_configuration *conf, size_t tailroom) 4485e5b75505Sopenharmony_ci{ 4486e5b75505Sopenharmony_ci struct wpabuf *buf; 4487e5b75505Sopenharmony_ci char ssid[6 * sizeof(conf->ssid) + 1]; 4488e5b75505Sopenharmony_ci 4489e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4490e5b75505Sopenharmony_ci if (auth->discovery_override) 4491e5b75505Sopenharmony_ci tailroom += os_strlen(auth->discovery_override); 4492e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4493e5b75505Sopenharmony_ci 4494e5b75505Sopenharmony_ci buf = wpabuf_alloc(200 + tailroom); 4495e5b75505Sopenharmony_ci if (!buf) 4496e5b75505Sopenharmony_ci return NULL; 4497e5b75505Sopenharmony_ci wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":"); 4498e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4499e5b75505Sopenharmony_ci if (auth->discovery_override) { 4500e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'", 4501e5b75505Sopenharmony_ci auth->discovery_override); 4502e5b75505Sopenharmony_ci wpabuf_put_str(buf, auth->discovery_override); 4503e5b75505Sopenharmony_ci wpabuf_put_u8(buf, ','); 4504e5b75505Sopenharmony_ci return buf; 4505e5b75505Sopenharmony_ci } 4506e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4507e5b75505Sopenharmony_ci wpabuf_put_str(buf, "{\"ssid\":\""); 4508e5b75505Sopenharmony_ci json_escape_string(ssid, sizeof(ssid), 4509e5b75505Sopenharmony_ci (const char *) conf->ssid, conf->ssid_len); 4510e5b75505Sopenharmony_ci wpabuf_put_str(buf, ssid); 4511e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\"},"); 4512e5b75505Sopenharmony_ci 4513e5b75505Sopenharmony_ci return buf; 4514e5b75505Sopenharmony_ci} 4515e5b75505Sopenharmony_ci 4516e5b75505Sopenharmony_ci 4517e5b75505Sopenharmony_cistatic int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, 4518e5b75505Sopenharmony_ci const char *kid, const struct dpp_curve_params *curve) 4519e5b75505Sopenharmony_ci{ 4520e5b75505Sopenharmony_ci struct wpabuf *pub; 4521e5b75505Sopenharmony_ci const u8 *pos; 4522e5b75505Sopenharmony_ci char *x = NULL, *y = NULL; 4523e5b75505Sopenharmony_ci int ret = -1; 4524e5b75505Sopenharmony_ci 4525e5b75505Sopenharmony_ci pub = dpp_get_pubkey_point(key, 0); 4526e5b75505Sopenharmony_ci if (!pub) 4527e5b75505Sopenharmony_ci goto fail; 4528e5b75505Sopenharmony_ci pos = wpabuf_head(pub); 4529e5b75505Sopenharmony_ci x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0); 4530e5b75505Sopenharmony_ci pos += curve->prime_len; 4531e5b75505Sopenharmony_ci y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0); 4532e5b75505Sopenharmony_ci if (!x || !y) 4533e5b75505Sopenharmony_ci goto fail; 4534e5b75505Sopenharmony_ci 4535e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\""); 4536e5b75505Sopenharmony_ci wpabuf_put_str(buf, name); 4537e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\""); 4538e5b75505Sopenharmony_ci wpabuf_put_str(buf, curve->jwk_crv); 4539e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\",\"x\":\""); 4540e5b75505Sopenharmony_ci wpabuf_put_str(buf, x); 4541e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\",\"y\":\""); 4542e5b75505Sopenharmony_ci wpabuf_put_str(buf, y); 4543e5b75505Sopenharmony_ci if (kid) { 4544e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\",\"kid\":\""); 4545e5b75505Sopenharmony_ci wpabuf_put_str(buf, kid); 4546e5b75505Sopenharmony_ci } 4547e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\"}"); 4548e5b75505Sopenharmony_ci ret = 0; 4549e5b75505Sopenharmony_cifail: 4550e5b75505Sopenharmony_ci wpabuf_free(pub); 4551e5b75505Sopenharmony_ci os_free(x); 4552e5b75505Sopenharmony_ci os_free(y); 4553e5b75505Sopenharmony_ci return ret; 4554e5b75505Sopenharmony_ci} 4555e5b75505Sopenharmony_ci 4556e5b75505Sopenharmony_ci 4557e5b75505Sopenharmony_cistatic void dpp_build_legacy_cred_params(struct wpabuf *buf, 4558e5b75505Sopenharmony_ci struct dpp_configuration *conf) 4559e5b75505Sopenharmony_ci{ 4560e5b75505Sopenharmony_ci if (conf->passphrase && os_strlen(conf->passphrase) < 64) { 4561e5b75505Sopenharmony_ci char pass[63 * 6 + 1]; 4562e5b75505Sopenharmony_ci 4563e5b75505Sopenharmony_ci json_escape_string(pass, sizeof(pass), conf->passphrase, 4564e5b75505Sopenharmony_ci os_strlen(conf->passphrase)); 4565e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\"pass\":\""); 4566e5b75505Sopenharmony_ci wpabuf_put_str(buf, pass); 4567e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\""); 4568e5b75505Sopenharmony_ci os_memset(pass, 0, sizeof(pass)); 4569e5b75505Sopenharmony_ci } else if (conf->psk_set) { 4570e5b75505Sopenharmony_ci char psk[2 * sizeof(conf->psk) + 1]; 4571e5b75505Sopenharmony_ci 4572e5b75505Sopenharmony_ci wpa_snprintf_hex(psk, sizeof(psk), 4573e5b75505Sopenharmony_ci conf->psk, sizeof(conf->psk)); 4574e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\"psk_hex\":\""); 4575e5b75505Sopenharmony_ci wpabuf_put_str(buf, psk); 4576e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\""); 4577e5b75505Sopenharmony_ci os_memset(psk, 0, sizeof(psk)); 4578e5b75505Sopenharmony_ci } 4579e5b75505Sopenharmony_ci} 4580e5b75505Sopenharmony_ci 4581e5b75505Sopenharmony_ci 4582e5b75505Sopenharmony_cistatic struct wpabuf * 4583e5b75505Sopenharmony_cidpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap, 4584e5b75505Sopenharmony_ci struct dpp_configuration *conf) 4585e5b75505Sopenharmony_ci{ 4586e5b75505Sopenharmony_ci struct wpabuf *buf = NULL; 4587e5b75505Sopenharmony_ci char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL; 4588e5b75505Sopenharmony_ci size_t tailroom; 4589e5b75505Sopenharmony_ci const struct dpp_curve_params *curve; 4590e5b75505Sopenharmony_ci char jws_prot_hdr[100]; 4591e5b75505Sopenharmony_ci size_t signed1_len, signed2_len, signed3_len; 4592e5b75505Sopenharmony_ci struct wpabuf *dppcon = NULL; 4593e5b75505Sopenharmony_ci unsigned char *signature = NULL; 4594e5b75505Sopenharmony_ci const unsigned char *p; 4595e5b75505Sopenharmony_ci size_t signature_len; 4596e5b75505Sopenharmony_ci EVP_MD_CTX *md_ctx = NULL; 4597e5b75505Sopenharmony_ci ECDSA_SIG *sig = NULL; 4598e5b75505Sopenharmony_ci char *dot = "."; 4599e5b75505Sopenharmony_ci const EVP_MD *sign_md; 4600e5b75505Sopenharmony_ci const BIGNUM *r, *s; 4601e5b75505Sopenharmony_ci size_t extra_len = 1000; 4602e5b75505Sopenharmony_ci int incl_legacy; 4603e5b75505Sopenharmony_ci enum dpp_akm akm; 4604e5b75505Sopenharmony_ci 4605e5b75505Sopenharmony_ci if (!auth->conf) { 4606e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 4607e5b75505Sopenharmony_ci "DPP: No configurator specified - cannot generate DPP config object"); 4608e5b75505Sopenharmony_ci goto fail; 4609e5b75505Sopenharmony_ci } 4610e5b75505Sopenharmony_ci curve = auth->conf->curve; 4611e5b75505Sopenharmony_ci if (curve->hash_len == SHA256_MAC_LEN) { 4612e5b75505Sopenharmony_ci sign_md = EVP_sha256(); 4613e5b75505Sopenharmony_ci } else if (curve->hash_len == SHA384_MAC_LEN) { 4614e5b75505Sopenharmony_ci sign_md = EVP_sha384(); 4615e5b75505Sopenharmony_ci } else if (curve->hash_len == SHA512_MAC_LEN) { 4616e5b75505Sopenharmony_ci sign_md = EVP_sha512(); 4617e5b75505Sopenharmony_ci } else { 4618e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm"); 4619e5b75505Sopenharmony_ci goto fail; 4620e5b75505Sopenharmony_ci } 4621e5b75505Sopenharmony_ci 4622e5b75505Sopenharmony_ci akm = conf->akm; 4623e5b75505Sopenharmony_ci if (dpp_akm_ver2(akm) && auth->peer_version < 2) { 4624e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4625e5b75505Sopenharmony_ci "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2"); 4626e5b75505Sopenharmony_ci akm = DPP_AKM_DPP; 4627e5b75505Sopenharmony_ci } 4628e5b75505Sopenharmony_ci 4629e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4630e5b75505Sopenharmony_ci if (auth->groups_override) 4631e5b75505Sopenharmony_ci extra_len += os_strlen(auth->groups_override); 4632e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4633e5b75505Sopenharmony_ci 4634e5b75505Sopenharmony_ci if (conf->group_id) 4635e5b75505Sopenharmony_ci extra_len += os_strlen(conf->group_id); 4636e5b75505Sopenharmony_ci 4637e5b75505Sopenharmony_ci /* Connector (JSON dppCon object) */ 4638e5b75505Sopenharmony_ci dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); 4639e5b75505Sopenharmony_ci if (!dppcon) 4640e5b75505Sopenharmony_ci goto fail; 4641e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4642e5b75505Sopenharmony_ci if (auth->groups_override) { 4643e5b75505Sopenharmony_ci wpabuf_put_u8(dppcon, '{'); 4644e5b75505Sopenharmony_ci if (auth->groups_override) { 4645e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4646e5b75505Sopenharmony_ci "DPP: TESTING - groups override: '%s'", 4647e5b75505Sopenharmony_ci auth->groups_override); 4648e5b75505Sopenharmony_ci wpabuf_put_str(dppcon, "\"groups\":"); 4649e5b75505Sopenharmony_ci wpabuf_put_str(dppcon, auth->groups_override); 4650e5b75505Sopenharmony_ci wpabuf_put_u8(dppcon, ','); 4651e5b75505Sopenharmony_ci } 4652e5b75505Sopenharmony_ci goto skip_groups; 4653e5b75505Sopenharmony_ci } 4654e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4655e5b75505Sopenharmony_ci wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",", 4656e5b75505Sopenharmony_ci conf->group_id ? conf->group_id : "*"); 4657e5b75505Sopenharmony_ci wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta"); 4658e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4659e5b75505Sopenharmony_ciskip_groups: 4660e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4661e5b75505Sopenharmony_ci if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, 4662e5b75505Sopenharmony_ci auth->curve) < 0) { 4663e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); 4664e5b75505Sopenharmony_ci goto fail; 4665e5b75505Sopenharmony_ci } 4666e5b75505Sopenharmony_ci if (conf->netaccesskey_expiry) { 4667e5b75505Sopenharmony_ci struct os_tm tm; 4668e5b75505Sopenharmony_ci 4669e5b75505Sopenharmony_ci if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) { 4670e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4671e5b75505Sopenharmony_ci "DPP: Failed to generate expiry string"); 4672e5b75505Sopenharmony_ci goto fail; 4673e5b75505Sopenharmony_ci } 4674e5b75505Sopenharmony_ci wpabuf_printf(dppcon, 4675e5b75505Sopenharmony_ci ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"", 4676e5b75505Sopenharmony_ci tm.year, tm.month, tm.day, 4677e5b75505Sopenharmony_ci tm.hour, tm.min, tm.sec); 4678e5b75505Sopenharmony_ci } 4679e5b75505Sopenharmony_ci wpabuf_put_u8(dppcon, '}'); 4680e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", 4681e5b75505Sopenharmony_ci (const char *) wpabuf_head(dppcon)); 4682e5b75505Sopenharmony_ci 4683e5b75505Sopenharmony_ci os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr), 4684e5b75505Sopenharmony_ci "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}", 4685e5b75505Sopenharmony_ci auth->conf->kid, curve->jws_alg); 4686e5b75505Sopenharmony_ci signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr, 4687e5b75505Sopenharmony_ci os_strlen(jws_prot_hdr), 4688e5b75505Sopenharmony_ci &signed1_len, 0); 4689e5b75505Sopenharmony_ci signed2 = (char *) base64_url_encode(wpabuf_head(dppcon), 4690e5b75505Sopenharmony_ci wpabuf_len(dppcon), 4691e5b75505Sopenharmony_ci &signed2_len, 0); 4692e5b75505Sopenharmony_ci if (!signed1 || !signed2) 4693e5b75505Sopenharmony_ci goto fail; 4694e5b75505Sopenharmony_ci 4695e5b75505Sopenharmony_ci md_ctx = EVP_MD_CTX_create(); 4696e5b75505Sopenharmony_ci if (!md_ctx) 4697e5b75505Sopenharmony_ci goto fail; 4698e5b75505Sopenharmony_ci 4699e5b75505Sopenharmony_ci ERR_clear_error(); 4700e5b75505Sopenharmony_ci if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, 4701e5b75505Sopenharmony_ci auth->conf->csign) != 1) { 4702e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s", 4703e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 4704e5b75505Sopenharmony_ci goto fail; 4705e5b75505Sopenharmony_ci } 4706e5b75505Sopenharmony_ci if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 || 4707e5b75505Sopenharmony_ci EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 || 4708e5b75505Sopenharmony_ci EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) { 4709e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s", 4710e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 4711e5b75505Sopenharmony_ci goto fail; 4712e5b75505Sopenharmony_ci } 4713e5b75505Sopenharmony_ci if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) { 4714e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", 4715e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 4716e5b75505Sopenharmony_ci goto fail; 4717e5b75505Sopenharmony_ci } 4718e5b75505Sopenharmony_ci signature = os_malloc(signature_len); 4719e5b75505Sopenharmony_ci if (!signature) 4720e5b75505Sopenharmony_ci goto fail; 4721e5b75505Sopenharmony_ci if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) { 4722e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", 4723e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 4724e5b75505Sopenharmony_ci goto fail; 4725e5b75505Sopenharmony_ci } 4726e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)", 4727e5b75505Sopenharmony_ci signature, signature_len); 4728e5b75505Sopenharmony_ci /* Convert to raw coordinates r,s */ 4729e5b75505Sopenharmony_ci p = signature; 4730e5b75505Sopenharmony_ci sig = d2i_ECDSA_SIG(NULL, &p, signature_len); 4731e5b75505Sopenharmony_ci if (!sig) 4732e5b75505Sopenharmony_ci goto fail; 4733e5b75505Sopenharmony_ci ECDSA_SIG_get0(sig, &r, &s); 4734e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 || 4735e5b75505Sopenharmony_ci dpp_bn2bin_pad(s, signature + curve->prime_len, 4736e5b75505Sopenharmony_ci curve->prime_len) < 0) 4737e5b75505Sopenharmony_ci goto fail; 4738e5b75505Sopenharmony_ci signature_len = 2 * curve->prime_len; 4739e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)", 4740e5b75505Sopenharmony_ci signature, signature_len); 4741e5b75505Sopenharmony_ci signed3 = (char *) base64_url_encode(signature, signature_len, 4742e5b75505Sopenharmony_ci &signed3_len, 0); 4743e5b75505Sopenharmony_ci if (!signed3) 4744e5b75505Sopenharmony_ci goto fail; 4745e5b75505Sopenharmony_ci 4746e5b75505Sopenharmony_ci incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm); 4747e5b75505Sopenharmony_ci tailroom = 1000; 4748e5b75505Sopenharmony_ci tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid); 4749e5b75505Sopenharmony_ci tailroom += signed1_len + signed2_len + signed3_len; 4750e5b75505Sopenharmony_ci if (incl_legacy) 4751e5b75505Sopenharmony_ci tailroom += 1000; 4752e5b75505Sopenharmony_ci buf = dpp_build_conf_start(auth, conf, tailroom); 4753e5b75505Sopenharmony_ci if (!buf) 4754e5b75505Sopenharmony_ci goto fail; 4755e5b75505Sopenharmony_ci 4756e5b75505Sopenharmony_ci wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm)); 4757e5b75505Sopenharmony_ci if (incl_legacy) { 4758e5b75505Sopenharmony_ci dpp_build_legacy_cred_params(buf, conf); 4759e5b75505Sopenharmony_ci wpabuf_put_str(buf, ","); 4760e5b75505Sopenharmony_ci } 4761e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\"signedConnector\":\""); 4762e5b75505Sopenharmony_ci wpabuf_put_str(buf, signed1); 4763e5b75505Sopenharmony_ci wpabuf_put_u8(buf, '.'); 4764e5b75505Sopenharmony_ci wpabuf_put_str(buf, signed2); 4765e5b75505Sopenharmony_ci wpabuf_put_u8(buf, '.'); 4766e5b75505Sopenharmony_ci wpabuf_put_str(buf, signed3); 4767e5b75505Sopenharmony_ci wpabuf_put_str(buf, "\","); 4768e5b75505Sopenharmony_ci if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid, 4769e5b75505Sopenharmony_ci curve) < 0) { 4770e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK"); 4771e5b75505Sopenharmony_ci goto fail; 4772e5b75505Sopenharmony_ci } 4773e5b75505Sopenharmony_ci 4774e5b75505Sopenharmony_ci wpabuf_put_str(buf, "}}"); 4775e5b75505Sopenharmony_ci 4776e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object", 4777e5b75505Sopenharmony_ci wpabuf_head(buf), wpabuf_len(buf)); 4778e5b75505Sopenharmony_ci 4779e5b75505Sopenharmony_ciout: 4780e5b75505Sopenharmony_ci EVP_MD_CTX_destroy(md_ctx); 4781e5b75505Sopenharmony_ci ECDSA_SIG_free(sig); 4782e5b75505Sopenharmony_ci os_free(signed1); 4783e5b75505Sopenharmony_ci os_free(signed2); 4784e5b75505Sopenharmony_ci os_free(signed3); 4785e5b75505Sopenharmony_ci os_free(signature); 4786e5b75505Sopenharmony_ci wpabuf_free(dppcon); 4787e5b75505Sopenharmony_ci return buf; 4788e5b75505Sopenharmony_cifail: 4789e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object"); 4790e5b75505Sopenharmony_ci wpabuf_free(buf); 4791e5b75505Sopenharmony_ci buf = NULL; 4792e5b75505Sopenharmony_ci goto out; 4793e5b75505Sopenharmony_ci} 4794e5b75505Sopenharmony_ci 4795e5b75505Sopenharmony_ci 4796e5b75505Sopenharmony_cistatic struct wpabuf * 4797e5b75505Sopenharmony_cidpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap, 4798e5b75505Sopenharmony_ci struct dpp_configuration *conf) 4799e5b75505Sopenharmony_ci{ 4800e5b75505Sopenharmony_ci struct wpabuf *buf; 4801e5b75505Sopenharmony_ci 4802e5b75505Sopenharmony_ci buf = dpp_build_conf_start(auth, conf, 1000); 4803e5b75505Sopenharmony_ci if (!buf) 4804e5b75505Sopenharmony_ci return NULL; 4805e5b75505Sopenharmony_ci 4806e5b75505Sopenharmony_ci wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm)); 4807e5b75505Sopenharmony_ci dpp_build_legacy_cred_params(buf, conf); 4808e5b75505Sopenharmony_ci wpabuf_put_str(buf, "}}"); 4809e5b75505Sopenharmony_ci 4810e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)", 4811e5b75505Sopenharmony_ci wpabuf_head(buf), wpabuf_len(buf)); 4812e5b75505Sopenharmony_ci 4813e5b75505Sopenharmony_ci return buf; 4814e5b75505Sopenharmony_ci} 4815e5b75505Sopenharmony_ci 4816e5b75505Sopenharmony_ci 4817e5b75505Sopenharmony_cistatic struct wpabuf * 4818e5b75505Sopenharmony_cidpp_build_conf_obj(struct dpp_authentication *auth, int ap) 4819e5b75505Sopenharmony_ci{ 4820e5b75505Sopenharmony_ci struct dpp_configuration *conf; 4821e5b75505Sopenharmony_ci 4822e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4823e5b75505Sopenharmony_ci if (auth->config_obj_override) { 4824e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override"); 4825e5b75505Sopenharmony_ci return wpabuf_alloc_copy(auth->config_obj_override, 4826e5b75505Sopenharmony_ci os_strlen(auth->config_obj_override)); 4827e5b75505Sopenharmony_ci } 4828e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4829e5b75505Sopenharmony_ci 4830e5b75505Sopenharmony_ci conf = ap ? auth->conf_ap : auth->conf_sta; 4831e5b75505Sopenharmony_ci if (!conf) { 4832e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4833e5b75505Sopenharmony_ci "DPP: No configuration available for Enrollee(%s) - reject configuration request", 4834e5b75505Sopenharmony_ci ap ? "ap" : "sta"); 4835e5b75505Sopenharmony_ci return NULL; 4836e5b75505Sopenharmony_ci } 4837e5b75505Sopenharmony_ci 4838e5b75505Sopenharmony_ci if (dpp_akm_dpp(conf->akm)) 4839e5b75505Sopenharmony_ci return dpp_build_conf_obj_dpp(auth, ap, conf); 4840e5b75505Sopenharmony_ci return dpp_build_conf_obj_legacy(auth, ap, conf); 4841e5b75505Sopenharmony_ci} 4842e5b75505Sopenharmony_ci 4843e5b75505Sopenharmony_ci 4844e5b75505Sopenharmony_cistatic struct wpabuf * 4845e5b75505Sopenharmony_cidpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, 4846e5b75505Sopenharmony_ci u16 e_nonce_len, int ap) 4847e5b75505Sopenharmony_ci{ 4848e5b75505Sopenharmony_ci struct wpabuf *conf; 4849e5b75505Sopenharmony_ci size_t clear_len, attr_len; 4850e5b75505Sopenharmony_ci struct wpabuf *clear = NULL, *msg = NULL; 4851e5b75505Sopenharmony_ci u8 *wrapped; 4852e5b75505Sopenharmony_ci const u8 *addr[1]; 4853e5b75505Sopenharmony_ci size_t len[1]; 4854e5b75505Sopenharmony_ci enum dpp_status_error status; 4855e5b75505Sopenharmony_ci 4856e5b75505Sopenharmony_ci conf = dpp_build_conf_obj(auth, ap); 4857e5b75505Sopenharmony_ci if (conf) { 4858e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", 4859e5b75505Sopenharmony_ci wpabuf_head(conf), wpabuf_len(conf)); 4860e5b75505Sopenharmony_ci } 4861e5b75505Sopenharmony_ci status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE; 4862e5b75505Sopenharmony_ci auth->conf_resp_status = status; 4863e5b75505Sopenharmony_ci 4864e5b75505Sopenharmony_ci /* { E-nonce, configurationObject}ke */ 4865e5b75505Sopenharmony_ci clear_len = 4 + e_nonce_len; 4866e5b75505Sopenharmony_ci if (conf) 4867e5b75505Sopenharmony_ci clear_len += 4 + wpabuf_len(conf); 4868e5b75505Sopenharmony_ci clear = wpabuf_alloc(clear_len); 4869e5b75505Sopenharmony_ci attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; 4870e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4871e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) 4872e5b75505Sopenharmony_ci attr_len += 5; 4873e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4874e5b75505Sopenharmony_ci msg = wpabuf_alloc(attr_len); 4875e5b75505Sopenharmony_ci if (!clear || !msg) 4876e5b75505Sopenharmony_ci goto fail; 4877e5b75505Sopenharmony_ci 4878e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4879e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) { 4880e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce"); 4881e5b75505Sopenharmony_ci goto skip_e_nonce; 4882e5b75505Sopenharmony_ci } 4883e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) { 4884e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch"); 4885e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 4886e5b75505Sopenharmony_ci wpabuf_put_le16(clear, e_nonce_len); 4887e5b75505Sopenharmony_ci wpabuf_put_data(clear, e_nonce, e_nonce_len - 1); 4888e5b75505Sopenharmony_ci wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01); 4889e5b75505Sopenharmony_ci goto skip_e_nonce; 4890e5b75505Sopenharmony_ci } 4891e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) { 4892e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 4893e5b75505Sopenharmony_ci goto skip_wrapped_data; 4894e5b75505Sopenharmony_ci } 4895e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4896e5b75505Sopenharmony_ci 4897e5b75505Sopenharmony_ci /* E-nonce */ 4898e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 4899e5b75505Sopenharmony_ci wpabuf_put_le16(clear, e_nonce_len); 4900e5b75505Sopenharmony_ci wpabuf_put_data(clear, e_nonce, e_nonce_len); 4901e5b75505Sopenharmony_ci 4902e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4903e5b75505Sopenharmony_ciskip_e_nonce: 4904e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) { 4905e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - Config Object"); 4906e5b75505Sopenharmony_ci goto skip_config_obj; 4907e5b75505Sopenharmony_ci } 4908e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4909e5b75505Sopenharmony_ci 4910e5b75505Sopenharmony_ci if (conf) { 4911e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ); 4912e5b75505Sopenharmony_ci wpabuf_put_le16(clear, wpabuf_len(conf)); 4913e5b75505Sopenharmony_ci wpabuf_put_buf(clear, conf); 4914e5b75505Sopenharmony_ci } 4915e5b75505Sopenharmony_ci 4916e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4917e5b75505Sopenharmony_ciskip_config_obj: 4918e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { 4919e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - Status"); 4920e5b75505Sopenharmony_ci goto skip_status; 4921e5b75505Sopenharmony_ci } 4922e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) { 4923e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 4924e5b75505Sopenharmony_ci status = 255; 4925e5b75505Sopenharmony_ci } 4926e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4927e5b75505Sopenharmony_ci 4928e5b75505Sopenharmony_ci /* DPP Status */ 4929e5b75505Sopenharmony_ci dpp_build_attr_status(msg, status); 4930e5b75505Sopenharmony_ci 4931e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4932e5b75505Sopenharmony_ciskip_status: 4933e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4934e5b75505Sopenharmony_ci 4935e5b75505Sopenharmony_ci addr[0] = wpabuf_head(msg); 4936e5b75505Sopenharmony_ci len[0] = wpabuf_len(msg); 4937e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 4938e5b75505Sopenharmony_ci 4939e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 4940e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 4941e5b75505Sopenharmony_ci wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 4942e5b75505Sopenharmony_ci 4943e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 4944e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 4945e5b75505Sopenharmony_ci wpabuf_head(clear), wpabuf_len(clear), 4946e5b75505Sopenharmony_ci 1, addr, len, wrapped) < 0) 4947e5b75505Sopenharmony_ci goto fail; 4948e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 4949e5b75505Sopenharmony_ci wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 4950e5b75505Sopenharmony_ci 4951e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4952e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) { 4953e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 4954e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 4955e5b75505Sopenharmony_ci } 4956e5b75505Sopenharmony_ciskip_wrapped_data: 4957e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4958e5b75505Sopenharmony_ci 4959e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, 4960e5b75505Sopenharmony_ci "DPP: Configuration Response attributes", msg); 4961e5b75505Sopenharmony_ciout: 4962e5b75505Sopenharmony_ci wpabuf_free(conf); 4963e5b75505Sopenharmony_ci wpabuf_free(clear); 4964e5b75505Sopenharmony_ci 4965e5b75505Sopenharmony_ci return msg; 4966e5b75505Sopenharmony_cifail: 4967e5b75505Sopenharmony_ci wpabuf_free(msg); 4968e5b75505Sopenharmony_ci msg = NULL; 4969e5b75505Sopenharmony_ci goto out; 4970e5b75505Sopenharmony_ci} 4971e5b75505Sopenharmony_ci 4972e5b75505Sopenharmony_ci 4973e5b75505Sopenharmony_cistruct wpabuf * 4974e5b75505Sopenharmony_cidpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, 4975e5b75505Sopenharmony_ci size_t attr_len) 4976e5b75505Sopenharmony_ci{ 4977e5b75505Sopenharmony_ci const u8 *wrapped_data, *e_nonce, *config_attr; 4978e5b75505Sopenharmony_ci u16 wrapped_data_len, e_nonce_len, config_attr_len; 4979e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 4980e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 4981e5b75505Sopenharmony_ci struct wpabuf *resp = NULL; 4982e5b75505Sopenharmony_ci struct json_token *root = NULL, *token; 4983e5b75505Sopenharmony_ci int ap; 4984e5b75505Sopenharmony_ci 4985e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 4986e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { 4987e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 4988e5b75505Sopenharmony_ci "DPP: TESTING - stop at Config Request"); 4989e5b75505Sopenharmony_ci return NULL; 4990e5b75505Sopenharmony_ci } 4991e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 4992e5b75505Sopenharmony_ci 4993e5b75505Sopenharmony_ci if (dpp_check_attrs(attr_start, attr_len) < 0) { 4994e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in config request"); 4995e5b75505Sopenharmony_ci return NULL; 4996e5b75505Sopenharmony_ci } 4997e5b75505Sopenharmony_ci 4998e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 4999e5b75505Sopenharmony_ci &wrapped_data_len); 5000e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 5001e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5002e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 5003e5b75505Sopenharmony_ci return NULL; 5004e5b75505Sopenharmony_ci } 5005e5b75505Sopenharmony_ci 5006e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5007e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 5008e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 5009e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 5010e5b75505Sopenharmony_ci if (!unwrapped) 5011e5b75505Sopenharmony_ci return NULL; 5012e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 5013e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 5014e5b75505Sopenharmony_ci 0, NULL, NULL, unwrapped) < 0) { 5015e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 5016e5b75505Sopenharmony_ci goto fail; 5017e5b75505Sopenharmony_ci } 5018e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 5019e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 5020e5b75505Sopenharmony_ci 5021e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 5022e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 5023e5b75505Sopenharmony_ci goto fail; 5024e5b75505Sopenharmony_ci } 5025e5b75505Sopenharmony_ci 5026e5b75505Sopenharmony_ci e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 5027e5b75505Sopenharmony_ci DPP_ATTR_ENROLLEE_NONCE, 5028e5b75505Sopenharmony_ci &e_nonce_len); 5029e5b75505Sopenharmony_ci if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 5030e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5031e5b75505Sopenharmony_ci "Missing or invalid Enrollee Nonce attribute"); 5032e5b75505Sopenharmony_ci goto fail; 5033e5b75505Sopenharmony_ci } 5034e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 5035e5b75505Sopenharmony_ci os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); 5036e5b75505Sopenharmony_ci 5037e5b75505Sopenharmony_ci config_attr = dpp_get_attr(unwrapped, unwrapped_len, 5038e5b75505Sopenharmony_ci DPP_ATTR_CONFIG_ATTR_OBJ, 5039e5b75505Sopenharmony_ci &config_attr_len); 5040e5b75505Sopenharmony_ci if (!config_attr) { 5041e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5042e5b75505Sopenharmony_ci "Missing or invalid Config Attributes attribute"); 5043e5b75505Sopenharmony_ci goto fail; 5044e5b75505Sopenharmony_ci } 5045e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes", 5046e5b75505Sopenharmony_ci config_attr, config_attr_len); 5047e5b75505Sopenharmony_ci 5048e5b75505Sopenharmony_ci root = json_parse((const char *) config_attr, config_attr_len); 5049e5b75505Sopenharmony_ci if (!root) { 5050e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Could not parse Config Attributes"); 5051e5b75505Sopenharmony_ci goto fail; 5052e5b75505Sopenharmony_ci } 5053e5b75505Sopenharmony_ci 5054e5b75505Sopenharmony_ci token = json_get_member(root, "name"); 5055e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5056e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No Config Attributes - name"); 5057e5b75505Sopenharmony_ci goto fail; 5058e5b75505Sopenharmony_ci } 5059e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string); 5060e5b75505Sopenharmony_ci 5061e5b75505Sopenharmony_ci token = json_get_member(root, "wi-fi_tech"); 5062e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5063e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech"); 5064e5b75505Sopenharmony_ci goto fail; 5065e5b75505Sopenharmony_ci } 5066e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string); 5067e5b75505Sopenharmony_ci if (os_strcmp(token->string, "infra") != 0) { 5068e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'", 5069e5b75505Sopenharmony_ci token->string); 5070e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unsupported wi-fi_tech"); 5071e5b75505Sopenharmony_ci goto fail; 5072e5b75505Sopenharmony_ci } 5073e5b75505Sopenharmony_ci 5074e5b75505Sopenharmony_ci token = json_get_member(root, "netRole"); 5075e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5076e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No Config Attributes - netRole"); 5077e5b75505Sopenharmony_ci goto fail; 5078e5b75505Sopenharmony_ci } 5079e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string); 5080e5b75505Sopenharmony_ci if (os_strcmp(token->string, "sta") == 0) { 5081e5b75505Sopenharmony_ci ap = 0; 5082e5b75505Sopenharmony_ci } else if (os_strcmp(token->string, "ap") == 0) { 5083e5b75505Sopenharmony_ci ap = 1; 5084e5b75505Sopenharmony_ci } else { 5085e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'", 5086e5b75505Sopenharmony_ci token->string); 5087e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unsupported netRole"); 5088e5b75505Sopenharmony_ci goto fail; 5089e5b75505Sopenharmony_ci } 5090e5b75505Sopenharmony_ci 5091e5b75505Sopenharmony_ci resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap); 5092e5b75505Sopenharmony_ci 5093e5b75505Sopenharmony_cifail: 5094e5b75505Sopenharmony_ci json_free(root); 5095e5b75505Sopenharmony_ci os_free(unwrapped); 5096e5b75505Sopenharmony_ci return resp; 5097e5b75505Sopenharmony_ci} 5098e5b75505Sopenharmony_ci 5099e5b75505Sopenharmony_ci 5100e5b75505Sopenharmony_cistatic struct wpabuf * 5101e5b75505Sopenharmony_cidpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, 5102e5b75505Sopenharmony_ci const u8 *prot_hdr, u16 prot_hdr_len, 5103e5b75505Sopenharmony_ci const EVP_MD **ret_md) 5104e5b75505Sopenharmony_ci{ 5105e5b75505Sopenharmony_ci struct json_token *root, *token; 5106e5b75505Sopenharmony_ci struct wpabuf *kid = NULL; 5107e5b75505Sopenharmony_ci 5108e5b75505Sopenharmony_ci root = json_parse((const char *) prot_hdr, prot_hdr_len); 5109e5b75505Sopenharmony_ci if (!root) { 5110e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5111e5b75505Sopenharmony_ci "DPP: JSON parsing failed for JWS Protected Header"); 5112e5b75505Sopenharmony_ci goto fail; 5113e5b75505Sopenharmony_ci } 5114e5b75505Sopenharmony_ci 5115e5b75505Sopenharmony_ci if (root->type != JSON_OBJECT) { 5116e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5117e5b75505Sopenharmony_ci "DPP: JWS Protected Header root is not an object"); 5118e5b75505Sopenharmony_ci goto fail; 5119e5b75505Sopenharmony_ci } 5120e5b75505Sopenharmony_ci 5121e5b75505Sopenharmony_ci token = json_get_member(root, "typ"); 5122e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5123e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No typ string value found"); 5124e5b75505Sopenharmony_ci goto fail; 5125e5b75505Sopenharmony_ci } 5126e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s", 5127e5b75505Sopenharmony_ci token->string); 5128e5b75505Sopenharmony_ci if (os_strcmp(token->string, "dppCon") != 0) { 5129e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5130e5b75505Sopenharmony_ci "DPP: Unsupported JWS Protected Header typ=%s", 5131e5b75505Sopenharmony_ci token->string); 5132e5b75505Sopenharmony_ci goto fail; 5133e5b75505Sopenharmony_ci } 5134e5b75505Sopenharmony_ci 5135e5b75505Sopenharmony_ci token = json_get_member(root, "alg"); 5136e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5137e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No alg string value found"); 5138e5b75505Sopenharmony_ci goto fail; 5139e5b75505Sopenharmony_ci } 5140e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s", 5141e5b75505Sopenharmony_ci token->string); 5142e5b75505Sopenharmony_ci if (os_strcmp(token->string, curve->jws_alg) != 0) { 5143e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5144e5b75505Sopenharmony_ci "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)", 5145e5b75505Sopenharmony_ci token->string, curve->jws_alg); 5146e5b75505Sopenharmony_ci goto fail; 5147e5b75505Sopenharmony_ci } 5148e5b75505Sopenharmony_ci if (os_strcmp(token->string, "ES256") == 0 || 5149e5b75505Sopenharmony_ci os_strcmp(token->string, "BS256") == 0) 5150e5b75505Sopenharmony_ci *ret_md = EVP_sha256(); 5151e5b75505Sopenharmony_ci else if (os_strcmp(token->string, "ES384") == 0 || 5152e5b75505Sopenharmony_ci os_strcmp(token->string, "BS384") == 0) 5153e5b75505Sopenharmony_ci *ret_md = EVP_sha384(); 5154e5b75505Sopenharmony_ci else if (os_strcmp(token->string, "ES512") == 0 || 5155e5b75505Sopenharmony_ci os_strcmp(token->string, "BS512") == 0) 5156e5b75505Sopenharmony_ci *ret_md = EVP_sha512(); 5157e5b75505Sopenharmony_ci else 5158e5b75505Sopenharmony_ci *ret_md = NULL; 5159e5b75505Sopenharmony_ci if (!*ret_md) { 5160e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5161e5b75505Sopenharmony_ci "DPP: Unsupported JWS Protected Header alg=%s", 5162e5b75505Sopenharmony_ci token->string); 5163e5b75505Sopenharmony_ci goto fail; 5164e5b75505Sopenharmony_ci } 5165e5b75505Sopenharmony_ci 5166e5b75505Sopenharmony_ci kid = json_get_member_base64url(root, "kid"); 5167e5b75505Sopenharmony_ci if (!kid) { 5168e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No kid string value found"); 5169e5b75505Sopenharmony_ci goto fail; 5170e5b75505Sopenharmony_ci } 5171e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)", 5172e5b75505Sopenharmony_ci kid); 5173e5b75505Sopenharmony_ci 5174e5b75505Sopenharmony_cifail: 5175e5b75505Sopenharmony_ci json_free(root); 5176e5b75505Sopenharmony_ci return kid; 5177e5b75505Sopenharmony_ci} 5178e5b75505Sopenharmony_ci 5179e5b75505Sopenharmony_ci 5180e5b75505Sopenharmony_cistatic int dpp_parse_cred_legacy(struct dpp_authentication *auth, 5181e5b75505Sopenharmony_ci struct json_token *cred) 5182e5b75505Sopenharmony_ci{ 5183e5b75505Sopenharmony_ci struct json_token *pass, *psk_hex; 5184e5b75505Sopenharmony_ci 5185e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential"); 5186e5b75505Sopenharmony_ci 5187e5b75505Sopenharmony_ci pass = json_get_member(cred, "pass"); 5188e5b75505Sopenharmony_ci psk_hex = json_get_member(cred, "psk_hex"); 5189e5b75505Sopenharmony_ci 5190e5b75505Sopenharmony_ci if (pass && pass->type == JSON_STRING) { 5191e5b75505Sopenharmony_ci size_t len = os_strlen(pass->string); 5192e5b75505Sopenharmony_ci 5193e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase", 5194e5b75505Sopenharmony_ci pass->string, len); 5195e5b75505Sopenharmony_ci if (len < 8 || len > 63) 5196e5b75505Sopenharmony_ci return -1; 5197e5b75505Sopenharmony_ci os_strlcpy(auth->passphrase, pass->string, 5198e5b75505Sopenharmony_ci sizeof(auth->passphrase)); 5199e5b75505Sopenharmony_ci } else if (psk_hex && psk_hex->type == JSON_STRING) { 5200e5b75505Sopenharmony_ci if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) { 5201e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5202e5b75505Sopenharmony_ci "DPP: Unexpected psk_hex with akm=sae"); 5203e5b75505Sopenharmony_ci return -1; 5204e5b75505Sopenharmony_ci } 5205e5b75505Sopenharmony_ci if (os_strlen(psk_hex->string) != PMK_LEN * 2 || 5206e5b75505Sopenharmony_ci hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) { 5207e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding"); 5208e5b75505Sopenharmony_ci return -1; 5209e5b75505Sopenharmony_ci } 5210e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK", 5211e5b75505Sopenharmony_ci auth->psk, PMK_LEN); 5212e5b75505Sopenharmony_ci auth->psk_set = 1; 5213e5b75505Sopenharmony_ci } else { 5214e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found"); 5215e5b75505Sopenharmony_ci return -1; 5216e5b75505Sopenharmony_ci } 5217e5b75505Sopenharmony_ci 5218e5b75505Sopenharmony_ci if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) { 5219e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No pass for sae found"); 5220e5b75505Sopenharmony_ci return -1; 5221e5b75505Sopenharmony_ci } 5222e5b75505Sopenharmony_ci 5223e5b75505Sopenharmony_ci return 0; 5224e5b75505Sopenharmony_ci} 5225e5b75505Sopenharmony_ci 5226e5b75505Sopenharmony_ci 5227e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_parse_jwk(struct json_token *jwk, 5228e5b75505Sopenharmony_ci const struct dpp_curve_params **key_curve) 5229e5b75505Sopenharmony_ci{ 5230e5b75505Sopenharmony_ci struct json_token *token; 5231e5b75505Sopenharmony_ci const struct dpp_curve_params *curve; 5232e5b75505Sopenharmony_ci struct wpabuf *x = NULL, *y = NULL; 5233e5b75505Sopenharmony_ci EC_GROUP *group; 5234e5b75505Sopenharmony_ci EVP_PKEY *pkey = NULL; 5235e5b75505Sopenharmony_ci 5236e5b75505Sopenharmony_ci token = json_get_member(jwk, "kty"); 5237e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5238e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No kty in JWK"); 5239e5b75505Sopenharmony_ci goto fail; 5240e5b75505Sopenharmony_ci } 5241e5b75505Sopenharmony_ci if (os_strcmp(token->string, "EC") != 0) { 5242e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'", 5243e5b75505Sopenharmony_ci token->string); 5244e5b75505Sopenharmony_ci goto fail; 5245e5b75505Sopenharmony_ci } 5246e5b75505Sopenharmony_ci 5247e5b75505Sopenharmony_ci token = json_get_member(jwk, "crv"); 5248e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5249e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No crv in JWK"); 5250e5b75505Sopenharmony_ci goto fail; 5251e5b75505Sopenharmony_ci } 5252e5b75505Sopenharmony_ci curve = dpp_get_curve_jwk_crv(token->string); 5253e5b75505Sopenharmony_ci if (!curve) { 5254e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'", 5255e5b75505Sopenharmony_ci token->string); 5256e5b75505Sopenharmony_ci goto fail; 5257e5b75505Sopenharmony_ci } 5258e5b75505Sopenharmony_ci 5259e5b75505Sopenharmony_ci x = json_get_member_base64url(jwk, "x"); 5260e5b75505Sopenharmony_ci if (!x) { 5261e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No x in JWK"); 5262e5b75505Sopenharmony_ci goto fail; 5263e5b75505Sopenharmony_ci } 5264e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x); 5265e5b75505Sopenharmony_ci if (wpabuf_len(x) != curve->prime_len) { 5266e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5267e5b75505Sopenharmony_ci "DPP: Unexpected JWK x length %u (expected %u for curve %s)", 5268e5b75505Sopenharmony_ci (unsigned int) wpabuf_len(x), 5269e5b75505Sopenharmony_ci (unsigned int) curve->prime_len, curve->name); 5270e5b75505Sopenharmony_ci goto fail; 5271e5b75505Sopenharmony_ci } 5272e5b75505Sopenharmony_ci 5273e5b75505Sopenharmony_ci y = json_get_member_base64url(jwk, "y"); 5274e5b75505Sopenharmony_ci if (!y) { 5275e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No y in JWK"); 5276e5b75505Sopenharmony_ci goto fail; 5277e5b75505Sopenharmony_ci } 5278e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y); 5279e5b75505Sopenharmony_ci if (wpabuf_len(y) != curve->prime_len) { 5280e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5281e5b75505Sopenharmony_ci "DPP: Unexpected JWK y length %u (expected %u for curve %s)", 5282e5b75505Sopenharmony_ci (unsigned int) wpabuf_len(y), 5283e5b75505Sopenharmony_ci (unsigned int) curve->prime_len, curve->name); 5284e5b75505Sopenharmony_ci goto fail; 5285e5b75505Sopenharmony_ci } 5286e5b75505Sopenharmony_ci 5287e5b75505Sopenharmony_ci group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 5288e5b75505Sopenharmony_ci if (!group) { 5289e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK"); 5290e5b75505Sopenharmony_ci goto fail; 5291e5b75505Sopenharmony_ci } 5292e5b75505Sopenharmony_ci 5293e5b75505Sopenharmony_ci pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y), 5294e5b75505Sopenharmony_ci wpabuf_len(x)); 5295e5b75505Sopenharmony_ci EC_GROUP_free(group); 5296e5b75505Sopenharmony_ci *key_curve = curve; 5297e5b75505Sopenharmony_ci 5298e5b75505Sopenharmony_cifail: 5299e5b75505Sopenharmony_ci wpabuf_free(x); 5300e5b75505Sopenharmony_ci wpabuf_free(y); 5301e5b75505Sopenharmony_ci 5302e5b75505Sopenharmony_ci return pkey; 5303e5b75505Sopenharmony_ci} 5304e5b75505Sopenharmony_ci 5305e5b75505Sopenharmony_ci 5306e5b75505Sopenharmony_ciint dpp_key_expired(const char *timestamp, os_time_t *expiry) 5307e5b75505Sopenharmony_ci{ 5308e5b75505Sopenharmony_ci struct os_time now; 5309e5b75505Sopenharmony_ci unsigned int year, month, day, hour, min, sec; 5310e5b75505Sopenharmony_ci os_time_t utime; 5311e5b75505Sopenharmony_ci const char *pos; 5312e5b75505Sopenharmony_ci 5313e5b75505Sopenharmony_ci /* ISO 8601 date and time: 5314e5b75505Sopenharmony_ci * <date>T<time> 5315e5b75505Sopenharmony_ci * YYYY-MM-DDTHH:MM:SSZ 5316e5b75505Sopenharmony_ci * YYYY-MM-DDTHH:MM:SS+03:00 5317e5b75505Sopenharmony_ci */ 5318e5b75505Sopenharmony_ci if (os_strlen(timestamp) < 19) { 5319e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5320e5b75505Sopenharmony_ci "DPP: Too short timestamp - assume expired key"); 5321e5b75505Sopenharmony_ci return 1; 5322e5b75505Sopenharmony_ci } 5323e5b75505Sopenharmony_ci if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u", 5324e5b75505Sopenharmony_ci &year, &month, &day, &hour, &min, &sec) != 6) { 5325e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5326e5b75505Sopenharmony_ci "DPP: Failed to parse expiration day - assume expired key"); 5327e5b75505Sopenharmony_ci return 1; 5328e5b75505Sopenharmony_ci } 5329e5b75505Sopenharmony_ci 5330e5b75505Sopenharmony_ci if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) { 5331e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5332e5b75505Sopenharmony_ci "DPP: Invalid date/time information - assume expired key"); 5333e5b75505Sopenharmony_ci return 1; 5334e5b75505Sopenharmony_ci } 5335e5b75505Sopenharmony_ci 5336e5b75505Sopenharmony_ci pos = timestamp + 19; 5337e5b75505Sopenharmony_ci if (*pos == 'Z' || *pos == '\0') { 5338e5b75505Sopenharmony_ci /* In UTC - no need to adjust */ 5339e5b75505Sopenharmony_ci } else if (*pos == '-' || *pos == '+') { 5340e5b75505Sopenharmony_ci int items; 5341e5b75505Sopenharmony_ci 5342e5b75505Sopenharmony_ci /* Adjust local time to UTC */ 5343e5b75505Sopenharmony_ci items = sscanf(pos + 1, "%02u:%02u", &hour, &min); 5344e5b75505Sopenharmony_ci if (items < 1) { 5345e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5346e5b75505Sopenharmony_ci "DPP: Invalid time zone designator (%s) - assume expired key", 5347e5b75505Sopenharmony_ci pos); 5348e5b75505Sopenharmony_ci return 1; 5349e5b75505Sopenharmony_ci } 5350e5b75505Sopenharmony_ci if (*pos == '-') 5351e5b75505Sopenharmony_ci utime += 3600 * hour; 5352e5b75505Sopenharmony_ci if (*pos == '+') 5353e5b75505Sopenharmony_ci utime -= 3600 * hour; 5354e5b75505Sopenharmony_ci if (items > 1) { 5355e5b75505Sopenharmony_ci if (*pos == '-') 5356e5b75505Sopenharmony_ci utime += 60 * min; 5357e5b75505Sopenharmony_ci if (*pos == '+') 5358e5b75505Sopenharmony_ci utime -= 60 * min; 5359e5b75505Sopenharmony_ci } 5360e5b75505Sopenharmony_ci } else { 5361e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5362e5b75505Sopenharmony_ci "DPP: Invalid time zone designator (%s) - assume expired key", 5363e5b75505Sopenharmony_ci pos); 5364e5b75505Sopenharmony_ci return 1; 5365e5b75505Sopenharmony_ci } 5366e5b75505Sopenharmony_ci if (expiry) 5367e5b75505Sopenharmony_ci *expiry = utime; 5368e5b75505Sopenharmony_ci 5369e5b75505Sopenharmony_ci if (os_get_time(&now) < 0) { 5370e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5371e5b75505Sopenharmony_ci "DPP: Cannot get current time - assume expired key"); 5372e5b75505Sopenharmony_ci return 1; 5373e5b75505Sopenharmony_ci } 5374e5b75505Sopenharmony_ci 5375e5b75505Sopenharmony_ci if (now.sec > utime) { 5376e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)", 5377e5b75505Sopenharmony_ci utime, now.sec); 5378e5b75505Sopenharmony_ci return 1; 5379e5b75505Sopenharmony_ci } 5380e5b75505Sopenharmony_ci 5381e5b75505Sopenharmony_ci return 0; 5382e5b75505Sopenharmony_ci} 5383e5b75505Sopenharmony_ci 5384e5b75505Sopenharmony_ci 5385e5b75505Sopenharmony_cistatic int dpp_parse_connector(struct dpp_authentication *auth, 5386e5b75505Sopenharmony_ci const unsigned char *payload, 5387e5b75505Sopenharmony_ci u16 payload_len) 5388e5b75505Sopenharmony_ci{ 5389e5b75505Sopenharmony_ci struct json_token *root, *groups, *netkey, *token; 5390e5b75505Sopenharmony_ci int ret = -1; 5391e5b75505Sopenharmony_ci EVP_PKEY *key = NULL; 5392e5b75505Sopenharmony_ci const struct dpp_curve_params *curve; 5393e5b75505Sopenharmony_ci unsigned int rules = 0; 5394e5b75505Sopenharmony_ci 5395e5b75505Sopenharmony_ci root = json_parse((const char *) payload, payload_len); 5396e5b75505Sopenharmony_ci if (!root) { 5397e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 5398e5b75505Sopenharmony_ci goto fail; 5399e5b75505Sopenharmony_ci } 5400e5b75505Sopenharmony_ci 5401e5b75505Sopenharmony_ci groups = json_get_member(root, "groups"); 5402e5b75505Sopenharmony_ci if (!groups || groups->type != JSON_ARRAY) { 5403e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No groups array found"); 5404e5b75505Sopenharmony_ci goto skip_groups; 5405e5b75505Sopenharmony_ci } 5406e5b75505Sopenharmony_ci for (token = groups->child; token; token = token->sibling) { 5407e5b75505Sopenharmony_ci struct json_token *id, *role; 5408e5b75505Sopenharmony_ci 5409e5b75505Sopenharmony_ci id = json_get_member(token, "groupId"); 5410e5b75505Sopenharmony_ci if (!id || id->type != JSON_STRING) { 5411e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Missing groupId string"); 5412e5b75505Sopenharmony_ci goto fail; 5413e5b75505Sopenharmony_ci } 5414e5b75505Sopenharmony_ci 5415e5b75505Sopenharmony_ci role = json_get_member(token, "netRole"); 5416e5b75505Sopenharmony_ci if (!role || role->type != JSON_STRING) { 5417e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Missing netRole string"); 5418e5b75505Sopenharmony_ci goto fail; 5419e5b75505Sopenharmony_ci } 5420e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5421e5b75505Sopenharmony_ci "DPP: connector group: groupId='%s' netRole='%s'", 5422e5b75505Sopenharmony_ci id->string, role->string); 5423e5b75505Sopenharmony_ci rules++; 5424e5b75505Sopenharmony_ci } 5425e5b75505Sopenharmony_ciskip_groups: 5426e5b75505Sopenharmony_ci 5427e5b75505Sopenharmony_ci if (!rules) { 5428e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5429e5b75505Sopenharmony_ci "DPP: Connector includes no groups"); 5430e5b75505Sopenharmony_ci goto fail; 5431e5b75505Sopenharmony_ci } 5432e5b75505Sopenharmony_ci 5433e5b75505Sopenharmony_ci token = json_get_member(root, "expiry"); 5434e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5435e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5436e5b75505Sopenharmony_ci "DPP: No expiry string found - connector does not expire"); 5437e5b75505Sopenharmony_ci } else { 5438e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 5439e5b75505Sopenharmony_ci if (dpp_key_expired(token->string, 5440e5b75505Sopenharmony_ci &auth->net_access_key_expiry)) { 5441e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5442e5b75505Sopenharmony_ci "DPP: Connector (netAccessKey) has expired"); 5443e5b75505Sopenharmony_ci goto fail; 5444e5b75505Sopenharmony_ci } 5445e5b75505Sopenharmony_ci } 5446e5b75505Sopenharmony_ci 5447e5b75505Sopenharmony_ci netkey = json_get_member(root, "netAccessKey"); 5448e5b75505Sopenharmony_ci if (!netkey || netkey->type != JSON_OBJECT) { 5449e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 5450e5b75505Sopenharmony_ci goto fail; 5451e5b75505Sopenharmony_ci } 5452e5b75505Sopenharmony_ci 5453e5b75505Sopenharmony_ci key = dpp_parse_jwk(netkey, &curve); 5454e5b75505Sopenharmony_ci if (!key) 5455e5b75505Sopenharmony_ci goto fail; 5456e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Received netAccessKey", key); 5457e5b75505Sopenharmony_ci 5458e5b75505Sopenharmony_ci if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) { 5459e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5460e5b75505Sopenharmony_ci "DPP: netAccessKey in connector does not match own protocol key"); 5461e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 5462e5b75505Sopenharmony_ci if (auth->ignore_netaccesskey_mismatch) { 5463e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5464e5b75505Sopenharmony_ci "DPP: TESTING - skip netAccessKey mismatch"); 5465e5b75505Sopenharmony_ci } else { 5466e5b75505Sopenharmony_ci goto fail; 5467e5b75505Sopenharmony_ci } 5468e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 5469e5b75505Sopenharmony_ci goto fail; 5470e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 5471e5b75505Sopenharmony_ci } 5472e5b75505Sopenharmony_ci 5473e5b75505Sopenharmony_ci ret = 0; 5474e5b75505Sopenharmony_cifail: 5475e5b75505Sopenharmony_ci EVP_PKEY_free(key); 5476e5b75505Sopenharmony_ci json_free(root); 5477e5b75505Sopenharmony_ci return ret; 5478e5b75505Sopenharmony_ci} 5479e5b75505Sopenharmony_ci 5480e5b75505Sopenharmony_ci 5481e5b75505Sopenharmony_cistatic int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash) 5482e5b75505Sopenharmony_ci{ 5483e5b75505Sopenharmony_ci struct wpabuf *uncomp; 5484e5b75505Sopenharmony_ci int res; 5485e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 5486e5b75505Sopenharmony_ci const u8 *addr[1]; 5487e5b75505Sopenharmony_ci size_t len[1]; 5488e5b75505Sopenharmony_ci 5489e5b75505Sopenharmony_ci if (wpabuf_len(r_hash) != SHA256_MAC_LEN) 5490e5b75505Sopenharmony_ci return -1; 5491e5b75505Sopenharmony_ci uncomp = dpp_get_pubkey_point(pub, 1); 5492e5b75505Sopenharmony_ci if (!uncomp) 5493e5b75505Sopenharmony_ci return -1; 5494e5b75505Sopenharmony_ci addr[0] = wpabuf_head(uncomp); 5495e5b75505Sopenharmony_ci len[0] = wpabuf_len(uncomp); 5496e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key", 5497e5b75505Sopenharmony_ci addr[0], len[0]); 5498e5b75505Sopenharmony_ci res = sha256_vector(1, addr, len, hash); 5499e5b75505Sopenharmony_ci wpabuf_free(uncomp); 5500e5b75505Sopenharmony_ci if (res < 0) 5501e5b75505Sopenharmony_ci return -1; 5502e5b75505Sopenharmony_ci if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) { 5503e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5504e5b75505Sopenharmony_ci "DPP: Received hash value does not match calculated public key hash value"); 5505e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash", 5506e5b75505Sopenharmony_ci hash, SHA256_MAC_LEN); 5507e5b75505Sopenharmony_ci return -1; 5508e5b75505Sopenharmony_ci } 5509e5b75505Sopenharmony_ci return 0; 5510e5b75505Sopenharmony_ci} 5511e5b75505Sopenharmony_ci 5512e5b75505Sopenharmony_ci 5513e5b75505Sopenharmony_cistatic void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign) 5514e5b75505Sopenharmony_ci{ 5515e5b75505Sopenharmony_ci unsigned char *der = NULL; 5516e5b75505Sopenharmony_ci int der_len; 5517e5b75505Sopenharmony_ci 5518e5b75505Sopenharmony_ci der_len = i2d_PUBKEY(csign, &der); 5519e5b75505Sopenharmony_ci if (der_len <= 0) 5520e5b75505Sopenharmony_ci return; 5521e5b75505Sopenharmony_ci wpabuf_free(auth->c_sign_key); 5522e5b75505Sopenharmony_ci auth->c_sign_key = wpabuf_alloc_copy(der, der_len); 5523e5b75505Sopenharmony_ci OPENSSL_free(der); 5524e5b75505Sopenharmony_ci} 5525e5b75505Sopenharmony_ci 5526e5b75505Sopenharmony_ci 5527e5b75505Sopenharmony_cistatic void dpp_copy_netaccesskey(struct dpp_authentication *auth) 5528e5b75505Sopenharmony_ci{ 5529e5b75505Sopenharmony_ci unsigned char *der = NULL; 5530e5b75505Sopenharmony_ci int der_len; 5531e5b75505Sopenharmony_ci EC_KEY *eckey; 5532e5b75505Sopenharmony_ci 5533e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key); 5534e5b75505Sopenharmony_ci if (!eckey) 5535e5b75505Sopenharmony_ci return; 5536e5b75505Sopenharmony_ci 5537e5b75505Sopenharmony_ci der_len = i2d_ECPrivateKey(eckey, &der); 5538e5b75505Sopenharmony_ci if (der_len <= 0) { 5539e5b75505Sopenharmony_ci EC_KEY_free(eckey); 5540e5b75505Sopenharmony_ci return; 5541e5b75505Sopenharmony_ci } 5542e5b75505Sopenharmony_ci wpabuf_free(auth->net_access_key); 5543e5b75505Sopenharmony_ci auth->net_access_key = wpabuf_alloc_copy(der, der_len); 5544e5b75505Sopenharmony_ci OPENSSL_free(der); 5545e5b75505Sopenharmony_ci EC_KEY_free(eckey); 5546e5b75505Sopenharmony_ci} 5547e5b75505Sopenharmony_ci 5548e5b75505Sopenharmony_ci 5549e5b75505Sopenharmony_cistruct dpp_signed_connector_info { 5550e5b75505Sopenharmony_ci unsigned char *payload; 5551e5b75505Sopenharmony_ci size_t payload_len; 5552e5b75505Sopenharmony_ci}; 5553e5b75505Sopenharmony_ci 5554e5b75505Sopenharmony_cistatic enum dpp_status_error 5555e5b75505Sopenharmony_cidpp_process_signed_connector(struct dpp_signed_connector_info *info, 5556e5b75505Sopenharmony_ci EVP_PKEY *csign_pub, const char *connector) 5557e5b75505Sopenharmony_ci{ 5558e5b75505Sopenharmony_ci enum dpp_status_error ret = 255; 5559e5b75505Sopenharmony_ci const char *pos, *end, *signed_start, *signed_end; 5560e5b75505Sopenharmony_ci struct wpabuf *kid = NULL; 5561e5b75505Sopenharmony_ci unsigned char *prot_hdr = NULL, *signature = NULL; 5562e5b75505Sopenharmony_ci size_t prot_hdr_len = 0, signature_len = 0; 5563e5b75505Sopenharmony_ci const EVP_MD *sign_md = NULL; 5564e5b75505Sopenharmony_ci unsigned char *der = NULL; 5565e5b75505Sopenharmony_ci int der_len; 5566e5b75505Sopenharmony_ci int res; 5567e5b75505Sopenharmony_ci EVP_MD_CTX *md_ctx = NULL; 5568e5b75505Sopenharmony_ci ECDSA_SIG *sig = NULL; 5569e5b75505Sopenharmony_ci BIGNUM *r = NULL, *s = NULL; 5570e5b75505Sopenharmony_ci const struct dpp_curve_params *curve; 5571e5b75505Sopenharmony_ci EC_KEY *eckey; 5572e5b75505Sopenharmony_ci const EC_GROUP *group; 5573e5b75505Sopenharmony_ci int nid; 5574e5b75505Sopenharmony_ci 5575e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(csign_pub); 5576e5b75505Sopenharmony_ci if (!eckey) 5577e5b75505Sopenharmony_ci goto fail; 5578e5b75505Sopenharmony_ci group = EC_KEY_get0_group(eckey); 5579e5b75505Sopenharmony_ci if (!group) 5580e5b75505Sopenharmony_ci goto fail; 5581e5b75505Sopenharmony_ci nid = EC_GROUP_get_curve_name(group); 5582e5b75505Sopenharmony_ci curve = dpp_get_curve_nid(nid); 5583e5b75505Sopenharmony_ci if (!curve) 5584e5b75505Sopenharmony_ci goto fail; 5585e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv); 5586e5b75505Sopenharmony_ci os_memset(info, 0, sizeof(*info)); 5587e5b75505Sopenharmony_ci 5588e5b75505Sopenharmony_ci signed_start = pos = connector; 5589e5b75505Sopenharmony_ci end = os_strchr(pos, '.'); 5590e5b75505Sopenharmony_ci if (!end) { 5591e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector"); 5592e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5593e5b75505Sopenharmony_ci goto fail; 5594e5b75505Sopenharmony_ci } 5595e5b75505Sopenharmony_ci prot_hdr = base64_url_decode((const unsigned char *) pos, 5596e5b75505Sopenharmony_ci end - pos, &prot_hdr_len); 5597e5b75505Sopenharmony_ci if (!prot_hdr) { 5598e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5599e5b75505Sopenharmony_ci "DPP: Failed to base64url decode signedConnector JWS Protected Header"); 5600e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5601e5b75505Sopenharmony_ci goto fail; 5602e5b75505Sopenharmony_ci } 5603e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, 5604e5b75505Sopenharmony_ci "DPP: signedConnector - JWS Protected Header", 5605e5b75505Sopenharmony_ci prot_hdr, prot_hdr_len); 5606e5b75505Sopenharmony_ci kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md); 5607e5b75505Sopenharmony_ci if (!kid) { 5608e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5609e5b75505Sopenharmony_ci goto fail; 5610e5b75505Sopenharmony_ci } 5611e5b75505Sopenharmony_ci if (wpabuf_len(kid) != SHA256_MAC_LEN) { 5612e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5613e5b75505Sopenharmony_ci "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)", 5614e5b75505Sopenharmony_ci (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN); 5615e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5616e5b75505Sopenharmony_ci goto fail; 5617e5b75505Sopenharmony_ci } 5618e5b75505Sopenharmony_ci 5619e5b75505Sopenharmony_ci pos = end + 1; 5620e5b75505Sopenharmony_ci end = os_strchr(pos, '.'); 5621e5b75505Sopenharmony_ci if (!end) { 5622e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5623e5b75505Sopenharmony_ci "DPP: Missing dot(2) in signedConnector"); 5624e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5625e5b75505Sopenharmony_ci goto fail; 5626e5b75505Sopenharmony_ci } 5627e5b75505Sopenharmony_ci signed_end = end - 1; 5628e5b75505Sopenharmony_ci info->payload = base64_url_decode((const unsigned char *) pos, 5629e5b75505Sopenharmony_ci end - pos, &info->payload_len); 5630e5b75505Sopenharmony_ci if (!info->payload) { 5631e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5632e5b75505Sopenharmony_ci "DPP: Failed to base64url decode signedConnector JWS Payload"); 5633e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5634e5b75505Sopenharmony_ci goto fail; 5635e5b75505Sopenharmony_ci } 5636e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, 5637e5b75505Sopenharmony_ci "DPP: signedConnector - JWS Payload", 5638e5b75505Sopenharmony_ci info->payload, info->payload_len); 5639e5b75505Sopenharmony_ci pos = end + 1; 5640e5b75505Sopenharmony_ci signature = base64_url_decode((const unsigned char *) pos, 5641e5b75505Sopenharmony_ci os_strlen(pos), &signature_len); 5642e5b75505Sopenharmony_ci if (!signature) { 5643e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5644e5b75505Sopenharmony_ci "DPP: Failed to base64url decode signedConnector signature"); 5645e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5646e5b75505Sopenharmony_ci goto fail; 5647e5b75505Sopenharmony_ci } 5648e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature", 5649e5b75505Sopenharmony_ci signature, signature_len); 5650e5b75505Sopenharmony_ci 5651e5b75505Sopenharmony_ci if (dpp_check_pubkey_match(csign_pub, kid) < 0) { 5652e5b75505Sopenharmony_ci ret = DPP_STATUS_NO_MATCH; 5653e5b75505Sopenharmony_ci goto fail; 5654e5b75505Sopenharmony_ci } 5655e5b75505Sopenharmony_ci 5656e5b75505Sopenharmony_ci if (signature_len & 0x01) { 5657e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5658e5b75505Sopenharmony_ci "DPP: Unexpected signedConnector signature length (%d)", 5659e5b75505Sopenharmony_ci (int) signature_len); 5660e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5661e5b75505Sopenharmony_ci goto fail; 5662e5b75505Sopenharmony_ci } 5663e5b75505Sopenharmony_ci 5664e5b75505Sopenharmony_ci /* JWS Signature encodes the signature (r,s) as two octet strings. Need 5665e5b75505Sopenharmony_ci * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */ 5666e5b75505Sopenharmony_ci r = BN_bin2bn(signature, signature_len / 2, NULL); 5667e5b75505Sopenharmony_ci s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL); 5668e5b75505Sopenharmony_ci sig = ECDSA_SIG_new(); 5669e5b75505Sopenharmony_ci if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1) 5670e5b75505Sopenharmony_ci goto fail; 5671e5b75505Sopenharmony_ci r = NULL; 5672e5b75505Sopenharmony_ci s = NULL; 5673e5b75505Sopenharmony_ci 5674e5b75505Sopenharmony_ci der_len = i2d_ECDSA_SIG(sig, &der); 5675e5b75505Sopenharmony_ci if (der_len <= 0) { 5676e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature"); 5677e5b75505Sopenharmony_ci goto fail; 5678e5b75505Sopenharmony_ci } 5679e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len); 5680e5b75505Sopenharmony_ci md_ctx = EVP_MD_CTX_create(); 5681e5b75505Sopenharmony_ci if (!md_ctx) 5682e5b75505Sopenharmony_ci goto fail; 5683e5b75505Sopenharmony_ci 5684e5b75505Sopenharmony_ci ERR_clear_error(); 5685e5b75505Sopenharmony_ci if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) { 5686e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s", 5687e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 5688e5b75505Sopenharmony_ci goto fail; 5689e5b75505Sopenharmony_ci } 5690e5b75505Sopenharmony_ci if (EVP_DigestVerifyUpdate(md_ctx, signed_start, 5691e5b75505Sopenharmony_ci signed_end - signed_start + 1) != 1) { 5692e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s", 5693e5b75505Sopenharmony_ci ERR_error_string(ERR_get_error(), NULL)); 5694e5b75505Sopenharmony_ci goto fail; 5695e5b75505Sopenharmony_ci } 5696e5b75505Sopenharmony_ci res = EVP_DigestVerifyFinal(md_ctx, der, der_len); 5697e5b75505Sopenharmony_ci if (res != 1) { 5698e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5699e5b75505Sopenharmony_ci "DPP: EVP_DigestVerifyFinal failed (res=%d): %s", 5700e5b75505Sopenharmony_ci res, ERR_error_string(ERR_get_error(), NULL)); 5701e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 5702e5b75505Sopenharmony_ci goto fail; 5703e5b75505Sopenharmony_ci } 5704e5b75505Sopenharmony_ci 5705e5b75505Sopenharmony_ci ret = DPP_STATUS_OK; 5706e5b75505Sopenharmony_cifail: 5707e5b75505Sopenharmony_ci EC_KEY_free(eckey); 5708e5b75505Sopenharmony_ci EVP_MD_CTX_destroy(md_ctx); 5709e5b75505Sopenharmony_ci os_free(prot_hdr); 5710e5b75505Sopenharmony_ci wpabuf_free(kid); 5711e5b75505Sopenharmony_ci os_free(signature); 5712e5b75505Sopenharmony_ci ECDSA_SIG_free(sig); 5713e5b75505Sopenharmony_ci BN_free(r); 5714e5b75505Sopenharmony_ci BN_free(s); 5715e5b75505Sopenharmony_ci OPENSSL_free(der); 5716e5b75505Sopenharmony_ci return ret; 5717e5b75505Sopenharmony_ci} 5718e5b75505Sopenharmony_ci 5719e5b75505Sopenharmony_ci 5720e5b75505Sopenharmony_cistatic int dpp_parse_cred_dpp(struct dpp_authentication *auth, 5721e5b75505Sopenharmony_ci struct json_token *cred) 5722e5b75505Sopenharmony_ci{ 5723e5b75505Sopenharmony_ci struct dpp_signed_connector_info info; 5724e5b75505Sopenharmony_ci struct json_token *token, *csign; 5725e5b75505Sopenharmony_ci int ret = -1; 5726e5b75505Sopenharmony_ci EVP_PKEY *csign_pub = NULL; 5727e5b75505Sopenharmony_ci const struct dpp_curve_params *key_curve = NULL; 5728e5b75505Sopenharmony_ci const char *signed_connector; 5729e5b75505Sopenharmony_ci 5730e5b75505Sopenharmony_ci os_memset(&info, 0, sizeof(info)); 5731e5b75505Sopenharmony_ci 5732e5b75505Sopenharmony_ci if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) { 5733e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5734e5b75505Sopenharmony_ci "DPP: Legacy credential included in Connector credential"); 5735e5b75505Sopenharmony_ci if (dpp_parse_cred_legacy(auth, cred) < 0) 5736e5b75505Sopenharmony_ci return -1; 5737e5b75505Sopenharmony_ci } 5738e5b75505Sopenharmony_ci 5739e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Connector credential"); 5740e5b75505Sopenharmony_ci 5741e5b75505Sopenharmony_ci csign = json_get_member(cred, "csign"); 5742e5b75505Sopenharmony_ci if (!csign || csign->type != JSON_OBJECT) { 5743e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON"); 5744e5b75505Sopenharmony_ci goto fail; 5745e5b75505Sopenharmony_ci } 5746e5b75505Sopenharmony_ci 5747e5b75505Sopenharmony_ci csign_pub = dpp_parse_jwk(csign, &key_curve); 5748e5b75505Sopenharmony_ci if (!csign_pub) { 5749e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK"); 5750e5b75505Sopenharmony_ci goto fail; 5751e5b75505Sopenharmony_ci } 5752e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Received C-sign-key", csign_pub); 5753e5b75505Sopenharmony_ci 5754e5b75505Sopenharmony_ci token = json_get_member(cred, "signedConnector"); 5755e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5756e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found"); 5757e5b75505Sopenharmony_ci goto fail; 5758e5b75505Sopenharmony_ci } 5759e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector", 5760e5b75505Sopenharmony_ci token->string, os_strlen(token->string)); 5761e5b75505Sopenharmony_ci signed_connector = token->string; 5762e5b75505Sopenharmony_ci 5763e5b75505Sopenharmony_ci if (os_strchr(signed_connector, '"') || 5764e5b75505Sopenharmony_ci os_strchr(signed_connector, '\n')) { 5765e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5766e5b75505Sopenharmony_ci "DPP: Unexpected character in signedConnector"); 5767e5b75505Sopenharmony_ci goto fail; 5768e5b75505Sopenharmony_ci } 5769e5b75505Sopenharmony_ci 5770e5b75505Sopenharmony_ci if (dpp_process_signed_connector(&info, csign_pub, 5771e5b75505Sopenharmony_ci signed_connector) != DPP_STATUS_OK) 5772e5b75505Sopenharmony_ci goto fail; 5773e5b75505Sopenharmony_ci 5774e5b75505Sopenharmony_ci if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) { 5775e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector"); 5776e5b75505Sopenharmony_ci goto fail; 5777e5b75505Sopenharmony_ci } 5778e5b75505Sopenharmony_ci 5779e5b75505Sopenharmony_ci os_free(auth->connector); 5780e5b75505Sopenharmony_ci auth->connector = os_strdup(signed_connector); 5781e5b75505Sopenharmony_ci 5782e5b75505Sopenharmony_ci dpp_copy_csign(auth, csign_pub); 5783e5b75505Sopenharmony_ci dpp_copy_netaccesskey(auth); 5784e5b75505Sopenharmony_ci 5785e5b75505Sopenharmony_ci ret = 0; 5786e5b75505Sopenharmony_cifail: 5787e5b75505Sopenharmony_ci EVP_PKEY_free(csign_pub); 5788e5b75505Sopenharmony_ci os_free(info.payload); 5789e5b75505Sopenharmony_ci return ret; 5790e5b75505Sopenharmony_ci} 5791e5b75505Sopenharmony_ci 5792e5b75505Sopenharmony_ci 5793e5b75505Sopenharmony_ciconst char * dpp_akm_str(enum dpp_akm akm) 5794e5b75505Sopenharmony_ci{ 5795e5b75505Sopenharmony_ci switch (akm) { 5796e5b75505Sopenharmony_ci case DPP_AKM_DPP: 5797e5b75505Sopenharmony_ci return "dpp"; 5798e5b75505Sopenharmony_ci case DPP_AKM_PSK: 5799e5b75505Sopenharmony_ci return "psk"; 5800e5b75505Sopenharmony_ci case DPP_AKM_SAE: 5801e5b75505Sopenharmony_ci return "sae"; 5802e5b75505Sopenharmony_ci case DPP_AKM_PSK_SAE: 5803e5b75505Sopenharmony_ci return "psk+sae"; 5804e5b75505Sopenharmony_ci case DPP_AKM_SAE_DPP: 5805e5b75505Sopenharmony_ci return "dpp+sae"; 5806e5b75505Sopenharmony_ci case DPP_AKM_PSK_SAE_DPP: 5807e5b75505Sopenharmony_ci return "dpp+psk+sae"; 5808e5b75505Sopenharmony_ci default: 5809e5b75505Sopenharmony_ci return "??"; 5810e5b75505Sopenharmony_ci } 5811e5b75505Sopenharmony_ci} 5812e5b75505Sopenharmony_ci 5813e5b75505Sopenharmony_ci 5814e5b75505Sopenharmony_cistatic enum dpp_akm dpp_akm_from_str(const char *akm) 5815e5b75505Sopenharmony_ci{ 5816e5b75505Sopenharmony_ci if (os_strcmp(akm, "psk") == 0) 5817e5b75505Sopenharmony_ci return DPP_AKM_PSK; 5818e5b75505Sopenharmony_ci if (os_strcmp(akm, "sae") == 0) 5819e5b75505Sopenharmony_ci return DPP_AKM_SAE; 5820e5b75505Sopenharmony_ci if (os_strcmp(akm, "psk+sae") == 0) 5821e5b75505Sopenharmony_ci return DPP_AKM_PSK_SAE; 5822e5b75505Sopenharmony_ci if (os_strcmp(akm, "dpp") == 0) 5823e5b75505Sopenharmony_ci return DPP_AKM_DPP; 5824e5b75505Sopenharmony_ci if (os_strcmp(akm, "dpp+sae") == 0) 5825e5b75505Sopenharmony_ci return DPP_AKM_SAE_DPP; 5826e5b75505Sopenharmony_ci if (os_strcmp(akm, "dpp+psk+sae") == 0) 5827e5b75505Sopenharmony_ci return DPP_AKM_PSK_SAE_DPP; 5828e5b75505Sopenharmony_ci return DPP_AKM_UNKNOWN; 5829e5b75505Sopenharmony_ci} 5830e5b75505Sopenharmony_ci 5831e5b75505Sopenharmony_ci 5832e5b75505Sopenharmony_cistatic int dpp_parse_conf_obj(struct dpp_authentication *auth, 5833e5b75505Sopenharmony_ci const u8 *conf_obj, u16 conf_obj_len) 5834e5b75505Sopenharmony_ci{ 5835e5b75505Sopenharmony_ci int ret = -1; 5836e5b75505Sopenharmony_ci struct json_token *root, *token, *discovery, *cred; 5837e5b75505Sopenharmony_ci 5838e5b75505Sopenharmony_ci root = json_parse((const char *) conf_obj, conf_obj_len); 5839e5b75505Sopenharmony_ci if (!root) 5840e5b75505Sopenharmony_ci return -1; 5841e5b75505Sopenharmony_ci if (root->type != JSON_OBJECT) { 5842e5b75505Sopenharmony_ci dpp_auth_fail(auth, "JSON root is not an object"); 5843e5b75505Sopenharmony_ci goto fail; 5844e5b75505Sopenharmony_ci } 5845e5b75505Sopenharmony_ci 5846e5b75505Sopenharmony_ci token = json_get_member(root, "wi-fi_tech"); 5847e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5848e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No wi-fi_tech string value found"); 5849e5b75505Sopenharmony_ci goto fail; 5850e5b75505Sopenharmony_ci } 5851e5b75505Sopenharmony_ci if (os_strcmp(token->string, "infra") != 0) { 5852e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'", 5853e5b75505Sopenharmony_ci token->string); 5854e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unsupported wi-fi_tech value"); 5855e5b75505Sopenharmony_ci goto fail; 5856e5b75505Sopenharmony_ci } 5857e5b75505Sopenharmony_ci 5858e5b75505Sopenharmony_ci discovery = json_get_member(root, "discovery"); 5859e5b75505Sopenharmony_ci if (!discovery || discovery->type != JSON_OBJECT) { 5860e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No discovery object in JSON"); 5861e5b75505Sopenharmony_ci goto fail; 5862e5b75505Sopenharmony_ci } 5863e5b75505Sopenharmony_ci 5864e5b75505Sopenharmony_ci token = json_get_member(discovery, "ssid"); 5865e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5866e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No discovery::ssid string value found"); 5867e5b75505Sopenharmony_ci goto fail; 5868e5b75505Sopenharmony_ci } 5869e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid", 5870e5b75505Sopenharmony_ci token->string, os_strlen(token->string)); 5871e5b75505Sopenharmony_ci if (os_strlen(token->string) > SSID_MAX_LEN) { 5872e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Too long discovery::ssid string value"); 5873e5b75505Sopenharmony_ci goto fail; 5874e5b75505Sopenharmony_ci } 5875e5b75505Sopenharmony_ci auth->ssid_len = os_strlen(token->string); 5876e5b75505Sopenharmony_ci os_memcpy(auth->ssid, token->string, auth->ssid_len); 5877e5b75505Sopenharmony_ci 5878e5b75505Sopenharmony_ci cred = json_get_member(root, "cred"); 5879e5b75505Sopenharmony_ci if (!cred || cred->type != JSON_OBJECT) { 5880e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No cred object in JSON"); 5881e5b75505Sopenharmony_ci goto fail; 5882e5b75505Sopenharmony_ci } 5883e5b75505Sopenharmony_ci 5884e5b75505Sopenharmony_ci token = json_get_member(cred, "akm"); 5885e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 5886e5b75505Sopenharmony_ci dpp_auth_fail(auth, "No cred::akm string value found"); 5887e5b75505Sopenharmony_ci goto fail; 5888e5b75505Sopenharmony_ci } 5889e5b75505Sopenharmony_ci auth->akm = dpp_akm_from_str(token->string); 5890e5b75505Sopenharmony_ci 5891e5b75505Sopenharmony_ci if (dpp_akm_legacy(auth->akm)) { 5892e5b75505Sopenharmony_ci if (dpp_parse_cred_legacy(auth, cred) < 0) 5893e5b75505Sopenharmony_ci goto fail; 5894e5b75505Sopenharmony_ci } else if (dpp_akm_dpp(auth->akm)) { 5895e5b75505Sopenharmony_ci if (dpp_parse_cred_dpp(auth, cred) < 0) 5896e5b75505Sopenharmony_ci goto fail; 5897e5b75505Sopenharmony_ci } else { 5898e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s", 5899e5b75505Sopenharmony_ci token->string); 5900e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Unsupported akm"); 5901e5b75505Sopenharmony_ci goto fail; 5902e5b75505Sopenharmony_ci } 5903e5b75505Sopenharmony_ci 5904e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully"); 5905e5b75505Sopenharmony_ci ret = 0; 5906e5b75505Sopenharmony_cifail: 5907e5b75505Sopenharmony_ci json_free(root); 5908e5b75505Sopenharmony_ci return ret; 5909e5b75505Sopenharmony_ci} 5910e5b75505Sopenharmony_ci 5911e5b75505Sopenharmony_ci 5912e5b75505Sopenharmony_ciint dpp_conf_resp_rx(struct dpp_authentication *auth, 5913e5b75505Sopenharmony_ci const struct wpabuf *resp) 5914e5b75505Sopenharmony_ci{ 5915e5b75505Sopenharmony_ci const u8 *wrapped_data, *e_nonce, *status, *conf_obj; 5916e5b75505Sopenharmony_ci u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len; 5917e5b75505Sopenharmony_ci const u8 *addr[1]; 5918e5b75505Sopenharmony_ci size_t len[1]; 5919e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 5920e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 5921e5b75505Sopenharmony_ci int ret = -1; 5922e5b75505Sopenharmony_ci 5923e5b75505Sopenharmony_ci auth->conf_resp_status = 255; 5924e5b75505Sopenharmony_ci 5925e5b75505Sopenharmony_ci if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { 5926e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in config response"); 5927e5b75505Sopenharmony_ci return -1; 5928e5b75505Sopenharmony_ci } 5929e5b75505Sopenharmony_ci 5930e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 5931e5b75505Sopenharmony_ci DPP_ATTR_WRAPPED_DATA, 5932e5b75505Sopenharmony_ci &wrapped_data_len); 5933e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 5934e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5935e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 5936e5b75505Sopenharmony_ci return -1; 5937e5b75505Sopenharmony_ci } 5938e5b75505Sopenharmony_ci 5939e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5940e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 5941e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 5942e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 5943e5b75505Sopenharmony_ci if (!unwrapped) 5944e5b75505Sopenharmony_ci return -1; 5945e5b75505Sopenharmony_ci 5946e5b75505Sopenharmony_ci addr[0] = wpabuf_head(resp); 5947e5b75505Sopenharmony_ci len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp); 5948e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 5949e5b75505Sopenharmony_ci 5950e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 5951e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 5952e5b75505Sopenharmony_ci 1, addr, len, unwrapped) < 0) { 5953e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 5954e5b75505Sopenharmony_ci goto fail; 5955e5b75505Sopenharmony_ci } 5956e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 5957e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 5958e5b75505Sopenharmony_ci 5959e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 5960e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 5961e5b75505Sopenharmony_ci goto fail; 5962e5b75505Sopenharmony_ci } 5963e5b75505Sopenharmony_ci 5964e5b75505Sopenharmony_ci e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 5965e5b75505Sopenharmony_ci DPP_ATTR_ENROLLEE_NONCE, 5966e5b75505Sopenharmony_ci &e_nonce_len); 5967e5b75505Sopenharmony_ci if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 5968e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5969e5b75505Sopenharmony_ci "Missing or invalid Enrollee Nonce attribute"); 5970e5b75505Sopenharmony_ci goto fail; 5971e5b75505Sopenharmony_ci } 5972e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 5973e5b75505Sopenharmony_ci if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 5974e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Enrollee Nonce mismatch"); 5975e5b75505Sopenharmony_ci goto fail; 5976e5b75505Sopenharmony_ci } 5977e5b75505Sopenharmony_ci 5978e5b75505Sopenharmony_ci status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 5979e5b75505Sopenharmony_ci DPP_ATTR_STATUS, &status_len); 5980e5b75505Sopenharmony_ci if (!status || status_len < 1) { 5981e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5982e5b75505Sopenharmony_ci "Missing or invalid required DPP Status attribute"); 5983e5b75505Sopenharmony_ci goto fail; 5984e5b75505Sopenharmony_ci } 5985e5b75505Sopenharmony_ci auth->conf_resp_status = status[0]; 5986e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 5987e5b75505Sopenharmony_ci if (status[0] != DPP_STATUS_OK) { 5988e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Configurator rejected configuration"); 5989e5b75505Sopenharmony_ci goto fail; 5990e5b75505Sopenharmony_ci } 5991e5b75505Sopenharmony_ci 5992e5b75505Sopenharmony_ci conf_obj = dpp_get_attr(unwrapped, unwrapped_len, 5993e5b75505Sopenharmony_ci DPP_ATTR_CONFIG_OBJ, &conf_obj_len); 5994e5b75505Sopenharmony_ci if (!conf_obj) { 5995e5b75505Sopenharmony_ci dpp_auth_fail(auth, 5996e5b75505Sopenharmony_ci "Missing required Configuration Object attribute"); 5997e5b75505Sopenharmony_ci goto fail; 5998e5b75505Sopenharmony_ci } 5999e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", 6000e5b75505Sopenharmony_ci conf_obj, conf_obj_len); 6001e5b75505Sopenharmony_ci if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0) 6002e5b75505Sopenharmony_ci goto fail; 6003e5b75505Sopenharmony_ci 6004e5b75505Sopenharmony_ci ret = 0; 6005e5b75505Sopenharmony_ci 6006e5b75505Sopenharmony_cifail: 6007e5b75505Sopenharmony_ci os_free(unwrapped); 6008e5b75505Sopenharmony_ci return ret; 6009e5b75505Sopenharmony_ci} 6010e5b75505Sopenharmony_ci 6011e5b75505Sopenharmony_ci 6012e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 6013e5b75505Sopenharmony_cienum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth, 6014e5b75505Sopenharmony_ci const u8 *hdr, 6015e5b75505Sopenharmony_ci const u8 *attr_start, size_t attr_len) 6016e5b75505Sopenharmony_ci{ 6017e5b75505Sopenharmony_ci const u8 *wrapped_data, *status, *e_nonce; 6018e5b75505Sopenharmony_ci u16 wrapped_data_len, status_len, e_nonce_len; 6019e5b75505Sopenharmony_ci const u8 *addr[2]; 6020e5b75505Sopenharmony_ci size_t len[2]; 6021e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 6022e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 6023e5b75505Sopenharmony_ci enum dpp_status_error ret = 256; 6024e5b75505Sopenharmony_ci 6025e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 6026e5b75505Sopenharmony_ci &wrapped_data_len); 6027e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 6028e5b75505Sopenharmony_ci dpp_auth_fail(auth, 6029e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 6030e5b75505Sopenharmony_ci goto fail; 6031e5b75505Sopenharmony_ci } 6032e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 6033e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 6034e5b75505Sopenharmony_ci 6035e5b75505Sopenharmony_ci attr_len = wrapped_data - 4 - attr_start; 6036e5b75505Sopenharmony_ci 6037e5b75505Sopenharmony_ci addr[0] = hdr; 6038e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 6039e5b75505Sopenharmony_ci addr[1] = attr_start; 6040e5b75505Sopenharmony_ci len[1] = attr_len; 6041e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 6042e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 6043e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 6044e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 6045e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 6046e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 6047e5b75505Sopenharmony_ci if (!unwrapped) 6048e5b75505Sopenharmony_ci goto fail; 6049e5b75505Sopenharmony_ci if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 6050e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 6051e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 6052e5b75505Sopenharmony_ci dpp_auth_fail(auth, "AES-SIV decryption failed"); 6053e5b75505Sopenharmony_ci goto fail; 6054e5b75505Sopenharmony_ci } 6055e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 6056e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 6057e5b75505Sopenharmony_ci 6058e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 6059e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 6060e5b75505Sopenharmony_ci goto fail; 6061e5b75505Sopenharmony_ci } 6062e5b75505Sopenharmony_ci 6063e5b75505Sopenharmony_ci e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 6064e5b75505Sopenharmony_ci DPP_ATTR_ENROLLEE_NONCE, 6065e5b75505Sopenharmony_ci &e_nonce_len); 6066e5b75505Sopenharmony_ci if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 6067e5b75505Sopenharmony_ci dpp_auth_fail(auth, 6068e5b75505Sopenharmony_ci "Missing or invalid Enrollee Nonce attribute"); 6069e5b75505Sopenharmony_ci goto fail; 6070e5b75505Sopenharmony_ci } 6071e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 6072e5b75505Sopenharmony_ci if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 6073e5b75505Sopenharmony_ci dpp_auth_fail(auth, "Enrollee Nonce mismatch"); 6074e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce", 6075e5b75505Sopenharmony_ci auth->e_nonce, e_nonce_len); 6076e5b75505Sopenharmony_ci goto fail; 6077e5b75505Sopenharmony_ci } 6078e5b75505Sopenharmony_ci 6079e5b75505Sopenharmony_ci status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS, 6080e5b75505Sopenharmony_ci &status_len); 6081e5b75505Sopenharmony_ci if (!status || status_len < 1) { 6082e5b75505Sopenharmony_ci dpp_auth_fail(auth, 6083e5b75505Sopenharmony_ci "Missing or invalid required DPP Status attribute"); 6084e5b75505Sopenharmony_ci goto fail; 6085e5b75505Sopenharmony_ci } 6086e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 6087e5b75505Sopenharmony_ci ret = status[0]; 6088e5b75505Sopenharmony_ci 6089e5b75505Sopenharmony_cifail: 6090e5b75505Sopenharmony_ci bin_clear_free(unwrapped, unwrapped_len); 6091e5b75505Sopenharmony_ci return ret; 6092e5b75505Sopenharmony_ci} 6093e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 6094e5b75505Sopenharmony_ci 6095e5b75505Sopenharmony_ci 6096e5b75505Sopenharmony_cistruct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth, 6097e5b75505Sopenharmony_ci enum dpp_status_error status) 6098e5b75505Sopenharmony_ci{ 6099e5b75505Sopenharmony_ci struct wpabuf *msg, *clear; 6100e5b75505Sopenharmony_ci size_t nonce_len, clear_len, attr_len; 6101e5b75505Sopenharmony_ci const u8 *addr[2]; 6102e5b75505Sopenharmony_ci size_t len[2]; 6103e5b75505Sopenharmony_ci u8 *wrapped; 6104e5b75505Sopenharmony_ci 6105e5b75505Sopenharmony_ci nonce_len = auth->curve->nonce_len; 6106e5b75505Sopenharmony_ci clear_len = 5 + 4 + nonce_len; 6107e5b75505Sopenharmony_ci attr_len = 4 + clear_len + AES_BLOCK_SIZE; 6108e5b75505Sopenharmony_ci clear = wpabuf_alloc(clear_len); 6109e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len); 6110e5b75505Sopenharmony_ci if (!clear || !msg) 6111e5b75505Sopenharmony_ci return NULL; 6112e5b75505Sopenharmony_ci 6113e5b75505Sopenharmony_ci /* DPP Status */ 6114e5b75505Sopenharmony_ci dpp_build_attr_status(clear, status); 6115e5b75505Sopenharmony_ci 6116e5b75505Sopenharmony_ci /* E-nonce */ 6117e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 6118e5b75505Sopenharmony_ci wpabuf_put_le16(clear, nonce_len); 6119e5b75505Sopenharmony_ci wpabuf_put_data(clear, auth->e_nonce, nonce_len); 6120e5b75505Sopenharmony_ci 6121e5b75505Sopenharmony_ci /* OUI, OUI type, Crypto Suite, DPP frame type */ 6122e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 6123e5b75505Sopenharmony_ci len[0] = 3 + 1 + 1 + 1; 6124e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 6125e5b75505Sopenharmony_ci 6126e5b75505Sopenharmony_ci /* Attributes before Wrapped Data (none) */ 6127e5b75505Sopenharmony_ci addr[1] = wpabuf_put(msg, 0); 6128e5b75505Sopenharmony_ci len[1] = 0; 6129e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 6130e5b75505Sopenharmony_ci 6131e5b75505Sopenharmony_ci /* Wrapped Data */ 6132e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 6133e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 6134e5b75505Sopenharmony_ci wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 6135e5b75505Sopenharmony_ci 6136e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 6137e5b75505Sopenharmony_ci if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 6138e5b75505Sopenharmony_ci wpabuf_head(clear), wpabuf_len(clear), 6139e5b75505Sopenharmony_ci 2, addr, len, wrapped) < 0) 6140e5b75505Sopenharmony_ci goto fail; 6141e5b75505Sopenharmony_ci 6142e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg); 6143e5b75505Sopenharmony_ci wpabuf_free(clear); 6144e5b75505Sopenharmony_ci return msg; 6145e5b75505Sopenharmony_cifail: 6146e5b75505Sopenharmony_ci wpabuf_free(clear); 6147e5b75505Sopenharmony_ci wpabuf_free(msg); 6148e5b75505Sopenharmony_ci return NULL; 6149e5b75505Sopenharmony_ci} 6150e5b75505Sopenharmony_ci 6151e5b75505Sopenharmony_ci 6152e5b75505Sopenharmony_civoid dpp_configurator_free(struct dpp_configurator *conf) 6153e5b75505Sopenharmony_ci{ 6154e5b75505Sopenharmony_ci if (!conf) 6155e5b75505Sopenharmony_ci return; 6156e5b75505Sopenharmony_ci EVP_PKEY_free(conf->csign); 6157e5b75505Sopenharmony_ci os_free(conf->kid); 6158e5b75505Sopenharmony_ci os_free(conf); 6159e5b75505Sopenharmony_ci} 6160e5b75505Sopenharmony_ci 6161e5b75505Sopenharmony_ci 6162e5b75505Sopenharmony_ciint dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf, 6163e5b75505Sopenharmony_ci size_t buflen) 6164e5b75505Sopenharmony_ci{ 6165e5b75505Sopenharmony_ci EC_KEY *eckey; 6166e5b75505Sopenharmony_ci int key_len, ret = -1; 6167e5b75505Sopenharmony_ci unsigned char *key = NULL; 6168e5b75505Sopenharmony_ci 6169e5b75505Sopenharmony_ci if (!conf->csign) 6170e5b75505Sopenharmony_ci return -1; 6171e5b75505Sopenharmony_ci 6172e5b75505Sopenharmony_ci eckey = EVP_PKEY_get1_EC_KEY(conf->csign); 6173e5b75505Sopenharmony_ci if (!eckey) 6174e5b75505Sopenharmony_ci return -1; 6175e5b75505Sopenharmony_ci 6176e5b75505Sopenharmony_ci key_len = i2d_ECPrivateKey(eckey, &key); 6177e5b75505Sopenharmony_ci if (key_len > 0) 6178e5b75505Sopenharmony_ci ret = wpa_snprintf_hex(buf, buflen, key, key_len); 6179e5b75505Sopenharmony_ci 6180e5b75505Sopenharmony_ci EC_KEY_free(eckey); 6181e5b75505Sopenharmony_ci OPENSSL_free(key); 6182e5b75505Sopenharmony_ci return ret; 6183e5b75505Sopenharmony_ci} 6184e5b75505Sopenharmony_ci 6185e5b75505Sopenharmony_ci 6186e5b75505Sopenharmony_cistruct dpp_configurator * 6187e5b75505Sopenharmony_cidpp_keygen_configurator(const char *curve, const u8 *privkey, 6188e5b75505Sopenharmony_ci size_t privkey_len) 6189e5b75505Sopenharmony_ci{ 6190e5b75505Sopenharmony_ci struct dpp_configurator *conf; 6191e5b75505Sopenharmony_ci struct wpabuf *csign_pub = NULL; 6192e5b75505Sopenharmony_ci u8 kid_hash[SHA256_MAC_LEN]; 6193e5b75505Sopenharmony_ci const u8 *addr[1]; 6194e5b75505Sopenharmony_ci size_t len[1]; 6195e5b75505Sopenharmony_ci 6196e5b75505Sopenharmony_ci conf = os_zalloc(sizeof(*conf)); 6197e5b75505Sopenharmony_ci if (!conf) 6198e5b75505Sopenharmony_ci return NULL; 6199e5b75505Sopenharmony_ci 6200e5b75505Sopenharmony_ci if (!curve) { 6201e5b75505Sopenharmony_ci conf->curve = &dpp_curves[0]; 6202e5b75505Sopenharmony_ci } else { 6203e5b75505Sopenharmony_ci conf->curve = dpp_get_curve_name(curve); 6204e5b75505Sopenharmony_ci if (!conf->curve) { 6205e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 6206e5b75505Sopenharmony_ci curve); 6207e5b75505Sopenharmony_ci os_free(conf); 6208e5b75505Sopenharmony_ci return NULL; 6209e5b75505Sopenharmony_ci } 6210e5b75505Sopenharmony_ci } 6211e5b75505Sopenharmony_ci if (privkey) 6212e5b75505Sopenharmony_ci conf->csign = dpp_set_keypair(&conf->curve, privkey, 6213e5b75505Sopenharmony_ci privkey_len); 6214e5b75505Sopenharmony_ci else 6215e5b75505Sopenharmony_ci conf->csign = dpp_gen_keypair(conf->curve); 6216e5b75505Sopenharmony_ci if (!conf->csign) 6217e5b75505Sopenharmony_ci goto fail; 6218e5b75505Sopenharmony_ci conf->own = 1; 6219e5b75505Sopenharmony_ci 6220e5b75505Sopenharmony_ci csign_pub = dpp_get_pubkey_point(conf->csign, 1); 6221e5b75505Sopenharmony_ci if (!csign_pub) { 6222e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key"); 6223e5b75505Sopenharmony_ci goto fail; 6224e5b75505Sopenharmony_ci } 6225e5b75505Sopenharmony_ci 6226e5b75505Sopenharmony_ci /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */ 6227e5b75505Sopenharmony_ci addr[0] = wpabuf_head(csign_pub); 6228e5b75505Sopenharmony_ci len[0] = wpabuf_len(csign_pub); 6229e5b75505Sopenharmony_ci if (sha256_vector(1, addr, len, kid_hash) < 0) { 6230e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6231e5b75505Sopenharmony_ci "DPP: Failed to derive kid for C-sign-key"); 6232e5b75505Sopenharmony_ci goto fail; 6233e5b75505Sopenharmony_ci } 6234e5b75505Sopenharmony_ci 6235e5b75505Sopenharmony_ci conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash), 6236e5b75505Sopenharmony_ci NULL, 0); 6237e5b75505Sopenharmony_ci if (!conf->kid) 6238e5b75505Sopenharmony_ci goto fail; 6239e5b75505Sopenharmony_ciout: 6240e5b75505Sopenharmony_ci wpabuf_free(csign_pub); 6241e5b75505Sopenharmony_ci return conf; 6242e5b75505Sopenharmony_cifail: 6243e5b75505Sopenharmony_ci dpp_configurator_free(conf); 6244e5b75505Sopenharmony_ci conf = NULL; 6245e5b75505Sopenharmony_ci goto out; 6246e5b75505Sopenharmony_ci} 6247e5b75505Sopenharmony_ci 6248e5b75505Sopenharmony_ci 6249e5b75505Sopenharmony_ciint dpp_configurator_own_config(struct dpp_authentication *auth, 6250e5b75505Sopenharmony_ci const char *curve, int ap) 6251e5b75505Sopenharmony_ci{ 6252e5b75505Sopenharmony_ci struct wpabuf *conf_obj; 6253e5b75505Sopenharmony_ci int ret = -1; 6254e5b75505Sopenharmony_ci 6255e5b75505Sopenharmony_ci if (!auth->conf) { 6256e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No configurator specified"); 6257e5b75505Sopenharmony_ci return -1; 6258e5b75505Sopenharmony_ci } 6259e5b75505Sopenharmony_ci 6260e5b75505Sopenharmony_ci if (!curve) { 6261e5b75505Sopenharmony_ci auth->curve = &dpp_curves[0]; 6262e5b75505Sopenharmony_ci } else { 6263e5b75505Sopenharmony_ci auth->curve = dpp_get_curve_name(curve); 6264e5b75505Sopenharmony_ci if (!auth->curve) { 6265e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 6266e5b75505Sopenharmony_ci curve); 6267e5b75505Sopenharmony_ci return -1; 6268e5b75505Sopenharmony_ci } 6269e5b75505Sopenharmony_ci } 6270e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6271e5b75505Sopenharmony_ci "DPP: Building own configuration/connector with curve %s", 6272e5b75505Sopenharmony_ci auth->curve->name); 6273e5b75505Sopenharmony_ci 6274e5b75505Sopenharmony_ci auth->own_protocol_key = dpp_gen_keypair(auth->curve); 6275e5b75505Sopenharmony_ci if (!auth->own_protocol_key) 6276e5b75505Sopenharmony_ci return -1; 6277e5b75505Sopenharmony_ci dpp_copy_netaccesskey(auth); 6278e5b75505Sopenharmony_ci auth->peer_protocol_key = auth->own_protocol_key; 6279e5b75505Sopenharmony_ci dpp_copy_csign(auth, auth->conf->csign); 6280e5b75505Sopenharmony_ci 6281e5b75505Sopenharmony_ci conf_obj = dpp_build_conf_obj(auth, ap); 6282e5b75505Sopenharmony_ci if (!conf_obj) 6283e5b75505Sopenharmony_ci goto fail; 6284e5b75505Sopenharmony_ci ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj), 6285e5b75505Sopenharmony_ci wpabuf_len(conf_obj)); 6286e5b75505Sopenharmony_cifail: 6287e5b75505Sopenharmony_ci wpabuf_free(conf_obj); 6288e5b75505Sopenharmony_ci auth->peer_protocol_key = NULL; 6289e5b75505Sopenharmony_ci return ret; 6290e5b75505Sopenharmony_ci} 6291e5b75505Sopenharmony_ci 6292e5b75505Sopenharmony_ci 6293e5b75505Sopenharmony_cistatic int dpp_compatible_netrole(const char *role1, const char *role2) 6294e5b75505Sopenharmony_ci{ 6295e5b75505Sopenharmony_ci return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) || 6296e5b75505Sopenharmony_ci (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0); 6297e5b75505Sopenharmony_ci} 6298e5b75505Sopenharmony_ci 6299e5b75505Sopenharmony_ci 6300e5b75505Sopenharmony_cistatic int dpp_connector_compatible_group(struct json_token *root, 6301e5b75505Sopenharmony_ci const char *group_id, 6302e5b75505Sopenharmony_ci const char *net_role) 6303e5b75505Sopenharmony_ci{ 6304e5b75505Sopenharmony_ci struct json_token *groups, *token; 6305e5b75505Sopenharmony_ci 6306e5b75505Sopenharmony_ci groups = json_get_member(root, "groups"); 6307e5b75505Sopenharmony_ci if (!groups || groups->type != JSON_ARRAY) 6308e5b75505Sopenharmony_ci return 0; 6309e5b75505Sopenharmony_ci 6310e5b75505Sopenharmony_ci for (token = groups->child; token; token = token->sibling) { 6311e5b75505Sopenharmony_ci struct json_token *id, *role; 6312e5b75505Sopenharmony_ci 6313e5b75505Sopenharmony_ci id = json_get_member(token, "groupId"); 6314e5b75505Sopenharmony_ci if (!id || id->type != JSON_STRING) 6315e5b75505Sopenharmony_ci continue; 6316e5b75505Sopenharmony_ci 6317e5b75505Sopenharmony_ci role = json_get_member(token, "netRole"); 6318e5b75505Sopenharmony_ci if (!role || role->type != JSON_STRING) 6319e5b75505Sopenharmony_ci continue; 6320e5b75505Sopenharmony_ci 6321e5b75505Sopenharmony_ci if (os_strcmp(id->string, "*") != 0 && 6322e5b75505Sopenharmony_ci os_strcmp(group_id, "*") != 0 && 6323e5b75505Sopenharmony_ci os_strcmp(id->string, group_id) != 0) 6324e5b75505Sopenharmony_ci continue; 6325e5b75505Sopenharmony_ci 6326e5b75505Sopenharmony_ci if (dpp_compatible_netrole(role->string, net_role)) 6327e5b75505Sopenharmony_ci return 1; 6328e5b75505Sopenharmony_ci } 6329e5b75505Sopenharmony_ci 6330e5b75505Sopenharmony_ci return 0; 6331e5b75505Sopenharmony_ci} 6332e5b75505Sopenharmony_ci 6333e5b75505Sopenharmony_ci 6334e5b75505Sopenharmony_cistatic int dpp_connector_match_groups(struct json_token *own_root, 6335e5b75505Sopenharmony_ci struct json_token *peer_root) 6336e5b75505Sopenharmony_ci{ 6337e5b75505Sopenharmony_ci struct json_token *groups, *token; 6338e5b75505Sopenharmony_ci 6339e5b75505Sopenharmony_ci groups = json_get_member(peer_root, "groups"); 6340e5b75505Sopenharmony_ci if (!groups || groups->type != JSON_ARRAY) { 6341e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No peer groups array found"); 6342e5b75505Sopenharmony_ci return 0; 6343e5b75505Sopenharmony_ci } 6344e5b75505Sopenharmony_ci 6345e5b75505Sopenharmony_ci for (token = groups->child; token; token = token->sibling) { 6346e5b75505Sopenharmony_ci struct json_token *id, *role; 6347e5b75505Sopenharmony_ci 6348e5b75505Sopenharmony_ci id = json_get_member(token, "groupId"); 6349e5b75505Sopenharmony_ci if (!id || id->type != JSON_STRING) { 6350e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6351e5b75505Sopenharmony_ci "DPP: Missing peer groupId string"); 6352e5b75505Sopenharmony_ci continue; 6353e5b75505Sopenharmony_ci } 6354e5b75505Sopenharmony_ci 6355e5b75505Sopenharmony_ci role = json_get_member(token, "netRole"); 6356e5b75505Sopenharmony_ci if (!role || role->type != JSON_STRING) { 6357e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6358e5b75505Sopenharmony_ci "DPP: Missing peer groups::netRole string"); 6359e5b75505Sopenharmony_ci continue; 6360e5b75505Sopenharmony_ci } 6361e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6362e5b75505Sopenharmony_ci "DPP: peer connector group: groupId='%s' netRole='%s'", 6363e5b75505Sopenharmony_ci id->string, role->string); 6364e5b75505Sopenharmony_ci if (dpp_connector_compatible_group(own_root, id->string, 6365e5b75505Sopenharmony_ci role->string)) { 6366e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6367e5b75505Sopenharmony_ci "DPP: Compatible group/netRole in own connector"); 6368e5b75505Sopenharmony_ci return 1; 6369e5b75505Sopenharmony_ci } 6370e5b75505Sopenharmony_ci } 6371e5b75505Sopenharmony_ci 6372e5b75505Sopenharmony_ci return 0; 6373e5b75505Sopenharmony_ci} 6374e5b75505Sopenharmony_ci 6375e5b75505Sopenharmony_ci 6376e5b75505Sopenharmony_cistatic int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, 6377e5b75505Sopenharmony_ci unsigned int hash_len) 6378e5b75505Sopenharmony_ci{ 6379e5b75505Sopenharmony_ci u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 6380e5b75505Sopenharmony_ci const char *info = "DPP PMK"; 6381e5b75505Sopenharmony_ci int res; 6382e5b75505Sopenharmony_ci 6383e5b75505Sopenharmony_ci /* PMK = HKDF(<>, "DPP PMK", N.x) */ 6384e5b75505Sopenharmony_ci 6385e5b75505Sopenharmony_ci /* HKDF-Extract(<>, N.x) */ 6386e5b75505Sopenharmony_ci os_memset(salt, 0, hash_len); 6387e5b75505Sopenharmony_ci if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0) 6388e5b75505Sopenharmony_ci return -1; 6389e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", 6390e5b75505Sopenharmony_ci prk, hash_len); 6391e5b75505Sopenharmony_ci 6392e5b75505Sopenharmony_ci /* HKDF-Expand(PRK, info, L) */ 6393e5b75505Sopenharmony_ci res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len); 6394e5b75505Sopenharmony_ci os_memset(prk, 0, hash_len); 6395e5b75505Sopenharmony_ci if (res < 0) 6396e5b75505Sopenharmony_ci return -1; 6397e5b75505Sopenharmony_ci 6398e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)", 6399e5b75505Sopenharmony_ci pmk, hash_len); 6400e5b75505Sopenharmony_ci return 0; 6401e5b75505Sopenharmony_ci} 6402e5b75505Sopenharmony_ci 6403e5b75505Sopenharmony_ci 6404e5b75505Sopenharmony_cistatic int dpp_derive_pmkid(const struct dpp_curve_params *curve, 6405e5b75505Sopenharmony_ci EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid) 6406e5b75505Sopenharmony_ci{ 6407e5b75505Sopenharmony_ci struct wpabuf *nkx, *pkx; 6408e5b75505Sopenharmony_ci int ret = -1, res; 6409e5b75505Sopenharmony_ci const u8 *addr[2]; 6410e5b75505Sopenharmony_ci size_t len[2]; 6411e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 6412e5b75505Sopenharmony_ci 6413e5b75505Sopenharmony_ci /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ 6414e5b75505Sopenharmony_ci nkx = dpp_get_pubkey_point(own_key, 0); 6415e5b75505Sopenharmony_ci pkx = dpp_get_pubkey_point(peer_key, 0); 6416e5b75505Sopenharmony_ci if (!nkx || !pkx) 6417e5b75505Sopenharmony_ci goto fail; 6418e5b75505Sopenharmony_ci addr[0] = wpabuf_head(nkx); 6419e5b75505Sopenharmony_ci len[0] = wpabuf_len(nkx) / 2; 6420e5b75505Sopenharmony_ci addr[1] = wpabuf_head(pkx); 6421e5b75505Sopenharmony_ci len[1] = wpabuf_len(pkx) / 2; 6422e5b75505Sopenharmony_ci if (len[0] != len[1]) 6423e5b75505Sopenharmony_ci goto fail; 6424e5b75505Sopenharmony_ci if (os_memcmp(addr[0], addr[1], len[0]) > 0) { 6425e5b75505Sopenharmony_ci addr[0] = wpabuf_head(pkx); 6426e5b75505Sopenharmony_ci addr[1] = wpabuf_head(nkx); 6427e5b75505Sopenharmony_ci } 6428e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]); 6429e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]); 6430e5b75505Sopenharmony_ci res = sha256_vector(2, addr, len, hash); 6431e5b75505Sopenharmony_ci if (res < 0) 6432e5b75505Sopenharmony_ci goto fail; 6433e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN); 6434e5b75505Sopenharmony_ci os_memcpy(pmkid, hash, PMKID_LEN); 6435e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN); 6436e5b75505Sopenharmony_ci ret = 0; 6437e5b75505Sopenharmony_cifail: 6438e5b75505Sopenharmony_ci wpabuf_free(nkx); 6439e5b75505Sopenharmony_ci wpabuf_free(pkx); 6440e5b75505Sopenharmony_ci return ret; 6441e5b75505Sopenharmony_ci} 6442e5b75505Sopenharmony_ci 6443e5b75505Sopenharmony_ci 6444e5b75505Sopenharmony_cienum dpp_status_error 6445e5b75505Sopenharmony_cidpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, 6446e5b75505Sopenharmony_ci const u8 *net_access_key, size_t net_access_key_len, 6447e5b75505Sopenharmony_ci const u8 *csign_key, size_t csign_key_len, 6448e5b75505Sopenharmony_ci const u8 *peer_connector, size_t peer_connector_len, 6449e5b75505Sopenharmony_ci os_time_t *expiry) 6450e5b75505Sopenharmony_ci{ 6451e5b75505Sopenharmony_ci struct json_token *root = NULL, *netkey, *token; 6452e5b75505Sopenharmony_ci struct json_token *own_root = NULL; 6453e5b75505Sopenharmony_ci enum dpp_status_error ret = 255, res; 6454e5b75505Sopenharmony_ci EVP_PKEY *own_key = NULL, *peer_key = NULL; 6455e5b75505Sopenharmony_ci struct wpabuf *own_key_pub = NULL; 6456e5b75505Sopenharmony_ci const struct dpp_curve_params *curve, *own_curve; 6457e5b75505Sopenharmony_ci struct dpp_signed_connector_info info; 6458e5b75505Sopenharmony_ci const unsigned char *p; 6459e5b75505Sopenharmony_ci EVP_PKEY *csign = NULL; 6460e5b75505Sopenharmony_ci char *signed_connector = NULL; 6461e5b75505Sopenharmony_ci const char *pos, *end; 6462e5b75505Sopenharmony_ci unsigned char *own_conn = NULL; 6463e5b75505Sopenharmony_ci size_t own_conn_len; 6464e5b75505Sopenharmony_ci size_t Nx_len; 6465e5b75505Sopenharmony_ci u8 Nx[DPP_MAX_SHARED_SECRET_LEN]; 6466e5b75505Sopenharmony_ci 6467e5b75505Sopenharmony_ci os_memset(intro, 0, sizeof(*intro)); 6468e5b75505Sopenharmony_ci os_memset(&info, 0, sizeof(info)); 6469e5b75505Sopenharmony_ci if (expiry) 6470e5b75505Sopenharmony_ci *expiry = 0; 6471e5b75505Sopenharmony_ci 6472e5b75505Sopenharmony_ci p = csign_key; 6473e5b75505Sopenharmony_ci csign = d2i_PUBKEY(NULL, &p, csign_key_len); 6474e5b75505Sopenharmony_ci if (!csign) { 6475e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 6476e5b75505Sopenharmony_ci "DPP: Failed to parse local C-sign-key information"); 6477e5b75505Sopenharmony_ci goto fail; 6478e5b75505Sopenharmony_ci } 6479e5b75505Sopenharmony_ci 6480e5b75505Sopenharmony_ci own_key = dpp_set_keypair(&own_curve, net_access_key, 6481e5b75505Sopenharmony_ci net_access_key_len); 6482e5b75505Sopenharmony_ci if (!own_key) { 6483e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 6484e5b75505Sopenharmony_ci goto fail; 6485e5b75505Sopenharmony_ci } 6486e5b75505Sopenharmony_ci 6487e5b75505Sopenharmony_ci pos = os_strchr(own_connector, '.'); 6488e5b75505Sopenharmony_ci if (!pos) { 6489e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)"); 6490e5b75505Sopenharmony_ci goto fail; 6491e5b75505Sopenharmony_ci } 6492e5b75505Sopenharmony_ci pos++; 6493e5b75505Sopenharmony_ci end = os_strchr(pos, '.'); 6494e5b75505Sopenharmony_ci if (!end) { 6495e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)"); 6496e5b75505Sopenharmony_ci goto fail; 6497e5b75505Sopenharmony_ci } 6498e5b75505Sopenharmony_ci own_conn = base64_url_decode((const unsigned char *) pos, 6499e5b75505Sopenharmony_ci end - pos, &own_conn_len); 6500e5b75505Sopenharmony_ci if (!own_conn) { 6501e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6502e5b75505Sopenharmony_ci "DPP: Failed to base64url decode own signedConnector JWS Payload"); 6503e5b75505Sopenharmony_ci goto fail; 6504e5b75505Sopenharmony_ci } 6505e5b75505Sopenharmony_ci 6506e5b75505Sopenharmony_ci own_root = json_parse((const char *) own_conn, own_conn_len); 6507e5b75505Sopenharmony_ci if (!own_root) { 6508e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector"); 6509e5b75505Sopenharmony_ci goto fail; 6510e5b75505Sopenharmony_ci } 6511e5b75505Sopenharmony_ci 6512e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector", 6513e5b75505Sopenharmony_ci peer_connector, peer_connector_len); 6514e5b75505Sopenharmony_ci signed_connector = os_malloc(peer_connector_len + 1); 6515e5b75505Sopenharmony_ci if (!signed_connector) 6516e5b75505Sopenharmony_ci goto fail; 6517e5b75505Sopenharmony_ci os_memcpy(signed_connector, peer_connector, peer_connector_len); 6518e5b75505Sopenharmony_ci signed_connector[peer_connector_len] = '\0'; 6519e5b75505Sopenharmony_ci 6520e5b75505Sopenharmony_ci res = dpp_process_signed_connector(&info, csign, signed_connector); 6521e5b75505Sopenharmony_ci if (res != DPP_STATUS_OK) { 6522e5b75505Sopenharmony_ci ret = res; 6523e5b75505Sopenharmony_ci goto fail; 6524e5b75505Sopenharmony_ci } 6525e5b75505Sopenharmony_ci 6526e5b75505Sopenharmony_ci root = json_parse((const char *) info.payload, info.payload_len); 6527e5b75505Sopenharmony_ci if (!root) { 6528e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 6529e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 6530e5b75505Sopenharmony_ci goto fail; 6531e5b75505Sopenharmony_ci } 6532e5b75505Sopenharmony_ci 6533e5b75505Sopenharmony_ci if (!dpp_connector_match_groups(own_root, root)) { 6534e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6535e5b75505Sopenharmony_ci "DPP: Peer connector does not include compatible group netrole with own connector"); 6536e5b75505Sopenharmony_ci ret = DPP_STATUS_NO_MATCH; 6537e5b75505Sopenharmony_ci goto fail; 6538e5b75505Sopenharmony_ci } 6539e5b75505Sopenharmony_ci 6540e5b75505Sopenharmony_ci token = json_get_member(root, "expiry"); 6541e5b75505Sopenharmony_ci if (!token || token->type != JSON_STRING) { 6542e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6543e5b75505Sopenharmony_ci "DPP: No expiry string found - connector does not expire"); 6544e5b75505Sopenharmony_ci } else { 6545e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 6546e5b75505Sopenharmony_ci if (dpp_key_expired(token->string, expiry)) { 6547e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6548e5b75505Sopenharmony_ci "DPP: Connector (netAccessKey) has expired"); 6549e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 6550e5b75505Sopenharmony_ci goto fail; 6551e5b75505Sopenharmony_ci } 6552e5b75505Sopenharmony_ci } 6553e5b75505Sopenharmony_ci 6554e5b75505Sopenharmony_ci netkey = json_get_member(root, "netAccessKey"); 6555e5b75505Sopenharmony_ci if (!netkey || netkey->type != JSON_OBJECT) { 6556e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 6557e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 6558e5b75505Sopenharmony_ci goto fail; 6559e5b75505Sopenharmony_ci } 6560e5b75505Sopenharmony_ci 6561e5b75505Sopenharmony_ci peer_key = dpp_parse_jwk(netkey, &curve); 6562e5b75505Sopenharmony_ci if (!peer_key) { 6563e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 6564e5b75505Sopenharmony_ci goto fail; 6565e5b75505Sopenharmony_ci } 6566e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Received netAccessKey", peer_key); 6567e5b75505Sopenharmony_ci 6568e5b75505Sopenharmony_ci if (own_curve != curve) { 6569e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 6570e5b75505Sopenharmony_ci "DPP: Mismatching netAccessKey curves (%s != %s)", 6571e5b75505Sopenharmony_ci own_curve->name, curve->name); 6572e5b75505Sopenharmony_ci ret = DPP_STATUS_INVALID_CONNECTOR; 6573e5b75505Sopenharmony_ci goto fail; 6574e5b75505Sopenharmony_ci } 6575e5b75505Sopenharmony_ci 6576e5b75505Sopenharmony_ci /* ECDH: N = nk * PK */ 6577e5b75505Sopenharmony_ci if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0) 6578e5b75505Sopenharmony_ci goto fail; 6579e5b75505Sopenharmony_ci 6580e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 6581e5b75505Sopenharmony_ci Nx, Nx_len); 6582e5b75505Sopenharmony_ci 6583e5b75505Sopenharmony_ci /* PMK = HKDF(<>, "DPP PMK", N.x) */ 6584e5b75505Sopenharmony_ci if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) { 6585e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK"); 6586e5b75505Sopenharmony_ci goto fail; 6587e5b75505Sopenharmony_ci } 6588e5b75505Sopenharmony_ci intro->pmk_len = curve->hash_len; 6589e5b75505Sopenharmony_ci 6590e5b75505Sopenharmony_ci /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ 6591e5b75505Sopenharmony_ci if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) { 6592e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID"); 6593e5b75505Sopenharmony_ci goto fail; 6594e5b75505Sopenharmony_ci } 6595e5b75505Sopenharmony_ci 6596e5b75505Sopenharmony_ci ret = DPP_STATUS_OK; 6597e5b75505Sopenharmony_cifail: 6598e5b75505Sopenharmony_ci if (ret != DPP_STATUS_OK) 6599e5b75505Sopenharmony_ci os_memset(intro, 0, sizeof(*intro)); 6600e5b75505Sopenharmony_ci os_memset(Nx, 0, sizeof(Nx)); 6601e5b75505Sopenharmony_ci os_free(own_conn); 6602e5b75505Sopenharmony_ci os_free(signed_connector); 6603e5b75505Sopenharmony_ci os_free(info.payload); 6604e5b75505Sopenharmony_ci EVP_PKEY_free(own_key); 6605e5b75505Sopenharmony_ci wpabuf_free(own_key_pub); 6606e5b75505Sopenharmony_ci EVP_PKEY_free(peer_key); 6607e5b75505Sopenharmony_ci EVP_PKEY_free(csign); 6608e5b75505Sopenharmony_ci json_free(root); 6609e5b75505Sopenharmony_ci json_free(own_root); 6610e5b75505Sopenharmony_ci return ret; 6611e5b75505Sopenharmony_ci} 6612e5b75505Sopenharmony_ci 6613e5b75505Sopenharmony_ci 6614e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, 6615e5b75505Sopenharmony_ci int init) 6616e5b75505Sopenharmony_ci{ 6617e5b75505Sopenharmony_ci EC_GROUP *group; 6618e5b75505Sopenharmony_ci size_t len = curve->prime_len; 6619e5b75505Sopenharmony_ci const u8 *x, *y; 6620e5b75505Sopenharmony_ci EVP_PKEY *res; 6621e5b75505Sopenharmony_ci 6622e5b75505Sopenharmony_ci switch (curve->ike_group) { 6623e5b75505Sopenharmony_ci case 19: 6624e5b75505Sopenharmony_ci x = init ? pkex_init_x_p256 : pkex_resp_x_p256; 6625e5b75505Sopenharmony_ci y = init ? pkex_init_y_p256 : pkex_resp_y_p256; 6626e5b75505Sopenharmony_ci break; 6627e5b75505Sopenharmony_ci case 20: 6628e5b75505Sopenharmony_ci x = init ? pkex_init_x_p384 : pkex_resp_x_p384; 6629e5b75505Sopenharmony_ci y = init ? pkex_init_y_p384 : pkex_resp_y_p384; 6630e5b75505Sopenharmony_ci break; 6631e5b75505Sopenharmony_ci case 21: 6632e5b75505Sopenharmony_ci x = init ? pkex_init_x_p521 : pkex_resp_x_p521; 6633e5b75505Sopenharmony_ci y = init ? pkex_init_y_p521 : pkex_resp_y_p521; 6634e5b75505Sopenharmony_ci break; 6635e5b75505Sopenharmony_ci case 28: 6636e5b75505Sopenharmony_ci x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1; 6637e5b75505Sopenharmony_ci y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1; 6638e5b75505Sopenharmony_ci break; 6639e5b75505Sopenharmony_ci case 29: 6640e5b75505Sopenharmony_ci x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1; 6641e5b75505Sopenharmony_ci y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1; 6642e5b75505Sopenharmony_ci break; 6643e5b75505Sopenharmony_ci case 30: 6644e5b75505Sopenharmony_ci x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1; 6645e5b75505Sopenharmony_ci y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1; 6646e5b75505Sopenharmony_ci break; 6647e5b75505Sopenharmony_ci default: 6648e5b75505Sopenharmony_ci return NULL; 6649e5b75505Sopenharmony_ci } 6650e5b75505Sopenharmony_ci 6651e5b75505Sopenharmony_ci group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 6652e5b75505Sopenharmony_ci if (!group) 6653e5b75505Sopenharmony_ci return NULL; 6654e5b75505Sopenharmony_ci res = dpp_set_pubkey_point_group(group, x, y, len); 6655e5b75505Sopenharmony_ci EC_GROUP_free(group); 6656e5b75505Sopenharmony_ci return res; 6657e5b75505Sopenharmony_ci} 6658e5b75505Sopenharmony_ci 6659e5b75505Sopenharmony_ci 6660e5b75505Sopenharmony_cistatic EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, 6661e5b75505Sopenharmony_ci const u8 *mac_init, const char *code, 6662e5b75505Sopenharmony_ci const char *identifier, BN_CTX *bnctx, 6663e5b75505Sopenharmony_ci EC_GROUP **ret_group) 6664e5b75505Sopenharmony_ci{ 6665e5b75505Sopenharmony_ci u8 hash[DPP_MAX_HASH_LEN]; 6666e5b75505Sopenharmony_ci const u8 *addr[3]; 6667e5b75505Sopenharmony_ci size_t len[3]; 6668e5b75505Sopenharmony_ci unsigned int num_elem = 0; 6669e5b75505Sopenharmony_ci EC_POINT *Qi = NULL; 6670e5b75505Sopenharmony_ci EVP_PKEY *Pi = NULL; 6671e5b75505Sopenharmony_ci EC_KEY *Pi_ec = NULL; 6672e5b75505Sopenharmony_ci const EC_POINT *Pi_point; 6673e5b75505Sopenharmony_ci BIGNUM *hash_bn = NULL; 6674e5b75505Sopenharmony_ci const EC_GROUP *group = NULL; 6675e5b75505Sopenharmony_ci EC_GROUP *group2 = NULL; 6676e5b75505Sopenharmony_ci 6677e5b75505Sopenharmony_ci /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 6678e5b75505Sopenharmony_ci 6679e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init)); 6680e5b75505Sopenharmony_ci addr[num_elem] = mac_init; 6681e5b75505Sopenharmony_ci len[num_elem] = ETH_ALEN; 6682e5b75505Sopenharmony_ci num_elem++; 6683e5b75505Sopenharmony_ci if (identifier) { 6684e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", 6685e5b75505Sopenharmony_ci identifier); 6686e5b75505Sopenharmony_ci addr[num_elem] = (const u8 *) identifier; 6687e5b75505Sopenharmony_ci len[num_elem] = os_strlen(identifier); 6688e5b75505Sopenharmony_ci num_elem++; 6689e5b75505Sopenharmony_ci } 6690e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); 6691e5b75505Sopenharmony_ci addr[num_elem] = (const u8 *) code; 6692e5b75505Sopenharmony_ci len[num_elem] = os_strlen(code); 6693e5b75505Sopenharmony_ci num_elem++; 6694e5b75505Sopenharmony_ci if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) 6695e5b75505Sopenharmony_ci goto fail; 6696e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, 6697e5b75505Sopenharmony_ci "DPP: H(MAC-Initiator | [identifier |] code)", 6698e5b75505Sopenharmony_ci hash, curve->hash_len); 6699e5b75505Sopenharmony_ci Pi = dpp_pkex_get_role_elem(curve, 1); 6700e5b75505Sopenharmony_ci if (!Pi) 6701e5b75505Sopenharmony_ci goto fail; 6702e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Pi", Pi); 6703e5b75505Sopenharmony_ci Pi_ec = EVP_PKEY_get1_EC_KEY(Pi); 6704e5b75505Sopenharmony_ci if (!Pi_ec) 6705e5b75505Sopenharmony_ci goto fail; 6706e5b75505Sopenharmony_ci Pi_point = EC_KEY_get0_public_key(Pi_ec); 6707e5b75505Sopenharmony_ci 6708e5b75505Sopenharmony_ci group = EC_KEY_get0_group(Pi_ec); 6709e5b75505Sopenharmony_ci if (!group) 6710e5b75505Sopenharmony_ci goto fail; 6711e5b75505Sopenharmony_ci group2 = EC_GROUP_dup(group); 6712e5b75505Sopenharmony_ci if (!group2) 6713e5b75505Sopenharmony_ci goto fail; 6714e5b75505Sopenharmony_ci Qi = EC_POINT_new(group2); 6715e5b75505Sopenharmony_ci if (!Qi) { 6716e5b75505Sopenharmony_ci EC_GROUP_free(group2); 6717e5b75505Sopenharmony_ci goto fail; 6718e5b75505Sopenharmony_ci } 6719e5b75505Sopenharmony_ci hash_bn = BN_bin2bn(hash, curve->hash_len, NULL); 6720e5b75505Sopenharmony_ci if (!hash_bn || 6721e5b75505Sopenharmony_ci EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1) 6722e5b75505Sopenharmony_ci goto fail; 6723e5b75505Sopenharmony_ci if (EC_POINT_is_at_infinity(group, Qi)) { 6724e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity"); 6725e5b75505Sopenharmony_ci goto fail; 6726e5b75505Sopenharmony_ci } 6727e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: Qi", group, Qi); 6728e5b75505Sopenharmony_ciout: 6729e5b75505Sopenharmony_ci EC_KEY_free(Pi_ec); 6730e5b75505Sopenharmony_ci EVP_PKEY_free(Pi); 6731e5b75505Sopenharmony_ci BN_clear_free(hash_bn); 6732e5b75505Sopenharmony_ci if (ret_group && Qi) 6733e5b75505Sopenharmony_ci *ret_group = group2; 6734e5b75505Sopenharmony_ci else 6735e5b75505Sopenharmony_ci EC_GROUP_free(group2); 6736e5b75505Sopenharmony_ci return Qi; 6737e5b75505Sopenharmony_cifail: 6738e5b75505Sopenharmony_ci EC_POINT_free(Qi); 6739e5b75505Sopenharmony_ci Qi = NULL; 6740e5b75505Sopenharmony_ci goto out; 6741e5b75505Sopenharmony_ci} 6742e5b75505Sopenharmony_ci 6743e5b75505Sopenharmony_ci 6744e5b75505Sopenharmony_cistatic EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, 6745e5b75505Sopenharmony_ci const u8 *mac_resp, const char *code, 6746e5b75505Sopenharmony_ci const char *identifier, BN_CTX *bnctx, 6747e5b75505Sopenharmony_ci EC_GROUP **ret_group) 6748e5b75505Sopenharmony_ci{ 6749e5b75505Sopenharmony_ci u8 hash[DPP_MAX_HASH_LEN]; 6750e5b75505Sopenharmony_ci const u8 *addr[3]; 6751e5b75505Sopenharmony_ci size_t len[3]; 6752e5b75505Sopenharmony_ci unsigned int num_elem = 0; 6753e5b75505Sopenharmony_ci EC_POINT *Qr = NULL; 6754e5b75505Sopenharmony_ci EVP_PKEY *Pr = NULL; 6755e5b75505Sopenharmony_ci EC_KEY *Pr_ec = NULL; 6756e5b75505Sopenharmony_ci const EC_POINT *Pr_point; 6757e5b75505Sopenharmony_ci BIGNUM *hash_bn = NULL; 6758e5b75505Sopenharmony_ci const EC_GROUP *group = NULL; 6759e5b75505Sopenharmony_ci EC_GROUP *group2 = NULL; 6760e5b75505Sopenharmony_ci 6761e5b75505Sopenharmony_ci /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ 6762e5b75505Sopenharmony_ci 6763e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp)); 6764e5b75505Sopenharmony_ci addr[num_elem] = mac_resp; 6765e5b75505Sopenharmony_ci len[num_elem] = ETH_ALEN; 6766e5b75505Sopenharmony_ci num_elem++; 6767e5b75505Sopenharmony_ci if (identifier) { 6768e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", 6769e5b75505Sopenharmony_ci identifier); 6770e5b75505Sopenharmony_ci addr[num_elem] = (const u8 *) identifier; 6771e5b75505Sopenharmony_ci len[num_elem] = os_strlen(identifier); 6772e5b75505Sopenharmony_ci num_elem++; 6773e5b75505Sopenharmony_ci } 6774e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); 6775e5b75505Sopenharmony_ci addr[num_elem] = (const u8 *) code; 6776e5b75505Sopenharmony_ci len[num_elem] = os_strlen(code); 6777e5b75505Sopenharmony_ci num_elem++; 6778e5b75505Sopenharmony_ci if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) 6779e5b75505Sopenharmony_ci goto fail; 6780e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, 6781e5b75505Sopenharmony_ci "DPP: H(MAC-Responder | [identifier |] code)", 6782e5b75505Sopenharmony_ci hash, curve->hash_len); 6783e5b75505Sopenharmony_ci Pr = dpp_pkex_get_role_elem(curve, 0); 6784e5b75505Sopenharmony_ci if (!Pr) 6785e5b75505Sopenharmony_ci goto fail; 6786e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Pr", Pr); 6787e5b75505Sopenharmony_ci Pr_ec = EVP_PKEY_get1_EC_KEY(Pr); 6788e5b75505Sopenharmony_ci if (!Pr_ec) 6789e5b75505Sopenharmony_ci goto fail; 6790e5b75505Sopenharmony_ci Pr_point = EC_KEY_get0_public_key(Pr_ec); 6791e5b75505Sopenharmony_ci 6792e5b75505Sopenharmony_ci group = EC_KEY_get0_group(Pr_ec); 6793e5b75505Sopenharmony_ci if (!group) 6794e5b75505Sopenharmony_ci goto fail; 6795e5b75505Sopenharmony_ci group2 = EC_GROUP_dup(group); 6796e5b75505Sopenharmony_ci if (!group2) 6797e5b75505Sopenharmony_ci goto fail; 6798e5b75505Sopenharmony_ci Qr = EC_POINT_new(group2); 6799e5b75505Sopenharmony_ci if (!Qr) { 6800e5b75505Sopenharmony_ci EC_GROUP_free(group2); 6801e5b75505Sopenharmony_ci goto fail; 6802e5b75505Sopenharmony_ci } 6803e5b75505Sopenharmony_ci hash_bn = BN_bin2bn(hash, curve->hash_len, NULL); 6804e5b75505Sopenharmony_ci if (!hash_bn || 6805e5b75505Sopenharmony_ci EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1) 6806e5b75505Sopenharmony_ci goto fail; 6807e5b75505Sopenharmony_ci if (EC_POINT_is_at_infinity(group, Qr)) { 6808e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity"); 6809e5b75505Sopenharmony_ci goto fail; 6810e5b75505Sopenharmony_ci } 6811e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: Qr", group, Qr); 6812e5b75505Sopenharmony_ciout: 6813e5b75505Sopenharmony_ci EC_KEY_free(Pr_ec); 6814e5b75505Sopenharmony_ci EVP_PKEY_free(Pr); 6815e5b75505Sopenharmony_ci BN_clear_free(hash_bn); 6816e5b75505Sopenharmony_ci if (ret_group && Qr) 6817e5b75505Sopenharmony_ci *ret_group = group2; 6818e5b75505Sopenharmony_ci else 6819e5b75505Sopenharmony_ci EC_GROUP_free(group2); 6820e5b75505Sopenharmony_ci return Qr; 6821e5b75505Sopenharmony_cifail: 6822e5b75505Sopenharmony_ci EC_POINT_free(Qr); 6823e5b75505Sopenharmony_ci Qr = NULL; 6824e5b75505Sopenharmony_ci goto out; 6825e5b75505Sopenharmony_ci} 6826e5b75505Sopenharmony_ci 6827e5b75505Sopenharmony_ci 6828e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6829e5b75505Sopenharmony_cistatic int dpp_test_gen_invalid_key(struct wpabuf *msg, 6830e5b75505Sopenharmony_ci const struct dpp_curve_params *curve) 6831e5b75505Sopenharmony_ci{ 6832e5b75505Sopenharmony_ci BN_CTX *ctx; 6833e5b75505Sopenharmony_ci BIGNUM *x, *y; 6834e5b75505Sopenharmony_ci int ret = -1; 6835e5b75505Sopenharmony_ci EC_GROUP *group; 6836e5b75505Sopenharmony_ci EC_POINT *point; 6837e5b75505Sopenharmony_ci 6838e5b75505Sopenharmony_ci group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 6839e5b75505Sopenharmony_ci if (!group) 6840e5b75505Sopenharmony_ci return -1; 6841e5b75505Sopenharmony_ci 6842e5b75505Sopenharmony_ci ctx = BN_CTX_new(); 6843e5b75505Sopenharmony_ci point = EC_POINT_new(group); 6844e5b75505Sopenharmony_ci x = BN_new(); 6845e5b75505Sopenharmony_ci y = BN_new(); 6846e5b75505Sopenharmony_ci if (!ctx || !point || !x || !y) 6847e5b75505Sopenharmony_ci goto fail; 6848e5b75505Sopenharmony_ci 6849e5b75505Sopenharmony_ci if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1) 6850e5b75505Sopenharmony_ci goto fail; 6851e5b75505Sopenharmony_ci 6852e5b75505Sopenharmony_ci /* Generate a random y coordinate that results in a point that is not 6853e5b75505Sopenharmony_ci * on the curve. */ 6854e5b75505Sopenharmony_ci for (;;) { 6855e5b75505Sopenharmony_ci if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1) 6856e5b75505Sopenharmony_ci goto fail; 6857e5b75505Sopenharmony_ci 6858e5b75505Sopenharmony_ci if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y, 6859e5b75505Sopenharmony_ci ctx) != 1) { 6860e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL) 6861e5b75505Sopenharmony_ci /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL 6862e5b75505Sopenharmony_ci * return an error from EC_POINT_set_affine_coordinates_GFp() 6863e5b75505Sopenharmony_ci * when the point is not on the curve. */ 6864e5b75505Sopenharmony_ci break; 6865e5b75505Sopenharmony_ci#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */ 6866e5b75505Sopenharmony_ci goto fail; 6867e5b75505Sopenharmony_ci#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */ 6868e5b75505Sopenharmony_ci } 6869e5b75505Sopenharmony_ci 6870e5b75505Sopenharmony_ci if (!EC_POINT_is_on_curve(group, point, ctx)) 6871e5b75505Sopenharmony_ci break; 6872e5b75505Sopenharmony_ci } 6873e5b75505Sopenharmony_ci 6874e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len), 6875e5b75505Sopenharmony_ci curve->prime_len) < 0 || 6876e5b75505Sopenharmony_ci dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len), 6877e5b75505Sopenharmony_ci curve->prime_len) < 0) 6878e5b75505Sopenharmony_ci goto fail; 6879e5b75505Sopenharmony_ci 6880e5b75505Sopenharmony_ci ret = 0; 6881e5b75505Sopenharmony_cifail: 6882e5b75505Sopenharmony_ci if (ret < 0) 6883e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key"); 6884e5b75505Sopenharmony_ci BN_free(x); 6885e5b75505Sopenharmony_ci BN_free(y); 6886e5b75505Sopenharmony_ci EC_POINT_free(point); 6887e5b75505Sopenharmony_ci BN_CTX_free(ctx); 6888e5b75505Sopenharmony_ci EC_GROUP_free(group); 6889e5b75505Sopenharmony_ci 6890e5b75505Sopenharmony_ci return ret; 6891e5b75505Sopenharmony_ci} 6892e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 6893e5b75505Sopenharmony_ci 6894e5b75505Sopenharmony_ci 6895e5b75505Sopenharmony_cistatic struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex) 6896e5b75505Sopenharmony_ci{ 6897e5b75505Sopenharmony_ci EC_KEY *X_ec = NULL; 6898e5b75505Sopenharmony_ci const EC_POINT *X_point; 6899e5b75505Sopenharmony_ci BN_CTX *bnctx = NULL; 6900e5b75505Sopenharmony_ci EC_GROUP *group = NULL; 6901e5b75505Sopenharmony_ci EC_POINT *Qi = NULL, *M = NULL; 6902e5b75505Sopenharmony_ci struct wpabuf *M_buf = NULL; 6903e5b75505Sopenharmony_ci BIGNUM *Mx = NULL, *My = NULL; 6904e5b75505Sopenharmony_ci struct wpabuf *msg = NULL; 6905e5b75505Sopenharmony_ci size_t attr_len; 6906e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 6907e5b75505Sopenharmony_ci 6908e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request"); 6909e5b75505Sopenharmony_ci 6910e5b75505Sopenharmony_ci /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 6911e5b75505Sopenharmony_ci bnctx = BN_CTX_new(); 6912e5b75505Sopenharmony_ci if (!bnctx) 6913e5b75505Sopenharmony_ci goto fail; 6914e5b75505Sopenharmony_ci Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code, 6915e5b75505Sopenharmony_ci pkex->identifier, bnctx, &group); 6916e5b75505Sopenharmony_ci if (!Qi) 6917e5b75505Sopenharmony_ci goto fail; 6918e5b75505Sopenharmony_ci 6919e5b75505Sopenharmony_ci /* Generate a random ephemeral keypair x/X */ 6920e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6921e5b75505Sopenharmony_ci if (dpp_pkex_ephemeral_key_override_len) { 6922e5b75505Sopenharmony_ci const struct dpp_curve_params *tmp_curve; 6923e5b75505Sopenharmony_ci 6924e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 6925e5b75505Sopenharmony_ci "DPP: TESTING - override ephemeral key x/X"); 6926e5b75505Sopenharmony_ci pkex->x = dpp_set_keypair(&tmp_curve, 6927e5b75505Sopenharmony_ci dpp_pkex_ephemeral_key_override, 6928e5b75505Sopenharmony_ci dpp_pkex_ephemeral_key_override_len); 6929e5b75505Sopenharmony_ci } else { 6930e5b75505Sopenharmony_ci pkex->x = dpp_gen_keypair(curve); 6931e5b75505Sopenharmony_ci } 6932e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 6933e5b75505Sopenharmony_ci pkex->x = dpp_gen_keypair(curve); 6934e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 6935e5b75505Sopenharmony_ci if (!pkex->x) 6936e5b75505Sopenharmony_ci goto fail; 6937e5b75505Sopenharmony_ci 6938e5b75505Sopenharmony_ci /* M = X + Qi */ 6939e5b75505Sopenharmony_ci X_ec = EVP_PKEY_get1_EC_KEY(pkex->x); 6940e5b75505Sopenharmony_ci if (!X_ec) 6941e5b75505Sopenharmony_ci goto fail; 6942e5b75505Sopenharmony_ci X_point = EC_KEY_get0_public_key(X_ec); 6943e5b75505Sopenharmony_ci if (!X_point) 6944e5b75505Sopenharmony_ci goto fail; 6945e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: X", group, X_point); 6946e5b75505Sopenharmony_ci M = EC_POINT_new(group); 6947e5b75505Sopenharmony_ci Mx = BN_new(); 6948e5b75505Sopenharmony_ci My = BN_new(); 6949e5b75505Sopenharmony_ci if (!M || !Mx || !My || 6950e5b75505Sopenharmony_ci EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 || 6951e5b75505Sopenharmony_ci EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1) 6952e5b75505Sopenharmony_ci goto fail; 6953e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: M", group, M); 6954e5b75505Sopenharmony_ci 6955e5b75505Sopenharmony_ci /* Initiator -> Responder: group, [identifier,] M */ 6956e5b75505Sopenharmony_ci attr_len = 4 + 2; 6957e5b75505Sopenharmony_ci if (pkex->identifier) 6958e5b75505Sopenharmony_ci attr_len += 4 + os_strlen(pkex->identifier); 6959e5b75505Sopenharmony_ci attr_len += 4 + 2 * curve->prime_len; 6960e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len); 6961e5b75505Sopenharmony_ci if (!msg) 6962e5b75505Sopenharmony_ci goto fail; 6963e5b75505Sopenharmony_ci 6964e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6965e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) { 6966e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group"); 6967e5b75505Sopenharmony_ci goto skip_finite_cyclic_group; 6968e5b75505Sopenharmony_ci } 6969e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 6970e5b75505Sopenharmony_ci 6971e5b75505Sopenharmony_ci /* Finite Cyclic Group attribute */ 6972e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 6973e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 2); 6974e5b75505Sopenharmony_ci wpabuf_put_le16(msg, curve->ike_group); 6975e5b75505Sopenharmony_ci 6976e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6977e5b75505Sopenharmony_ciskip_finite_cyclic_group: 6978e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 6979e5b75505Sopenharmony_ci 6980e5b75505Sopenharmony_ci /* Code Identifier attribute */ 6981e5b75505Sopenharmony_ci if (pkex->identifier) { 6982e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 6983e5b75505Sopenharmony_ci wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 6984e5b75505Sopenharmony_ci wpabuf_put_str(msg, pkex->identifier); 6985e5b75505Sopenharmony_ci } 6986e5b75505Sopenharmony_ci 6987e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6988e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 6989e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 6990e5b75505Sopenharmony_ci goto out; 6991e5b75505Sopenharmony_ci } 6992e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 6993e5b75505Sopenharmony_ci 6994e5b75505Sopenharmony_ci /* M in Encrypted Key attribute */ 6995e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 6996e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 2 * curve->prime_len); 6997e5b75505Sopenharmony_ci 6998e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 6999e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 7000e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 7001e5b75505Sopenharmony_ci if (dpp_test_gen_invalid_key(msg, curve) < 0) 7002e5b75505Sopenharmony_ci goto fail; 7003e5b75505Sopenharmony_ci goto out; 7004e5b75505Sopenharmony_ci } 7005e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7006e5b75505Sopenharmony_ci 7007e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len), 7008e5b75505Sopenharmony_ci curve->prime_len) < 0 || 7009e5b75505Sopenharmony_ci dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 || 7010e5b75505Sopenharmony_ci dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len), 7011e5b75505Sopenharmony_ci curve->prime_len) < 0) 7012e5b75505Sopenharmony_ci goto fail; 7013e5b75505Sopenharmony_ci 7014e5b75505Sopenharmony_ciout: 7015e5b75505Sopenharmony_ci wpabuf_free(M_buf); 7016e5b75505Sopenharmony_ci EC_KEY_free(X_ec); 7017e5b75505Sopenharmony_ci EC_POINT_free(M); 7018e5b75505Sopenharmony_ci EC_POINT_free(Qi); 7019e5b75505Sopenharmony_ci BN_clear_free(Mx); 7020e5b75505Sopenharmony_ci BN_clear_free(My); 7021e5b75505Sopenharmony_ci BN_CTX_free(bnctx); 7022e5b75505Sopenharmony_ci EC_GROUP_free(group); 7023e5b75505Sopenharmony_ci return msg; 7024e5b75505Sopenharmony_cifail: 7025e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request"); 7026e5b75505Sopenharmony_ci wpabuf_free(msg); 7027e5b75505Sopenharmony_ci msg = NULL; 7028e5b75505Sopenharmony_ci goto out; 7029e5b75505Sopenharmony_ci} 7030e5b75505Sopenharmony_ci 7031e5b75505Sopenharmony_ci 7032e5b75505Sopenharmony_cistatic void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt) 7033e5b75505Sopenharmony_ci{ 7034e5b75505Sopenharmony_ci wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); 7035e5b75505Sopenharmony_ci} 7036e5b75505Sopenharmony_ci 7037e5b75505Sopenharmony_ci 7038e5b75505Sopenharmony_cistruct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, 7039e5b75505Sopenharmony_ci const u8 *own_mac, 7040e5b75505Sopenharmony_ci const char *identifier, 7041e5b75505Sopenharmony_ci const char *code) 7042e5b75505Sopenharmony_ci{ 7043e5b75505Sopenharmony_ci struct dpp_pkex *pkex; 7044e5b75505Sopenharmony_ci 7045e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7046e5b75505Sopenharmony_ci if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 7047e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 7048e5b75505Sopenharmony_ci MAC2STR(dpp_pkex_own_mac_override)); 7049e5b75505Sopenharmony_ci own_mac = dpp_pkex_own_mac_override; 7050e5b75505Sopenharmony_ci } 7051e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7052e5b75505Sopenharmony_ci 7053e5b75505Sopenharmony_ci pkex = os_zalloc(sizeof(*pkex)); 7054e5b75505Sopenharmony_ci if (!pkex) 7055e5b75505Sopenharmony_ci return NULL; 7056e5b75505Sopenharmony_ci pkex->msg_ctx = msg_ctx; 7057e5b75505Sopenharmony_ci pkex->initiator = 1; 7058e5b75505Sopenharmony_ci pkex->own_bi = bi; 7059e5b75505Sopenharmony_ci os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 7060e5b75505Sopenharmony_ci if (identifier) { 7061e5b75505Sopenharmony_ci pkex->identifier = os_strdup(identifier); 7062e5b75505Sopenharmony_ci if (!pkex->identifier) 7063e5b75505Sopenharmony_ci goto fail; 7064e5b75505Sopenharmony_ci } 7065e5b75505Sopenharmony_ci pkex->code = os_strdup(code); 7066e5b75505Sopenharmony_ci if (!pkex->code) 7067e5b75505Sopenharmony_ci goto fail; 7068e5b75505Sopenharmony_ci pkex->exchange_req = dpp_pkex_build_exchange_req(pkex); 7069e5b75505Sopenharmony_ci if (!pkex->exchange_req) 7070e5b75505Sopenharmony_ci goto fail; 7071e5b75505Sopenharmony_ci return pkex; 7072e5b75505Sopenharmony_cifail: 7073e5b75505Sopenharmony_ci dpp_pkex_free(pkex); 7074e5b75505Sopenharmony_ci return NULL; 7075e5b75505Sopenharmony_ci} 7076e5b75505Sopenharmony_ci 7077e5b75505Sopenharmony_ci 7078e5b75505Sopenharmony_cistatic struct wpabuf * 7079e5b75505Sopenharmony_cidpp_pkex_build_exchange_resp(struct dpp_pkex *pkex, 7080e5b75505Sopenharmony_ci enum dpp_status_error status, 7081e5b75505Sopenharmony_ci const BIGNUM *Nx, const BIGNUM *Ny) 7082e5b75505Sopenharmony_ci{ 7083e5b75505Sopenharmony_ci struct wpabuf *msg = NULL; 7084e5b75505Sopenharmony_ci size_t attr_len; 7085e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 7086e5b75505Sopenharmony_ci 7087e5b75505Sopenharmony_ci /* Initiator -> Responder: DPP Status, [identifier,] N */ 7088e5b75505Sopenharmony_ci attr_len = 4 + 1; 7089e5b75505Sopenharmony_ci if (pkex->identifier) 7090e5b75505Sopenharmony_ci attr_len += 4 + os_strlen(pkex->identifier); 7091e5b75505Sopenharmony_ci attr_len += 4 + 2 * curve->prime_len; 7092e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len); 7093e5b75505Sopenharmony_ci if (!msg) 7094e5b75505Sopenharmony_ci goto fail; 7095e5b75505Sopenharmony_ci 7096e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7097e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) { 7098e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 7099e5b75505Sopenharmony_ci goto skip_status; 7100e5b75505Sopenharmony_ci } 7101e5b75505Sopenharmony_ci 7102e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) { 7103e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 7104e5b75505Sopenharmony_ci status = 255; 7105e5b75505Sopenharmony_ci } 7106e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7107e5b75505Sopenharmony_ci 7108e5b75505Sopenharmony_ci /* DPP Status */ 7109e5b75505Sopenharmony_ci dpp_build_attr_status(msg, status); 7110e5b75505Sopenharmony_ci 7111e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7112e5b75505Sopenharmony_ciskip_status: 7113e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7114e5b75505Sopenharmony_ci 7115e5b75505Sopenharmony_ci /* Code Identifier attribute */ 7116e5b75505Sopenharmony_ci if (pkex->identifier) { 7117e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 7118e5b75505Sopenharmony_ci wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 7119e5b75505Sopenharmony_ci wpabuf_put_str(msg, pkex->identifier); 7120e5b75505Sopenharmony_ci } 7121e5b75505Sopenharmony_ci 7122e5b75505Sopenharmony_ci if (status != DPP_STATUS_OK) 7123e5b75505Sopenharmony_ci goto skip_encrypted_key; 7124e5b75505Sopenharmony_ci 7125e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7126e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 7127e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 7128e5b75505Sopenharmony_ci goto skip_encrypted_key; 7129e5b75505Sopenharmony_ci } 7130e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7131e5b75505Sopenharmony_ci 7132e5b75505Sopenharmony_ci /* N in Encrypted Key attribute */ 7133e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 7134e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 2 * curve->prime_len); 7135e5b75505Sopenharmony_ci 7136e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7137e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 7138e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 7139e5b75505Sopenharmony_ci if (dpp_test_gen_invalid_key(msg, curve) < 0) 7140e5b75505Sopenharmony_ci goto fail; 7141e5b75505Sopenharmony_ci goto skip_encrypted_key; 7142e5b75505Sopenharmony_ci } 7143e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7144e5b75505Sopenharmony_ci 7145e5b75505Sopenharmony_ci if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len), 7146e5b75505Sopenharmony_ci curve->prime_len) < 0 || 7147e5b75505Sopenharmony_ci dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 || 7148e5b75505Sopenharmony_ci dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len), 7149e5b75505Sopenharmony_ci curve->prime_len) < 0) 7150e5b75505Sopenharmony_ci goto fail; 7151e5b75505Sopenharmony_ci 7152e5b75505Sopenharmony_ciskip_encrypted_key: 7153e5b75505Sopenharmony_ci if (status == DPP_STATUS_BAD_GROUP) { 7154e5b75505Sopenharmony_ci /* Finite Cyclic Group attribute */ 7155e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 7156e5b75505Sopenharmony_ci wpabuf_put_le16(msg, 2); 7157e5b75505Sopenharmony_ci wpabuf_put_le16(msg, curve->ike_group); 7158e5b75505Sopenharmony_ci } 7159e5b75505Sopenharmony_ci 7160e5b75505Sopenharmony_ci return msg; 7161e5b75505Sopenharmony_cifail: 7162e5b75505Sopenharmony_ci wpabuf_free(msg); 7163e5b75505Sopenharmony_ci return NULL; 7164e5b75505Sopenharmony_ci} 7165e5b75505Sopenharmony_ci 7166e5b75505Sopenharmony_ci 7167e5b75505Sopenharmony_cistatic int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, 7168e5b75505Sopenharmony_ci const u8 *Mx, size_t Mx_len, 7169e5b75505Sopenharmony_ci const u8 *Nx, size_t Nx_len, 7170e5b75505Sopenharmony_ci const char *code, 7171e5b75505Sopenharmony_ci const u8 *Kx, size_t Kx_len, 7172e5b75505Sopenharmony_ci u8 *z, unsigned int hash_len) 7173e5b75505Sopenharmony_ci{ 7174e5b75505Sopenharmony_ci u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 7175e5b75505Sopenharmony_ci int res; 7176e5b75505Sopenharmony_ci u8 *info, *pos; 7177e5b75505Sopenharmony_ci size_t info_len; 7178e5b75505Sopenharmony_ci 7179e5b75505Sopenharmony_ci /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 7180e5b75505Sopenharmony_ci */ 7181e5b75505Sopenharmony_ci 7182e5b75505Sopenharmony_ci /* HKDF-Extract(<>, IKM=K.x) */ 7183e5b75505Sopenharmony_ci os_memset(salt, 0, hash_len); 7184e5b75505Sopenharmony_ci if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0) 7185e5b75505Sopenharmony_ci return -1; 7186e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", 7187e5b75505Sopenharmony_ci prk, hash_len); 7188e5b75505Sopenharmony_ci info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code); 7189e5b75505Sopenharmony_ci info = os_malloc(info_len); 7190e5b75505Sopenharmony_ci if (!info) 7191e5b75505Sopenharmony_ci return -1; 7192e5b75505Sopenharmony_ci pos = info; 7193e5b75505Sopenharmony_ci os_memcpy(pos, mac_init, ETH_ALEN); 7194e5b75505Sopenharmony_ci pos += ETH_ALEN; 7195e5b75505Sopenharmony_ci os_memcpy(pos, mac_resp, ETH_ALEN); 7196e5b75505Sopenharmony_ci pos += ETH_ALEN; 7197e5b75505Sopenharmony_ci os_memcpy(pos, Mx, Mx_len); 7198e5b75505Sopenharmony_ci pos += Mx_len; 7199e5b75505Sopenharmony_ci os_memcpy(pos, Nx, Nx_len); 7200e5b75505Sopenharmony_ci pos += Nx_len; 7201e5b75505Sopenharmony_ci os_memcpy(pos, code, os_strlen(code)); 7202e5b75505Sopenharmony_ci 7203e5b75505Sopenharmony_ci /* HKDF-Expand(PRK, info, L) */ 7204e5b75505Sopenharmony_ci if (hash_len == 32) 7205e5b75505Sopenharmony_ci res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len, 7206e5b75505Sopenharmony_ci z, hash_len); 7207e5b75505Sopenharmony_ci else if (hash_len == 48) 7208e5b75505Sopenharmony_ci res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len, 7209e5b75505Sopenharmony_ci z, hash_len); 7210e5b75505Sopenharmony_ci else if (hash_len == 64) 7211e5b75505Sopenharmony_ci res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len, 7212e5b75505Sopenharmony_ci z, hash_len); 7213e5b75505Sopenharmony_ci else 7214e5b75505Sopenharmony_ci res = -1; 7215e5b75505Sopenharmony_ci os_free(info); 7216e5b75505Sopenharmony_ci os_memset(prk, 0, hash_len); 7217e5b75505Sopenharmony_ci if (res < 0) 7218e5b75505Sopenharmony_ci return -1; 7219e5b75505Sopenharmony_ci 7220e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)", 7221e5b75505Sopenharmony_ci z, hash_len); 7222e5b75505Sopenharmony_ci return 0; 7223e5b75505Sopenharmony_ci} 7224e5b75505Sopenharmony_ci 7225e5b75505Sopenharmony_ci 7226e5b75505Sopenharmony_cistatic int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len, 7227e5b75505Sopenharmony_ci const char *identifier) 7228e5b75505Sopenharmony_ci{ 7229e5b75505Sopenharmony_ci if (!attr_id && identifier) { 7230e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 7231e5b75505Sopenharmony_ci "DPP: No PKEX code identifier received, but expected one"); 7232e5b75505Sopenharmony_ci return 0; 7233e5b75505Sopenharmony_ci } 7234e5b75505Sopenharmony_ci 7235e5b75505Sopenharmony_ci if (attr_id && !identifier) { 7236e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 7237e5b75505Sopenharmony_ci "DPP: PKEX code identifier received, but not expecting one"); 7238e5b75505Sopenharmony_ci return 0; 7239e5b75505Sopenharmony_ci } 7240e5b75505Sopenharmony_ci 7241e5b75505Sopenharmony_ci if (attr_id && identifier && 7242e5b75505Sopenharmony_ci (os_strlen(identifier) != attr_id_len || 7243e5b75505Sopenharmony_ci os_memcmp(identifier, attr_id, attr_id_len) != 0)) { 7244e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); 7245e5b75505Sopenharmony_ci return 0; 7246e5b75505Sopenharmony_ci } 7247e5b75505Sopenharmony_ci 7248e5b75505Sopenharmony_ci return 1; 7249e5b75505Sopenharmony_ci} 7250e5b75505Sopenharmony_ci 7251e5b75505Sopenharmony_ci 7252e5b75505Sopenharmony_cistruct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, 7253e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi, 7254e5b75505Sopenharmony_ci const u8 *own_mac, 7255e5b75505Sopenharmony_ci const u8 *peer_mac, 7256e5b75505Sopenharmony_ci const char *identifier, 7257e5b75505Sopenharmony_ci const char *code, 7258e5b75505Sopenharmony_ci const u8 *buf, size_t len) 7259e5b75505Sopenharmony_ci{ 7260e5b75505Sopenharmony_ci const u8 *attr_group, *attr_id, *attr_key; 7261e5b75505Sopenharmony_ci u16 attr_group_len, attr_id_len, attr_key_len; 7262e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = bi->curve; 7263e5b75505Sopenharmony_ci u16 ike_group; 7264e5b75505Sopenharmony_ci struct dpp_pkex *pkex = NULL; 7265e5b75505Sopenharmony_ci EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL; 7266e5b75505Sopenharmony_ci BN_CTX *bnctx = NULL; 7267e5b75505Sopenharmony_ci EC_GROUP *group = NULL; 7268e5b75505Sopenharmony_ci BIGNUM *Mx = NULL, *My = NULL; 7269e5b75505Sopenharmony_ci EC_KEY *Y_ec = NULL, *X_ec = NULL;; 7270e5b75505Sopenharmony_ci const EC_POINT *Y_point; 7271e5b75505Sopenharmony_ci BIGNUM *Nx = NULL, *Ny = NULL; 7272e5b75505Sopenharmony_ci u8 Kx[DPP_MAX_SHARED_SECRET_LEN]; 7273e5b75505Sopenharmony_ci size_t Kx_len; 7274e5b75505Sopenharmony_ci int res; 7275e5b75505Sopenharmony_ci 7276e5b75505Sopenharmony_ci if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) { 7277e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7278e5b75505Sopenharmony_ci "PKEX counter t limit reached - ignore message"); 7279e5b75505Sopenharmony_ci return NULL; 7280e5b75505Sopenharmony_ci } 7281e5b75505Sopenharmony_ci 7282e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7283e5b75505Sopenharmony_ci if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 7284e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 7285e5b75505Sopenharmony_ci MAC2STR(dpp_pkex_peer_mac_override)); 7286e5b75505Sopenharmony_ci peer_mac = dpp_pkex_peer_mac_override; 7287e5b75505Sopenharmony_ci } 7288e5b75505Sopenharmony_ci if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 7289e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 7290e5b75505Sopenharmony_ci MAC2STR(dpp_pkex_own_mac_override)); 7291e5b75505Sopenharmony_ci own_mac = dpp_pkex_own_mac_override; 7292e5b75505Sopenharmony_ci } 7293e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7294e5b75505Sopenharmony_ci 7295e5b75505Sopenharmony_ci attr_id_len = 0; 7296e5b75505Sopenharmony_ci attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, 7297e5b75505Sopenharmony_ci &attr_id_len); 7298e5b75505Sopenharmony_ci if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier)) 7299e5b75505Sopenharmony_ci return NULL; 7300e5b75505Sopenharmony_ci 7301e5b75505Sopenharmony_ci attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, 7302e5b75505Sopenharmony_ci &attr_group_len); 7303e5b75505Sopenharmony_ci if (!attr_group || attr_group_len != 2) { 7304e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7305e5b75505Sopenharmony_ci "Missing or invalid Finite Cyclic Group attribute"); 7306e5b75505Sopenharmony_ci return NULL; 7307e5b75505Sopenharmony_ci } 7308e5b75505Sopenharmony_ci ike_group = WPA_GET_LE16(attr_group); 7309e5b75505Sopenharmony_ci if (ike_group != curve->ike_group) { 7310e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7311e5b75505Sopenharmony_ci "Mismatching PKEX curve: peer=%u own=%u", 7312e5b75505Sopenharmony_ci ike_group, curve->ike_group); 7313e5b75505Sopenharmony_ci pkex = os_zalloc(sizeof(*pkex)); 7314e5b75505Sopenharmony_ci if (!pkex) 7315e5b75505Sopenharmony_ci goto fail; 7316e5b75505Sopenharmony_ci pkex->own_bi = bi; 7317e5b75505Sopenharmony_ci pkex->failed = 1; 7318e5b75505Sopenharmony_ci pkex->exchange_resp = dpp_pkex_build_exchange_resp( 7319e5b75505Sopenharmony_ci pkex, DPP_STATUS_BAD_GROUP, NULL, NULL); 7320e5b75505Sopenharmony_ci if (!pkex->exchange_resp) 7321e5b75505Sopenharmony_ci goto fail; 7322e5b75505Sopenharmony_ci return pkex; 7323e5b75505Sopenharmony_ci } 7324e5b75505Sopenharmony_ci 7325e5b75505Sopenharmony_ci /* M in Encrypted Key attribute */ 7326e5b75505Sopenharmony_ci attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY, 7327e5b75505Sopenharmony_ci &attr_key_len); 7328e5b75505Sopenharmony_ci if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 || 7329e5b75505Sopenharmony_ci attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) { 7330e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7331e5b75505Sopenharmony_ci "Missing Encrypted Key attribute"); 7332e5b75505Sopenharmony_ci return NULL; 7333e5b75505Sopenharmony_ci } 7334e5b75505Sopenharmony_ci 7335e5b75505Sopenharmony_ci /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 7336e5b75505Sopenharmony_ci bnctx = BN_CTX_new(); 7337e5b75505Sopenharmony_ci if (!bnctx) 7338e5b75505Sopenharmony_ci goto fail; 7339e5b75505Sopenharmony_ci Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx, 7340e5b75505Sopenharmony_ci &group); 7341e5b75505Sopenharmony_ci if (!Qi) 7342e5b75505Sopenharmony_ci goto fail; 7343e5b75505Sopenharmony_ci 7344e5b75505Sopenharmony_ci /* X' = M - Qi */ 7345e5b75505Sopenharmony_ci X = EC_POINT_new(group); 7346e5b75505Sopenharmony_ci M = EC_POINT_new(group); 7347e5b75505Sopenharmony_ci Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL); 7348e5b75505Sopenharmony_ci My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL); 7349e5b75505Sopenharmony_ci if (!X || !M || !Mx || !My || 7350e5b75505Sopenharmony_ci EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 || 7351e5b75505Sopenharmony_ci EC_POINT_is_at_infinity(group, M) || 7352e5b75505Sopenharmony_ci !EC_POINT_is_on_curve(group, M, bnctx) || 7353e5b75505Sopenharmony_ci EC_POINT_invert(group, Qi, bnctx) != 1 || 7354e5b75505Sopenharmony_ci EC_POINT_add(group, X, M, Qi, bnctx) != 1 || 7355e5b75505Sopenharmony_ci EC_POINT_is_at_infinity(group, X) || 7356e5b75505Sopenharmony_ci !EC_POINT_is_on_curve(group, X, bnctx)) { 7357e5b75505Sopenharmony_ci wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7358e5b75505Sopenharmony_ci "Invalid Encrypted Key value"); 7359e5b75505Sopenharmony_ci bi->pkex_t++; 7360e5b75505Sopenharmony_ci goto fail; 7361e5b75505Sopenharmony_ci } 7362e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: M", group, M); 7363e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: X'", group, X); 7364e5b75505Sopenharmony_ci 7365e5b75505Sopenharmony_ci pkex = os_zalloc(sizeof(*pkex)); 7366e5b75505Sopenharmony_ci if (!pkex) 7367e5b75505Sopenharmony_ci goto fail; 7368e5b75505Sopenharmony_ci pkex->t = bi->pkex_t; 7369e5b75505Sopenharmony_ci pkex->msg_ctx = msg_ctx; 7370e5b75505Sopenharmony_ci pkex->own_bi = bi; 7371e5b75505Sopenharmony_ci os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 7372e5b75505Sopenharmony_ci os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 7373e5b75505Sopenharmony_ci if (identifier) { 7374e5b75505Sopenharmony_ci pkex->identifier = os_strdup(identifier); 7375e5b75505Sopenharmony_ci if (!pkex->identifier) 7376e5b75505Sopenharmony_ci goto fail; 7377e5b75505Sopenharmony_ci } 7378e5b75505Sopenharmony_ci pkex->code = os_strdup(code); 7379e5b75505Sopenharmony_ci if (!pkex->code) 7380e5b75505Sopenharmony_ci goto fail; 7381e5b75505Sopenharmony_ci 7382e5b75505Sopenharmony_ci os_memcpy(pkex->Mx, attr_key, attr_key_len / 2); 7383e5b75505Sopenharmony_ci 7384e5b75505Sopenharmony_ci X_ec = EC_KEY_new(); 7385e5b75505Sopenharmony_ci if (!X_ec || 7386e5b75505Sopenharmony_ci EC_KEY_set_group(X_ec, group) != 1 || 7387e5b75505Sopenharmony_ci EC_KEY_set_public_key(X_ec, X) != 1) 7388e5b75505Sopenharmony_ci goto fail; 7389e5b75505Sopenharmony_ci pkex->x = EVP_PKEY_new(); 7390e5b75505Sopenharmony_ci if (!pkex->x || 7391e5b75505Sopenharmony_ci EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1) 7392e5b75505Sopenharmony_ci goto fail; 7393e5b75505Sopenharmony_ci 7394e5b75505Sopenharmony_ci /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ 7395e5b75505Sopenharmony_ci Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL); 7396e5b75505Sopenharmony_ci if (!Qr) 7397e5b75505Sopenharmony_ci goto fail; 7398e5b75505Sopenharmony_ci 7399e5b75505Sopenharmony_ci /* Generate a random ephemeral keypair y/Y */ 7400e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7401e5b75505Sopenharmony_ci if (dpp_pkex_ephemeral_key_override_len) { 7402e5b75505Sopenharmony_ci const struct dpp_curve_params *tmp_curve; 7403e5b75505Sopenharmony_ci 7404e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 7405e5b75505Sopenharmony_ci "DPP: TESTING - override ephemeral key y/Y"); 7406e5b75505Sopenharmony_ci pkex->y = dpp_set_keypair(&tmp_curve, 7407e5b75505Sopenharmony_ci dpp_pkex_ephemeral_key_override, 7408e5b75505Sopenharmony_ci dpp_pkex_ephemeral_key_override_len); 7409e5b75505Sopenharmony_ci } else { 7410e5b75505Sopenharmony_ci pkex->y = dpp_gen_keypair(curve); 7411e5b75505Sopenharmony_ci } 7412e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */ 7413e5b75505Sopenharmony_ci pkex->y = dpp_gen_keypair(curve); 7414e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7415e5b75505Sopenharmony_ci if (!pkex->y) 7416e5b75505Sopenharmony_ci goto fail; 7417e5b75505Sopenharmony_ci 7418e5b75505Sopenharmony_ci /* N = Y + Qr */ 7419e5b75505Sopenharmony_ci Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y); 7420e5b75505Sopenharmony_ci if (!Y_ec) 7421e5b75505Sopenharmony_ci goto fail; 7422e5b75505Sopenharmony_ci Y_point = EC_KEY_get0_public_key(Y_ec); 7423e5b75505Sopenharmony_ci if (!Y_point) 7424e5b75505Sopenharmony_ci goto fail; 7425e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: Y", group, Y_point); 7426e5b75505Sopenharmony_ci N = EC_POINT_new(group); 7427e5b75505Sopenharmony_ci Nx = BN_new(); 7428e5b75505Sopenharmony_ci Ny = BN_new(); 7429e5b75505Sopenharmony_ci if (!N || !Nx || !Ny || 7430e5b75505Sopenharmony_ci EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 || 7431e5b75505Sopenharmony_ci EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1) 7432e5b75505Sopenharmony_ci goto fail; 7433e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: N", group, N); 7434e5b75505Sopenharmony_ci 7435e5b75505Sopenharmony_ci pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK, 7436e5b75505Sopenharmony_ci Nx, Ny); 7437e5b75505Sopenharmony_ci if (!pkex->exchange_resp) 7438e5b75505Sopenharmony_ci goto fail; 7439e5b75505Sopenharmony_ci 7440e5b75505Sopenharmony_ci /* K = y * X' */ 7441e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0) 7442e5b75505Sopenharmony_ci goto fail; 7443e5b75505Sopenharmony_ci 7444e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 7445e5b75505Sopenharmony_ci Kx, Kx_len); 7446e5b75505Sopenharmony_ci 7447e5b75505Sopenharmony_ci /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 7448e5b75505Sopenharmony_ci */ 7449e5b75505Sopenharmony_ci res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac, 7450e5b75505Sopenharmony_ci pkex->Mx, curve->prime_len, 7451e5b75505Sopenharmony_ci pkex->Nx, curve->prime_len, pkex->code, 7452e5b75505Sopenharmony_ci Kx, Kx_len, pkex->z, curve->hash_len); 7453e5b75505Sopenharmony_ci os_memset(Kx, 0, Kx_len); 7454e5b75505Sopenharmony_ci if (res < 0) 7455e5b75505Sopenharmony_ci goto fail; 7456e5b75505Sopenharmony_ci 7457e5b75505Sopenharmony_ci pkex->exchange_done = 1; 7458e5b75505Sopenharmony_ci 7459e5b75505Sopenharmony_ciout: 7460e5b75505Sopenharmony_ci BN_CTX_free(bnctx); 7461e5b75505Sopenharmony_ci EC_POINT_free(Qi); 7462e5b75505Sopenharmony_ci EC_POINT_free(Qr); 7463e5b75505Sopenharmony_ci BN_free(Mx); 7464e5b75505Sopenharmony_ci BN_free(My); 7465e5b75505Sopenharmony_ci BN_free(Nx); 7466e5b75505Sopenharmony_ci BN_free(Ny); 7467e5b75505Sopenharmony_ci EC_POINT_free(M); 7468e5b75505Sopenharmony_ci EC_POINT_free(N); 7469e5b75505Sopenharmony_ci EC_POINT_free(X); 7470e5b75505Sopenharmony_ci EC_KEY_free(X_ec); 7471e5b75505Sopenharmony_ci EC_KEY_free(Y_ec); 7472e5b75505Sopenharmony_ci EC_GROUP_free(group); 7473e5b75505Sopenharmony_ci return pkex; 7474e5b75505Sopenharmony_cifail: 7475e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed"); 7476e5b75505Sopenharmony_ci dpp_pkex_free(pkex); 7477e5b75505Sopenharmony_ci pkex = NULL; 7478e5b75505Sopenharmony_ci goto out; 7479e5b75505Sopenharmony_ci} 7480e5b75505Sopenharmony_ci 7481e5b75505Sopenharmony_ci 7482e5b75505Sopenharmony_cistatic struct wpabuf * 7483e5b75505Sopenharmony_cidpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex, 7484e5b75505Sopenharmony_ci const struct wpabuf *A_pub, const u8 *u) 7485e5b75505Sopenharmony_ci{ 7486e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 7487e5b75505Sopenharmony_ci struct wpabuf *msg = NULL; 7488e5b75505Sopenharmony_ci size_t clear_len, attr_len; 7489e5b75505Sopenharmony_ci struct wpabuf *clear = NULL; 7490e5b75505Sopenharmony_ci u8 *wrapped; 7491e5b75505Sopenharmony_ci u8 octet; 7492e5b75505Sopenharmony_ci const u8 *addr[2]; 7493e5b75505Sopenharmony_ci size_t len[2]; 7494e5b75505Sopenharmony_ci 7495e5b75505Sopenharmony_ci /* {A, u, [bootstrapping info]}z */ 7496e5b75505Sopenharmony_ci clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 7497e5b75505Sopenharmony_ci clear = wpabuf_alloc(clear_len); 7498e5b75505Sopenharmony_ci attr_len = 4 + clear_len + AES_BLOCK_SIZE; 7499e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7500e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) 7501e5b75505Sopenharmony_ci attr_len += 5; 7502e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7503e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len); 7504e5b75505Sopenharmony_ci if (!clear || !msg) 7505e5b75505Sopenharmony_ci goto fail; 7506e5b75505Sopenharmony_ci 7507e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7508e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) { 7509e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 7510e5b75505Sopenharmony_ci goto skip_bootstrap_key; 7511e5b75505Sopenharmony_ci } 7512e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) { 7513e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 7514e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 7515e5b75505Sopenharmony_ci wpabuf_put_le16(clear, 2 * curve->prime_len); 7516e5b75505Sopenharmony_ci if (dpp_test_gen_invalid_key(clear, curve) < 0) 7517e5b75505Sopenharmony_ci goto fail; 7518e5b75505Sopenharmony_ci goto skip_bootstrap_key; 7519e5b75505Sopenharmony_ci } 7520e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7521e5b75505Sopenharmony_ci 7522e5b75505Sopenharmony_ci /* A in Bootstrap Key attribute */ 7523e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 7524e5b75505Sopenharmony_ci wpabuf_put_le16(clear, wpabuf_len(A_pub)); 7525e5b75505Sopenharmony_ci wpabuf_put_buf(clear, A_pub); 7526e5b75505Sopenharmony_ci 7527e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7528e5b75505Sopenharmony_ciskip_bootstrap_key: 7529e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) { 7530e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag"); 7531e5b75505Sopenharmony_ci goto skip_i_auth_tag; 7532e5b75505Sopenharmony_ci } 7533e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) { 7534e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch"); 7535e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 7536e5b75505Sopenharmony_ci wpabuf_put_le16(clear, curve->hash_len); 7537e5b75505Sopenharmony_ci wpabuf_put_data(clear, u, curve->hash_len - 1); 7538e5b75505Sopenharmony_ci wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01); 7539e5b75505Sopenharmony_ci goto skip_i_auth_tag; 7540e5b75505Sopenharmony_ci } 7541e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7542e5b75505Sopenharmony_ci 7543e5b75505Sopenharmony_ci /* u in I-Auth tag attribute */ 7544e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 7545e5b75505Sopenharmony_ci wpabuf_put_le16(clear, curve->hash_len); 7546e5b75505Sopenharmony_ci wpabuf_put_data(clear, u, curve->hash_len); 7547e5b75505Sopenharmony_ci 7548e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7549e5b75505Sopenharmony_ciskip_i_auth_tag: 7550e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) { 7551e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 7552e5b75505Sopenharmony_ci goto skip_wrapped_data; 7553e5b75505Sopenharmony_ci } 7554e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7555e5b75505Sopenharmony_ci 7556e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 7557e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 7558e5b75505Sopenharmony_ci octet = 0; 7559e5b75505Sopenharmony_ci addr[1] = &octet; 7560e5b75505Sopenharmony_ci len[1] = sizeof(octet); 7561e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 7562e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 7563e5b75505Sopenharmony_ci 7564e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 7565e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 7566e5b75505Sopenharmony_ci wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 7567e5b75505Sopenharmony_ci 7568e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 7569e5b75505Sopenharmony_ci if (aes_siv_encrypt(pkex->z, curve->hash_len, 7570e5b75505Sopenharmony_ci wpabuf_head(clear), wpabuf_len(clear), 7571e5b75505Sopenharmony_ci 2, addr, len, wrapped) < 0) 7572e5b75505Sopenharmony_ci goto fail; 7573e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 7574e5b75505Sopenharmony_ci wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 7575e5b75505Sopenharmony_ci 7576e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7577e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) { 7578e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 7579e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 7580e5b75505Sopenharmony_ci } 7581e5b75505Sopenharmony_ciskip_wrapped_data: 7582e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7583e5b75505Sopenharmony_ci 7584e5b75505Sopenharmony_ciout: 7585e5b75505Sopenharmony_ci wpabuf_free(clear); 7586e5b75505Sopenharmony_ci return msg; 7587e5b75505Sopenharmony_ci 7588e5b75505Sopenharmony_cifail: 7589e5b75505Sopenharmony_ci wpabuf_free(msg); 7590e5b75505Sopenharmony_ci msg = NULL; 7591e5b75505Sopenharmony_ci goto out; 7592e5b75505Sopenharmony_ci} 7593e5b75505Sopenharmony_ci 7594e5b75505Sopenharmony_ci 7595e5b75505Sopenharmony_cistruct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, 7596e5b75505Sopenharmony_ci const u8 *peer_mac, 7597e5b75505Sopenharmony_ci const u8 *buf, size_t buflen) 7598e5b75505Sopenharmony_ci{ 7599e5b75505Sopenharmony_ci const u8 *attr_status, *attr_id, *attr_key, *attr_group; 7600e5b75505Sopenharmony_ci u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len; 7601e5b75505Sopenharmony_ci EC_GROUP *group = NULL; 7602e5b75505Sopenharmony_ci BN_CTX *bnctx = NULL; 7603e5b75505Sopenharmony_ci struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 7604e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 7605e5b75505Sopenharmony_ci EC_POINT *Qr = NULL, *Y = NULL, *N = NULL; 7606e5b75505Sopenharmony_ci BIGNUM *Nx = NULL, *Ny = NULL; 7607e5b75505Sopenharmony_ci EC_KEY *Y_ec = NULL; 7608e5b75505Sopenharmony_ci size_t Jx_len, Kx_len; 7609e5b75505Sopenharmony_ci u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; 7610e5b75505Sopenharmony_ci const u8 *addr[4]; 7611e5b75505Sopenharmony_ci size_t len[4]; 7612e5b75505Sopenharmony_ci u8 u[DPP_MAX_HASH_LEN]; 7613e5b75505Sopenharmony_ci int res; 7614e5b75505Sopenharmony_ci 7615e5b75505Sopenharmony_ci if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 7616e5b75505Sopenharmony_ci return NULL; 7617e5b75505Sopenharmony_ci 7618e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7619e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) { 7620e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 7621e5b75505Sopenharmony_ci "DPP: TESTING - stop at PKEX Exchange Response"); 7622e5b75505Sopenharmony_ci pkex->failed = 1; 7623e5b75505Sopenharmony_ci return NULL; 7624e5b75505Sopenharmony_ci } 7625e5b75505Sopenharmony_ci 7626e5b75505Sopenharmony_ci if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 7627e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 7628e5b75505Sopenharmony_ci MAC2STR(dpp_pkex_peer_mac_override)); 7629e5b75505Sopenharmony_ci peer_mac = dpp_pkex_peer_mac_override; 7630e5b75505Sopenharmony_ci } 7631e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7632e5b75505Sopenharmony_ci 7633e5b75505Sopenharmony_ci os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 7634e5b75505Sopenharmony_ci 7635e5b75505Sopenharmony_ci attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, 7636e5b75505Sopenharmony_ci &attr_status_len); 7637e5b75505Sopenharmony_ci if (!attr_status || attr_status_len != 1) { 7638e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "No DPP Status attribute"); 7639e5b75505Sopenharmony_ci return NULL; 7640e5b75505Sopenharmony_ci } 7641e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]); 7642e5b75505Sopenharmony_ci 7643e5b75505Sopenharmony_ci if (attr_status[0] == DPP_STATUS_BAD_GROUP) { 7644e5b75505Sopenharmony_ci attr_group = dpp_get_attr(buf, buflen, 7645e5b75505Sopenharmony_ci DPP_ATTR_FINITE_CYCLIC_GROUP, 7646e5b75505Sopenharmony_ci &attr_group_len); 7647e5b75505Sopenharmony_ci if (attr_group && attr_group_len == 2) { 7648e5b75505Sopenharmony_ci wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 7649e5b75505Sopenharmony_ci "Peer indicated mismatching PKEX group - proposed %u", 7650e5b75505Sopenharmony_ci WPA_GET_LE16(attr_group)); 7651e5b75505Sopenharmony_ci return NULL; 7652e5b75505Sopenharmony_ci } 7653e5b75505Sopenharmony_ci } 7654e5b75505Sopenharmony_ci 7655e5b75505Sopenharmony_ci if (attr_status[0] != DPP_STATUS_OK) { 7656e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)"); 7657e5b75505Sopenharmony_ci return NULL; 7658e5b75505Sopenharmony_ci } 7659e5b75505Sopenharmony_ci 7660e5b75505Sopenharmony_ci attr_id_len = 0; 7661e5b75505Sopenharmony_ci attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER, 7662e5b75505Sopenharmony_ci &attr_id_len); 7663e5b75505Sopenharmony_ci if (!dpp_pkex_identifier_match(attr_id, attr_id_len, 7664e5b75505Sopenharmony_ci pkex->identifier)) { 7665e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "PKEX code identifier mismatch"); 7666e5b75505Sopenharmony_ci return NULL; 7667e5b75505Sopenharmony_ci } 7668e5b75505Sopenharmony_ci 7669e5b75505Sopenharmony_ci /* N in Encrypted Key attribute */ 7670e5b75505Sopenharmony_ci attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY, 7671e5b75505Sopenharmony_ci &attr_key_len); 7672e5b75505Sopenharmony_ci if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) { 7673e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Missing Encrypted Key attribute"); 7674e5b75505Sopenharmony_ci return NULL; 7675e5b75505Sopenharmony_ci } 7676e5b75505Sopenharmony_ci 7677e5b75505Sopenharmony_ci /* Qr = H(MAC-Responder | [identifier |] code) * Pr */ 7678e5b75505Sopenharmony_ci bnctx = BN_CTX_new(); 7679e5b75505Sopenharmony_ci if (!bnctx) 7680e5b75505Sopenharmony_ci goto fail; 7681e5b75505Sopenharmony_ci Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code, 7682e5b75505Sopenharmony_ci pkex->identifier, bnctx, &group); 7683e5b75505Sopenharmony_ci if (!Qr) 7684e5b75505Sopenharmony_ci goto fail; 7685e5b75505Sopenharmony_ci 7686e5b75505Sopenharmony_ci /* Y' = N - Qr */ 7687e5b75505Sopenharmony_ci Y = EC_POINT_new(group); 7688e5b75505Sopenharmony_ci N = EC_POINT_new(group); 7689e5b75505Sopenharmony_ci Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL); 7690e5b75505Sopenharmony_ci Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL); 7691e5b75505Sopenharmony_ci if (!Y || !N || !Nx || !Ny || 7692e5b75505Sopenharmony_ci EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 || 7693e5b75505Sopenharmony_ci EC_POINT_is_at_infinity(group, N) || 7694e5b75505Sopenharmony_ci !EC_POINT_is_on_curve(group, N, bnctx) || 7695e5b75505Sopenharmony_ci EC_POINT_invert(group, Qr, bnctx) != 1 || 7696e5b75505Sopenharmony_ci EC_POINT_add(group, Y, N, Qr, bnctx) != 1 || 7697e5b75505Sopenharmony_ci EC_POINT_is_at_infinity(group, Y) || 7698e5b75505Sopenharmony_ci !EC_POINT_is_on_curve(group, Y, bnctx)) { 7699e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Invalid Encrypted Key value"); 7700e5b75505Sopenharmony_ci pkex->t++; 7701e5b75505Sopenharmony_ci goto fail; 7702e5b75505Sopenharmony_ci } 7703e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: N", group, N); 7704e5b75505Sopenharmony_ci dpp_debug_print_point("DPP: Y'", group, Y); 7705e5b75505Sopenharmony_ci 7706e5b75505Sopenharmony_ci pkex->exchange_done = 1; 7707e5b75505Sopenharmony_ci 7708e5b75505Sopenharmony_ci /* ECDH: J = a * Y’ */ 7709e5b75505Sopenharmony_ci Y_ec = EC_KEY_new(); 7710e5b75505Sopenharmony_ci if (!Y_ec || 7711e5b75505Sopenharmony_ci EC_KEY_set_group(Y_ec, group) != 1 || 7712e5b75505Sopenharmony_ci EC_KEY_set_public_key(Y_ec, Y) != 1) 7713e5b75505Sopenharmony_ci goto fail; 7714e5b75505Sopenharmony_ci pkex->y = EVP_PKEY_new(); 7715e5b75505Sopenharmony_ci if (!pkex->y || 7716e5b75505Sopenharmony_ci EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1) 7717e5b75505Sopenharmony_ci goto fail; 7718e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0) 7719e5b75505Sopenharmony_ci goto fail; 7720e5b75505Sopenharmony_ci 7721e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 7722e5b75505Sopenharmony_ci Jx, Jx_len); 7723e5b75505Sopenharmony_ci 7724e5b75505Sopenharmony_ci /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */ 7725e5b75505Sopenharmony_ci A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0); 7726e5b75505Sopenharmony_ci Y_pub = dpp_get_pubkey_point(pkex->y, 0); 7727e5b75505Sopenharmony_ci X_pub = dpp_get_pubkey_point(pkex->x, 0); 7728e5b75505Sopenharmony_ci if (!A_pub || !Y_pub || !X_pub) 7729e5b75505Sopenharmony_ci goto fail; 7730e5b75505Sopenharmony_ci addr[0] = pkex->own_mac; 7731e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 7732e5b75505Sopenharmony_ci addr[1] = wpabuf_head(A_pub); 7733e5b75505Sopenharmony_ci len[1] = wpabuf_len(A_pub) / 2; 7734e5b75505Sopenharmony_ci addr[2] = wpabuf_head(Y_pub); 7735e5b75505Sopenharmony_ci len[2] = wpabuf_len(Y_pub) / 2; 7736e5b75505Sopenharmony_ci addr[3] = wpabuf_head(X_pub); 7737e5b75505Sopenharmony_ci len[3] = wpabuf_len(X_pub) / 2; 7738e5b75505Sopenharmony_ci if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) 7739e5b75505Sopenharmony_ci goto fail; 7740e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len); 7741e5b75505Sopenharmony_ci 7742e5b75505Sopenharmony_ci /* K = x * Y’ */ 7743e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0) 7744e5b75505Sopenharmony_ci goto fail; 7745e5b75505Sopenharmony_ci 7746e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 7747e5b75505Sopenharmony_ci Kx, Kx_len); 7748e5b75505Sopenharmony_ci 7749e5b75505Sopenharmony_ci /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 7750e5b75505Sopenharmony_ci */ 7751e5b75505Sopenharmony_ci res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac, 7752e5b75505Sopenharmony_ci pkex->Mx, curve->prime_len, 7753e5b75505Sopenharmony_ci attr_key /* N.x */, attr_key_len / 2, 7754e5b75505Sopenharmony_ci pkex->code, Kx, Kx_len, 7755e5b75505Sopenharmony_ci pkex->z, curve->hash_len); 7756e5b75505Sopenharmony_ci os_memset(Kx, 0, Kx_len); 7757e5b75505Sopenharmony_ci if (res < 0) 7758e5b75505Sopenharmony_ci goto fail; 7759e5b75505Sopenharmony_ci 7760e5b75505Sopenharmony_ci msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u); 7761e5b75505Sopenharmony_ci if (!msg) 7762e5b75505Sopenharmony_ci goto fail; 7763e5b75505Sopenharmony_ci 7764e5b75505Sopenharmony_ciout: 7765e5b75505Sopenharmony_ci wpabuf_free(A_pub); 7766e5b75505Sopenharmony_ci wpabuf_free(X_pub); 7767e5b75505Sopenharmony_ci wpabuf_free(Y_pub); 7768e5b75505Sopenharmony_ci EC_POINT_free(Qr); 7769e5b75505Sopenharmony_ci EC_POINT_free(Y); 7770e5b75505Sopenharmony_ci EC_POINT_free(N); 7771e5b75505Sopenharmony_ci BN_free(Nx); 7772e5b75505Sopenharmony_ci BN_free(Ny); 7773e5b75505Sopenharmony_ci EC_KEY_free(Y_ec); 7774e5b75505Sopenharmony_ci BN_CTX_free(bnctx); 7775e5b75505Sopenharmony_ci EC_GROUP_free(group); 7776e5b75505Sopenharmony_ci return msg; 7777e5b75505Sopenharmony_cifail: 7778e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed"); 7779e5b75505Sopenharmony_ci goto out; 7780e5b75505Sopenharmony_ci} 7781e5b75505Sopenharmony_ci 7782e5b75505Sopenharmony_ci 7783e5b75505Sopenharmony_cistatic struct wpabuf * 7784e5b75505Sopenharmony_cidpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex, 7785e5b75505Sopenharmony_ci const struct wpabuf *B_pub, const u8 *v) 7786e5b75505Sopenharmony_ci{ 7787e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 7788e5b75505Sopenharmony_ci struct wpabuf *msg = NULL; 7789e5b75505Sopenharmony_ci const u8 *addr[2]; 7790e5b75505Sopenharmony_ci size_t len[2]; 7791e5b75505Sopenharmony_ci u8 octet; 7792e5b75505Sopenharmony_ci u8 *wrapped; 7793e5b75505Sopenharmony_ci struct wpabuf *clear = NULL; 7794e5b75505Sopenharmony_ci size_t clear_len, attr_len; 7795e5b75505Sopenharmony_ci 7796e5b75505Sopenharmony_ci /* {B, v [bootstrapping info]}z */ 7797e5b75505Sopenharmony_ci clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 7798e5b75505Sopenharmony_ci clear = wpabuf_alloc(clear_len); 7799e5b75505Sopenharmony_ci attr_len = 4 + clear_len + AES_BLOCK_SIZE; 7800e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7801e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) 7802e5b75505Sopenharmony_ci attr_len += 5; 7803e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7804e5b75505Sopenharmony_ci msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len); 7805e5b75505Sopenharmony_ci if (!clear || !msg) 7806e5b75505Sopenharmony_ci goto fail; 7807e5b75505Sopenharmony_ci 7808e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7809e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) { 7810e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 7811e5b75505Sopenharmony_ci goto skip_bootstrap_key; 7812e5b75505Sopenharmony_ci } 7813e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) { 7814e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 7815e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 7816e5b75505Sopenharmony_ci wpabuf_put_le16(clear, 2 * curve->prime_len); 7817e5b75505Sopenharmony_ci if (dpp_test_gen_invalid_key(clear, curve) < 0) 7818e5b75505Sopenharmony_ci goto fail; 7819e5b75505Sopenharmony_ci goto skip_bootstrap_key; 7820e5b75505Sopenharmony_ci } 7821e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7822e5b75505Sopenharmony_ci 7823e5b75505Sopenharmony_ci /* B in Bootstrap Key attribute */ 7824e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 7825e5b75505Sopenharmony_ci wpabuf_put_le16(clear, wpabuf_len(B_pub)); 7826e5b75505Sopenharmony_ci wpabuf_put_buf(clear, B_pub); 7827e5b75505Sopenharmony_ci 7828e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7829e5b75505Sopenharmony_ciskip_bootstrap_key: 7830e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) { 7831e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag"); 7832e5b75505Sopenharmony_ci goto skip_r_auth_tag; 7833e5b75505Sopenharmony_ci } 7834e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) { 7835e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch"); 7836e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 7837e5b75505Sopenharmony_ci wpabuf_put_le16(clear, curve->hash_len); 7838e5b75505Sopenharmony_ci wpabuf_put_data(clear, v, curve->hash_len - 1); 7839e5b75505Sopenharmony_ci wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01); 7840e5b75505Sopenharmony_ci goto skip_r_auth_tag; 7841e5b75505Sopenharmony_ci } 7842e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7843e5b75505Sopenharmony_ci 7844e5b75505Sopenharmony_ci /* v in R-Auth tag attribute */ 7845e5b75505Sopenharmony_ci wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 7846e5b75505Sopenharmony_ci wpabuf_put_le16(clear, curve->hash_len); 7847e5b75505Sopenharmony_ci wpabuf_put_data(clear, v, curve->hash_len); 7848e5b75505Sopenharmony_ci 7849e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7850e5b75505Sopenharmony_ciskip_r_auth_tag: 7851e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) { 7852e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 7853e5b75505Sopenharmony_ci goto skip_wrapped_data; 7854e5b75505Sopenharmony_ci } 7855e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7856e5b75505Sopenharmony_ci 7857e5b75505Sopenharmony_ci addr[0] = wpabuf_head_u8(msg) + 2; 7858e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 7859e5b75505Sopenharmony_ci octet = 1; 7860e5b75505Sopenharmony_ci addr[1] = &octet; 7861e5b75505Sopenharmony_ci len[1] = sizeof(octet); 7862e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 7863e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 7864e5b75505Sopenharmony_ci 7865e5b75505Sopenharmony_ci wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 7866e5b75505Sopenharmony_ci wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 7867e5b75505Sopenharmony_ci wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 7868e5b75505Sopenharmony_ci 7869e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 7870e5b75505Sopenharmony_ci if (aes_siv_encrypt(pkex->z, curve->hash_len, 7871e5b75505Sopenharmony_ci wpabuf_head(clear), wpabuf_len(clear), 7872e5b75505Sopenharmony_ci 2, addr, len, wrapped) < 0) 7873e5b75505Sopenharmony_ci goto fail; 7874e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 7875e5b75505Sopenharmony_ci wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 7876e5b75505Sopenharmony_ci 7877e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7878e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) { 7879e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 7880e5b75505Sopenharmony_ci dpp_build_attr_status(msg, DPP_STATUS_OK); 7881e5b75505Sopenharmony_ci } 7882e5b75505Sopenharmony_ciskip_wrapped_data: 7883e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7884e5b75505Sopenharmony_ci 7885e5b75505Sopenharmony_ciout: 7886e5b75505Sopenharmony_ci wpabuf_free(clear); 7887e5b75505Sopenharmony_ci return msg; 7888e5b75505Sopenharmony_ci 7889e5b75505Sopenharmony_cifail: 7890e5b75505Sopenharmony_ci wpabuf_free(msg); 7891e5b75505Sopenharmony_ci msg = NULL; 7892e5b75505Sopenharmony_ci goto out; 7893e5b75505Sopenharmony_ci} 7894e5b75505Sopenharmony_ci 7895e5b75505Sopenharmony_ci 7896e5b75505Sopenharmony_cistruct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, 7897e5b75505Sopenharmony_ci const u8 *hdr, 7898e5b75505Sopenharmony_ci const u8 *buf, size_t buflen) 7899e5b75505Sopenharmony_ci{ 7900e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 7901e5b75505Sopenharmony_ci size_t Jx_len, Lx_len; 7902e5b75505Sopenharmony_ci u8 Jx[DPP_MAX_SHARED_SECRET_LEN]; 7903e5b75505Sopenharmony_ci u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 7904e5b75505Sopenharmony_ci const u8 *wrapped_data, *b_key, *peer_u; 7905e5b75505Sopenharmony_ci u16 wrapped_data_len, b_key_len, peer_u_len = 0; 7906e5b75505Sopenharmony_ci const u8 *addr[4]; 7907e5b75505Sopenharmony_ci size_t len[4]; 7908e5b75505Sopenharmony_ci u8 octet; 7909e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 7910e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 7911e5b75505Sopenharmony_ci struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 7912e5b75505Sopenharmony_ci struct wpabuf *B_pub = NULL; 7913e5b75505Sopenharmony_ci u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; 7914e5b75505Sopenharmony_ci 7915e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 7916e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) { 7917e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 7918e5b75505Sopenharmony_ci "DPP: TESTING - stop at PKEX CR Request"); 7919e5b75505Sopenharmony_ci pkex->failed = 1; 7920e5b75505Sopenharmony_ci return NULL; 7921e5b75505Sopenharmony_ci } 7922e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 7923e5b75505Sopenharmony_ci 7924e5b75505Sopenharmony_ci if (!pkex->exchange_done || pkex->failed || 7925e5b75505Sopenharmony_ci pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator) 7926e5b75505Sopenharmony_ci goto fail; 7927e5b75505Sopenharmony_ci 7928e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 7929e5b75505Sopenharmony_ci &wrapped_data_len); 7930e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 7931e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, 7932e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 7933e5b75505Sopenharmony_ci goto fail; 7934e5b75505Sopenharmony_ci } 7935e5b75505Sopenharmony_ci 7936e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 7937e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 7938e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 7939e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 7940e5b75505Sopenharmony_ci if (!unwrapped) 7941e5b75505Sopenharmony_ci goto fail; 7942e5b75505Sopenharmony_ci 7943e5b75505Sopenharmony_ci addr[0] = hdr; 7944e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 7945e5b75505Sopenharmony_ci octet = 0; 7946e5b75505Sopenharmony_ci addr[1] = &octet; 7947e5b75505Sopenharmony_ci len[1] = sizeof(octet); 7948e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 7949e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 7950e5b75505Sopenharmony_ci 7951e5b75505Sopenharmony_ci if (aes_siv_decrypt(pkex->z, curve->hash_len, 7952e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 7953e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 7954e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, 7955e5b75505Sopenharmony_ci "AES-SIV decryption failed - possible PKEX code mismatch"); 7956e5b75505Sopenharmony_ci pkex->failed = 1; 7957e5b75505Sopenharmony_ci pkex->t++; 7958e5b75505Sopenharmony_ci goto fail; 7959e5b75505Sopenharmony_ci } 7960e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 7961e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 7962e5b75505Sopenharmony_ci 7963e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 7964e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 7965e5b75505Sopenharmony_ci goto fail; 7966e5b75505Sopenharmony_ci } 7967e5b75505Sopenharmony_ci 7968e5b75505Sopenharmony_ci b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 7969e5b75505Sopenharmony_ci &b_key_len); 7970e5b75505Sopenharmony_ci if (!b_key || b_key_len != 2 * curve->prime_len) { 7971e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 7972e5b75505Sopenharmony_ci goto fail; 7973e5b75505Sopenharmony_ci } 7974e5b75505Sopenharmony_ci pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 7975e5b75505Sopenharmony_ci b_key_len); 7976e5b75505Sopenharmony_ci if (!pkex->peer_bootstrap_key) { 7977e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 7978e5b75505Sopenharmony_ci goto fail; 7979e5b75505Sopenharmony_ci } 7980e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Peer bootstrap public key", 7981e5b75505Sopenharmony_ci pkex->peer_bootstrap_key); 7982e5b75505Sopenharmony_ci 7983e5b75505Sopenharmony_ci /* ECDH: J' = y * A' */ 7984e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0) 7985e5b75505Sopenharmony_ci goto fail; 7986e5b75505Sopenharmony_ci 7987e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 7988e5b75505Sopenharmony_ci Jx, Jx_len); 7989e5b75505Sopenharmony_ci 7990e5b75505Sopenharmony_ci /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */ 7991e5b75505Sopenharmony_ci A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0); 7992e5b75505Sopenharmony_ci Y_pub = dpp_get_pubkey_point(pkex->y, 0); 7993e5b75505Sopenharmony_ci X_pub = dpp_get_pubkey_point(pkex->x, 0); 7994e5b75505Sopenharmony_ci if (!A_pub || !Y_pub || !X_pub) 7995e5b75505Sopenharmony_ci goto fail; 7996e5b75505Sopenharmony_ci addr[0] = pkex->peer_mac; 7997e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 7998e5b75505Sopenharmony_ci addr[1] = wpabuf_head(A_pub); 7999e5b75505Sopenharmony_ci len[1] = wpabuf_len(A_pub) / 2; 8000e5b75505Sopenharmony_ci addr[2] = wpabuf_head(Y_pub); 8001e5b75505Sopenharmony_ci len[2] = wpabuf_len(Y_pub) / 2; 8002e5b75505Sopenharmony_ci addr[3] = wpabuf_head(X_pub); 8003e5b75505Sopenharmony_ci len[3] = wpabuf_len(X_pub) / 2; 8004e5b75505Sopenharmony_ci if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) 8005e5b75505Sopenharmony_ci goto fail; 8006e5b75505Sopenharmony_ci 8007e5b75505Sopenharmony_ci peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 8008e5b75505Sopenharmony_ci &peer_u_len); 8009e5b75505Sopenharmony_ci if (!peer_u || peer_u_len != curve->hash_len || 8010e5b75505Sopenharmony_ci os_memcmp(peer_u, u, curve->hash_len) != 0) { 8011e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found"); 8012e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'", 8013e5b75505Sopenharmony_ci u, curve->hash_len); 8014e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len); 8015e5b75505Sopenharmony_ci pkex->t++; 8016e5b75505Sopenharmony_ci goto fail; 8017e5b75505Sopenharmony_ci } 8018e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received"); 8019e5b75505Sopenharmony_ci 8020e5b75505Sopenharmony_ci /* ECDH: L = b * X' */ 8021e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0) 8022e5b75505Sopenharmony_ci goto fail; 8023e5b75505Sopenharmony_ci 8024e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 8025e5b75505Sopenharmony_ci Lx, Lx_len); 8026e5b75505Sopenharmony_ci 8027e5b75505Sopenharmony_ci /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */ 8028e5b75505Sopenharmony_ci B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0); 8029e5b75505Sopenharmony_ci if (!B_pub) 8030e5b75505Sopenharmony_ci goto fail; 8031e5b75505Sopenharmony_ci addr[0] = pkex->own_mac; 8032e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 8033e5b75505Sopenharmony_ci addr[1] = wpabuf_head(B_pub); 8034e5b75505Sopenharmony_ci len[1] = wpabuf_len(B_pub) / 2; 8035e5b75505Sopenharmony_ci addr[2] = wpabuf_head(X_pub); 8036e5b75505Sopenharmony_ci len[2] = wpabuf_len(X_pub) / 2; 8037e5b75505Sopenharmony_ci addr[3] = wpabuf_head(Y_pub); 8038e5b75505Sopenharmony_ci len[3] = wpabuf_len(Y_pub) / 2; 8039e5b75505Sopenharmony_ci if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) 8040e5b75505Sopenharmony_ci goto fail; 8041e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len); 8042e5b75505Sopenharmony_ci 8043e5b75505Sopenharmony_ci msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v); 8044e5b75505Sopenharmony_ci if (!msg) 8045e5b75505Sopenharmony_ci goto fail; 8046e5b75505Sopenharmony_ci 8047e5b75505Sopenharmony_ciout: 8048e5b75505Sopenharmony_ci os_free(unwrapped); 8049e5b75505Sopenharmony_ci wpabuf_free(A_pub); 8050e5b75505Sopenharmony_ci wpabuf_free(B_pub); 8051e5b75505Sopenharmony_ci wpabuf_free(X_pub); 8052e5b75505Sopenharmony_ci wpabuf_free(Y_pub); 8053e5b75505Sopenharmony_ci return msg; 8054e5b75505Sopenharmony_cifail: 8055e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 8056e5b75505Sopenharmony_ci "DPP: PKEX Commit-Reveal Request processing failed"); 8057e5b75505Sopenharmony_ci goto out; 8058e5b75505Sopenharmony_ci} 8059e5b75505Sopenharmony_ci 8060e5b75505Sopenharmony_ci 8061e5b75505Sopenharmony_ciint dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, 8062e5b75505Sopenharmony_ci const u8 *buf, size_t buflen) 8063e5b75505Sopenharmony_ci{ 8064e5b75505Sopenharmony_ci const struct dpp_curve_params *curve = pkex->own_bi->curve; 8065e5b75505Sopenharmony_ci const u8 *wrapped_data, *b_key, *peer_v; 8066e5b75505Sopenharmony_ci u16 wrapped_data_len, b_key_len, peer_v_len = 0; 8067e5b75505Sopenharmony_ci const u8 *addr[4]; 8068e5b75505Sopenharmony_ci size_t len[4]; 8069e5b75505Sopenharmony_ci u8 octet; 8070e5b75505Sopenharmony_ci u8 *unwrapped = NULL; 8071e5b75505Sopenharmony_ci size_t unwrapped_len = 0; 8072e5b75505Sopenharmony_ci int ret = -1; 8073e5b75505Sopenharmony_ci u8 v[DPP_MAX_HASH_LEN]; 8074e5b75505Sopenharmony_ci size_t Lx_len; 8075e5b75505Sopenharmony_ci u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 8076e5b75505Sopenharmony_ci struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 8077e5b75505Sopenharmony_ci 8078e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 8079e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) { 8080e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 8081e5b75505Sopenharmony_ci "DPP: TESTING - stop at PKEX CR Response"); 8082e5b75505Sopenharmony_ci pkex->failed = 1; 8083e5b75505Sopenharmony_ci goto fail; 8084e5b75505Sopenharmony_ci } 8085e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 8086e5b75505Sopenharmony_ci 8087e5b75505Sopenharmony_ci if (!pkex->exchange_done || pkex->failed || 8088e5b75505Sopenharmony_ci pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 8089e5b75505Sopenharmony_ci goto fail; 8090e5b75505Sopenharmony_ci 8091e5b75505Sopenharmony_ci wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 8092e5b75505Sopenharmony_ci &wrapped_data_len); 8093e5b75505Sopenharmony_ci if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 8094e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, 8095e5b75505Sopenharmony_ci "Missing or invalid required Wrapped Data attribute"); 8096e5b75505Sopenharmony_ci goto fail; 8097e5b75505Sopenharmony_ci } 8098e5b75505Sopenharmony_ci 8099e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 8100e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len); 8101e5b75505Sopenharmony_ci unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 8102e5b75505Sopenharmony_ci unwrapped = os_malloc(unwrapped_len); 8103e5b75505Sopenharmony_ci if (!unwrapped) 8104e5b75505Sopenharmony_ci goto fail; 8105e5b75505Sopenharmony_ci 8106e5b75505Sopenharmony_ci addr[0] = hdr; 8107e5b75505Sopenharmony_ci len[0] = DPP_HDR_LEN; 8108e5b75505Sopenharmony_ci octet = 1; 8109e5b75505Sopenharmony_ci addr[1] = &octet; 8110e5b75505Sopenharmony_ci len[1] = sizeof(octet); 8111e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 8112e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 8113e5b75505Sopenharmony_ci 8114e5b75505Sopenharmony_ci if (aes_siv_decrypt(pkex->z, curve->hash_len, 8115e5b75505Sopenharmony_ci wrapped_data, wrapped_data_len, 8116e5b75505Sopenharmony_ci 2, addr, len, unwrapped) < 0) { 8117e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, 8118e5b75505Sopenharmony_ci "AES-SIV decryption failed - possible PKEX code mismatch"); 8119e5b75505Sopenharmony_ci pkex->t++; 8120e5b75505Sopenharmony_ci goto fail; 8121e5b75505Sopenharmony_ci } 8122e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 8123e5b75505Sopenharmony_ci unwrapped, unwrapped_len); 8124e5b75505Sopenharmony_ci 8125e5b75505Sopenharmony_ci if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 8126e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 8127e5b75505Sopenharmony_ci goto fail; 8128e5b75505Sopenharmony_ci } 8129e5b75505Sopenharmony_ci 8130e5b75505Sopenharmony_ci b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 8131e5b75505Sopenharmony_ci &b_key_len); 8132e5b75505Sopenharmony_ci if (!b_key || b_key_len != 2 * curve->prime_len) { 8133e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 8134e5b75505Sopenharmony_ci goto fail; 8135e5b75505Sopenharmony_ci } 8136e5b75505Sopenharmony_ci pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 8137e5b75505Sopenharmony_ci b_key_len); 8138e5b75505Sopenharmony_ci if (!pkex->peer_bootstrap_key) { 8139e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 8140e5b75505Sopenharmony_ci goto fail; 8141e5b75505Sopenharmony_ci } 8142e5b75505Sopenharmony_ci dpp_debug_print_key("DPP: Peer bootstrap public key", 8143e5b75505Sopenharmony_ci pkex->peer_bootstrap_key); 8144e5b75505Sopenharmony_ci 8145e5b75505Sopenharmony_ci /* ECDH: L' = x * B' */ 8146e5b75505Sopenharmony_ci if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0) 8147e5b75505Sopenharmony_ci goto fail; 8148e5b75505Sopenharmony_ci 8149e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 8150e5b75505Sopenharmony_ci Lx, Lx_len); 8151e5b75505Sopenharmony_ci 8152e5b75505Sopenharmony_ci /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */ 8153e5b75505Sopenharmony_ci B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0); 8154e5b75505Sopenharmony_ci X_pub = dpp_get_pubkey_point(pkex->x, 0); 8155e5b75505Sopenharmony_ci Y_pub = dpp_get_pubkey_point(pkex->y, 0); 8156e5b75505Sopenharmony_ci if (!B_pub || !X_pub || !Y_pub) 8157e5b75505Sopenharmony_ci goto fail; 8158e5b75505Sopenharmony_ci addr[0] = pkex->peer_mac; 8159e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 8160e5b75505Sopenharmony_ci addr[1] = wpabuf_head(B_pub); 8161e5b75505Sopenharmony_ci len[1] = wpabuf_len(B_pub) / 2; 8162e5b75505Sopenharmony_ci addr[2] = wpabuf_head(X_pub); 8163e5b75505Sopenharmony_ci len[2] = wpabuf_len(X_pub) / 2; 8164e5b75505Sopenharmony_ci addr[3] = wpabuf_head(Y_pub); 8165e5b75505Sopenharmony_ci len[3] = wpabuf_len(Y_pub) / 2; 8166e5b75505Sopenharmony_ci if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) 8167e5b75505Sopenharmony_ci goto fail; 8168e5b75505Sopenharmony_ci 8169e5b75505Sopenharmony_ci peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG, 8170e5b75505Sopenharmony_ci &peer_v_len); 8171e5b75505Sopenharmony_ci if (!peer_v || peer_v_len != curve->hash_len || 8172e5b75505Sopenharmony_ci os_memcmp(peer_v, v, curve->hash_len) != 0) { 8173e5b75505Sopenharmony_ci dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found"); 8174e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'", 8175e5b75505Sopenharmony_ci v, curve->hash_len); 8176e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len); 8177e5b75505Sopenharmony_ci pkex->t++; 8178e5b75505Sopenharmony_ci goto fail; 8179e5b75505Sopenharmony_ci } 8180e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received"); 8181e5b75505Sopenharmony_ci 8182e5b75505Sopenharmony_ci ret = 0; 8183e5b75505Sopenharmony_ciout: 8184e5b75505Sopenharmony_ci wpabuf_free(B_pub); 8185e5b75505Sopenharmony_ci wpabuf_free(X_pub); 8186e5b75505Sopenharmony_ci wpabuf_free(Y_pub); 8187e5b75505Sopenharmony_ci os_free(unwrapped); 8188e5b75505Sopenharmony_ci return ret; 8189e5b75505Sopenharmony_cifail: 8190e5b75505Sopenharmony_ci goto out; 8191e5b75505Sopenharmony_ci} 8192e5b75505Sopenharmony_ci 8193e5b75505Sopenharmony_ci 8194e5b75505Sopenharmony_civoid dpp_pkex_free(struct dpp_pkex *pkex) 8195e5b75505Sopenharmony_ci{ 8196e5b75505Sopenharmony_ci if (!pkex) 8197e5b75505Sopenharmony_ci return; 8198e5b75505Sopenharmony_ci 8199e5b75505Sopenharmony_ci os_free(pkex->identifier); 8200e5b75505Sopenharmony_ci os_free(pkex->code); 8201e5b75505Sopenharmony_ci EVP_PKEY_free(pkex->x); 8202e5b75505Sopenharmony_ci EVP_PKEY_free(pkex->y); 8203e5b75505Sopenharmony_ci EVP_PKEY_free(pkex->peer_bootstrap_key); 8204e5b75505Sopenharmony_ci wpabuf_free(pkex->exchange_req); 8205e5b75505Sopenharmony_ci wpabuf_free(pkex->exchange_resp); 8206e5b75505Sopenharmony_ci os_free(pkex); 8207e5b75505Sopenharmony_ci} 8208e5b75505Sopenharmony_ci 8209e5b75505Sopenharmony_ci 8210e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 8211e5b75505Sopenharmony_cichar * dpp_corrupt_connector_signature(const char *connector) 8212e5b75505Sopenharmony_ci{ 8213e5b75505Sopenharmony_ci char *tmp, *pos, *signed3 = NULL; 8214e5b75505Sopenharmony_ci unsigned char *signature = NULL; 8215e5b75505Sopenharmony_ci size_t signature_len = 0, signed3_len; 8216e5b75505Sopenharmony_ci 8217e5b75505Sopenharmony_ci tmp = os_zalloc(os_strlen(connector) + 5); 8218e5b75505Sopenharmony_ci if (!tmp) 8219e5b75505Sopenharmony_ci goto fail; 8220e5b75505Sopenharmony_ci os_memcpy(tmp, connector, os_strlen(connector)); 8221e5b75505Sopenharmony_ci 8222e5b75505Sopenharmony_ci pos = os_strchr(tmp, '.'); 8223e5b75505Sopenharmony_ci if (!pos) 8224e5b75505Sopenharmony_ci goto fail; 8225e5b75505Sopenharmony_ci 8226e5b75505Sopenharmony_ci pos = os_strchr(pos + 1, '.'); 8227e5b75505Sopenharmony_ci if (!pos) 8228e5b75505Sopenharmony_ci goto fail; 8229e5b75505Sopenharmony_ci pos++; 8230e5b75505Sopenharmony_ci 8231e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s", 8232e5b75505Sopenharmony_ci pos); 8233e5b75505Sopenharmony_ci signature = base64_url_decode((const unsigned char *) pos, 8234e5b75505Sopenharmony_ci os_strlen(pos), &signature_len); 8235e5b75505Sopenharmony_ci if (!signature || signature_len == 0) 8236e5b75505Sopenharmony_ci goto fail; 8237e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature", 8238e5b75505Sopenharmony_ci signature, signature_len); 8239e5b75505Sopenharmony_ci signature[signature_len - 1] ^= 0x01; 8240e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature", 8241e5b75505Sopenharmony_ci signature, signature_len); 8242e5b75505Sopenharmony_ci signed3 = (char *) base64_url_encode(signature, signature_len, 8243e5b75505Sopenharmony_ci &signed3_len, 0); 8244e5b75505Sopenharmony_ci if (!signed3) 8245e5b75505Sopenharmony_ci goto fail; 8246e5b75505Sopenharmony_ci os_memcpy(pos, signed3, signed3_len); 8247e5b75505Sopenharmony_ci pos[signed3_len] = '\0'; 8248e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s", 8249e5b75505Sopenharmony_ci pos); 8250e5b75505Sopenharmony_ci 8251e5b75505Sopenharmony_ciout: 8252e5b75505Sopenharmony_ci os_free(signature); 8253e5b75505Sopenharmony_ci os_free(signed3); 8254e5b75505Sopenharmony_ci return tmp; 8255e5b75505Sopenharmony_cifail: 8256e5b75505Sopenharmony_ci os_free(tmp); 8257e5b75505Sopenharmony_ci tmp = NULL; 8258e5b75505Sopenharmony_ci goto out; 8259e5b75505Sopenharmony_ci} 8260e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 8261e5b75505Sopenharmony_ci 8262e5b75505Sopenharmony_ci 8263e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8264e5b75505Sopenharmony_ci 8265e5b75505Sopenharmony_cistruct dpp_pfs * dpp_pfs_init(const u8 *net_access_key, 8266e5b75505Sopenharmony_ci size_t net_access_key_len) 8267e5b75505Sopenharmony_ci{ 8268e5b75505Sopenharmony_ci struct wpabuf *pub = NULL; 8269e5b75505Sopenharmony_ci EVP_PKEY *own_key; 8270e5b75505Sopenharmony_ci struct dpp_pfs *pfs; 8271e5b75505Sopenharmony_ci 8272e5b75505Sopenharmony_ci pfs = os_zalloc(sizeof(*pfs)); 8273e5b75505Sopenharmony_ci if (!pfs) 8274e5b75505Sopenharmony_ci return NULL; 8275e5b75505Sopenharmony_ci 8276e5b75505Sopenharmony_ci own_key = dpp_set_keypair(&pfs->curve, net_access_key, 8277e5b75505Sopenharmony_ci net_access_key_len); 8278e5b75505Sopenharmony_ci if (!own_key) { 8279e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 8280e5b75505Sopenharmony_ci goto fail; 8281e5b75505Sopenharmony_ci } 8282e5b75505Sopenharmony_ci EVP_PKEY_free(own_key); 8283e5b75505Sopenharmony_ci 8284e5b75505Sopenharmony_ci pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group); 8285e5b75505Sopenharmony_ci if (!pfs->ecdh) 8286e5b75505Sopenharmony_ci goto fail; 8287e5b75505Sopenharmony_ci 8288e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0); 8289e5b75505Sopenharmony_ci pub = wpabuf_zeropad(pub, pfs->curve->prime_len); 8290e5b75505Sopenharmony_ci if (!pub) 8291e5b75505Sopenharmony_ci goto fail; 8292e5b75505Sopenharmony_ci 8293e5b75505Sopenharmony_ci pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub)); 8294e5b75505Sopenharmony_ci if (!pfs->ie) 8295e5b75505Sopenharmony_ci goto fail; 8296e5b75505Sopenharmony_ci wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION); 8297e5b75505Sopenharmony_ci wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub)); 8298e5b75505Sopenharmony_ci wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM); 8299e5b75505Sopenharmony_ci wpabuf_put_le16(pfs->ie, pfs->curve->ike_group); 8300e5b75505Sopenharmony_ci wpabuf_put_buf(pfs->ie, pub); 8301e5b75505Sopenharmony_ci wpabuf_free(pub); 8302e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element", 8303e5b75505Sopenharmony_ci pfs->ie); 8304e5b75505Sopenharmony_ci 8305e5b75505Sopenharmony_ci return pfs; 8306e5b75505Sopenharmony_cifail: 8307e5b75505Sopenharmony_ci wpabuf_free(pub); 8308e5b75505Sopenharmony_ci dpp_pfs_free(pfs); 8309e5b75505Sopenharmony_ci return NULL; 8310e5b75505Sopenharmony_ci} 8311e5b75505Sopenharmony_ci 8312e5b75505Sopenharmony_ci 8313e5b75505Sopenharmony_ciint dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len) 8314e5b75505Sopenharmony_ci{ 8315e5b75505Sopenharmony_ci if (peer_ie_len < 2) 8316e5b75505Sopenharmony_ci return -1; 8317e5b75505Sopenharmony_ci if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) { 8318e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS"); 8319e5b75505Sopenharmony_ci return -1; 8320e5b75505Sopenharmony_ci } 8321e5b75505Sopenharmony_ci 8322e5b75505Sopenharmony_ci pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2, 8323e5b75505Sopenharmony_ci peer_ie_len - 2); 8324e5b75505Sopenharmony_ci pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len); 8325e5b75505Sopenharmony_ci if (!pfs->secret) { 8326e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key"); 8327e5b75505Sopenharmony_ci return -1; 8328e5b75505Sopenharmony_ci } 8329e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret); 8330e5b75505Sopenharmony_ci return 0; 8331e5b75505Sopenharmony_ci} 8332e5b75505Sopenharmony_ci 8333e5b75505Sopenharmony_ci 8334e5b75505Sopenharmony_civoid dpp_pfs_free(struct dpp_pfs *pfs) 8335e5b75505Sopenharmony_ci{ 8336e5b75505Sopenharmony_ci if (!pfs) 8337e5b75505Sopenharmony_ci return; 8338e5b75505Sopenharmony_ci crypto_ecdh_deinit(pfs->ecdh); 8339e5b75505Sopenharmony_ci wpabuf_free(pfs->ie); 8340e5b75505Sopenharmony_ci wpabuf_clear_free(pfs->secret); 8341e5b75505Sopenharmony_ci os_free(pfs); 8342e5b75505Sopenharmony_ci} 8343e5b75505Sopenharmony_ci 8344e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 8345e5b75505Sopenharmony_ci 8346e5b75505Sopenharmony_ci 8347e5b75505Sopenharmony_cistatic unsigned int dpp_next_id(struct dpp_global *dpp) 8348e5b75505Sopenharmony_ci{ 8349e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8350e5b75505Sopenharmony_ci unsigned int max_id = 0; 8351e5b75505Sopenharmony_ci 8352e5b75505Sopenharmony_ci dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 8353e5b75505Sopenharmony_ci if (bi->id > max_id) 8354e5b75505Sopenharmony_ci max_id = bi->id; 8355e5b75505Sopenharmony_ci } 8356e5b75505Sopenharmony_ci return max_id + 1; 8357e5b75505Sopenharmony_ci} 8358e5b75505Sopenharmony_ci 8359e5b75505Sopenharmony_ci 8360e5b75505Sopenharmony_cistatic int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id) 8361e5b75505Sopenharmony_ci{ 8362e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi, *tmp; 8363e5b75505Sopenharmony_ci int found = 0; 8364e5b75505Sopenharmony_ci 8365e5b75505Sopenharmony_ci if (!dpp) 8366e5b75505Sopenharmony_ci return -1; 8367e5b75505Sopenharmony_ci 8368e5b75505Sopenharmony_ci dl_list_for_each_safe(bi, tmp, &dpp->bootstrap, 8369e5b75505Sopenharmony_ci struct dpp_bootstrap_info, list) { 8370e5b75505Sopenharmony_ci if (id && bi->id != id) 8371e5b75505Sopenharmony_ci continue; 8372e5b75505Sopenharmony_ci found = 1; 8373e5b75505Sopenharmony_ci dl_list_del(&bi->list); 8374e5b75505Sopenharmony_ci dpp_bootstrap_info_free(bi); 8375e5b75505Sopenharmony_ci } 8376e5b75505Sopenharmony_ci 8377e5b75505Sopenharmony_ci if (id == 0) 8378e5b75505Sopenharmony_ci return 0; /* flush succeeds regardless of entries found */ 8379e5b75505Sopenharmony_ci return found ? 0 : -1; 8380e5b75505Sopenharmony_ci} 8381e5b75505Sopenharmony_ci 8382e5b75505Sopenharmony_ci 8383e5b75505Sopenharmony_cistruct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp, 8384e5b75505Sopenharmony_ci const char *uri) 8385e5b75505Sopenharmony_ci{ 8386e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8387e5b75505Sopenharmony_ci 8388e5b75505Sopenharmony_ci if (!dpp) 8389e5b75505Sopenharmony_ci return NULL; 8390e5b75505Sopenharmony_ci 8391e5b75505Sopenharmony_ci bi = dpp_parse_qr_code(uri); 8392e5b75505Sopenharmony_ci if (!bi) 8393e5b75505Sopenharmony_ci return NULL; 8394e5b75505Sopenharmony_ci 8395e5b75505Sopenharmony_ci bi->id = dpp_next_id(dpp); 8396e5b75505Sopenharmony_ci dl_list_add(&dpp->bootstrap, &bi->list); 8397e5b75505Sopenharmony_ci return bi; 8398e5b75505Sopenharmony_ci} 8399e5b75505Sopenharmony_ci 8400e5b75505Sopenharmony_ci 8401e5b75505Sopenharmony_ciint dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) 8402e5b75505Sopenharmony_ci{ 8403e5b75505Sopenharmony_ci char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL; 8404e5b75505Sopenharmony_ci char *key = NULL; 8405e5b75505Sopenharmony_ci u8 *privkey = NULL; 8406e5b75505Sopenharmony_ci size_t privkey_len = 0; 8407e5b75505Sopenharmony_ci size_t len; 8408e5b75505Sopenharmony_ci int ret = -1; 8409e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8410e5b75505Sopenharmony_ci 8411e5b75505Sopenharmony_ci if (!dpp) 8412e5b75505Sopenharmony_ci return -1; 8413e5b75505Sopenharmony_ci 8414e5b75505Sopenharmony_ci bi = os_zalloc(sizeof(*bi)); 8415e5b75505Sopenharmony_ci if (!bi) 8416e5b75505Sopenharmony_ci goto fail; 8417e5b75505Sopenharmony_ci 8418e5b75505Sopenharmony_ci if (os_strstr(cmd, "type=qrcode")) 8419e5b75505Sopenharmony_ci bi->type = DPP_BOOTSTRAP_QR_CODE; 8420e5b75505Sopenharmony_ci else if (os_strstr(cmd, "type=pkex")) 8421e5b75505Sopenharmony_ci bi->type = DPP_BOOTSTRAP_PKEX; 8422e5b75505Sopenharmony_ci else 8423e5b75505Sopenharmony_ci goto fail; 8424e5b75505Sopenharmony_ci 8425e5b75505Sopenharmony_ci chan = get_param(cmd, " chan="); 8426e5b75505Sopenharmony_ci mac = get_param(cmd, " mac="); 8427e5b75505Sopenharmony_ci info = get_param(cmd, " info="); 8428e5b75505Sopenharmony_ci curve = get_param(cmd, " curve="); 8429e5b75505Sopenharmony_ci key = get_param(cmd, " key="); 8430e5b75505Sopenharmony_ci 8431e5b75505Sopenharmony_ci if (key) { 8432e5b75505Sopenharmony_ci privkey_len = os_strlen(key) / 2; 8433e5b75505Sopenharmony_ci privkey = os_malloc(privkey_len); 8434e5b75505Sopenharmony_ci if (!privkey || 8435e5b75505Sopenharmony_ci hexstr2bin(key, privkey, privkey_len) < 0) 8436e5b75505Sopenharmony_ci goto fail; 8437e5b75505Sopenharmony_ci } 8438e5b75505Sopenharmony_ci 8439e5b75505Sopenharmony_ci pk = dpp_keygen(bi, curve, privkey, privkey_len); 8440e5b75505Sopenharmony_ci if (!pk) 8441e5b75505Sopenharmony_ci goto fail; 8442e5b75505Sopenharmony_ci 8443e5b75505Sopenharmony_ci len = 4; /* "DPP:" */ 8444e5b75505Sopenharmony_ci if (chan) { 8445e5b75505Sopenharmony_ci if (dpp_parse_uri_chan_list(bi, chan) < 0) 8446e5b75505Sopenharmony_ci goto fail; 8447e5b75505Sopenharmony_ci len += 3 + os_strlen(chan); /* C:...; */ 8448e5b75505Sopenharmony_ci } 8449e5b75505Sopenharmony_ci if (mac) { 8450e5b75505Sopenharmony_ci if (dpp_parse_uri_mac(bi, mac) < 0) 8451e5b75505Sopenharmony_ci goto fail; 8452e5b75505Sopenharmony_ci len += 3 + os_strlen(mac); /* M:...; */ 8453e5b75505Sopenharmony_ci } 8454e5b75505Sopenharmony_ci if (info) { 8455e5b75505Sopenharmony_ci if (dpp_parse_uri_info(bi, info) < 0) 8456e5b75505Sopenharmony_ci goto fail; 8457e5b75505Sopenharmony_ci len += 3 + os_strlen(info); /* I:...; */ 8458e5b75505Sopenharmony_ci } 8459e5b75505Sopenharmony_ci len += 4 + os_strlen(pk); 8460e5b75505Sopenharmony_ci bi->uri = os_malloc(len + 1); 8461e5b75505Sopenharmony_ci if (!bi->uri) 8462e5b75505Sopenharmony_ci goto fail; 8463e5b75505Sopenharmony_ci os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;", 8464e5b75505Sopenharmony_ci chan ? "C:" : "", chan ? chan : "", chan ? ";" : "", 8465e5b75505Sopenharmony_ci mac ? "M:" : "", mac ? mac : "", mac ? ";" : "", 8466e5b75505Sopenharmony_ci info ? "I:" : "", info ? info : "", info ? ";" : "", 8467e5b75505Sopenharmony_ci pk); 8468e5b75505Sopenharmony_ci bi->id = dpp_next_id(dpp); 8469e5b75505Sopenharmony_ci dl_list_add(&dpp->bootstrap, &bi->list); 8470e5b75505Sopenharmony_ci ret = bi->id; 8471e5b75505Sopenharmony_ci bi = NULL; 8472e5b75505Sopenharmony_cifail: 8473e5b75505Sopenharmony_ci os_free(curve); 8474e5b75505Sopenharmony_ci os_free(pk); 8475e5b75505Sopenharmony_ci os_free(chan); 8476e5b75505Sopenharmony_ci os_free(mac); 8477e5b75505Sopenharmony_ci os_free(info); 8478e5b75505Sopenharmony_ci str_clear_free(key); 8479e5b75505Sopenharmony_ci bin_clear_free(privkey, privkey_len); 8480e5b75505Sopenharmony_ci dpp_bootstrap_info_free(bi); 8481e5b75505Sopenharmony_ci return ret; 8482e5b75505Sopenharmony_ci} 8483e5b75505Sopenharmony_ci 8484e5b75505Sopenharmony_ci 8485e5b75505Sopenharmony_cistruct dpp_bootstrap_info * 8486e5b75505Sopenharmony_cidpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id) 8487e5b75505Sopenharmony_ci{ 8488e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8489e5b75505Sopenharmony_ci 8490e5b75505Sopenharmony_ci if (!dpp) 8491e5b75505Sopenharmony_ci return NULL; 8492e5b75505Sopenharmony_ci 8493e5b75505Sopenharmony_ci dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 8494e5b75505Sopenharmony_ci if (bi->id == id) 8495e5b75505Sopenharmony_ci return bi; 8496e5b75505Sopenharmony_ci } 8497e5b75505Sopenharmony_ci return NULL; 8498e5b75505Sopenharmony_ci} 8499e5b75505Sopenharmony_ci 8500e5b75505Sopenharmony_ci 8501e5b75505Sopenharmony_ciint dpp_bootstrap_remove(struct dpp_global *dpp, const char *id) 8502e5b75505Sopenharmony_ci{ 8503e5b75505Sopenharmony_ci unsigned int id_val; 8504e5b75505Sopenharmony_ci 8505e5b75505Sopenharmony_ci if (os_strcmp(id, "*") == 0) { 8506e5b75505Sopenharmony_ci id_val = 0; 8507e5b75505Sopenharmony_ci } else { 8508e5b75505Sopenharmony_ci id_val = atoi(id); 8509e5b75505Sopenharmony_ci if (id_val == 0) 8510e5b75505Sopenharmony_ci return -1; 8511e5b75505Sopenharmony_ci } 8512e5b75505Sopenharmony_ci 8513e5b75505Sopenharmony_ci return dpp_bootstrap_del(dpp, id_val); 8514e5b75505Sopenharmony_ci} 8515e5b75505Sopenharmony_ci 8516e5b75505Sopenharmony_ci 8517e5b75505Sopenharmony_cistruct dpp_bootstrap_info * 8518e5b75505Sopenharmony_cidpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, 8519e5b75505Sopenharmony_ci unsigned int freq) 8520e5b75505Sopenharmony_ci{ 8521e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8522e5b75505Sopenharmony_ci 8523e5b75505Sopenharmony_ci bi = os_zalloc(sizeof(*bi)); 8524e5b75505Sopenharmony_ci if (!bi) 8525e5b75505Sopenharmony_ci return NULL; 8526e5b75505Sopenharmony_ci bi->id = dpp_next_id(dpp); 8527e5b75505Sopenharmony_ci bi->type = DPP_BOOTSTRAP_PKEX; 8528e5b75505Sopenharmony_ci os_memcpy(bi->mac_addr, peer, ETH_ALEN); 8529e5b75505Sopenharmony_ci bi->num_freq = 1; 8530e5b75505Sopenharmony_ci bi->freq[0] = freq; 8531e5b75505Sopenharmony_ci bi->curve = pkex->own_bi->curve; 8532e5b75505Sopenharmony_ci bi->pubkey = pkex->peer_bootstrap_key; 8533e5b75505Sopenharmony_ci pkex->peer_bootstrap_key = NULL; 8534e5b75505Sopenharmony_ci if (dpp_bootstrap_key_hash(bi) < 0) { 8535e5b75505Sopenharmony_ci dpp_bootstrap_info_free(bi); 8536e5b75505Sopenharmony_ci return NULL; 8537e5b75505Sopenharmony_ci } 8538e5b75505Sopenharmony_ci dpp_pkex_free(pkex); 8539e5b75505Sopenharmony_ci dl_list_add(&dpp->bootstrap, &bi->list); 8540e5b75505Sopenharmony_ci return bi; 8541e5b75505Sopenharmony_ci} 8542e5b75505Sopenharmony_ci 8543e5b75505Sopenharmony_ci 8544e5b75505Sopenharmony_ciconst char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id) 8545e5b75505Sopenharmony_ci{ 8546e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8547e5b75505Sopenharmony_ci 8548e5b75505Sopenharmony_ci bi = dpp_bootstrap_get_id(dpp, id); 8549e5b75505Sopenharmony_ci if (!bi) 8550e5b75505Sopenharmony_ci return NULL; 8551e5b75505Sopenharmony_ci return bi->uri; 8552e5b75505Sopenharmony_ci} 8553e5b75505Sopenharmony_ci 8554e5b75505Sopenharmony_ci 8555e5b75505Sopenharmony_ciint dpp_bootstrap_info(struct dpp_global *dpp, int id, 8556e5b75505Sopenharmony_ci char *reply, int reply_size) 8557e5b75505Sopenharmony_ci{ 8558e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8559e5b75505Sopenharmony_ci char pkhash[2 * SHA256_MAC_LEN + 1]; 8560e5b75505Sopenharmony_ci 8561e5b75505Sopenharmony_ci bi = dpp_bootstrap_get_id(dpp, id); 8562e5b75505Sopenharmony_ci if (!bi) 8563e5b75505Sopenharmony_ci return -1; 8564e5b75505Sopenharmony_ci wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash, 8565e5b75505Sopenharmony_ci SHA256_MAC_LEN); 8566e5b75505Sopenharmony_ci return os_snprintf(reply, reply_size, "type=%s\n" 8567e5b75505Sopenharmony_ci "mac_addr=" MACSTR "\n" 8568e5b75505Sopenharmony_ci "info=%s\n" 8569e5b75505Sopenharmony_ci "num_freq=%u\n" 8570e5b75505Sopenharmony_ci "curve=%s\n" 8571e5b75505Sopenharmony_ci "pkhash=%s\n", 8572e5b75505Sopenharmony_ci dpp_bootstrap_type_txt(bi->type), 8573e5b75505Sopenharmony_ci MAC2STR(bi->mac_addr), 8574e5b75505Sopenharmony_ci bi->info ? bi->info : "", 8575e5b75505Sopenharmony_ci bi->num_freq, 8576e5b75505Sopenharmony_ci bi->curve->name, 8577e5b75505Sopenharmony_ci pkhash); 8578e5b75505Sopenharmony_ci} 8579e5b75505Sopenharmony_ci 8580e5b75505Sopenharmony_ci 8581e5b75505Sopenharmony_civoid dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, 8582e5b75505Sopenharmony_ci const u8 *r_bootstrap, 8583e5b75505Sopenharmony_ci struct dpp_bootstrap_info **own_bi, 8584e5b75505Sopenharmony_ci struct dpp_bootstrap_info **peer_bi) 8585e5b75505Sopenharmony_ci{ 8586e5b75505Sopenharmony_ci struct dpp_bootstrap_info *bi; 8587e5b75505Sopenharmony_ci 8588e5b75505Sopenharmony_ci *own_bi = NULL; 8589e5b75505Sopenharmony_ci *peer_bi = NULL; 8590e5b75505Sopenharmony_ci if (!dpp) 8591e5b75505Sopenharmony_ci return; 8592e5b75505Sopenharmony_ci 8593e5b75505Sopenharmony_ci dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { 8594e5b75505Sopenharmony_ci if (!*own_bi && bi->own && 8595e5b75505Sopenharmony_ci os_memcmp(bi->pubkey_hash, r_bootstrap, 8596e5b75505Sopenharmony_ci SHA256_MAC_LEN) == 0) { 8597e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 8598e5b75505Sopenharmony_ci "DPP: Found matching own bootstrapping information"); 8599e5b75505Sopenharmony_ci *own_bi = bi; 8600e5b75505Sopenharmony_ci } 8601e5b75505Sopenharmony_ci 8602e5b75505Sopenharmony_ci if (!*peer_bi && !bi->own && 8603e5b75505Sopenharmony_ci os_memcmp(bi->pubkey_hash, i_bootstrap, 8604e5b75505Sopenharmony_ci SHA256_MAC_LEN) == 0) { 8605e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 8606e5b75505Sopenharmony_ci "DPP: Found matching peer bootstrapping information"); 8607e5b75505Sopenharmony_ci *peer_bi = bi; 8608e5b75505Sopenharmony_ci } 8609e5b75505Sopenharmony_ci 8610e5b75505Sopenharmony_ci if (*own_bi && *peer_bi) 8611e5b75505Sopenharmony_ci break; 8612e5b75505Sopenharmony_ci } 8613e5b75505Sopenharmony_ci 8614e5b75505Sopenharmony_ci} 8615e5b75505Sopenharmony_ci 8616e5b75505Sopenharmony_ci 8617e5b75505Sopenharmony_cistatic unsigned int dpp_next_configurator_id(struct dpp_global *dpp) 8618e5b75505Sopenharmony_ci{ 8619e5b75505Sopenharmony_ci struct dpp_configurator *conf; 8620e5b75505Sopenharmony_ci unsigned int max_id = 0; 8621e5b75505Sopenharmony_ci 8622e5b75505Sopenharmony_ci dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator, 8623e5b75505Sopenharmony_ci list) { 8624e5b75505Sopenharmony_ci if (conf->id > max_id) 8625e5b75505Sopenharmony_ci max_id = conf->id; 8626e5b75505Sopenharmony_ci } 8627e5b75505Sopenharmony_ci return max_id + 1; 8628e5b75505Sopenharmony_ci} 8629e5b75505Sopenharmony_ci 8630e5b75505Sopenharmony_ci 8631e5b75505Sopenharmony_ciint dpp_configurator_add(struct dpp_global *dpp, const char *cmd) 8632e5b75505Sopenharmony_ci{ 8633e5b75505Sopenharmony_ci char *curve = NULL; 8634e5b75505Sopenharmony_ci char *key = NULL; 8635e5b75505Sopenharmony_ci u8 *privkey = NULL; 8636e5b75505Sopenharmony_ci size_t privkey_len = 0; 8637e5b75505Sopenharmony_ci int ret = -1; 8638e5b75505Sopenharmony_ci struct dpp_configurator *conf = NULL; 8639e5b75505Sopenharmony_ci 8640e5b75505Sopenharmony_ci curve = get_param(cmd, " curve="); 8641e5b75505Sopenharmony_ci key = get_param(cmd, " key="); 8642e5b75505Sopenharmony_ci 8643e5b75505Sopenharmony_ci if (key) { 8644e5b75505Sopenharmony_ci privkey_len = os_strlen(key) / 2; 8645e5b75505Sopenharmony_ci privkey = os_malloc(privkey_len); 8646e5b75505Sopenharmony_ci if (!privkey || 8647e5b75505Sopenharmony_ci hexstr2bin(key, privkey, privkey_len) < 0) 8648e5b75505Sopenharmony_ci goto fail; 8649e5b75505Sopenharmony_ci } 8650e5b75505Sopenharmony_ci 8651e5b75505Sopenharmony_ci conf = dpp_keygen_configurator(curve, privkey, privkey_len); 8652e5b75505Sopenharmony_ci if (!conf) 8653e5b75505Sopenharmony_ci goto fail; 8654e5b75505Sopenharmony_ci 8655e5b75505Sopenharmony_ci conf->id = dpp_next_configurator_id(dpp); 8656e5b75505Sopenharmony_ci dl_list_add(&dpp->configurator, &conf->list); 8657e5b75505Sopenharmony_ci ret = conf->id; 8658e5b75505Sopenharmony_ci conf = NULL; 8659e5b75505Sopenharmony_cifail: 8660e5b75505Sopenharmony_ci os_free(curve); 8661e5b75505Sopenharmony_ci str_clear_free(key); 8662e5b75505Sopenharmony_ci bin_clear_free(privkey, privkey_len); 8663e5b75505Sopenharmony_ci dpp_configurator_free(conf); 8664e5b75505Sopenharmony_ci return ret; 8665e5b75505Sopenharmony_ci} 8666e5b75505Sopenharmony_ci 8667e5b75505Sopenharmony_ci 8668e5b75505Sopenharmony_cistatic int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) 8669e5b75505Sopenharmony_ci{ 8670e5b75505Sopenharmony_ci struct dpp_configurator *conf, *tmp; 8671e5b75505Sopenharmony_ci int found = 0; 8672e5b75505Sopenharmony_ci 8673e5b75505Sopenharmony_ci if (!dpp) 8674e5b75505Sopenharmony_ci return -1; 8675e5b75505Sopenharmony_ci 8676e5b75505Sopenharmony_ci dl_list_for_each_safe(conf, tmp, &dpp->configurator, 8677e5b75505Sopenharmony_ci struct dpp_configurator, list) { 8678e5b75505Sopenharmony_ci if (id && conf->id != id) 8679e5b75505Sopenharmony_ci continue; 8680e5b75505Sopenharmony_ci found = 1; 8681e5b75505Sopenharmony_ci dl_list_del(&conf->list); 8682e5b75505Sopenharmony_ci dpp_configurator_free(conf); 8683e5b75505Sopenharmony_ci } 8684e5b75505Sopenharmony_ci 8685e5b75505Sopenharmony_ci if (id == 0) 8686e5b75505Sopenharmony_ci return 0; /* flush succeeds regardless of entries found */ 8687e5b75505Sopenharmony_ci return found ? 0 : -1; 8688e5b75505Sopenharmony_ci} 8689e5b75505Sopenharmony_ci 8690e5b75505Sopenharmony_ci 8691e5b75505Sopenharmony_ciint dpp_configurator_remove(struct dpp_global *dpp, const char *id) 8692e5b75505Sopenharmony_ci{ 8693e5b75505Sopenharmony_ci unsigned int id_val; 8694e5b75505Sopenharmony_ci 8695e5b75505Sopenharmony_ci if (os_strcmp(id, "*") == 0) { 8696e5b75505Sopenharmony_ci id_val = 0; 8697e5b75505Sopenharmony_ci } else { 8698e5b75505Sopenharmony_ci id_val = atoi(id); 8699e5b75505Sopenharmony_ci if (id_val == 0) 8700e5b75505Sopenharmony_ci return -1; 8701e5b75505Sopenharmony_ci } 8702e5b75505Sopenharmony_ci 8703e5b75505Sopenharmony_ci return dpp_configurator_del(dpp, id_val); 8704e5b75505Sopenharmony_ci} 8705e5b75505Sopenharmony_ci 8706e5b75505Sopenharmony_ci 8707e5b75505Sopenharmony_ciint dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, 8708e5b75505Sopenharmony_ci char *buf, size_t buflen) 8709e5b75505Sopenharmony_ci{ 8710e5b75505Sopenharmony_ci struct dpp_configurator *conf; 8711e5b75505Sopenharmony_ci 8712e5b75505Sopenharmony_ci conf = dpp_configurator_get_id(dpp, id); 8713e5b75505Sopenharmony_ci if (!conf) 8714e5b75505Sopenharmony_ci return -1; 8715e5b75505Sopenharmony_ci 8716e5b75505Sopenharmony_ci return dpp_configurator_get_key(conf, buf, buflen); 8717e5b75505Sopenharmony_ci} 8718e5b75505Sopenharmony_ci 8719e5b75505Sopenharmony_ci 8720e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8721e5b75505Sopenharmony_ci 8722e5b75505Sopenharmony_cistatic void dpp_connection_free(struct dpp_connection *conn) 8723e5b75505Sopenharmony_ci{ 8724e5b75505Sopenharmony_ci if (conn->sock >= 0) { 8725e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d", 8726e5b75505Sopenharmony_ci conn->sock); 8727e5b75505Sopenharmony_ci eloop_unregister_sock(conn->sock, EVENT_TYPE_READ); 8728e5b75505Sopenharmony_ci eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 8729e5b75505Sopenharmony_ci close(conn->sock); 8730e5b75505Sopenharmony_ci } 8731e5b75505Sopenharmony_ci wpabuf_free(conn->msg); 8732e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 8733e5b75505Sopenharmony_ci dpp_auth_deinit(conn->auth); 8734e5b75505Sopenharmony_ci os_free(conn); 8735e5b75505Sopenharmony_ci} 8736e5b75505Sopenharmony_ci 8737e5b75505Sopenharmony_ci 8738e5b75505Sopenharmony_cistatic void dpp_connection_remove(struct dpp_connection *conn) 8739e5b75505Sopenharmony_ci{ 8740e5b75505Sopenharmony_ci dl_list_del(&conn->list); 8741e5b75505Sopenharmony_ci dpp_connection_free(conn); 8742e5b75505Sopenharmony_ci} 8743e5b75505Sopenharmony_ci 8744e5b75505Sopenharmony_ci 8745e5b75505Sopenharmony_cistatic void dpp_tcp_init_flush(struct dpp_global *dpp) 8746e5b75505Sopenharmony_ci{ 8747e5b75505Sopenharmony_ci struct dpp_connection *conn, *tmp; 8748e5b75505Sopenharmony_ci 8749e5b75505Sopenharmony_ci dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection, 8750e5b75505Sopenharmony_ci list) 8751e5b75505Sopenharmony_ci dpp_connection_remove(conn); 8752e5b75505Sopenharmony_ci} 8753e5b75505Sopenharmony_ci 8754e5b75505Sopenharmony_ci 8755e5b75505Sopenharmony_cistatic void dpp_relay_controller_free(struct dpp_relay_controller *ctrl) 8756e5b75505Sopenharmony_ci{ 8757e5b75505Sopenharmony_ci struct dpp_connection *conn, *tmp; 8758e5b75505Sopenharmony_ci 8759e5b75505Sopenharmony_ci dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection, 8760e5b75505Sopenharmony_ci list) 8761e5b75505Sopenharmony_ci dpp_connection_remove(conn); 8762e5b75505Sopenharmony_ci os_free(ctrl); 8763e5b75505Sopenharmony_ci} 8764e5b75505Sopenharmony_ci 8765e5b75505Sopenharmony_ci 8766e5b75505Sopenharmony_cistatic void dpp_relay_flush_controllers(struct dpp_global *dpp) 8767e5b75505Sopenharmony_ci{ 8768e5b75505Sopenharmony_ci struct dpp_relay_controller *ctrl, *tmp; 8769e5b75505Sopenharmony_ci 8770e5b75505Sopenharmony_ci if (!dpp) 8771e5b75505Sopenharmony_ci return; 8772e5b75505Sopenharmony_ci 8773e5b75505Sopenharmony_ci dl_list_for_each_safe(ctrl, tmp, &dpp->controllers, 8774e5b75505Sopenharmony_ci struct dpp_relay_controller, list) { 8775e5b75505Sopenharmony_ci dl_list_del(&ctrl->list); 8776e5b75505Sopenharmony_ci dpp_relay_controller_free(ctrl); 8777e5b75505Sopenharmony_ci } 8778e5b75505Sopenharmony_ci} 8779e5b75505Sopenharmony_ci 8780e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 8781e5b75505Sopenharmony_ci 8782e5b75505Sopenharmony_ci 8783e5b75505Sopenharmony_cistruct dpp_global * dpp_global_init(struct dpp_global_config *config) 8784e5b75505Sopenharmony_ci{ 8785e5b75505Sopenharmony_ci struct dpp_global *dpp; 8786e5b75505Sopenharmony_ci 8787e5b75505Sopenharmony_ci dpp = os_zalloc(sizeof(*dpp)); 8788e5b75505Sopenharmony_ci if (!dpp) 8789e5b75505Sopenharmony_ci return NULL; 8790e5b75505Sopenharmony_ci dpp->msg_ctx = config->msg_ctx; 8791e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8792e5b75505Sopenharmony_ci dpp->cb_ctx = config->cb_ctx; 8793e5b75505Sopenharmony_ci dpp->process_conf_obj = config->process_conf_obj; 8794e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 8795e5b75505Sopenharmony_ci 8796e5b75505Sopenharmony_ci dl_list_init(&dpp->bootstrap); 8797e5b75505Sopenharmony_ci dl_list_init(&dpp->configurator); 8798e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8799e5b75505Sopenharmony_ci dl_list_init(&dpp->controllers); 8800e5b75505Sopenharmony_ci dl_list_init(&dpp->tcp_init); 8801e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 8802e5b75505Sopenharmony_ci 8803e5b75505Sopenharmony_ci return dpp; 8804e5b75505Sopenharmony_ci} 8805e5b75505Sopenharmony_ci 8806e5b75505Sopenharmony_ci 8807e5b75505Sopenharmony_civoid dpp_global_clear(struct dpp_global *dpp) 8808e5b75505Sopenharmony_ci{ 8809e5b75505Sopenharmony_ci if (!dpp) 8810e5b75505Sopenharmony_ci return; 8811e5b75505Sopenharmony_ci 8812e5b75505Sopenharmony_ci dpp_bootstrap_del(dpp, 0); 8813e5b75505Sopenharmony_ci dpp_configurator_del(dpp, 0); 8814e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8815e5b75505Sopenharmony_ci dpp_tcp_init_flush(dpp); 8816e5b75505Sopenharmony_ci dpp_relay_flush_controllers(dpp); 8817e5b75505Sopenharmony_ci dpp_controller_stop(dpp); 8818e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 8819e5b75505Sopenharmony_ci} 8820e5b75505Sopenharmony_ci 8821e5b75505Sopenharmony_ci 8822e5b75505Sopenharmony_civoid dpp_global_deinit(struct dpp_global *dpp) 8823e5b75505Sopenharmony_ci{ 8824e5b75505Sopenharmony_ci dpp_global_clear(dpp); 8825e5b75505Sopenharmony_ci os_free(dpp); 8826e5b75505Sopenharmony_ci} 8827e5b75505Sopenharmony_ci 8828e5b75505Sopenharmony_ci 8829e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 8830e5b75505Sopenharmony_ci 8831e5b75505Sopenharmony_cistatic void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx); 8832e5b75505Sopenharmony_cistatic void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx); 8833e5b75505Sopenharmony_cistatic void dpp_controller_auth_success(struct dpp_connection *conn, 8834e5b75505Sopenharmony_ci int initiator); 8835e5b75505Sopenharmony_ci 8836e5b75505Sopenharmony_ci 8837e5b75505Sopenharmony_ciint dpp_relay_add_controller(struct dpp_global *dpp, 8838e5b75505Sopenharmony_ci struct dpp_relay_config *config) 8839e5b75505Sopenharmony_ci{ 8840e5b75505Sopenharmony_ci struct dpp_relay_controller *ctrl; 8841e5b75505Sopenharmony_ci 8842e5b75505Sopenharmony_ci if (!dpp) 8843e5b75505Sopenharmony_ci return -1; 8844e5b75505Sopenharmony_ci 8845e5b75505Sopenharmony_ci ctrl = os_zalloc(sizeof(*ctrl)); 8846e5b75505Sopenharmony_ci if (!ctrl) 8847e5b75505Sopenharmony_ci return -1; 8848e5b75505Sopenharmony_ci dl_list_init(&ctrl->conn); 8849e5b75505Sopenharmony_ci ctrl->global = dpp; 8850e5b75505Sopenharmony_ci os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr)); 8851e5b75505Sopenharmony_ci os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN); 8852e5b75505Sopenharmony_ci ctrl->cb_ctx = config->cb_ctx; 8853e5b75505Sopenharmony_ci ctrl->tx = config->tx; 8854e5b75505Sopenharmony_ci ctrl->gas_resp_tx = config->gas_resp_tx; 8855e5b75505Sopenharmony_ci dl_list_add(&dpp->controllers, &ctrl->list); 8856e5b75505Sopenharmony_ci return 0; 8857e5b75505Sopenharmony_ci} 8858e5b75505Sopenharmony_ci 8859e5b75505Sopenharmony_ci 8860e5b75505Sopenharmony_cistatic struct dpp_relay_controller * 8861e5b75505Sopenharmony_cidpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash) 8862e5b75505Sopenharmony_ci{ 8863e5b75505Sopenharmony_ci struct dpp_relay_controller *ctrl; 8864e5b75505Sopenharmony_ci 8865e5b75505Sopenharmony_ci if (!dpp) 8866e5b75505Sopenharmony_ci return NULL; 8867e5b75505Sopenharmony_ci 8868e5b75505Sopenharmony_ci dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, 8869e5b75505Sopenharmony_ci list) { 8870e5b75505Sopenharmony_ci if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0) 8871e5b75505Sopenharmony_ci return ctrl; 8872e5b75505Sopenharmony_ci } 8873e5b75505Sopenharmony_ci 8874e5b75505Sopenharmony_ci return NULL; 8875e5b75505Sopenharmony_ci} 8876e5b75505Sopenharmony_ci 8877e5b75505Sopenharmony_ci 8878e5b75505Sopenharmony_cistatic void dpp_controller_gas_done(struct dpp_connection *conn) 8879e5b75505Sopenharmony_ci{ 8880e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 8881e5b75505Sopenharmony_ci 8882e5b75505Sopenharmony_ci if (auth->peer_version >= 2 && 8883e5b75505Sopenharmony_ci auth->conf_resp_status == DPP_STATUS_OK) { 8884e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 8885e5b75505Sopenharmony_ci auth->waiting_conf_result = 1; 8886e5b75505Sopenharmony_ci return; 8887e5b75505Sopenharmony_ci } 8888e5b75505Sopenharmony_ci 8889e5b75505Sopenharmony_ci wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); 8890e5b75505Sopenharmony_ci dpp_connection_remove(conn); 8891e5b75505Sopenharmony_ci} 8892e5b75505Sopenharmony_ci 8893e5b75505Sopenharmony_ci 8894e5b75505Sopenharmony_cistatic int dpp_tcp_send(struct dpp_connection *conn) 8895e5b75505Sopenharmony_ci{ 8896e5b75505Sopenharmony_ci int res; 8897e5b75505Sopenharmony_ci 8898e5b75505Sopenharmony_ci if (!conn->msg_out) { 8899e5b75505Sopenharmony_ci eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 8900e5b75505Sopenharmony_ci conn->write_eloop = 0; 8901e5b75505Sopenharmony_ci return -1; 8902e5b75505Sopenharmony_ci } 8903e5b75505Sopenharmony_ci res = send(conn->sock, 8904e5b75505Sopenharmony_ci wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos, 8905e5b75505Sopenharmony_ci wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0); 8906e5b75505Sopenharmony_ci if (res < 0) { 8907e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s", 8908e5b75505Sopenharmony_ci strerror(errno)); 8909e5b75505Sopenharmony_ci dpp_connection_remove(conn); 8910e5b75505Sopenharmony_ci return -1; 8911e5b75505Sopenharmony_ci } 8912e5b75505Sopenharmony_ci 8913e5b75505Sopenharmony_ci conn->msg_out_pos += res; 8914e5b75505Sopenharmony_ci if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) { 8915e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 8916e5b75505Sopenharmony_ci "DPP: %u/%u bytes of message sent to Controller", 8917e5b75505Sopenharmony_ci (unsigned int) conn->msg_out_pos, 8918e5b75505Sopenharmony_ci (unsigned int) wpabuf_len(conn->msg_out)); 8919e5b75505Sopenharmony_ci if (!conn->write_eloop && 8920e5b75505Sopenharmony_ci eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 8921e5b75505Sopenharmony_ci dpp_conn_tx_ready, conn, NULL) == 0) 8922e5b75505Sopenharmony_ci conn->write_eloop = 1; 8923e5b75505Sopenharmony_ci return 1; 8924e5b75505Sopenharmony_ci } 8925e5b75505Sopenharmony_ci 8926e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP"); 8927e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 8928e5b75505Sopenharmony_ci conn->msg_out = NULL; 8929e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 8930e5b75505Sopenharmony_ci eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE); 8931e5b75505Sopenharmony_ci conn->write_eloop = 0; 8932e5b75505Sopenharmony_ci if (!conn->read_eloop && 8933e5b75505Sopenharmony_ci eloop_register_sock(conn->sock, EVENT_TYPE_READ, 8934e5b75505Sopenharmony_ci dpp_controller_rx, conn, NULL) == 0) 8935e5b75505Sopenharmony_ci conn->read_eloop = 1; 8936e5b75505Sopenharmony_ci if (conn->on_tcp_tx_complete_remove) { 8937e5b75505Sopenharmony_ci dpp_connection_remove(conn); 8938e5b75505Sopenharmony_ci } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done && 8939e5b75505Sopenharmony_ci conn->auth) { 8940e5b75505Sopenharmony_ci dpp_controller_gas_done(conn); 8941e5b75505Sopenharmony_ci } else if (conn->on_tcp_tx_complete_auth_ok) { 8942e5b75505Sopenharmony_ci conn->on_tcp_tx_complete_auth_ok = 0; 8943e5b75505Sopenharmony_ci dpp_controller_auth_success(conn, 1); 8944e5b75505Sopenharmony_ci } 8945e5b75505Sopenharmony_ci 8946e5b75505Sopenharmony_ci return 0; 8947e5b75505Sopenharmony_ci} 8948e5b75505Sopenharmony_ci 8949e5b75505Sopenharmony_ci 8950e5b75505Sopenharmony_cistatic void dpp_controller_start_gas_client(struct dpp_connection *conn) 8951e5b75505Sopenharmony_ci{ 8952e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 8953e5b75505Sopenharmony_ci struct wpabuf *buf; 8954e5b75505Sopenharmony_ci char json[100]; 8955e5b75505Sopenharmony_ci int netrole_ap = 0; /* TODO: make this configurable */ 8956e5b75505Sopenharmony_ci 8957e5b75505Sopenharmony_ci os_snprintf(json, sizeof(json), 8958e5b75505Sopenharmony_ci "{\"name\":\"Test\"," 8959e5b75505Sopenharmony_ci "\"wi-fi_tech\":\"infra\"," 8960e5b75505Sopenharmony_ci "\"netRole\":\"%s\"}", 8961e5b75505Sopenharmony_ci netrole_ap ? "ap" : "sta"); 8962e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 8963e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) { 8964e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr"); 8965e5b75505Sopenharmony_ci json[29] = 'k'; /* replace "infra" with "knfra" */ 8966e5b75505Sopenharmony_ci } 8967e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 8968e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json); 8969e5b75505Sopenharmony_ci 8970e5b75505Sopenharmony_ci buf = dpp_build_conf_req(auth, json); 8971e5b75505Sopenharmony_ci if (!buf) { 8972e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 8973e5b75505Sopenharmony_ci "DPP: No configuration request data available"); 8974e5b75505Sopenharmony_ci return; 8975e5b75505Sopenharmony_ci } 8976e5b75505Sopenharmony_ci 8977e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 8978e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 8979e5b75505Sopenharmony_ci conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1); 8980e5b75505Sopenharmony_ci if (!conn->msg_out) { 8981e5b75505Sopenharmony_ci wpabuf_free(buf); 8982e5b75505Sopenharmony_ci return; 8983e5b75505Sopenharmony_ci } 8984e5b75505Sopenharmony_ci wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1); 8985e5b75505Sopenharmony_ci wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1, 8986e5b75505Sopenharmony_ci wpabuf_len(buf) - 1); 8987e5b75505Sopenharmony_ci wpabuf_free(buf); 8988e5b75505Sopenharmony_ci 8989e5b75505Sopenharmony_ci if (dpp_tcp_send(conn) == 1) { 8990e5b75505Sopenharmony_ci if (!conn->write_eloop) { 8991e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 8992e5b75505Sopenharmony_ci dpp_conn_tx_ready, 8993e5b75505Sopenharmony_ci conn, NULL) < 0) 8994e5b75505Sopenharmony_ci return; 8995e5b75505Sopenharmony_ci conn->write_eloop = 1; 8996e5b75505Sopenharmony_ci } 8997e5b75505Sopenharmony_ci } 8998e5b75505Sopenharmony_ci} 8999e5b75505Sopenharmony_ci 9000e5b75505Sopenharmony_ci 9001e5b75505Sopenharmony_cistatic void dpp_controller_auth_success(struct dpp_connection *conn, 9002e5b75505Sopenharmony_ci int initiator) 9003e5b75505Sopenharmony_ci{ 9004e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9005e5b75505Sopenharmony_ci 9006e5b75505Sopenharmony_ci if (!auth) 9007e5b75505Sopenharmony_ci return; 9008e5b75505Sopenharmony_ci 9009e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); 9010e5b75505Sopenharmony_ci wpa_msg(conn->global->msg_ctx, MSG_INFO, 9011e5b75505Sopenharmony_ci DPP_EVENT_AUTH_SUCCESS "init=%d", initiator); 9012e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 9013e5b75505Sopenharmony_ci if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { 9014e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 9015e5b75505Sopenharmony_ci "DPP: TESTING - stop at Authentication Confirm"); 9016e5b75505Sopenharmony_ci if (auth->configurator) { 9017e5b75505Sopenharmony_ci /* Prevent GAS response */ 9018e5b75505Sopenharmony_ci auth->auth_success = 0; 9019e5b75505Sopenharmony_ci } 9020e5b75505Sopenharmony_ci return; 9021e5b75505Sopenharmony_ci } 9022e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 9023e5b75505Sopenharmony_ci 9024e5b75505Sopenharmony_ci if (!auth->configurator) 9025e5b75505Sopenharmony_ci dpp_controller_start_gas_client(conn); 9026e5b75505Sopenharmony_ci} 9027e5b75505Sopenharmony_ci 9028e5b75505Sopenharmony_ci 9029e5b75505Sopenharmony_cistatic void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) 9030e5b75505Sopenharmony_ci{ 9031e5b75505Sopenharmony_ci struct dpp_connection *conn = eloop_ctx; 9032e5b75505Sopenharmony_ci 9033e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock); 9034e5b75505Sopenharmony_ci dpp_tcp_send(conn); 9035e5b75505Sopenharmony_ci} 9036e5b75505Sopenharmony_ci 9037e5b75505Sopenharmony_ci 9038e5b75505Sopenharmony_cistatic int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen, 9039e5b75505Sopenharmony_ci const struct hostapd_ip_addr *ipaddr, 9040e5b75505Sopenharmony_ci int port) 9041e5b75505Sopenharmony_ci{ 9042e5b75505Sopenharmony_ci struct sockaddr_in *dst; 9043e5b75505Sopenharmony_ci#ifdef CONFIG_IPV6 9044e5b75505Sopenharmony_ci struct sockaddr_in6 *dst6; 9045e5b75505Sopenharmony_ci#endif /* CONFIG_IPV6 */ 9046e5b75505Sopenharmony_ci 9047e5b75505Sopenharmony_ci switch (ipaddr->af) { 9048e5b75505Sopenharmony_ci case AF_INET: 9049e5b75505Sopenharmony_ci dst = (struct sockaddr_in *) addr; 9050e5b75505Sopenharmony_ci os_memset(dst, 0, sizeof(*dst)); 9051e5b75505Sopenharmony_ci dst->sin_family = AF_INET; 9052e5b75505Sopenharmony_ci dst->sin_addr.s_addr = ipaddr->u.v4.s_addr; 9053e5b75505Sopenharmony_ci dst->sin_port = htons(port); 9054e5b75505Sopenharmony_ci *addrlen = sizeof(*dst); 9055e5b75505Sopenharmony_ci break; 9056e5b75505Sopenharmony_ci#ifdef CONFIG_IPV6 9057e5b75505Sopenharmony_ci case AF_INET6: 9058e5b75505Sopenharmony_ci dst6 = (struct sockaddr_in6 *) addr; 9059e5b75505Sopenharmony_ci os_memset(dst6, 0, sizeof(*dst6)); 9060e5b75505Sopenharmony_ci dst6->sin6_family = AF_INET6; 9061e5b75505Sopenharmony_ci os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6, 9062e5b75505Sopenharmony_ci sizeof(struct in6_addr)); 9063e5b75505Sopenharmony_ci dst6->sin6_port = htons(port); 9064e5b75505Sopenharmony_ci *addrlen = sizeof(*dst6); 9065e5b75505Sopenharmony_ci break; 9066e5b75505Sopenharmony_ci#endif /* CONFIG_IPV6 */ 9067e5b75505Sopenharmony_ci default: 9068e5b75505Sopenharmony_ci return -1; 9069e5b75505Sopenharmony_ci } 9070e5b75505Sopenharmony_ci 9071e5b75505Sopenharmony_ci return 0; 9072e5b75505Sopenharmony_ci} 9073e5b75505Sopenharmony_ci 9074e5b75505Sopenharmony_ci 9075e5b75505Sopenharmony_cistatic struct dpp_connection * 9076e5b75505Sopenharmony_cidpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src, 9077e5b75505Sopenharmony_ci unsigned int freq) 9078e5b75505Sopenharmony_ci{ 9079e5b75505Sopenharmony_ci struct dpp_connection *conn; 9080e5b75505Sopenharmony_ci struct sockaddr_storage addr; 9081e5b75505Sopenharmony_ci socklen_t addrlen; 9082e5b75505Sopenharmony_ci char txt[100]; 9083e5b75505Sopenharmony_ci 9084e5b75505Sopenharmony_ci if (dl_list_len(&ctrl->conn) >= 15) { 9085e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9086e5b75505Sopenharmony_ci "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one"); 9087e5b75505Sopenharmony_ci return NULL; 9088e5b75505Sopenharmony_ci } 9089e5b75505Sopenharmony_ci 9090e5b75505Sopenharmony_ci if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen, 9091e5b75505Sopenharmony_ci &ctrl->ipaddr, DPP_TCP_PORT) < 0) 9092e5b75505Sopenharmony_ci return NULL; 9093e5b75505Sopenharmony_ci 9094e5b75505Sopenharmony_ci conn = os_zalloc(sizeof(*conn)); 9095e5b75505Sopenharmony_ci if (!conn) 9096e5b75505Sopenharmony_ci return NULL; 9097e5b75505Sopenharmony_ci 9098e5b75505Sopenharmony_ci conn->global = ctrl->global; 9099e5b75505Sopenharmony_ci conn->relay = ctrl; 9100e5b75505Sopenharmony_ci os_memcpy(conn->mac_addr, src, ETH_ALEN); 9101e5b75505Sopenharmony_ci conn->freq = freq; 9102e5b75505Sopenharmony_ci 9103e5b75505Sopenharmony_ci conn->sock = socket(AF_INET, SOCK_STREAM, 0); 9104e5b75505Sopenharmony_ci if (conn->sock < 0) 9105e5b75505Sopenharmony_ci goto fail; 9106e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s", 9107e5b75505Sopenharmony_ci conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); 9108e5b75505Sopenharmony_ci 9109e5b75505Sopenharmony_ci if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 9110e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 9111e5b75505Sopenharmony_ci strerror(errno)); 9112e5b75505Sopenharmony_ci goto fail; 9113e5b75505Sopenharmony_ci } 9114e5b75505Sopenharmony_ci 9115e5b75505Sopenharmony_ci if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) { 9116e5b75505Sopenharmony_ci if (errno != EINPROGRESS) { 9117e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", 9118e5b75505Sopenharmony_ci strerror(errno)); 9119e5b75505Sopenharmony_ci goto fail; 9120e5b75505Sopenharmony_ci } 9121e5b75505Sopenharmony_ci 9122e5b75505Sopenharmony_ci /* 9123e5b75505Sopenharmony_ci * Continue connecting in the background; eloop will call us 9124e5b75505Sopenharmony_ci * once the connection is ready (or failed). 9125e5b75505Sopenharmony_ci */ 9126e5b75505Sopenharmony_ci } 9127e5b75505Sopenharmony_ci 9128e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 9129e5b75505Sopenharmony_ci dpp_conn_tx_ready, conn, NULL) < 0) 9130e5b75505Sopenharmony_ci goto fail; 9131e5b75505Sopenharmony_ci conn->write_eloop = 1; 9132e5b75505Sopenharmony_ci 9133e5b75505Sopenharmony_ci /* TODO: eloop timeout to clear a connection if it does not complete 9134e5b75505Sopenharmony_ci * properly */ 9135e5b75505Sopenharmony_ci 9136e5b75505Sopenharmony_ci dl_list_add(&ctrl->conn, &conn->list); 9137e5b75505Sopenharmony_ci return conn; 9138e5b75505Sopenharmony_cifail: 9139e5b75505Sopenharmony_ci dpp_connection_free(conn); 9140e5b75505Sopenharmony_ci return NULL; 9141e5b75505Sopenharmony_ci} 9142e5b75505Sopenharmony_ci 9143e5b75505Sopenharmony_ci 9144e5b75505Sopenharmony_cistatic struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len) 9145e5b75505Sopenharmony_ci{ 9146e5b75505Sopenharmony_ci struct wpabuf *msg; 9147e5b75505Sopenharmony_ci 9148e5b75505Sopenharmony_ci msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len); 9149e5b75505Sopenharmony_ci if (!msg) 9150e5b75505Sopenharmony_ci return NULL; 9151e5b75505Sopenharmony_ci wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len); 9152e5b75505Sopenharmony_ci wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC); 9153e5b75505Sopenharmony_ci wpabuf_put_data(msg, hdr, DPP_HDR_LEN); 9154e5b75505Sopenharmony_ci wpabuf_put_data(msg, buf, len); 9155e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg); 9156e5b75505Sopenharmony_ci return msg; 9157e5b75505Sopenharmony_ci} 9158e5b75505Sopenharmony_ci 9159e5b75505Sopenharmony_ci 9160e5b75505Sopenharmony_cistatic int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr, 9161e5b75505Sopenharmony_ci const u8 *buf, size_t len) 9162e5b75505Sopenharmony_ci{ 9163e5b75505Sopenharmony_ci u8 type = hdr[DPP_HDR_LEN - 1]; 9164e5b75505Sopenharmony_ci 9165e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9166e5b75505Sopenharmony_ci "DPP: Continue already established Relay/Controller connection for this session"); 9167e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9168e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9169e5b75505Sopenharmony_ci conn->msg_out = dpp_tcp_encaps(hdr, buf, len); 9170e5b75505Sopenharmony_ci if (!conn->msg_out) { 9171e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9172e5b75505Sopenharmony_ci return -1; 9173e5b75505Sopenharmony_ci } 9174e5b75505Sopenharmony_ci 9175e5b75505Sopenharmony_ci /* TODO: for proto ver 1, need to do remove connection based on GAS Resp 9176e5b75505Sopenharmony_ci * TX status */ 9177e5b75505Sopenharmony_ci if (type == DPP_PA_CONFIGURATION_RESULT) 9178e5b75505Sopenharmony_ci conn->on_tcp_tx_complete_remove = 1; 9179e5b75505Sopenharmony_ci dpp_tcp_send(conn); 9180e5b75505Sopenharmony_ci return 0; 9181e5b75505Sopenharmony_ci} 9182e5b75505Sopenharmony_ci 9183e5b75505Sopenharmony_ci 9184e5b75505Sopenharmony_ciint dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, 9185e5b75505Sopenharmony_ci const u8 *buf, size_t len, unsigned int freq, 9186e5b75505Sopenharmony_ci const u8 *i_bootstrap, const u8 *r_bootstrap) 9187e5b75505Sopenharmony_ci{ 9188e5b75505Sopenharmony_ci struct dpp_relay_controller *ctrl; 9189e5b75505Sopenharmony_ci struct dpp_connection *conn; 9190e5b75505Sopenharmony_ci u8 type = hdr[DPP_HDR_LEN - 1]; 9191e5b75505Sopenharmony_ci 9192e5b75505Sopenharmony_ci /* Check if there is an already started session for this peer and if so, 9193e5b75505Sopenharmony_ci * continue that session (send this over TCP) and return 0. 9194e5b75505Sopenharmony_ci */ 9195e5b75505Sopenharmony_ci if (type != DPP_PA_PEER_DISCOVERY_REQ && 9196e5b75505Sopenharmony_ci type != DPP_PA_PEER_DISCOVERY_RESP) { 9197e5b75505Sopenharmony_ci dl_list_for_each(ctrl, &dpp->controllers, 9198e5b75505Sopenharmony_ci struct dpp_relay_controller, list) { 9199e5b75505Sopenharmony_ci dl_list_for_each(conn, &ctrl->conn, 9200e5b75505Sopenharmony_ci struct dpp_connection, list) { 9201e5b75505Sopenharmony_ci if (os_memcmp(src, conn->mac_addr, 9202e5b75505Sopenharmony_ci ETH_ALEN) == 0) 9203e5b75505Sopenharmony_ci return dpp_relay_tx(conn, hdr, buf, len); 9204e5b75505Sopenharmony_ci } 9205e5b75505Sopenharmony_ci } 9206e5b75505Sopenharmony_ci } 9207e5b75505Sopenharmony_ci 9208e5b75505Sopenharmony_ci if (!r_bootstrap) 9209e5b75505Sopenharmony_ci return -1; 9210e5b75505Sopenharmony_ci 9211e5b75505Sopenharmony_ci ctrl = dpp_relay_controller_get(dpp, r_bootstrap); 9212e5b75505Sopenharmony_ci if (!ctrl) 9213e5b75505Sopenharmony_ci return -1; 9214e5b75505Sopenharmony_ci 9215e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9216e5b75505Sopenharmony_ci "DPP: Authentication Request for a configured Controller"); 9217e5b75505Sopenharmony_ci conn = dpp_relay_new_conn(ctrl, src, freq); 9218e5b75505Sopenharmony_ci if (!conn) 9219e5b75505Sopenharmony_ci return -1; 9220e5b75505Sopenharmony_ci 9221e5b75505Sopenharmony_ci conn->msg_out = dpp_tcp_encaps(hdr, buf, len); 9222e5b75505Sopenharmony_ci if (!conn->msg_out) { 9223e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9224e5b75505Sopenharmony_ci return -1; 9225e5b75505Sopenharmony_ci } 9226e5b75505Sopenharmony_ci /* Message will be sent in dpp_conn_tx_ready() */ 9227e5b75505Sopenharmony_ci 9228e5b75505Sopenharmony_ci return 0; 9229e5b75505Sopenharmony_ci} 9230e5b75505Sopenharmony_ci 9231e5b75505Sopenharmony_ci 9232e5b75505Sopenharmony_ciint dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, 9233e5b75505Sopenharmony_ci size_t data_len) 9234e5b75505Sopenharmony_ci{ 9235e5b75505Sopenharmony_ci struct dpp_relay_controller *ctrl; 9236e5b75505Sopenharmony_ci struct dpp_connection *conn, *found = NULL; 9237e5b75505Sopenharmony_ci struct wpabuf *msg; 9238e5b75505Sopenharmony_ci 9239e5b75505Sopenharmony_ci /* Check if there is a successfully completed authentication for this 9240e5b75505Sopenharmony_ci * and if so, continue that session (send this over TCP) and return 0. 9241e5b75505Sopenharmony_ci */ 9242e5b75505Sopenharmony_ci dl_list_for_each(ctrl, &dpp->controllers, 9243e5b75505Sopenharmony_ci struct dpp_relay_controller, list) { 9244e5b75505Sopenharmony_ci if (found) 9245e5b75505Sopenharmony_ci break; 9246e5b75505Sopenharmony_ci dl_list_for_each(conn, &ctrl->conn, 9247e5b75505Sopenharmony_ci struct dpp_connection, list) { 9248e5b75505Sopenharmony_ci if (os_memcmp(src, conn->mac_addr, 9249e5b75505Sopenharmony_ci ETH_ALEN) == 0) { 9250e5b75505Sopenharmony_ci found = conn; 9251e5b75505Sopenharmony_ci break; 9252e5b75505Sopenharmony_ci } 9253e5b75505Sopenharmony_ci } 9254e5b75505Sopenharmony_ci } 9255e5b75505Sopenharmony_ci 9256e5b75505Sopenharmony_ci if (!found) 9257e5b75505Sopenharmony_ci return -1; 9258e5b75505Sopenharmony_ci 9259e5b75505Sopenharmony_ci msg = wpabuf_alloc(4 + 1 + data_len); 9260e5b75505Sopenharmony_ci if (!msg) 9261e5b75505Sopenharmony_ci return -1; 9262e5b75505Sopenharmony_ci wpabuf_put_be32(msg, 1 + data_len); 9263e5b75505Sopenharmony_ci wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ); 9264e5b75505Sopenharmony_ci wpabuf_put_data(msg, data, data_len); 9265e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg); 9266e5b75505Sopenharmony_ci 9267e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9268e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9269e5b75505Sopenharmony_ci conn->msg_out = msg; 9270e5b75505Sopenharmony_ci dpp_tcp_send(conn); 9271e5b75505Sopenharmony_ci return 0; 9272e5b75505Sopenharmony_ci} 9273e5b75505Sopenharmony_ci 9274e5b75505Sopenharmony_ci 9275e5b75505Sopenharmony_cistatic void dpp_controller_free(struct dpp_controller *ctrl) 9276e5b75505Sopenharmony_ci{ 9277e5b75505Sopenharmony_ci struct dpp_connection *conn, *tmp; 9278e5b75505Sopenharmony_ci 9279e5b75505Sopenharmony_ci if (!ctrl) 9280e5b75505Sopenharmony_ci return; 9281e5b75505Sopenharmony_ci 9282e5b75505Sopenharmony_ci dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection, 9283e5b75505Sopenharmony_ci list) 9284e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9285e5b75505Sopenharmony_ci 9286e5b75505Sopenharmony_ci if (ctrl->sock >= 0) { 9287e5b75505Sopenharmony_ci close(ctrl->sock); 9288e5b75505Sopenharmony_ci eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ); 9289e5b75505Sopenharmony_ci } 9290e5b75505Sopenharmony_ci os_free(ctrl->configurator_params); 9291e5b75505Sopenharmony_ci os_free(ctrl); 9292e5b75505Sopenharmony_ci} 9293e5b75505Sopenharmony_ci 9294e5b75505Sopenharmony_ci 9295e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_req(struct dpp_connection *conn, 9296e5b75505Sopenharmony_ci const u8 *hdr, const u8 *buf, size_t len) 9297e5b75505Sopenharmony_ci{ 9298e5b75505Sopenharmony_ci const u8 *r_bootstrap, *i_bootstrap; 9299e5b75505Sopenharmony_ci u16 r_bootstrap_len, i_bootstrap_len; 9300e5b75505Sopenharmony_ci struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL; 9301e5b75505Sopenharmony_ci 9302e5b75505Sopenharmony_ci if (!conn->ctrl) 9303e5b75505Sopenharmony_ci return 0; 9304e5b75505Sopenharmony_ci 9305e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Authentication Request"); 9306e5b75505Sopenharmony_ci 9307e5b75505Sopenharmony_ci r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 9308e5b75505Sopenharmony_ci &r_bootstrap_len); 9309e5b75505Sopenharmony_ci if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 9310e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 9311e5b75505Sopenharmony_ci "Missing or invalid required Responder Bootstrapping Key Hash attribute"); 9312e5b75505Sopenharmony_ci return -1; 9313e5b75505Sopenharmony_ci } 9314e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", 9315e5b75505Sopenharmony_ci r_bootstrap, r_bootstrap_len); 9316e5b75505Sopenharmony_ci 9317e5b75505Sopenharmony_ci i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 9318e5b75505Sopenharmony_ci &i_bootstrap_len); 9319e5b75505Sopenharmony_ci if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { 9320e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 9321e5b75505Sopenharmony_ci "Missing or invalid required Initiator Bootstrapping Key Hash attribute"); 9322e5b75505Sopenharmony_ci return -1; 9323e5b75505Sopenharmony_ci } 9324e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", 9325e5b75505Sopenharmony_ci i_bootstrap, i_bootstrap_len); 9326e5b75505Sopenharmony_ci 9327e5b75505Sopenharmony_ci /* Try to find own and peer bootstrapping key matches based on the 9328e5b75505Sopenharmony_ci * received hash values */ 9329e5b75505Sopenharmony_ci dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap, 9330e5b75505Sopenharmony_ci &own_bi, &peer_bi); 9331e5b75505Sopenharmony_ci if (!own_bi) { 9332e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 9333e5b75505Sopenharmony_ci "No matching own bootstrapping key found - ignore message"); 9334e5b75505Sopenharmony_ci return -1; 9335e5b75505Sopenharmony_ci } 9336e5b75505Sopenharmony_ci 9337e5b75505Sopenharmony_ci if (conn->auth) { 9338e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 9339e5b75505Sopenharmony_ci "Already in DPP authentication exchange - ignore new one"); 9340e5b75505Sopenharmony_ci return 0; 9341e5b75505Sopenharmony_ci } 9342e5b75505Sopenharmony_ci 9343e5b75505Sopenharmony_ci conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx, 9344e5b75505Sopenharmony_ci conn->ctrl->allowed_roles, 9345e5b75505Sopenharmony_ci conn->ctrl->qr_mutual, 9346e5b75505Sopenharmony_ci peer_bi, own_bi, -1, hdr, buf, len); 9347e5b75505Sopenharmony_ci if (!conn->auth) { 9348e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No response generated"); 9349e5b75505Sopenharmony_ci return -1; 9350e5b75505Sopenharmony_ci } 9351e5b75505Sopenharmony_ci 9352e5b75505Sopenharmony_ci if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx, 9353e5b75505Sopenharmony_ci conn->auth, 9354e5b75505Sopenharmony_ci conn->ctrl->configurator_params) < 0) { 9355e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9356e5b75505Sopenharmony_ci return -1; 9357e5b75505Sopenharmony_ci } 9358e5b75505Sopenharmony_ci 9359e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9360e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9361e5b75505Sopenharmony_ci conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1); 9362e5b75505Sopenharmony_ci if (!conn->msg_out) 9363e5b75505Sopenharmony_ci return -1; 9364e5b75505Sopenharmony_ci wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1); 9365e5b75505Sopenharmony_ci wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1, 9366e5b75505Sopenharmony_ci wpabuf_len(conn->auth->resp_msg) - 1); 9367e5b75505Sopenharmony_ci 9368e5b75505Sopenharmony_ci if (dpp_tcp_send(conn) == 1) { 9369e5b75505Sopenharmony_ci if (!conn->write_eloop) { 9370e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 9371e5b75505Sopenharmony_ci dpp_conn_tx_ready, 9372e5b75505Sopenharmony_ci conn, NULL) < 0) 9373e5b75505Sopenharmony_ci return -1; 9374e5b75505Sopenharmony_ci conn->write_eloop = 1; 9375e5b75505Sopenharmony_ci } 9376e5b75505Sopenharmony_ci } 9377e5b75505Sopenharmony_ci 9378e5b75505Sopenharmony_ci return 0; 9379e5b75505Sopenharmony_ci} 9380e5b75505Sopenharmony_ci 9381e5b75505Sopenharmony_ci 9382e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_resp(struct dpp_connection *conn, 9383e5b75505Sopenharmony_ci const u8 *hdr, const u8 *buf, size_t len) 9384e5b75505Sopenharmony_ci{ 9385e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9386e5b75505Sopenharmony_ci struct wpabuf *msg; 9387e5b75505Sopenharmony_ci 9388e5b75505Sopenharmony_ci if (!auth) 9389e5b75505Sopenharmony_ci return -1; 9390e5b75505Sopenharmony_ci 9391e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Authentication Response"); 9392e5b75505Sopenharmony_ci 9393e5b75505Sopenharmony_ci msg = dpp_auth_resp_rx(auth, hdr, buf, len); 9394e5b75505Sopenharmony_ci if (!msg) { 9395e5b75505Sopenharmony_ci if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) { 9396e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9397e5b75505Sopenharmony_ci "DPP: Start wait for full response"); 9398e5b75505Sopenharmony_ci return -1; 9399e5b75505Sopenharmony_ci } 9400e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No confirm generated"); 9401e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9402e5b75505Sopenharmony_ci return -1; 9403e5b75505Sopenharmony_ci } 9404e5b75505Sopenharmony_ci 9405e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9406e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9407e5b75505Sopenharmony_ci conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1); 9408e5b75505Sopenharmony_ci if (!conn->msg_out) { 9409e5b75505Sopenharmony_ci wpabuf_free(msg); 9410e5b75505Sopenharmony_ci return -1; 9411e5b75505Sopenharmony_ci } 9412e5b75505Sopenharmony_ci wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1); 9413e5b75505Sopenharmony_ci wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1, 9414e5b75505Sopenharmony_ci wpabuf_len(msg) - 1); 9415e5b75505Sopenharmony_ci wpabuf_free(msg); 9416e5b75505Sopenharmony_ci 9417e5b75505Sopenharmony_ci conn->on_tcp_tx_complete_auth_ok = 1; 9418e5b75505Sopenharmony_ci if (dpp_tcp_send(conn) == 1) { 9419e5b75505Sopenharmony_ci if (!conn->write_eloop) { 9420e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 9421e5b75505Sopenharmony_ci dpp_conn_tx_ready, 9422e5b75505Sopenharmony_ci conn, NULL) < 0) 9423e5b75505Sopenharmony_ci return -1; 9424e5b75505Sopenharmony_ci conn->write_eloop = 1; 9425e5b75505Sopenharmony_ci } 9426e5b75505Sopenharmony_ci } 9427e5b75505Sopenharmony_ci 9428e5b75505Sopenharmony_ci return 0; 9429e5b75505Sopenharmony_ci} 9430e5b75505Sopenharmony_ci 9431e5b75505Sopenharmony_ci 9432e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_conf(struct dpp_connection *conn, 9433e5b75505Sopenharmony_ci const u8 *hdr, const u8 *buf, size_t len) 9434e5b75505Sopenharmony_ci{ 9435e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9436e5b75505Sopenharmony_ci 9437e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation"); 9438e5b75505Sopenharmony_ci 9439e5b75505Sopenharmony_ci if (!auth) { 9440e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9441e5b75505Sopenharmony_ci "DPP: No DPP Authentication in progress - drop"); 9442e5b75505Sopenharmony_ci return -1; 9443e5b75505Sopenharmony_ci } 9444e5b75505Sopenharmony_ci 9445e5b75505Sopenharmony_ci if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) { 9446e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 9447e5b75505Sopenharmony_ci return -1; 9448e5b75505Sopenharmony_ci } 9449e5b75505Sopenharmony_ci 9450e5b75505Sopenharmony_ci dpp_controller_auth_success(conn, 0); 9451e5b75505Sopenharmony_ci return 0; 9452e5b75505Sopenharmony_ci} 9453e5b75505Sopenharmony_ci 9454e5b75505Sopenharmony_ci 9455e5b75505Sopenharmony_cistatic int dpp_controller_rx_conf_result(struct dpp_connection *conn, 9456e5b75505Sopenharmony_ci const u8 *hdr, const u8 *buf, 9457e5b75505Sopenharmony_ci size_t len) 9458e5b75505Sopenharmony_ci{ 9459e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9460e5b75505Sopenharmony_ci enum dpp_status_error status; 9461e5b75505Sopenharmony_ci 9462e5b75505Sopenharmony_ci if (!conn->ctrl) 9463e5b75505Sopenharmony_ci return 0; 9464e5b75505Sopenharmony_ci 9465e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Configuration Result"); 9466e5b75505Sopenharmony_ci 9467e5b75505Sopenharmony_ci if (!auth || !auth->waiting_conf_result) { 9468e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9469e5b75505Sopenharmony_ci "DPP: No DPP Configuration waiting for result - drop"); 9470e5b75505Sopenharmony_ci return -1; 9471e5b75505Sopenharmony_ci } 9472e5b75505Sopenharmony_ci 9473e5b75505Sopenharmony_ci status = dpp_conf_result_rx(auth, hdr, buf, len); 9474e5b75505Sopenharmony_ci if (status == DPP_STATUS_OK) 9475e5b75505Sopenharmony_ci wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, 9476e5b75505Sopenharmony_ci DPP_EVENT_CONF_SENT); 9477e5b75505Sopenharmony_ci else 9478e5b75505Sopenharmony_ci wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, 9479e5b75505Sopenharmony_ci DPP_EVENT_CONF_FAILED); 9480e5b75505Sopenharmony_ci return -1; /* to remove the completed connection */ 9481e5b75505Sopenharmony_ci} 9482e5b75505Sopenharmony_ci 9483e5b75505Sopenharmony_ci 9484e5b75505Sopenharmony_cistatic int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, 9485e5b75505Sopenharmony_ci size_t len) 9486e5b75505Sopenharmony_ci{ 9487e5b75505Sopenharmony_ci const u8 *pos, *end; 9488e5b75505Sopenharmony_ci u8 type; 9489e5b75505Sopenharmony_ci 9490e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP"); 9491e5b75505Sopenharmony_ci pos = msg; 9492e5b75505Sopenharmony_ci end = msg + len; 9493e5b75505Sopenharmony_ci 9494e5b75505Sopenharmony_ci if (end - pos < DPP_HDR_LEN || 9495e5b75505Sopenharmony_ci WPA_GET_BE24(pos) != OUI_WFA || 9496e5b75505Sopenharmony_ci pos[3] != DPP_OUI_TYPE) { 9497e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unrecognized header"); 9498e5b75505Sopenharmony_ci return -1; 9499e5b75505Sopenharmony_ci } 9500e5b75505Sopenharmony_ci 9501e5b75505Sopenharmony_ci if (pos[4] != 1) { 9502e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u", 9503e5b75505Sopenharmony_ci pos[4]); 9504e5b75505Sopenharmony_ci return -1; 9505e5b75505Sopenharmony_ci } 9506e5b75505Sopenharmony_ci type = pos[5]; 9507e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type); 9508e5b75505Sopenharmony_ci pos += DPP_HDR_LEN; 9509e5b75505Sopenharmony_ci 9510e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", 9511e5b75505Sopenharmony_ci pos, end - pos); 9512e5b75505Sopenharmony_ci if (dpp_check_attrs(pos, end - pos) < 0) 9513e5b75505Sopenharmony_ci return -1; 9514e5b75505Sopenharmony_ci 9515e5b75505Sopenharmony_ci if (conn->relay) { 9516e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN"); 9517e5b75505Sopenharmony_ci conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr, 9518e5b75505Sopenharmony_ci conn->freq, msg, len); 9519e5b75505Sopenharmony_ci return 0; 9520e5b75505Sopenharmony_ci } 9521e5b75505Sopenharmony_ci 9522e5b75505Sopenharmony_ci switch (type) { 9523e5b75505Sopenharmony_ci case DPP_PA_AUTHENTICATION_REQ: 9524e5b75505Sopenharmony_ci return dpp_controller_rx_auth_req(conn, msg, pos, end - pos); 9525e5b75505Sopenharmony_ci case DPP_PA_AUTHENTICATION_RESP: 9526e5b75505Sopenharmony_ci return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos); 9527e5b75505Sopenharmony_ci case DPP_PA_AUTHENTICATION_CONF: 9528e5b75505Sopenharmony_ci return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos); 9529e5b75505Sopenharmony_ci case DPP_PA_CONFIGURATION_RESULT: 9530e5b75505Sopenharmony_ci return dpp_controller_rx_conf_result(conn, msg, pos, end - pos); 9531e5b75505Sopenharmony_ci default: 9532e5b75505Sopenharmony_ci /* TODO: missing messages types */ 9533e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9534e5b75505Sopenharmony_ci "DPP: Unsupported frame subtype %d", type); 9535e5b75505Sopenharmony_ci return -1; 9536e5b75505Sopenharmony_ci } 9537e5b75505Sopenharmony_ci} 9538e5b75505Sopenharmony_ci 9539e5b75505Sopenharmony_ci 9540e5b75505Sopenharmony_cistatic int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg, 9541e5b75505Sopenharmony_ci size_t len) 9542e5b75505Sopenharmony_ci{ 9543e5b75505Sopenharmony_ci const u8 *pos, *end, *next; 9544e5b75505Sopenharmony_ci u8 dialog_token; 9545e5b75505Sopenharmony_ci const u8 *adv_proto; 9546e5b75505Sopenharmony_ci u16 slen; 9547e5b75505Sopenharmony_ci struct wpabuf *resp, *buf; 9548e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9549e5b75505Sopenharmony_ci 9550e5b75505Sopenharmony_ci if (len < 1 + 2) 9551e5b75505Sopenharmony_ci return -1; 9552e5b75505Sopenharmony_ci 9553e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9554e5b75505Sopenharmony_ci "DPP: Received DPP Configuration Request over TCP"); 9555e5b75505Sopenharmony_ci 9556e5b75505Sopenharmony_ci if (!conn->ctrl || !auth || !auth->auth_success) { 9557e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 9558e5b75505Sopenharmony_ci return -1; 9559e5b75505Sopenharmony_ci } 9560e5b75505Sopenharmony_ci 9561e5b75505Sopenharmony_ci pos = msg; 9562e5b75505Sopenharmony_ci end = msg + len; 9563e5b75505Sopenharmony_ci 9564e5b75505Sopenharmony_ci dialog_token = *pos++; 9565e5b75505Sopenharmony_ci adv_proto = pos++; 9566e5b75505Sopenharmony_ci slen = *pos++; 9567e5b75505Sopenharmony_ci if (*adv_proto != WLAN_EID_ADV_PROTO || 9568e5b75505Sopenharmony_ci slen > end - pos || slen < 2) 9569e5b75505Sopenharmony_ci return -1; 9570e5b75505Sopenharmony_ci 9571e5b75505Sopenharmony_ci next = pos + slen; 9572e5b75505Sopenharmony_ci pos++; /* skip QueryRespLenLimit and PAME-BI */ 9573e5b75505Sopenharmony_ci 9574e5b75505Sopenharmony_ci if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC || 9575e5b75505Sopenharmony_ci pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA || 9576e5b75505Sopenharmony_ci pos[5] != DPP_OUI_TYPE || pos[6] != 0x01) 9577e5b75505Sopenharmony_ci return -1; 9578e5b75505Sopenharmony_ci 9579e5b75505Sopenharmony_ci pos = next; 9580e5b75505Sopenharmony_ci /* Query Request */ 9581e5b75505Sopenharmony_ci if (end - pos < 2) 9582e5b75505Sopenharmony_ci return -1; 9583e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 9584e5b75505Sopenharmony_ci pos += 2; 9585e5b75505Sopenharmony_ci if (slen > end - pos) 9586e5b75505Sopenharmony_ci return -1; 9587e5b75505Sopenharmony_ci 9588e5b75505Sopenharmony_ci resp = dpp_conf_req_rx(auth, pos, slen); 9589e5b75505Sopenharmony_ci if (!resp) 9590e5b75505Sopenharmony_ci return -1; 9591e5b75505Sopenharmony_ci 9592e5b75505Sopenharmony_ci buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp)); 9593e5b75505Sopenharmony_ci if (!buf) { 9594e5b75505Sopenharmony_ci wpabuf_free(resp); 9595e5b75505Sopenharmony_ci return -1; 9596e5b75505Sopenharmony_ci } 9597e5b75505Sopenharmony_ci 9598e5b75505Sopenharmony_ci wpabuf_put_be32(buf, 18 + wpabuf_len(resp)); 9599e5b75505Sopenharmony_ci 9600e5b75505Sopenharmony_ci wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP); 9601e5b75505Sopenharmony_ci wpabuf_put_u8(buf, dialog_token); 9602e5b75505Sopenharmony_ci wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); 9603e5b75505Sopenharmony_ci wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */ 9604e5b75505Sopenharmony_ci 9605e5b75505Sopenharmony_ci dpp_write_adv_proto(buf); 9606e5b75505Sopenharmony_ci dpp_write_gas_query(buf, resp); 9607e5b75505Sopenharmony_ci wpabuf_free(resp); 9608e5b75505Sopenharmony_ci 9609e5b75505Sopenharmony_ci /* Send Config Response over TCP; GAS fragmentation is taken care of by 9610e5b75505Sopenharmony_ci * the Relay */ 9611e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf); 9612e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9613e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9614e5b75505Sopenharmony_ci conn->msg_out = buf; 9615e5b75505Sopenharmony_ci conn->on_tcp_tx_complete_gas_done = 1; 9616e5b75505Sopenharmony_ci dpp_tcp_send(conn); 9617e5b75505Sopenharmony_ci return 0; 9618e5b75505Sopenharmony_ci} 9619e5b75505Sopenharmony_ci 9620e5b75505Sopenharmony_ci 9621e5b75505Sopenharmony_cistatic int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) 9622e5b75505Sopenharmony_ci{ 9623e5b75505Sopenharmony_ci struct dpp_authentication *auth = conn->auth; 9624e5b75505Sopenharmony_ci int res; 9625e5b75505Sopenharmony_ci struct wpabuf *msg, *encaps; 9626e5b75505Sopenharmony_ci enum dpp_status_error status; 9627e5b75505Sopenharmony_ci 9628e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9629e5b75505Sopenharmony_ci "DPP: Configuration Response for local stack from TCP"); 9630e5b75505Sopenharmony_ci 9631e5b75505Sopenharmony_ci res = dpp_conf_resp_rx(auth, resp); 9632e5b75505Sopenharmony_ci wpabuf_free(resp); 9633e5b75505Sopenharmony_ci if (res < 0) { 9634e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); 9635e5b75505Sopenharmony_ci return -1; 9636e5b75505Sopenharmony_ci } 9637e5b75505Sopenharmony_ci 9638e5b75505Sopenharmony_ci if (conn->global->process_conf_obj) 9639e5b75505Sopenharmony_ci res = conn->global->process_conf_obj(conn->global->cb_ctx, 9640e5b75505Sopenharmony_ci auth); 9641e5b75505Sopenharmony_ci else 9642e5b75505Sopenharmony_ci res = 0; 9643e5b75505Sopenharmony_ci 9644e5b75505Sopenharmony_ci if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK) 9645e5b75505Sopenharmony_ci return -1; 9646e5b75505Sopenharmony_ci 9647e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); 9648e5b75505Sopenharmony_ci status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK; 9649e5b75505Sopenharmony_ci msg = dpp_build_conf_result(auth, status); 9650e5b75505Sopenharmony_ci if (!msg) 9651e5b75505Sopenharmony_ci return -1; 9652e5b75505Sopenharmony_ci 9653e5b75505Sopenharmony_ci encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1); 9654e5b75505Sopenharmony_ci if (!encaps) { 9655e5b75505Sopenharmony_ci wpabuf_free(msg); 9656e5b75505Sopenharmony_ci return -1; 9657e5b75505Sopenharmony_ci } 9658e5b75505Sopenharmony_ci wpabuf_put_be32(encaps, wpabuf_len(msg) - 1); 9659e5b75505Sopenharmony_ci wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1); 9660e5b75505Sopenharmony_ci wpabuf_free(msg); 9661e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps); 9662e5b75505Sopenharmony_ci 9663e5b75505Sopenharmony_ci wpabuf_free(conn->msg_out); 9664e5b75505Sopenharmony_ci conn->msg_out_pos = 0; 9665e5b75505Sopenharmony_ci conn->msg_out = encaps; 9666e5b75505Sopenharmony_ci conn->on_tcp_tx_complete_remove = 1; 9667e5b75505Sopenharmony_ci dpp_tcp_send(conn); 9668e5b75505Sopenharmony_ci 9669e5b75505Sopenharmony_ci /* This exchange will be terminated in the TX status handler */ 9670e5b75505Sopenharmony_ci 9671e5b75505Sopenharmony_ci return 0; 9672e5b75505Sopenharmony_ci} 9673e5b75505Sopenharmony_ci 9674e5b75505Sopenharmony_ci 9675e5b75505Sopenharmony_cistatic int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg, 9676e5b75505Sopenharmony_ci size_t len) 9677e5b75505Sopenharmony_ci{ 9678e5b75505Sopenharmony_ci struct wpabuf *buf; 9679e5b75505Sopenharmony_ci u8 dialog_token; 9680e5b75505Sopenharmony_ci const u8 *pos, *end, *next, *adv_proto; 9681e5b75505Sopenharmony_ci u16 status, slen; 9682e5b75505Sopenharmony_ci 9683e5b75505Sopenharmony_ci if (len < 5 + 2) 9684e5b75505Sopenharmony_ci return -1; 9685e5b75505Sopenharmony_ci 9686e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9687e5b75505Sopenharmony_ci "DPP: Received DPP Configuration Response over TCP"); 9688e5b75505Sopenharmony_ci 9689e5b75505Sopenharmony_ci pos = msg; 9690e5b75505Sopenharmony_ci end = msg + len; 9691e5b75505Sopenharmony_ci 9692e5b75505Sopenharmony_ci dialog_token = *pos++; 9693e5b75505Sopenharmony_ci status = WPA_GET_LE16(pos); 9694e5b75505Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) { 9695e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status); 9696e5b75505Sopenharmony_ci return -1; 9697e5b75505Sopenharmony_ci } 9698e5b75505Sopenharmony_ci pos += 2; 9699e5b75505Sopenharmony_ci pos += 2; /* ignore GAS Comeback Delay */ 9700e5b75505Sopenharmony_ci 9701e5b75505Sopenharmony_ci adv_proto = pos++; 9702e5b75505Sopenharmony_ci slen = *pos++; 9703e5b75505Sopenharmony_ci if (*adv_proto != WLAN_EID_ADV_PROTO || 9704e5b75505Sopenharmony_ci slen > end - pos || slen < 2) 9705e5b75505Sopenharmony_ci return -1; 9706e5b75505Sopenharmony_ci 9707e5b75505Sopenharmony_ci next = pos + slen; 9708e5b75505Sopenharmony_ci pos++; /* skip QueryRespLenLimit and PAME-BI */ 9709e5b75505Sopenharmony_ci 9710e5b75505Sopenharmony_ci if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC || 9711e5b75505Sopenharmony_ci pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA || 9712e5b75505Sopenharmony_ci pos[5] != DPP_OUI_TYPE || pos[6] != 0x01) 9713e5b75505Sopenharmony_ci return -1; 9714e5b75505Sopenharmony_ci 9715e5b75505Sopenharmony_ci pos = next; 9716e5b75505Sopenharmony_ci /* Query Response */ 9717e5b75505Sopenharmony_ci if (end - pos < 2) 9718e5b75505Sopenharmony_ci return -1; 9719e5b75505Sopenharmony_ci slen = WPA_GET_LE16(pos); 9720e5b75505Sopenharmony_ci pos += 2; 9721e5b75505Sopenharmony_ci if (slen > end - pos) 9722e5b75505Sopenharmony_ci return -1; 9723e5b75505Sopenharmony_ci 9724e5b75505Sopenharmony_ci buf = wpabuf_alloc(slen); 9725e5b75505Sopenharmony_ci if (!buf) 9726e5b75505Sopenharmony_ci return -1; 9727e5b75505Sopenharmony_ci wpabuf_put_data(buf, pos, slen); 9728e5b75505Sopenharmony_ci 9729e5b75505Sopenharmony_ci if (!conn->relay && !conn->ctrl) 9730e5b75505Sopenharmony_ci return dpp_tcp_rx_gas_resp(conn, buf); 9731e5b75505Sopenharmony_ci 9732e5b75505Sopenharmony_ci if (!conn->relay) { 9733e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 9734e5b75505Sopenharmony_ci wpabuf_free(buf); 9735e5b75505Sopenharmony_ci return -1; 9736e5b75505Sopenharmony_ci } 9737e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN"); 9738e5b75505Sopenharmony_ci conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr, 9739e5b75505Sopenharmony_ci dialog_token, 0, buf); 9740e5b75505Sopenharmony_ci 9741e5b75505Sopenharmony_ci return 0; 9742e5b75505Sopenharmony_ci} 9743e5b75505Sopenharmony_ci 9744e5b75505Sopenharmony_ci 9745e5b75505Sopenharmony_cistatic void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx) 9746e5b75505Sopenharmony_ci{ 9747e5b75505Sopenharmony_ci struct dpp_connection *conn = eloop_ctx; 9748e5b75505Sopenharmony_ci int res; 9749e5b75505Sopenharmony_ci const u8 *pos; 9750e5b75505Sopenharmony_ci 9751e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)", 9752e5b75505Sopenharmony_ci sd); 9753e5b75505Sopenharmony_ci 9754e5b75505Sopenharmony_ci if (conn->msg_len_octets < 4) { 9755e5b75505Sopenharmony_ci u32 msglen; 9756e5b75505Sopenharmony_ci 9757e5b75505Sopenharmony_ci res = recv(sd, &conn->msg_len[conn->msg_len_octets], 9758e5b75505Sopenharmony_ci 4 - conn->msg_len_octets, 0); 9759e5b75505Sopenharmony_ci if (res < 0) { 9760e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", 9761e5b75505Sopenharmony_ci strerror(errno)); 9762e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9763e5b75505Sopenharmony_ci return; 9764e5b75505Sopenharmony_ci } 9765e5b75505Sopenharmony_ci if (res == 0) { 9766e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9767e5b75505Sopenharmony_ci "DPP: No more data available over TCP"); 9768e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9769e5b75505Sopenharmony_ci return; 9770e5b75505Sopenharmony_ci } 9771e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9772e5b75505Sopenharmony_ci "DPP: Received %d/%d octet(s) of message length field", 9773e5b75505Sopenharmony_ci res, (int) (4 - conn->msg_len_octets)); 9774e5b75505Sopenharmony_ci conn->msg_len_octets += res; 9775e5b75505Sopenharmony_ci 9776e5b75505Sopenharmony_ci if (conn->msg_len_octets < 4) { 9777e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9778e5b75505Sopenharmony_ci "DPP: Need %d more octets of message length field", 9779e5b75505Sopenharmony_ci (int) (4 - conn->msg_len_octets)); 9780e5b75505Sopenharmony_ci return; 9781e5b75505Sopenharmony_ci } 9782e5b75505Sopenharmony_ci 9783e5b75505Sopenharmony_ci msglen = WPA_GET_BE32(conn->msg_len); 9784e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen); 9785e5b75505Sopenharmony_ci if (msglen > 65535) { 9786e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: Unexpectedly long message"); 9787e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9788e5b75505Sopenharmony_ci return; 9789e5b75505Sopenharmony_ci } 9790e5b75505Sopenharmony_ci 9791e5b75505Sopenharmony_ci wpabuf_free(conn->msg); 9792e5b75505Sopenharmony_ci conn->msg = wpabuf_alloc(msglen); 9793e5b75505Sopenharmony_ci } 9794e5b75505Sopenharmony_ci 9795e5b75505Sopenharmony_ci if (!conn->msg) { 9796e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9797e5b75505Sopenharmony_ci "DPP: No buffer available for receiving the message"); 9798e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9799e5b75505Sopenharmony_ci return; 9800e5b75505Sopenharmony_ci } 9801e5b75505Sopenharmony_ci 9802e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload", 9803e5b75505Sopenharmony_ci (unsigned int) wpabuf_tailroom(conn->msg)); 9804e5b75505Sopenharmony_ci 9805e5b75505Sopenharmony_ci res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0); 9806e5b75505Sopenharmony_ci if (res < 0) { 9807e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno)); 9808e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9809e5b75505Sopenharmony_ci return; 9810e5b75505Sopenharmony_ci } 9811e5b75505Sopenharmony_ci if (res == 0) { 9812e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP"); 9813e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9814e5b75505Sopenharmony_ci return; 9815e5b75505Sopenharmony_ci } 9816e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res); 9817e5b75505Sopenharmony_ci wpabuf_put(conn->msg, res); 9818e5b75505Sopenharmony_ci 9819e5b75505Sopenharmony_ci if (wpabuf_tailroom(conn->msg) > 0) { 9820e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9821e5b75505Sopenharmony_ci "DPP: Need %u more octets of message payload", 9822e5b75505Sopenharmony_ci (unsigned int) wpabuf_tailroom(conn->msg)); 9823e5b75505Sopenharmony_ci return; 9824e5b75505Sopenharmony_ci } 9825e5b75505Sopenharmony_ci 9826e5b75505Sopenharmony_ci conn->msg_len_octets = 0; 9827e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg); 9828e5b75505Sopenharmony_ci if (wpabuf_len(conn->msg) < 1) { 9829e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9830e5b75505Sopenharmony_ci return; 9831e5b75505Sopenharmony_ci } 9832e5b75505Sopenharmony_ci 9833e5b75505Sopenharmony_ci pos = wpabuf_head(conn->msg); 9834e5b75505Sopenharmony_ci switch (*pos) { 9835e5b75505Sopenharmony_ci case WLAN_PA_VENDOR_SPECIFIC: 9836e5b75505Sopenharmony_ci if (dpp_controller_rx_action(conn, pos + 1, 9837e5b75505Sopenharmony_ci wpabuf_len(conn->msg) - 1) < 0) 9838e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9839e5b75505Sopenharmony_ci break; 9840e5b75505Sopenharmony_ci case WLAN_PA_GAS_INITIAL_REQ: 9841e5b75505Sopenharmony_ci if (dpp_controller_rx_gas_req(conn, pos + 1, 9842e5b75505Sopenharmony_ci wpabuf_len(conn->msg) - 1) < 0) 9843e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9844e5b75505Sopenharmony_ci break; 9845e5b75505Sopenharmony_ci case WLAN_PA_GAS_INITIAL_RESP: 9846e5b75505Sopenharmony_ci if (dpp_rx_gas_resp(conn, pos + 1, 9847e5b75505Sopenharmony_ci wpabuf_len(conn->msg) - 1) < 0) 9848e5b75505Sopenharmony_ci dpp_connection_remove(conn); 9849e5b75505Sopenharmony_ci break; 9850e5b75505Sopenharmony_ci default: 9851e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u", 9852e5b75505Sopenharmony_ci *pos); 9853e5b75505Sopenharmony_ci break; 9854e5b75505Sopenharmony_ci } 9855e5b75505Sopenharmony_ci} 9856e5b75505Sopenharmony_ci 9857e5b75505Sopenharmony_ci 9858e5b75505Sopenharmony_cistatic void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) 9859e5b75505Sopenharmony_ci{ 9860e5b75505Sopenharmony_ci struct dpp_controller *ctrl = eloop_ctx; 9861e5b75505Sopenharmony_ci struct sockaddr_in addr; 9862e5b75505Sopenharmony_ci socklen_t addr_len = sizeof(addr); 9863e5b75505Sopenharmony_ci int fd; 9864e5b75505Sopenharmony_ci struct dpp_connection *conn; 9865e5b75505Sopenharmony_ci 9866e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: New TCP connection"); 9867e5b75505Sopenharmony_ci 9868e5b75505Sopenharmony_ci fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len); 9869e5b75505Sopenharmony_ci if (fd < 0) { 9870e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 9871e5b75505Sopenharmony_ci "DPP: Failed to accept new connection: %s", 9872e5b75505Sopenharmony_ci strerror(errno)); 9873e5b75505Sopenharmony_ci return; 9874e5b75505Sopenharmony_ci } 9875e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d", 9876e5b75505Sopenharmony_ci inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 9877e5b75505Sopenharmony_ci 9878e5b75505Sopenharmony_ci conn = os_zalloc(sizeof(*conn)); 9879e5b75505Sopenharmony_ci if (!conn) 9880e5b75505Sopenharmony_ci goto fail; 9881e5b75505Sopenharmony_ci 9882e5b75505Sopenharmony_ci conn->global = ctrl->global; 9883e5b75505Sopenharmony_ci conn->ctrl = ctrl; 9884e5b75505Sopenharmony_ci conn->sock = fd; 9885e5b75505Sopenharmony_ci 9886e5b75505Sopenharmony_ci if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 9887e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 9888e5b75505Sopenharmony_ci strerror(errno)); 9889e5b75505Sopenharmony_ci goto fail; 9890e5b75505Sopenharmony_ci } 9891e5b75505Sopenharmony_ci 9892e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_READ, 9893e5b75505Sopenharmony_ci dpp_controller_rx, conn, NULL) < 0) 9894e5b75505Sopenharmony_ci goto fail; 9895e5b75505Sopenharmony_ci conn->read_eloop = 1; 9896e5b75505Sopenharmony_ci 9897e5b75505Sopenharmony_ci /* TODO: eloop timeout to expire connections that do not complete in 9898e5b75505Sopenharmony_ci * reasonable time */ 9899e5b75505Sopenharmony_ci dl_list_add(&ctrl->conn, &conn->list); 9900e5b75505Sopenharmony_ci return; 9901e5b75505Sopenharmony_ci 9902e5b75505Sopenharmony_cifail: 9903e5b75505Sopenharmony_ci close(fd); 9904e5b75505Sopenharmony_ci os_free(conn); 9905e5b75505Sopenharmony_ci} 9906e5b75505Sopenharmony_ci 9907e5b75505Sopenharmony_ci 9908e5b75505Sopenharmony_ciint dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, 9909e5b75505Sopenharmony_ci const struct hostapd_ip_addr *addr, int port) 9910e5b75505Sopenharmony_ci{ 9911e5b75505Sopenharmony_ci struct dpp_connection *conn; 9912e5b75505Sopenharmony_ci struct sockaddr_storage saddr; 9913e5b75505Sopenharmony_ci socklen_t addrlen; 9914e5b75505Sopenharmony_ci const u8 *hdr, *pos, *end; 9915e5b75505Sopenharmony_ci char txt[100]; 9916e5b75505Sopenharmony_ci 9917e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d", 9918e5b75505Sopenharmony_ci hostapd_ip_txt(addr, txt, sizeof(txt)), port); 9919e5b75505Sopenharmony_ci if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen, 9920e5b75505Sopenharmony_ci addr, port) < 0) { 9921e5b75505Sopenharmony_ci dpp_auth_deinit(auth); 9922e5b75505Sopenharmony_ci return -1; 9923e5b75505Sopenharmony_ci } 9924e5b75505Sopenharmony_ci 9925e5b75505Sopenharmony_ci conn = os_zalloc(sizeof(*conn)); 9926e5b75505Sopenharmony_ci if (!conn) { 9927e5b75505Sopenharmony_ci dpp_auth_deinit(auth); 9928e5b75505Sopenharmony_ci return -1; 9929e5b75505Sopenharmony_ci } 9930e5b75505Sopenharmony_ci 9931e5b75505Sopenharmony_ci conn->global = dpp; 9932e5b75505Sopenharmony_ci conn->auth = auth; 9933e5b75505Sopenharmony_ci conn->sock = socket(AF_INET, SOCK_STREAM, 0); 9934e5b75505Sopenharmony_ci if (conn->sock < 0) 9935e5b75505Sopenharmony_ci goto fail; 9936e5b75505Sopenharmony_ci 9937e5b75505Sopenharmony_ci if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { 9938e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", 9939e5b75505Sopenharmony_ci strerror(errno)); 9940e5b75505Sopenharmony_ci goto fail; 9941e5b75505Sopenharmony_ci } 9942e5b75505Sopenharmony_ci 9943e5b75505Sopenharmony_ci if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) { 9944e5b75505Sopenharmony_ci if (errno != EINPROGRESS) { 9945e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", 9946e5b75505Sopenharmony_ci strerror(errno)); 9947e5b75505Sopenharmony_ci goto fail; 9948e5b75505Sopenharmony_ci } 9949e5b75505Sopenharmony_ci 9950e5b75505Sopenharmony_ci /* 9951e5b75505Sopenharmony_ci * Continue connecting in the background; eloop will call us 9952e5b75505Sopenharmony_ci * once the connection is ready (or failed). 9953e5b75505Sopenharmony_ci */ 9954e5b75505Sopenharmony_ci } 9955e5b75505Sopenharmony_ci 9956e5b75505Sopenharmony_ci if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, 9957e5b75505Sopenharmony_ci dpp_conn_tx_ready, conn, NULL) < 0) 9958e5b75505Sopenharmony_ci goto fail; 9959e5b75505Sopenharmony_ci conn->write_eloop = 1; 9960e5b75505Sopenharmony_ci 9961e5b75505Sopenharmony_ci hdr = wpabuf_head(auth->req_msg); 9962e5b75505Sopenharmony_ci end = hdr + wpabuf_len(auth->req_msg); 9963e5b75505Sopenharmony_ci hdr += 2; /* skip Category and Actiom */ 9964e5b75505Sopenharmony_ci pos = hdr + DPP_HDR_LEN; 9965e5b75505Sopenharmony_ci conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); 9966e5b75505Sopenharmony_ci if (!conn->msg_out) 9967e5b75505Sopenharmony_ci goto fail; 9968e5b75505Sopenharmony_ci /* Message will be sent in dpp_conn_tx_ready() */ 9969e5b75505Sopenharmony_ci 9970e5b75505Sopenharmony_ci /* TODO: eloop timeout to clear a connection if it does not complete 9971e5b75505Sopenharmony_ci * properly */ 9972e5b75505Sopenharmony_ci dl_list_add(&dpp->tcp_init, &conn->list); 9973e5b75505Sopenharmony_ci return 0; 9974e5b75505Sopenharmony_cifail: 9975e5b75505Sopenharmony_ci dpp_connection_free(conn); 9976e5b75505Sopenharmony_ci return -1; 9977e5b75505Sopenharmony_ci} 9978e5b75505Sopenharmony_ci 9979e5b75505Sopenharmony_ci 9980e5b75505Sopenharmony_ciint dpp_controller_start(struct dpp_global *dpp, 9981e5b75505Sopenharmony_ci struct dpp_controller_config *config) 9982e5b75505Sopenharmony_ci{ 9983e5b75505Sopenharmony_ci struct dpp_controller *ctrl; 9984e5b75505Sopenharmony_ci int on = 1; 9985e5b75505Sopenharmony_ci struct sockaddr_in sin; 9986e5b75505Sopenharmony_ci int port; 9987e5b75505Sopenharmony_ci 9988e5b75505Sopenharmony_ci if (!dpp || dpp->controller) 9989e5b75505Sopenharmony_ci return -1; 9990e5b75505Sopenharmony_ci 9991e5b75505Sopenharmony_ci ctrl = os_zalloc(sizeof(*ctrl)); 9992e5b75505Sopenharmony_ci if (!ctrl) 9993e5b75505Sopenharmony_ci return -1; 9994e5b75505Sopenharmony_ci ctrl->global = dpp; 9995e5b75505Sopenharmony_ci if (config->configurator_params) 9996e5b75505Sopenharmony_ci ctrl->configurator_params = 9997e5b75505Sopenharmony_ci os_strdup(config->configurator_params); 9998e5b75505Sopenharmony_ci dl_list_init(&ctrl->conn); 9999e5b75505Sopenharmony_ci /* TODO: configure these somehow */ 10000e5b75505Sopenharmony_ci ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR; 10001e5b75505Sopenharmony_ci ctrl->qr_mutual = 0; 10002e5b75505Sopenharmony_ci 10003e5b75505Sopenharmony_ci ctrl->sock = socket(AF_INET, SOCK_STREAM, 0); 10004e5b75505Sopenharmony_ci if (ctrl->sock < 0) 10005e5b75505Sopenharmony_ci goto fail; 10006e5b75505Sopenharmony_ci 10007e5b75505Sopenharmony_ci if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR, 10008e5b75505Sopenharmony_ci &on, sizeof(on)) < 0) { 10009e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 10010e5b75505Sopenharmony_ci "DPP: setsockopt(SO_REUSEADDR) failed: %s", 10011e5b75505Sopenharmony_ci strerror(errno)); 10012e5b75505Sopenharmony_ci /* try to continue anyway */ 10013e5b75505Sopenharmony_ci } 10014e5b75505Sopenharmony_ci 10015e5b75505Sopenharmony_ci if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) { 10016e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s", 10017e5b75505Sopenharmony_ci strerror(errno)); 10018e5b75505Sopenharmony_ci goto fail; 10019e5b75505Sopenharmony_ci } 10020e5b75505Sopenharmony_ci 10021e5b75505Sopenharmony_ci /* TODO: IPv6 */ 10022e5b75505Sopenharmony_ci os_memset(&sin, 0, sizeof(sin)); 10023e5b75505Sopenharmony_ci sin.sin_family = AF_INET; 10024e5b75505Sopenharmony_ci sin.sin_addr.s_addr = INADDR_ANY; 10025e5b75505Sopenharmony_ci port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT; 10026e5b75505Sopenharmony_ci sin.sin_port = htons(port); 10027e5b75505Sopenharmony_ci if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 10028e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 10029e5b75505Sopenharmony_ci "DPP: Failed to bind Controller TCP port: %s", 10030e5b75505Sopenharmony_ci strerror(errno)); 10031e5b75505Sopenharmony_ci goto fail; 10032e5b75505Sopenharmony_ci } 10033e5b75505Sopenharmony_ci if (listen(ctrl->sock, 10 /* max backlog */) < 0 || 10034e5b75505Sopenharmony_ci fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 || 10035e5b75505Sopenharmony_ci eloop_register_sock(ctrl->sock, EVENT_TYPE_READ, 10036e5b75505Sopenharmony_ci dpp_controller_tcp_cb, ctrl, NULL)) 10037e5b75505Sopenharmony_ci goto fail; 10038e5b75505Sopenharmony_ci 10039e5b75505Sopenharmony_ci dpp->controller = ctrl; 10040e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port); 10041e5b75505Sopenharmony_ci return 0; 10042e5b75505Sopenharmony_cifail: 10043e5b75505Sopenharmony_ci dpp_controller_free(ctrl); 10044e5b75505Sopenharmony_ci return -1; 10045e5b75505Sopenharmony_ci} 10046e5b75505Sopenharmony_ci 10047e5b75505Sopenharmony_ci 10048e5b75505Sopenharmony_civoid dpp_controller_stop(struct dpp_global *dpp) 10049e5b75505Sopenharmony_ci{ 10050e5b75505Sopenharmony_ci if (dpp) { 10051e5b75505Sopenharmony_ci dpp_controller_free(dpp->controller); 10052e5b75505Sopenharmony_ci dpp->controller = NULL; 10053e5b75505Sopenharmony_ci } 10054e5b75505Sopenharmony_ci} 10055e5b75505Sopenharmony_ci 10056e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 10057