diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index ebbe874f2f..ec704fa60e 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -202,6 +202,7 @@ endif() if(CONFIG_ESP_WIFI_DPP_SUPPORT) set(dpp_src "src/common/dpp.c" + "src/common/dpp_crypto.c" "esp_supplicant/src/esp_dpp.c") else() set(dpp_src "") diff --git a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c index 87d445abc1..c0a7a4acbc 100644 --- a/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c +++ b/components/wpa_supplicant/esp_supplicant/src/crypto/crypto_mbedtls-ec.c @@ -565,7 +565,7 @@ void crypto_ec_free_key(struct crypto_key *key) os_free(key); } -struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key) +struct crypto_ec_point *crypto_ec_key_get_public_key(struct crypto_key *key) { mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; @@ -615,7 +615,7 @@ int crypto_ec_key_group(struct crypto_ec_key *key) return iana_group; } -struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key) +struct crypto_bignum *crypto_ec_key_get_private_key(struct crypto_key *key) { mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; @@ -670,7 +670,7 @@ int crypto_write_pubkey_der(struct crypto_key *key, unsigned char **key_buf) return len; } -struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len) +struct crypto_key *crypto_ec_key_parse_priv(const u8 *privkey, size_t privkey_len) { int ret; mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key(); @@ -842,7 +842,7 @@ int crypto_edcsa_sign_verify(const unsigned char *hash, return ret; } -void crypto_debug_print_ec_key(const char *title, struct crypto_key *key) +void crypto_ec_key_debug_print(const char *title, struct crypto_key *key) { #ifdef DEBUG_PRINT mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; @@ -853,12 +853,12 @@ void crypto_debug_print_ec_key(const char *title, struct crypto_key *key) int len = mbedtls_mpi_size((mbedtls_mpi *)crypto_ec_get_prime((struct crypto_ec *)crypto_ec_get_group_from_key(key))); wpa_printf(MSG_ERROR, "prime len is %d", len); - crypto_ec_point_to_bin((struct crypto_ec *)crypto_ec_get_group_from_key(key), crypto_ec_get_public_key(key), x, y); - crypto_bignum_to_bin(crypto_ec_get_private_key(key), - d, len, len); - wpa_hexdump(MSG_ERROR, "Q_x:", x, 32); - wpa_hexdump(MSG_ERROR, "Q_y:", y, 32); - wpa_hexdump(MSG_ERROR, "d: ", d, 32); + crypto_ec_point_to_bin((struct crypto_ec *)crypto_ec_get_group_from_key(key), crypto_ec_key_get_public_key(key), x, y); + crypto_bignum_to_bin(crypto_ec_key_get_private_key(key), + d, len, len); + wpa_hexdump(MSG_INFO, "Q_x:", x, 32); + wpa_hexdump(MSG_INFO, "Q_y:", y, 32); + wpa_hexdump(MSG_INFO, "d: ", d , 32); #endif } @@ -886,7 +886,7 @@ int crypto_is_ec_key(struct crypto_key *key) return ret; } -struct crypto_key * crypto_ec_gen_keypair(u16 ike_group) +struct crypto_key * crypto_ec_key_gen(u16 ike_group) { mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key(); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h index 6761e86ac2..b8e4c280ef 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,7 +10,6 @@ #include "esp_err.h" #include "utils/includes.h" #include "utils/common.h" - #include "common/dpp.h" #include "esp_dpp.h" #include "esp_wifi_driver.h" @@ -59,6 +58,12 @@ struct esp_dpp_context_t { int esp_supp_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel); esp_err_t esp_dpp_post_evt(uint32_t evt_id, uint32_t data); +#ifdef CONFIG_TESTING_OPTIONS +int dpp_test_gen_invalid_key(struct wpabuf *msg, + const struct dpp_curve_params *curve); +char * dpp_corrupt_connector_signature(const char *connector); +#endif /* CONFIG_TESTING_OPTIONS */ + #ifdef CONFIG_ESP_WIFI_DPP_SUPPORT bool is_dpp_enabled(void); #else diff --git a/components/wpa_supplicant/src/common/dpp.c b/components/wpa_supplicant/src/common/dpp.c index b5d57d1e01..968c7ff17b 100644 --- a/components/wpa_supplicant/src/common/dpp.c +++ b/components/wpa_supplicant/src/common/dpp.c @@ -40,17 +40,7 @@ struct dpp_global { struct dl_list configurator; /* struct dpp_configurator */ }; -static const struct dpp_curve_params dpp_curves[] = { - /* The mandatory to support and the default NIST P-256 curve needs to - * be the first entry on this list. */ - { "secp256r1", 32, 32, 16, 32, "P-256", 19, "ES256" }, - { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" }, - { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" }, - { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" }, - { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" }, - { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" }, - { NULL, 0, 0, 0, 0, NULL, 0, NULL } -}; +extern struct dpp_curve_params dpp_curves[]; #define TRANSACTION_ID_ATTR_SET_LEN 5 #define CONNECTOR_ATTR_SET_LEN 4 @@ -71,181 +61,30 @@ gas_build_req(u8 action, u8 dialog_token, size_t size) return buf; } - struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size) { return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token, size); } -static void dpp_debug_print_key(const char *title, struct crypto_key *key) -{ - crypto_debug_print_ec_key(title, key); -} - void dpp_debug_print_point(const char *title, struct crypto_ec *e, const struct crypto_ec_point *point) { u8 x[64], y[64]; if (crypto_ec_point_to_bin(e, point, x, y) < 0) { - printf("error: failed to get corrdinates\n"); + printf("error: failed to get coordinates\n"); return; } wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x, y); } -static int dpp_hash_vector(const struct dpp_curve_params *curve, - size_t num_elem, const u8 *addr[], const size_t *len, - u8 *mac) -{ - if (curve->hash_len == 32) - return sha256_vector(num_elem, addr, len, mac); -#ifndef ESP_SUPPLICANT - if (curve->hash_len == 48) - return sha384_vector(num_elem, addr, len, mac); - if (curve->hash_len == 64) - return sha512_vector(num_elem, addr, len, mac); -#endif - return -1; -} - - -static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len, - const char *label, u8 *out, size_t outlen) -{ - if (hash_len == 32) - return hmac_sha256_kdf(secret, secret_len, NULL, - (const u8 *) label, os_strlen(label), - out, outlen); -#ifndef ESP_SUPPLICANT - if (hash_len == 48) - return hmac_sha384_kdf(secret, secret_len, NULL, - (const u8 *) label, os_strlen(label), - out, outlen); - if (hash_len == 64) - return hmac_sha512_kdf(secret, secret_len, NULL, - (const u8 *) label, os_strlen(label), - out, outlen); -#endif - return -1; -} - - -static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len, - size_t num_elem, const u8 *addr[], - const size_t *len, u8 *mac) -{ - if (hash_len == 32) - return hmac_sha256_vector(key, key_len, num_elem, addr, len, - mac); -#ifndef ESP_SUPPLICANT - if (hash_len == 48) - return hmac_sha384_vector(key, key_len, num_elem, addr, len, - mac); - if (hash_len == 64) - return hmac_sha512_vector(key, key_len, num_elem, addr, len, - mac); -#endif - return -1; -} - - -static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, - const u8 *data, size_t data_len, u8 *mac) -{ - if (hash_len == 32) - return hmac_sha256(key, key_len, data, data_len, mac); -#ifndef ESP_SUPPLICANT - if (hash_len == 48) - return hmac_sha384(key, key_len, data, data_len, mac); - if (hash_len == 64) - return hmac_sha512(key, key_len, data, data_len, mac); -#endif - return -1; -} - - -static int dpp_bn2bin_pad(const struct crypto_bignum *bn, u8 *pos, size_t len) -{ - if (crypto_bignum_to_bin(bn, pos, len, 0) < 0) - return -1; - - return 0; -} - -static struct wpabuf * dpp_get_pubkey_point(struct crypto_key *pkey, int prefix) -{ - int len, res; - struct wpabuf *buf; - unsigned char *pos = NULL; - - len = crypto_ec_get_publickey_buf(pkey, pos, 0); - if (len <= 0) { - wpa_printf(MSG_ERROR, - "DDP: Failed to determine public key encoding length"); - return NULL; - } - - buf = wpabuf_alloc(len); - if (!buf) { - return NULL; - } - - pos = wpabuf_put(buf, len); - - res = crypto_ec_get_publickey_buf(pkey, pos, len); - if (res != len) { - wpa_printf(MSG_ERROR, - "DDP: Failed to encode public key (res=%d/%d)", - res, len); - wpabuf_free(buf); - return NULL; - } - - if (!prefix) { - /* Remove 0x04 prefix to match DPP definition */ - pos = wpabuf_mhead(buf); - os_memmove(pos, pos + 1, len - 1); - buf->used--; - } - - return buf; -} - -static struct crypto_key * dpp_set_pubkey_point(struct crypto_key *group_key, - const u8 *buf, size_t len) -{ - const struct crypto_ec_group *group; - struct crypto_key *pkey = NULL; - - if (len & 1) - return NULL; - - group = crypto_ec_get_group_from_key(group_key); - if (group) - pkey = crypto_ec_set_pubkey_point(group, buf, - len); - else - wpa_printf(MSG_ERROR, "DPP: Could not get EC group"); - - return pkey; -} - -static int dpp_ecdh(struct crypto_key *own, struct crypto_key *peer, - u8 *secret, size_t *secret_len) -{ - return crypto_ecdh(own, peer, secret, secret_len); -} - - static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt) { wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); } - struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, size_t len) { @@ -263,7 +102,6 @@ struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, return msg; } - const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len) { u16 id, alen; @@ -286,7 +124,6 @@ const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len) return NULL; } - static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len, u16 req_id, u16 *ret_len) { @@ -314,7 +151,6 @@ static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len, return NULL; } - int dpp_check_attrs(const u8 *buf, size_t len) { const u8 *pos, *end; @@ -356,7 +192,6 @@ int dpp_check_attrs(const u8 *buf, size_t len) return 0; } - void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) { if (!info) @@ -367,7 +202,6 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) os_free(info); } - const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type) { switch (type) { @@ -381,7 +215,6 @@ const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type) return "??"; } - static int dpp_uri_valid_info(const char *info) { while (*info) { @@ -394,7 +227,6 @@ static int dpp_uri_valid_info(const char *info) return 1; } - static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri) { bi->uri = os_strdup(uri); @@ -455,7 +287,6 @@ fail: return 0; } - int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac) { if (!mac) @@ -495,29 +326,12 @@ int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info) return 0; } -static const struct dpp_curve_params * dpp_get_curve_group_id(int group_id) -{ - unsigned int i; - - if (!group_id) - return NULL; - - for (i = 0; dpp_curves[i].ike_group; i++) { - if (group_id == dpp_curves[i].ike_group) - return &dpp_curves[i]; - } - return NULL; -} - static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) { const char *end; u8 *data; size_t data_len; - struct crypto_key *pkey; - const unsigned char *p; - struct crypto_ec_group *group; - int id; + int res; end = os_strchr(info, ';'); if (!end) @@ -532,6 +346,10 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key", data, data_len); + res = dpp_get_subject_public_key(bi, data, data_len); + os_free(data); + return res; +#if 0 if (sha256_vector(1, (const u8 **) &data, &data_len, bi->pubkey_hash) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); @@ -592,9 +410,9 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) fail: crypto_ec_free_key(pkey); return -1; +#endif } - static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) { const char *pos = uri; @@ -658,296 +476,6 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) return bi; } - -static struct crypto_key * dpp_gen_keypair(const struct dpp_curve_params *curve) -{ - struct crypto_key *key = crypto_ec_gen_keypair(curve->ike_group); - - wpa_printf(MSG_DEBUG, "DPP: Generating a keypair"); - dpp_debug_print_key("Own generated key", key); - - return key; -} - -static const struct dpp_curve_params *dpp_get_curve_name(const char *name) -{ - int i; - - for (i = 0; dpp_curves[i].name; i++) { - if (os_strcmp(name, dpp_curves[i].name) == 0 || - (dpp_curves[i].jwk_crv && - os_strcmp(name, dpp_curves[i].jwk_crv) == 0)) - return &dpp_curves[i]; - } - return NULL; -} - - -static const struct dpp_curve_params *dpp_get_curve_jwk_crv(const char *name) -{ - int i; - - for (i = 0; dpp_curves[i].name; i++) { - if (dpp_curves[i].jwk_crv && - os_strcmp(name, dpp_curves[i].jwk_crv) == 0) - return &dpp_curves[i]; - } - - return NULL; -} - - -static struct crypto_key * dpp_set_keypair(const struct dpp_curve_params **curve, - const u8 *privkey, size_t privkey_len) -{ - struct crypto_ec_group *group; - struct crypto_key *pkey = crypto_ec_get_key(privkey, privkey_len); - int id; - - if (!pkey) { - wpa_printf(MSG_ERROR, "%s: failed to get pkey", __func__); - return NULL; - } - group = crypto_ec_get_group_from_key(pkey); - if (!group) { - return NULL; - } - id = crypto_ec_get_curve_id(group); - *curve = dpp_get_curve_group_id(id); - if (!*curve) { - wpa_printf(MSG_INFO, - "DPP: Unsupported curve (id=%d) in pre-assigned key", - id); - crypto_ec_free_key(pkey); - return NULL; - } - - return pkey; -} - -static struct wpabuf * dpp_bootstrap_key_der(struct crypto_key *key) -{ - unsigned char *der = NULL; - struct wpabuf *ret = NULL; - int der_len; - - der_len = crypto_ec_write_pub_key(key, &der); - if (!der) { - printf("failed to get der for bootstrapping key\n"); - return NULL; - } - ret = wpabuf_alloc_copy(der, der_len); - - os_free(der); - return ret; -} - -int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) -{ - struct wpabuf *der; - int res; - const u8 *addr[1]; - size_t len[1]; - - der = dpp_bootstrap_key_der(bi->pubkey); - if (!der) - return -1; - wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", - der); - - addr[0] = wpabuf_head(der); - len[0] = wpabuf_len(der); - res = sha256_vector(1, addr, len, bi->pubkey_hash); - if (res < 0) - wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); - else - wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, - SHA256_MAC_LEN); - wpabuf_free(der); - return res; -} - - -char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, - u8 *privkey, size_t privkey_len) -{ - char *base64 = NULL; - char *pos, *end; - size_t len; - struct wpabuf *der = NULL; - const u8 *addr[1]; - int res; - - if (!curve) { - bi->curve = &dpp_curves[0]; - } else { - bi->curve = dpp_get_curve_name(curve); - if (!bi->curve) { - wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", - curve); - return NULL; - } - } - if (privkey) - bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len); - else - bi->pubkey = dpp_gen_keypair(bi->curve); - if (!bi->pubkey) - goto fail; - bi->own = 1; - - der = dpp_bootstrap_key_der(bi->pubkey); - if (!der) - goto fail; - wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", - der); - - addr[0] = wpabuf_head(der); - len = wpabuf_len(der); - res = sha256_vector(1, addr, &len, bi->pubkey_hash); - if (res < 0) { - wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); - goto fail; - } - wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, - SHA256_MAC_LEN); - - base64 = (char *)base64_encode(wpabuf_head(der), wpabuf_len(der), &len); - wpabuf_free(der); - der = NULL; - if (!base64) - goto fail; - pos = base64; - end = pos + len; - for (;;) { - pos = os_strchr(pos, '\n'); - if (!pos) - break; - os_memmove(pos, pos + 1, end - pos); - } - return base64; -fail: - os_free(base64); - wpabuf_free(der); - return NULL; -} - -static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, - unsigned int hash_len) -{ - u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; - const char *info = "first intermediate key"; - int res; - - /* k1 = HKDF(<>, "first intermediate key", M.x) */ - - /* HKDF-Extract(<>, M.x) */ - os_memset(salt, 0, hash_len); - if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)", - prk, hash_len); - - /* HKDF-Expand(PRK, info, L) */ - res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len); - forced_memzero(prk, hash_len); - if (res < 0) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)", - k1, hash_len); - return 0; -} - - -static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, - unsigned int hash_len) -{ - u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; - const char *info = "second intermediate key"; - int res; - - /* k2 = HKDF(<>, "second intermediate key", N.x) */ - - /* HKDF-Extract(<>, N.x) */ - os_memset(salt, 0, hash_len); - res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk); - if (res < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", - prk, hash_len); - - /* HKDF-Expand(PRK, info, L) */ - res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len); - forced_memzero(prk, hash_len); - if (res < 0) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)", - k2, hash_len); - return 0; -} - - -static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke, - unsigned int hash_len) -{ - size_t nonce_len; - u8 nonces[2 * DPP_MAX_NONCE_LEN]; - const char *info_ke = "DPP Key"; - u8 prk[DPP_MAX_HASH_LEN]; - int res; - const u8 *addr[3]; - size_t len[3]; - size_t num_elem = 0; - - if (!auth->Mx_len || !auth->Nx_len) { - wpa_printf(MSG_DEBUG, - "DPP: Mx/Nx not available - cannot derive ke"); - return -1; - } - - /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */ - - /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */ - nonce_len = auth->curve->nonce_len; - os_memcpy(nonces, auth->i_nonce, nonce_len); - os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len); - addr[num_elem] = auth->Mx; - len[num_elem] = auth->Mx_len; - num_elem++; - addr[num_elem] = auth->Nx; - len[num_elem] = auth->Nx_len; - num_elem++; - if (auth->peer_bi && auth->own_bi) { - if (!auth->Lx_len) { - wpa_printf(MSG_DEBUG, - "DPP: Lx not available - cannot derive ke"); - return -1; - } - addr[num_elem] = auth->Lx; - len[num_elem] = auth->secret_len; - num_elem++; - } - res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len, - num_elem, addr, len, prk); - if (res < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", - prk, hash_len); - - /* HKDF-Expand(PRK, info, L) */ - res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len); - forced_memzero(prk, hash_len); - if (res < 0) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)", - ke, hash_len); - return 0; -} - - static void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status) { @@ -957,7 +485,6 @@ static void dpp_build_attr_status(struct wpabuf *msg, wpabuf_put_u8(msg, status); } - static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash) { @@ -969,7 +496,6 @@ static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, } } - static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash) { @@ -981,7 +507,6 @@ static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg, } } - static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, const struct wpabuf *pi, size_t nonce_len, @@ -994,7 +519,6 @@ static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth, u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE]; u8 *pos; const u8 *addr[2]; - size_t len[2], siv_len, attr_len; u8 *attr_start, *attr_end; @@ -1136,7 +660,6 @@ skip_wrapped_data: return msg; } - static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth, enum dpp_status_error status, const struct wpabuf *pr, @@ -1159,6 +682,7 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth, auth->waiting_auth_conf = 1; auth->auth_resp_tries = 0; + auth->auth_resp_status = status; /* Build DPP Authentication Response frame attributes */ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + @@ -1389,7 +913,6 @@ skip_connector: return msg; } - static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes, u16 num_modes, unsigned int freq) { @@ -1419,7 +942,6 @@ static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes, return 1; } - static int freq_included(const unsigned int freqs[], unsigned int num, unsigned int freq) { @@ -1446,7 +968,6 @@ static void freq_to_start(unsigned int freqs[], unsigned int num, freqs[0] = freq; } - static int dpp_channel_intersect(struct dpp_authentication *auth, struct hostapd_hw_modes *own_modes, u16 num_modes) @@ -1470,7 +991,6 @@ static int dpp_channel_intersect(struct dpp_authentication *auth, return 0; } - static int dpp_channel_local_list(struct dpp_authentication *auth, struct hostapd_hw_modes *own_modes, u16 num_modes) @@ -1514,7 +1034,6 @@ static int dpp_channel_local_list(struct dpp_authentication *auth, return auth->num_freq == 0 ? -1 : 0; } - static int dpp_prepare_channel_list(struct dpp_authentication *auth, struct hostapd_hw_modes *own_modes, u16 num_modes) @@ -1554,7 +1073,6 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth, return 0; } - static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth) { struct dpp_bootstrap_info *bi; @@ -1593,7 +1111,6 @@ fail: return -1; } - struct dpp_authentication * dpp_auth_init(void *msg_ctx, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, @@ -1734,7 +1251,6 @@ fail: goto out; } - static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, const char *json) { @@ -1839,7 +1355,6 @@ fail: return NULL; } - static void dpp_write_adv_proto(struct wpabuf *buf) { /* Advertisement Protocol IE */ @@ -1853,7 +1368,6 @@ static void dpp_write_adv_proto(struct wpabuf *buf) wpabuf_put_u8(buf, 0x01); } - static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query) { /* GAS Query */ @@ -1861,7 +1375,6 @@ static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query) wpabuf_put_buf(buf, query); } - struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, const char *json) { @@ -1888,7 +1401,6 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, return buf; } - struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, @@ -1948,7 +1460,6 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, return buf; } - static void dpp_auth_success(struct dpp_authentication *auth) { wpa_printf(MSG_DEBUG, @@ -1965,265 +1476,6 @@ static void dpp_auth_success(struct dpp_authentication *auth) auth->auth_success = 1; } - -static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth) -{ - struct wpabuf *pix, *prx, *bix, *brx; - const u8 *addr[7]; - size_t len[7]; - size_t i, num_elem = 0; - size_t nonce_len; - u8 zero = 0; - int res = -1; - - /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ - nonce_len = auth->curve->nonce_len; - - if (auth->initiator) { - pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); - prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); - if (auth->own_bi) - bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); - else - bix = NULL; - brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); - } else { - pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); - prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); - if (auth->peer_bi) - bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); - else - bix = NULL; - brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); - } - if (!pix || !prx || !brx) - goto fail; - - addr[num_elem] = auth->i_nonce; - len[num_elem] = nonce_len; - num_elem++; - - addr[num_elem] = auth->r_nonce; - len[num_elem] = nonce_len; - num_elem++; - - addr[num_elem] = wpabuf_head(pix); - len[num_elem] = wpabuf_len(pix) / 2; - num_elem++; - - addr[num_elem] = wpabuf_head(prx); - len[num_elem] = wpabuf_len(prx) / 2; - num_elem++; - - if (bix) { - addr[num_elem] = wpabuf_head(bix); - len[num_elem] = wpabuf_len(bix) / 2; - num_elem++; - } - - addr[num_elem] = wpabuf_head(brx); - len[num_elem] = wpabuf_len(brx) / 2; - num_elem++; - - addr[num_elem] = &zero; - len[num_elem] = 1; - num_elem++; - - wpa_printf(MSG_DEBUG, "DPP: R-auth hash components"); - for (i = 0; i < num_elem; i++) - wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); - res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth); - if (res == 0) - wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth, - auth->curve->hash_len); -fail: - wpabuf_free(pix); - wpabuf_free(prx); - wpabuf_free(bix); - wpabuf_free(brx); - return res; -} - -static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth) -{ - struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL; - const u8 *addr[7]; - size_t len[7]; - size_t i, num_elem = 0; - size_t nonce_len; - u8 one = 1; - int res = -1; - - /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ - nonce_len = auth->curve->nonce_len; - - if (auth->initiator) { - pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); - prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); - if (auth->own_bi) - bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); - else - bix = NULL; - if (!auth->peer_bi) - goto fail; - brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); - } else { - pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); - prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); - if (auth->peer_bi) - bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); - else - bix = NULL; - if (!auth->own_bi) - goto fail; - brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); - } - if (!pix || !prx || !brx) - goto fail; - - addr[num_elem] = auth->r_nonce; - len[num_elem] = nonce_len; - num_elem++; - - addr[num_elem] = auth->i_nonce; - len[num_elem] = nonce_len; - num_elem++; - - addr[num_elem] = wpabuf_head(prx); - len[num_elem] = wpabuf_len(prx) / 2; - num_elem++; - - addr[num_elem] = wpabuf_head(pix); - len[num_elem] = wpabuf_len(pix) / 2; - num_elem++; - - addr[num_elem] = wpabuf_head(brx); - len[num_elem] = wpabuf_len(brx) / 2; - num_elem++; - - if (bix) { - addr[num_elem] = wpabuf_head(bix); - len[num_elem] = wpabuf_len(bix) / 2; - num_elem++; - } - - addr[num_elem] = &one; - len[num_elem] = 1; - num_elem++; - - wpa_printf(MSG_DEBUG, "DPP: I-auth hash components"); - for (i = 0; i < num_elem; i++) - wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); - res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth); - if (res == 0) - wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth, - auth->curve->hash_len); -fail: - wpabuf_free(pix); - wpabuf_free(prx); - wpabuf_free(bix); - wpabuf_free(brx); - return res; -} - - -static int dpp_auth_derive_l_responder(struct dpp_authentication *auth) -{ - struct crypto_ec_group *group; - struct crypto_ec_point *l = NULL; - struct crypto_ec_point *BI_point; - struct crypto_bignum *lx, *sum, *q; - struct crypto_bignum *bR_bn, *pR_bn; - int ret = -1; - - /* L = ((bR + pR) modulo q) * BI */ - - sum = crypto_bignum_init(); - q = crypto_bignum_init(); - lx = crypto_bignum_init(); - if (!sum || !q || !lx) - goto fail; - - BI_point = crypto_ec_get_public_key(auth->peer_bi->pubkey); - group = crypto_ec_get_group_from_key(auth->peer_bi->pubkey); - bR_bn = crypto_ec_get_private_key(auth->own_bi->pubkey); - pR_bn = crypto_ec_get_private_key(auth->own_protocol_key); - - if (!bR_bn || !pR_bn) - goto fail; - - if ((crypto_get_order(group, q) != 0) || - (crypto_bignum_addmod(sum, bR_bn, pR_bn, q) != 0)) - goto fail; - - l = crypto_ec_point_init((struct crypto_ec *)group); - if (!l || (crypto_ec_point_mul((struct crypto_ec *)group, BI_point, sum, l) != 0) || - (crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0)) { - wpa_printf(MSG_ERROR, - "OpenSSL: failed: %s", __func__); - goto fail; - } - if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) - goto fail; - wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); - auth->Lx_len = auth->secret_len; - ret = 0; -fail: - crypto_ec_point_deinit(l, 1); - crypto_bignum_deinit(lx, 0); - crypto_bignum_deinit(sum, 0); - crypto_bignum_deinit(q, 0); - - return ret; -} - -static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) -{ - struct crypto_ec_group *group; - struct crypto_ec_point *l = NULL, *sum = NULL; - struct crypto_ec_point *BR_point, *PR_point; - struct crypto_bignum *lx; - struct crypto_bignum *bI_bn; - int ret = -1; - - /* L = bI * (BR + PR) */ - - lx = crypto_bignum_init(); - if (!lx) - goto fail; - BR_point = crypto_ec_get_public_key(auth->peer_bi->pubkey); - PR_point = crypto_ec_get_public_key(auth->peer_protocol_key); - - group = crypto_ec_get_group_from_key(auth->own_bi->pubkey); - bI_bn = crypto_ec_get_private_key(auth->own_bi->pubkey); - if (!group || !bI_bn) - goto fail; - sum = crypto_ec_point_init((struct crypto_ec *)group); - l = crypto_ec_point_init((struct crypto_ec *)group); - if (!sum || !l || - crypto_ec_point_add((struct crypto_ec *)group, BR_point, PR_point, sum) != 0 || - crypto_ec_point_mul((struct crypto_ec *)group, sum, bI_bn, l) != 0 || - crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0) { - wpa_printf(MSG_ERROR, - "OpenSSL: failed: %s", __func__); - goto fail; - } - - if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) - goto fail; - wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); - auth->Lx_len = auth->secret_len; - ret = 0; -fail: - crypto_ec_point_deinit(l, 1); - crypto_ec_point_deinit(sum, 1); - crypto_bignum_deinit(lx, 0); - - - return ret; -} - - static int dpp_auth_build_resp_ok(struct dpp_authentication *auth) { size_t nonce_len; @@ -2307,7 +1559,7 @@ static int dpp_auth_build_resp_ok(struct dpp_authentication *auth) goto fail; } - if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) + if (dpp_derive_bk_ke(auth) < 0) goto fail; /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ @@ -2407,7 +1659,6 @@ fail: return ret; } - static int dpp_auth_build_resp_status(struct dpp_authentication *auth, enum dpp_status_error status) { @@ -2472,7 +1723,6 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, return 0; } - struct dpp_authentication * dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, struct dpp_bootstrap_info *peer_bi, @@ -2728,7 +1978,6 @@ fail: return NULL; } - int dpp_notify_new_qr_code(struct dpp_authentication *auth, struct dpp_bootstrap_info *peer_bi) { @@ -2748,7 +1997,6 @@ int dpp_notify_new_qr_code(struct dpp_authentication *auth, return 1; } - static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth, enum dpp_status_error status) { @@ -2926,7 +2174,6 @@ fail: return NULL; } - static void dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len, @@ -3024,7 +2271,6 @@ fail: bin_clear_free(unwrapped, unwrapped_len); } - struct wpabuf * dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len) @@ -3273,7 +2519,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", wrapped2, wrapped2_len); - if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) + if (dpp_derive_bk_ke(auth) < 0) goto fail; unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE; @@ -3339,7 +2585,6 @@ fail: return NULL; } - static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len, @@ -3410,7 +2655,6 @@ fail: return -1; } - int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len) { @@ -3569,13 +2813,11 @@ fail: return -1; } - static int bin_str_eq(const char *val, size_t len, const char *cmp) { return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0; } - struct dpp_configuration * dpp_configuration_alloc(const char *type) { struct dpp_configuration *conf; @@ -3616,41 +2858,35 @@ fail: return NULL; } - int dpp_akm_psk(enum dpp_akm akm) { return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || akm == DPP_AKM_PSK_SAE_DPP; } - int dpp_akm_sae(enum dpp_akm akm) { return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE || akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; } - int dpp_akm_legacy(enum dpp_akm akm) { return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE || akm == DPP_AKM_SAE; } - int dpp_akm_dpp(enum dpp_akm akm) { return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; } - int dpp_akm_ver2(enum dpp_akm akm) { return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP; } - int dpp_configuration_valid(const struct dpp_configuration *conf) { if (conf->ssid_len == 0) @@ -3662,7 +2898,6 @@ int dpp_configuration_valid(const struct dpp_configuration *conf) return 1; } - void dpp_configuration_free(struct dpp_configuration *conf) { if (!conf) @@ -3672,7 +2907,6 @@ void dpp_configuration_free(struct dpp_configuration *conf) bin_clear_free(conf, sizeof(*conf)); } - static int dpp_configuration_parse_helper(struct dpp_authentication *auth, const char *cmd, int idx) { @@ -3799,7 +3033,6 @@ fail: return -1; } - static int dpp_configuration_parse(struct dpp_authentication *auth, const char *cmd) { @@ -3834,7 +3067,6 @@ fail: return -1; } - static struct dpp_configurator * dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id) { @@ -3851,7 +3083,6 @@ dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id) return NULL; } - int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, struct dpp_authentication *auth, const char *cmd) @@ -3894,7 +3125,6 @@ int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, return 0; } - void dpp_auth_deinit(struct dpp_authentication *auth) { unsigned int i; @@ -3926,7 +3156,6 @@ void dpp_auth_deinit(struct dpp_authentication *auth) bin_clear_free(auth, sizeof(*auth)); } - static struct wpabuf * dpp_build_conf_start(struct dpp_authentication *auth, struct dpp_configuration *conf, size_t tailroom) @@ -3974,7 +3203,6 @@ dpp_build_conf_start(struct dpp_authentication *auth, return buf; } - static int dpp_build_jwk(struct wpabuf *buf, const char *name, struct crypto_key *key, const char *kid, const struct dpp_curve_params *curve) { @@ -4009,7 +3237,6 @@ fail: return ret; } - static void dpp_build_legacy_cred_params(struct wpabuf *buf, struct dpp_configuration *conf) { @@ -4026,7 +3253,6 @@ static void dpp_build_legacy_cred_params(struct wpabuf *buf, } } - static const char * dpp_netrole_str(enum dpp_netrole netrole) { switch (netrole) { @@ -4298,7 +3524,6 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, return buf; } - static struct wpabuf * dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, int idx) @@ -4339,7 +3564,6 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, return dpp_build_conf_obj_legacy(auth, conf); } - static struct wpabuf * dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, u16 e_nonce_len, enum dpp_netrole netrole) @@ -4490,7 +3714,6 @@ fail: goto out; } - struct wpabuf * dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, size_t attr_len) @@ -4638,77 +3861,6 @@ fail: return resp; } - -static struct wpabuf * -dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, - const u8 *prot_hdr, u16 prot_hdr_len, int *hash_func) -{ - struct json_token *root, *token; - struct wpabuf *kid = NULL; - - root = json_parse((const char *) prot_hdr, prot_hdr_len); - if (!root) { - wpa_printf(MSG_DEBUG, - "DPP: JSON parsing failed for JWS Protected Header"); - goto fail; - } - - if (root->type != JSON_OBJECT) { - wpa_printf(MSG_DEBUG, - "DPP: JWS Protected Header root is not an object"); - goto fail; - } - - token = json_get_member(root, "typ"); - if (!token || token->type != JSON_STRING) { - wpa_printf(MSG_DEBUG, "DPP: No typ string value found"); - goto fail; - } - wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s", - token->string); - if (os_strcmp(token->string, "dppCon") != 0) { - wpa_printf(MSG_DEBUG, - "DPP: Unsupported JWS Protected Header typ=%s", - token->string); - goto fail; - } - - token = json_get_member(root, "alg"); - if (!token || token->type != JSON_STRING) { - wpa_printf(MSG_DEBUG, "DPP: No alg string value found"); - goto fail; - } - wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s", - token->string); - if (os_strcmp(token->string, curve->jws_alg) != 0) { - wpa_printf(MSG_DEBUG, - "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)", - token->string, curve->jws_alg); - goto fail; - } - - if (os_strcmp(token->string, "ES256") == 0 || - os_strcmp(token->string, "BS256") == 0) { - *hash_func = CRYPTO_HASH_ALG_SHA256; - } else { - *hash_func = -1; - wpa_printf(MSG_ERROR, "Unsupported JWS Protected Header alg=%s", token->string); - } - - kid = json_get_member_base64url(root, "kid"); - if (!kid) { - wpa_printf(MSG_DEBUG, "DPP: No kid string value found"); - goto fail; - } - wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)", - kid); - -fail: - json_free(root); - return kid; -} - - static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, struct json_token *cred) { @@ -4755,7 +3907,6 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, return 0; } - static struct crypto_key * dpp_parse_jwk(struct json_token *jwk, const struct dpp_curve_params **key_curve) { @@ -4841,7 +3992,6 @@ fail: return pkey; } - int dpp_key_expired(const char *timestamp, os_time_t *expiry) { struct os_time now; @@ -4920,7 +4070,6 @@ int dpp_key_expired(const char *timestamp, os_time_t *expiry) return 0; } - static int dpp_parse_connector(struct dpp_authentication *auth, struct dpp_config_obj *conf, const unsigned char *payload, @@ -5017,38 +4166,6 @@ fail: return ret; } -static int dpp_check_pubkey_match(struct crypto_key *pub, struct wpabuf *r_hash) -{ - struct wpabuf *uncomp; - int res; - u8 hash[SHA256_MAC_LEN]; - const u8 *addr[1]; - size_t len[1]; - - if (wpabuf_len(r_hash) != SHA256_MAC_LEN) - return -1; - uncomp = dpp_get_pubkey_point(pub, 1); - if (!uncomp) - return -1; - addr[0] = wpabuf_head(uncomp); - len[0] = wpabuf_len(uncomp); - wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key", - addr[0], len[0]); - res = sha256_vector(1, addr, len, hash); - wpabuf_free(uncomp); - if (res < 0) - return -1; - if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, - "DPP: Received hash value does not match calculated public key hash value"); - wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash", - hash, SHA256_MAC_LEN); - return -1; - } - return 0; -} - - static void dpp_copy_csign(struct dpp_config_obj *conf, struct crypto_key *csign) { unsigned char *der = NULL; @@ -5076,148 +4193,6 @@ static void dpp_copy_netaccesskey(struct dpp_authentication *auth, crypto_free_buffer(der); } -struct dpp_signed_connector_info { - unsigned char *payload; - size_t payload_len; -}; - -static enum dpp_status_error -dpp_process_signed_connector(struct dpp_signed_connector_info *info, - struct crypto_key *csign_pub, const char *connector) -{ - enum dpp_status_error ret = 255; - const char *pos, *end, *signed_start, *signed_end; - struct wpabuf *kid = NULL; - unsigned char *prot_hdr = NULL, *signature = NULL; - size_t prot_hdr_len = 0, signature_len = 0, signed_len; - struct crypto_bignum *r = NULL, *s = NULL; - const struct dpp_curve_params *curve; - const struct crypto_ec_group *group; - int id, hash_func = -1; - u8 *hash = NULL; - - group = crypto_ec_get_group_from_key(csign_pub); - if (!group) - goto fail; - id = crypto_ec_get_curve_id(group); - curve = dpp_get_curve_group_id(id); - if (!curve) - goto fail; - wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv); - os_memset(info, 0, sizeof(*info)); - - signed_start = pos = connector; - end = os_strchr(pos, '.'); - if (!end) { - wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector"); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len); - if (!prot_hdr) { - wpa_printf(MSG_DEBUG, - "DPP: Failed to base64url decode signedConnector JWS Protected Header"); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - wpa_hexdump_ascii(MSG_DEBUG, - "DPP: signedConnector - JWS Protected Header", - (u8 *)prot_hdr, prot_hdr_len); - kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &hash_func); - if (!kid) { - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - if (wpabuf_len(kid) != SHA256_MAC_LEN) { - wpa_printf(MSG_DEBUG, - "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)", - (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - - pos = end + 1; - end = os_strchr(pos, '.'); - if (!end) { - wpa_printf(MSG_DEBUG, - "DPP: Missing dot(2) in signedConnector"); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - signed_end = end - 1; - info->payload = base64_url_decode(pos, end - pos, &info->payload_len); - if (!info->payload) { - wpa_printf(MSG_DEBUG, - "DPP: Failed to base64url decode signedConnector JWS Payload"); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - wpa_hexdump_ascii(MSG_DEBUG, - "DPP: signedConnector - JWS Payload", - (u8 *)info->payload, info->payload_len); - pos = end + 1; - signature = base64_url_decode(pos, os_strlen(pos), &signature_len); - if (!signature) { - wpa_printf(MSG_DEBUG, - "DPP: Failed to base64url decode signedConnector signature"); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature", - signature, signature_len); - - if (dpp_check_pubkey_match(csign_pub, kid) < 0) { - ret = DPP_STATUS_NO_MATCH; - goto fail; - } - - if (signature_len & 0x01) { - wpa_printf(MSG_DEBUG, - "DPP: Unexpected signedConnector signature length (%d)", - (int) signature_len); - ret = DPP_STATUS_INVALID_CONNECTOR; - goto fail; - } - - /* JWS Signature encodes the signature (r,s) as two octet strings. Need - * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */ - r = crypto_bignum_init_set(signature, signature_len / 2); - s = crypto_bignum_init_set(signature + signature_len / 2, signature_len / 2); - - signed_len = signed_end - signed_start + 1; - hash = os_malloc(curve->hash_len); - if (!hash) { - wpa_printf(MSG_ERROR, "malloc failed"); - goto fail; - } - - if (hash_func == CRYPTO_HASH_ALG_SHA256) { - if ((sha256_vector(1, (const u8 **) &signed_start, &signed_len, hash)) != 0) { - goto fail; - } - } else { - goto fail; - } - - if ((crypto_edcsa_sign_verify((unsigned char *)hash, r, s, - csign_pub, curve->hash_len)) != 0) { - goto fail; - } - - ret = DPP_STATUS_OK; -fail: - if (hash != NULL) { - os_free(hash); - } - os_free(prot_hdr); - wpabuf_free(kid); - os_free(signature); - crypto_bignum_deinit(r, 0); - crypto_bignum_deinit(s, 0); - return ret; -} - - static int dpp_parse_cred_dpp(struct dpp_authentication *auth, struct dpp_config_obj *conf, struct json_token *cred) @@ -5292,7 +4267,6 @@ fail: return ret; } - const char * dpp_akm_str(enum dpp_akm akm) { switch (akm) { @@ -5313,7 +4287,6 @@ const char * dpp_akm_str(enum dpp_akm akm) } } - const char * dpp_akm_selector_str(enum dpp_akm akm) { switch (akm) { @@ -5334,7 +4307,6 @@ const char * dpp_akm_selector_str(enum dpp_akm akm) } } - static enum dpp_akm dpp_akm_from_str(const char *akm) { const char *pos; @@ -5387,7 +4359,6 @@ static enum dpp_akm dpp_akm_from_str(const char *akm) return DPP_AKM_UNKNOWN; } - static int dpp_parse_conf_obj(struct dpp_authentication *auth, const u8 *conf_obj, u16 conf_obj_len) { @@ -5503,7 +4474,6 @@ fail: return ret; } - int dpp_conf_resp_rx(struct dpp_authentication *auth, const uint8_t *resp, uint32_t resp_len) { @@ -5617,7 +4587,6 @@ void dpp_configurator_free(struct dpp_configurator *conf) os_free(conf); } - int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf, size_t buflen) { @@ -5637,7 +4606,6 @@ int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf, return ret; } - struct dpp_configurator * dpp_keygen_configurator(const char *curve, u8 *privkey, size_t privkey_len) @@ -5699,7 +4667,6 @@ fail: goto out; } - int dpp_configurator_own_config(struct dpp_authentication *auth, const char *curve, int ap) { @@ -5746,7 +4713,6 @@ fail: return ret; } - static int dpp_compatible_netrole(const char *role1, const char *role2) { return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) || @@ -5827,74 +4793,39 @@ static int dpp_connector_match_groups(struct json_token *own_root, return 0; } -static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, - unsigned int hash_len) +struct json_token * dpp_parse_own_connector(const char *own_connector) { - u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; - const char *info = "DPP PMK"; - int res; + unsigned char *own_conn; + size_t own_conn_len; + const char *pos, *end; + struct json_token *own_root; - /* PMK = HKDF(<>, "DPP PMK", N.x) */ + pos = os_strchr(own_connector, '.'); + if (!pos) { + wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the firstdot (.)"); + return NULL; + } + pos++; + end = os_strchr(pos, '.'); + if (!end) { + wpa_printf(MSG_DEBUG, "DPP: Own connector is missing second dot (.)"); + return NULL; + } + own_conn = base64_url_decode(pos, end - pos, &own_conn_len); + if (!own_conn) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to base64url decode own signedConnectior JWS Payload"); + return NULL; + } - /* HKDF-Extract(<>, N.x) */ - os_memset(salt, 0, hash_len); - if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", - prk, hash_len); + own_root = json_parse((const char *) own_conn, own_conn_len); + os_free(own_conn); + if (!own_root) + wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector"); - /* HKDF-Expand(PRK, info, L) */ - res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len); - forced_memzero(prk, hash_len); - if (res < 0) - return -1; - - wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)", - pmk, hash_len); - return 0; + return own_root; } - -static int dpp_derive_pmkid(const struct dpp_curve_params *curve, - struct crypto_key *own_key, struct crypto_key *peer_key, u8 *pmkid) -{ - struct wpabuf *nkx, *pkx; - int ret = -1, res; - const u8 *addr[2]; - size_t len[2]; - u8 hash[SHA256_MAC_LEN]; - - /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ - nkx = dpp_get_pubkey_point(own_key, 0); - pkx = dpp_get_pubkey_point(peer_key, 0); - if (!nkx || !pkx) - goto fail; - addr[0] = wpabuf_head(nkx); - len[0] = wpabuf_len(nkx) / 2; - addr[1] = wpabuf_head(pkx); - len[1] = wpabuf_len(pkx) / 2; - if (len[0] != len[1]) - goto fail; - if (os_memcmp(addr[0], addr[1], len[0]) > 0) { - addr[0] = wpabuf_head(pkx); - addr[1] = wpabuf_head(nkx); - } - wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]); - wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]); - res = sha256_vector(2, addr, len, hash); - if (res < 0) - goto fail; - wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN); - os_memcpy(pmkid, hash, PMKID_LEN); - wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN); - ret = 0; -fail: - wpabuf_free(nkx); - wpabuf_free(pkx); - return ret; -} - - enum dpp_status_error dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, const u8 *net_access_key, size_t net_access_key_len, @@ -5909,12 +4840,6 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, struct wpabuf *own_key_pub = NULL; const struct dpp_curve_params *curve, *own_curve; struct dpp_signed_connector_info info; - const unsigned char *p; - struct crypto_key *csign = NULL; - char *signed_connector = NULL; - const char *pos, *end; - unsigned char *own_conn = NULL; - size_t own_conn_len; size_t Nx_len; u8 Nx[DPP_MAX_SHARED_SECRET_LEN]; @@ -5923,14 +4848,6 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, if (expiry) *expiry = 0; - p = csign_key; - csign = crypto_ec_parse_subpub_key(p, csign_key_len); - if (!csign) { - wpa_printf(MSG_ERROR, - "DPP: Failed to parse local C-sign-key information"); - goto fail; - } - own_key = dpp_set_keypair(&own_curve, net_access_key, net_access_key_len); if (!own_key) { @@ -5938,39 +4855,14 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, goto fail; } - pos = os_strchr(own_connector, '.'); - if (!pos) { - wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)"); - goto fail; - } - pos++; - end = os_strchr(pos, '.'); - if (!end) { - wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)"); - goto fail; - } - own_conn = base64_url_decode(pos, end - pos, &own_conn_len); - if (!own_conn) { - wpa_printf(MSG_DEBUG, - "DPP: Failed to base64url decode own signedConnector JWS Payload"); - goto fail; - } - - own_root = json_parse((const char *) own_conn, own_conn_len); + own_root = dpp_parse_own_connector(own_connector); if (!own_root) { - wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector"); goto fail; } - wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector", - (u8 *)peer_connector, peer_connector_len); - signed_connector = os_malloc(peer_connector_len + 1); - if (!signed_connector) - goto fail; - os_memcpy(signed_connector, peer_connector, peer_connector_len); - signed_connector[peer_connector_len] = '\0'; - res = dpp_process_signed_connector(&info, csign, signed_connector); + res = dpp_check_signed_connector(&info, csign_key, csign_key_len, + peer_connector, peer_connector_len); if (res != DPP_STATUS_OK) { ret = res; goto fail; @@ -6051,74 +4943,15 @@ fail: if (ret != DPP_STATUS_OK) os_memset(intro, 0, sizeof(*intro)); forced_memzero(Nx, sizeof(Nx)); - os_free(own_conn); - os_free(signed_connector); os_free(info.payload); crypto_ec_free_key(own_key); wpabuf_free(own_key_pub); crypto_ec_free_key(peer_key); - crypto_ec_free_key(csign); json_free(root); json_free(own_root); return ret; } -#ifdef CONFIG_TESTING_OPTIONS -static int dpp_test_gen_invalid_key(struct wpabuf *msg, - const struct dpp_curve_params *curve) -{ - return 0; -} - -char * dpp_corrupt_connector_signature(const char *connector) -{ - char *tmp, *pos, *signed3 = NULL; - unsigned char *signature = NULL; - size_t signature_len = 0, signed3_len; - - tmp = os_zalloc(os_strlen(connector) + 5); - if (!tmp) - goto fail; - os_memcpy(tmp, connector, os_strlen(connector)); - - pos = os_strchr(tmp, '.'); - if (!pos) - goto fail; - - pos = os_strchr(pos + 1, '.'); - if (!pos) - goto fail; - pos++; - - wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s", - pos); - signature = base64_url_decode(pos, os_strlen(pos), &signature_len); - if (!signature || signature_len == 0) - goto fail; - wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature", - signature, signature_len); - signature[signature_len - 1] ^= 0x01; - wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature", - signature, signature_len); - signed3 = base64_url_encode(signature, signature_len, &signed3_len); - if (!signed3) - goto fail; - os_memcpy(pos, signed3, signed3_len); - pos[signed3_len] = '\0'; - wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s", - pos); - -out: - os_free(signature); - os_free(signed3); - return tmp; -fail: - os_free(tmp); - tmp = NULL; - goto out; -} -#endif /* CONFIG_TESTING_OPTIONS */ - static unsigned int dpp_next_id(struct dpp_global *dpp) { struct dpp_bootstrap_info *bi; @@ -6153,7 +4986,6 @@ static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id) return found ? 0 : -1; } - struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp, const char *uri) { @@ -6172,7 +5004,6 @@ struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp, return bi; } - struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, const char *uri) { @@ -6191,7 +5022,6 @@ struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, return bi; } - int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) { char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL; @@ -6202,6 +5032,9 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) int ret = -1; struct dpp_bootstrap_info *bi; + if (!dpp) + return -1; + bi = os_zalloc(sizeof(*bi)); if (!bi) goto fail; @@ -6276,7 +5109,6 @@ fail: return ret; } - struct dpp_bootstrap_info * dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id) { @@ -6292,7 +5124,6 @@ dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id) return NULL; } - int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id) { unsigned int id_val; @@ -6343,7 +5174,6 @@ int dpp_get_bootstrap_info(struct dpp_global *dpp, int id, pkhash); } - void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, const u8 *r_bootstrap, struct dpp_bootstrap_info **own_bi, @@ -6379,7 +5209,6 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, } - static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) { struct dpp_configurator *conf; @@ -6393,7 +5222,6 @@ static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) return max_id + 1; } - int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) { char *curve = NULL; @@ -6430,7 +5258,6 @@ fail: return ret; } - static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) { struct dpp_configurator *conf, *tmp; @@ -6453,7 +5280,6 @@ static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) return found ? 0 : -1; } - int dpp_configurator_remove(struct dpp_global *dpp, const char *id) { unsigned int id_val; @@ -6469,7 +5295,6 @@ int dpp_configurator_remove(struct dpp_global *dpp, const char *id) return dpp_configurator_del(dpp, id_val); } - int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, char *buf, size_t buflen) { @@ -6497,7 +5322,6 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config) return dpp; } - void dpp_global_clear(struct dpp_global *dpp) { if (!dpp) @@ -6507,7 +5331,6 @@ void dpp_global_clear(struct dpp_global *dpp) dpp_configurator_del(dpp, 0); } - void dpp_global_deinit(struct dpp_global *dpp) { dpp_global_clear(dpp); diff --git a/components/wpa_supplicant/src/common/dpp.h b/components/wpa_supplicant/src/common/dpp.h index 61c056c380..da09aba2e8 100644 --- a/components/wpa_supplicant/src/common/dpp.h +++ b/components/wpa_supplicant/src/common/dpp.h @@ -18,6 +18,7 @@ #include "utils/common.h" #include "esp_err.h" #include "esp_dpp.h" +#include "crypto/crypto.h" struct crypto_ecdh; struct hostapd_ip_addr; @@ -594,5 +595,64 @@ void dpp_global_deinit(struct dpp_global *dpp); int dpp_connect(uint8_t *bssid, bool pdr_done); esp_err_t esp_dpp_start_net_intro_protocol(uint8_t *bssid); +/* dpp_crypto.c */ + +struct dpp_signed_connector_info { + unsigned char *payload; + size_t payload_len; +}; + +const struct dpp_curve_params *dpp_get_curve_name(const char *name); +const struct dpp_curve_params *dpp_get_curve_jwk_crv(const char *name); +const struct dpp_curve_params * dpp_get_curve_group_id(int group_id); +void dpp_debug_print_key(const char *title, struct crypto_key *key); +int dpp_hash_vector(const struct dpp_curve_params *curve, + size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); +int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len, + const char *label, u8 *out, size_t outlen); +int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, + const u8 *data, size_t data_len, u8 *mac); +struct crypto_key * dpp_set_pubkey_point(struct crypto_key *group_key, + const u8 *buf, size_t len); +struct crypto_key * dpp_gen_keypair(const struct dpp_curve_params *curve); +struct crypto_key * dpp_set_keypair(const struct dpp_curve_params **curve, + const u8 *privkey, size_t privkey_len); +int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi); +char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, + u8 *privkey, size_t privkey_len); +int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, + unsigned int hash_len); +int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, + unsigned int hash_len); +int dpp_ecdh(struct crypto_key *own, struct crypto_key *peer, + u8 *secret, size_t *secret_len); +struct wpabuf *dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, + const u8 *prot_hdr, u16 prot_hdr_len, int *hash_func); +int dpp_check_pubkey_match(struct crypto_key *pub, struct wpabuf *r_hash); +enum dpp_status_error dpp_process_signed_connector(struct dpp_signed_connector_info *info, + struct crypto_key *csign_pub, const char *connector); +int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth); +int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth); +int dpp_auth_derive_l_responder(struct dpp_authentication *auth); +int dpp_auth_derive_l_initiator(struct dpp_authentication *auth); +int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, + unsigned int hash_len); +int dpp_derive_pmkid(const struct dpp_curve_params *curve, + struct crypto_key *own_key, struct crypto_key *peer_key, u8 *pmkid); +int dpp_bn2bin_pad(const struct crypto_bignum *bn, u8 *pos, size_t len); +struct wpabuf * dpp_bootstrap_key_der(struct crypto_key *key); +struct wpabuf * dpp_get_pubkey_point(struct crypto_key *pkey, int prefix); +int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi, const u8 *data, size_t data_len); +int dpp_derive_bk_ke(struct dpp_authentication *auth); +enum dpp_status_error +dpp_check_signed_connector(struct dpp_signed_connector_info *info, + const u8 *csign_key, size_t csign_key_len, + const u8 *peer_connector, size_t peer_connector_len); + +/* dpp crypto apis */ + #endif /* CONFIG_DPP */ #endif /* DPP_H */ diff --git a/components/wpa_supplicant/src/common/dpp_crypto.c b/components/wpa_supplicant/src/common/dpp_crypto.c new file mode 100644 index 0000000000..c5a4f5b7f9 --- /dev/null +++ b/components/wpa_supplicant/src/common/dpp_crypto.c @@ -0,0 +1,1191 @@ +/* + * DPP functionality shared between hostapd and wpa_supplicant + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include + +#include "utils/common.h" +#include "common/defs.h" +#include "utils/base64.h" +#include "utils/json.h" +#include "crypto/crypto.h" +#include "crypto/random.h" +#include "crypto/aes.h" +#include "crypto/aes_siv.h" +#include "crypto/sha256.h" +#include "dpp.h" +#include "esp_dpp_i.h" + +const struct dpp_curve_params dpp_curves[] = { + /* The mandatory to support and the default NIST P-256 curve needs to + * be the first entry on this list. */ + { "secp256r1", 32, 32, 16, 32, "P-256", 19, "ES256" }, + { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" }, + { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" }, + { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" }, + { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" }, + { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" }, + { NULL, 0, 0, 0, 0, NULL, 0, NULL } +}; + +const struct dpp_curve_params *dpp_get_curve_name(const char *name) +{ + int i; + + for (i = 0; dpp_curves[i].name; i++) { + if (os_strcmp(name, dpp_curves[i].name) == 0 || + (dpp_curves[i].jwk_crv && + os_strcmp(name, dpp_curves[i].jwk_crv) == 0)) + return &dpp_curves[i]; + } + return NULL; +} + +const struct dpp_curve_params *dpp_get_curve_jwk_crv(const char *name) +{ + int i; + + for (i = 0; dpp_curves[i].name; i++) { + if (dpp_curves[i].jwk_crv && + os_strcmp(name, dpp_curves[i].jwk_crv) == 0) + return &dpp_curves[i]; + } + + return NULL; +} + +const struct dpp_curve_params * dpp_get_curve_group_id(int group_id) +{ + unsigned int i; + + if (!group_id) + return NULL; + + for (i = 0; dpp_curves[i].ike_group; i++) { + if (group_id == dpp_curves[i].ike_group) + return &dpp_curves[i]; + } + return NULL; +} + +void dpp_debug_print_key(const char *title, struct crypto_key *key) +{ + crypto_ec_key_debug_print(title, key); +} + +int dpp_hash_vector(const struct dpp_curve_params *curve, + size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + if (curve->hash_len == 32) + return sha256_vector(num_elem, addr, len, mac); +#ifndef ESP_SUPPLICANT + if (curve->hash_len == 48) + return sha384_vector(num_elem, addr, len, mac); + if (curve->hash_len == 64) + return sha512_vector(num_elem, addr, len, mac); +#endif + return -1; +} + +int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len, + const char *label, u8 *out, size_t outlen) +{ + if (hash_len == 32) + return hmac_sha256_kdf(secret, secret_len, NULL, + (const u8 *) label, os_strlen(label), + out, outlen); +#ifndef ESP_SUPPLICANT + if (hash_len == 48) + return hmac_sha384_kdf(secret, secret_len, NULL, + (const u8 *) label, os_strlen(label), + out, outlen); + if (hash_len == 64) + return hmac_sha512_kdf(secret, secret_len, NULL, + (const u8 *) label, os_strlen(label), + out, outlen); +#endif + return -1; +} + +int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len, + size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + if (hash_len == 32) + return hmac_sha256_vector(key, key_len, num_elem, addr, len, + mac); +#ifndef ESP_SUPPLICANT + if (hash_len == 48) + return hmac_sha384_vector(key, key_len, num_elem, addr, len, + mac); + if (hash_len == 64) + return hmac_sha512_vector(key, key_len, num_elem, addr, len, + mac); +#endif + return -1; +} + +int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, + const u8 *data, size_t data_len, u8 *mac) +{ + if (hash_len == 32) + return hmac_sha256(key, key_len, data, data_len, mac); +#ifndef ESP_SUPPLICANT + if (hash_len == 48) + return hmac_sha384(key, key_len, data, data_len, mac); + if (hash_len == 64) + return hmac_sha512(key, key_len, data, data_len, mac); +#endif + return -1; +} + +struct crypto_key * dpp_set_pubkey_point(struct crypto_key *group_key, + const u8 *buf, size_t len) +{ + const struct crypto_ec_group *group; + struct crypto_key *pkey = NULL; + + if (len & 1) + return NULL; + + group = crypto_ec_get_group_from_key(group_key); + if (group) + pkey = crypto_ec_set_pubkey_point(group, buf, + len); + else + wpa_printf(MSG_ERROR, "DPP: Could not get EC group"); + + return pkey; +} + +struct crypto_key * dpp_gen_keypair(const struct dpp_curve_params *curve) +{ + struct crypto_key *key = crypto_ec_key_gen(curve->ike_group); + + wpa_printf(MSG_DEBUG, "DPP: Generating a keypair"); + dpp_debug_print_key("Own generated key", key); + + return key; +} + +struct crypto_key * dpp_set_keypair(const struct dpp_curve_params **curve, + const u8 *privkey, size_t privkey_len) +{ + struct crypto_ec_group *group; + struct crypto_key *pkey = crypto_ec_key_parse_priv(privkey, privkey_len); + int id; + + if (!pkey) { + wpa_printf(MSG_ERROR, "%s: failed to get pkey", __func__); + return NULL; + } + group = crypto_ec_get_group_from_key(pkey); + if (!group) { + crypto_ec_free_key(pkey); + return NULL; + } + id = crypto_ec_get_curve_id(group); + *curve = dpp_get_curve_group_id(id); + if (!*curve) { + wpa_printf(MSG_INFO, + "DPP: Unsupported curve (id=%d) in pre-assigned key", + id); + crypto_ec_free_key(pkey); + return NULL; + } + + return pkey; +} + +struct wpabuf * dpp_bootstrap_key_der(struct crypto_key *key) +{ + unsigned char *der = NULL; + struct wpabuf *ret = NULL; + int der_len; + + der_len = crypto_ec_write_pub_key(key, &der); + if (!der) { + printf("failed to get der for bootstrapping key\n"); + return NULL; + } + ret = wpabuf_alloc_copy(der, der_len); + + os_free(der); + return ret; +} + +int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) +{ + struct wpabuf *der; + int res; + const u8 *addr[1]; + size_t len[1]; + + der = dpp_bootstrap_key_der(bi->pubkey); + if (!der) + return -1; + wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", + der); + + addr[0] = wpabuf_head(der); + len[0] = wpabuf_len(der); + res = sha256_vector(1, addr, len, bi->pubkey_hash); + if (res < 0) + wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); + else + wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, + SHA256_MAC_LEN); + wpabuf_free(der); + return res; +} + +char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, + u8 *privkey, size_t privkey_len) +{ + char *base64 = NULL; + char *pos, *end; + size_t len; + struct wpabuf *der = NULL; + const u8 *addr[1]; + int res; + + if (!curve) { + bi->curve = &dpp_curves[0]; + } else { + bi->curve = dpp_get_curve_name(curve); + if (!bi->curve) { + wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", + curve); + return NULL; + } + } + if (privkey) + bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len); + else + bi->pubkey = dpp_gen_keypair(bi->curve); + if (!bi->pubkey) + goto fail; + bi->own = 1; + + der = dpp_bootstrap_key_der(bi->pubkey); + if (!der) + goto fail; + wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", + der); + + addr[0] = wpabuf_head(der); + len = wpabuf_len(der); + res = sha256_vector(1, addr, &len, bi->pubkey_hash); + if (res < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, + SHA256_MAC_LEN); + + base64 = (char *)base64_encode(wpabuf_head(der), wpabuf_len(der), &len); + wpabuf_free(der); + der = NULL; + if (!base64) + goto fail; + pos = base64; + end = pos + len; + for (;;) { + pos = os_strchr(pos, '\n'); + if (!pos) + break; + os_memmove(pos, pos + 1, end - pos); + } + return base64; +fail: + os_free(base64); + wpabuf_free(der); + return NULL; +} + +int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, + unsigned int hash_len) +{ + u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; + const char *info = "first intermediate key"; + int res; + + /* k1 = HKDF(<>, "first intermediate key", M.x) */ + + /* HKDF-Extract(<>, M.x) */ + os_memset(salt, 0, hash_len); + if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)", + prk, hash_len); + + /* HKDF-Expand(PRK, info, L) */ + res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len); + forced_memzero(prk, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)", + k1, hash_len); + return 0; +} + +int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, + unsigned int hash_len) +{ + u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; + const char *info = "second intermediate key"; + int res; + + /* k2 = HKDF(<>, "second intermediate key", N.x) */ + + /* HKDF-Extract(<>, N.x) */ + os_memset(salt, 0, hash_len); + res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk); + if (res < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", + prk, hash_len); + + /* HKDF-Expand(PRK, info, L) */ + res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len); + forced_memzero(prk, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)", + k2, hash_len); + return 0; +} + +int dpp_ecdh(struct crypto_key *own, struct crypto_key *peer, + u8 *secret, size_t *secret_len) +{ + return crypto_ecdh(own, peer, secret, secret_len); +} + +struct wpabuf * +dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, + const u8 *prot_hdr, u16 prot_hdr_len, int *hash_func) +{ + struct json_token *root, *token; + struct wpabuf *kid = NULL; + + root = json_parse((const char *) prot_hdr, prot_hdr_len); + if (!root) { + wpa_printf(MSG_DEBUG, + "DPP: JSON parsing failed for JWS Protected Header"); + goto fail; + } + + if (root->type != JSON_OBJECT) { + wpa_printf(MSG_DEBUG, + "DPP: JWS Protected Header root is not an object"); + goto fail; + } + + token = json_get_member(root, "typ"); + if (!token || token->type != JSON_STRING) { + wpa_printf(MSG_DEBUG, "DPP: No typ string value found"); + goto fail; + } + wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s", + token->string); + if (os_strcmp(token->string, "dppCon") != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported JWS Protected Header typ=%s", + token->string); + goto fail; + } + + token = json_get_member(root, "alg"); + if (!token || token->type != JSON_STRING) { + wpa_printf(MSG_DEBUG, "DPP: No alg string value found"); + goto fail; + } + wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s", + token->string); + if (os_strcmp(token->string, curve->jws_alg) != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)", + token->string, curve->jws_alg); + goto fail; + } + + if (os_strcmp(token->string, "ES256") == 0 || + os_strcmp(token->string, "BS256") == 0) { + *hash_func = CRYPTO_HASH_ALG_SHA256; + } else { + *hash_func = -1; + wpa_printf(MSG_ERROR, "Unsupported JWS Protected Header alg=%s", token->string); + } + + kid = json_get_member_base64url(root, "kid"); + if (!kid) { + wpa_printf(MSG_DEBUG, "DPP: No kid string value found"); + goto fail; + } + wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)", + kid); + +fail: + json_free(root); + return kid; +} + +int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi, const u8 *data, size_t data_len) +{ + struct crypto_key *pkey; + const unsigned char *p; + struct crypto_ec_group *group; + int id; + + if (sha256_vector(1, (const u8 **) &data, &data_len, + bi->pubkey_hash) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); + return -1; + } + wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", + bi->pubkey_hash, SHA256_MAC_LEN); + + /* DER encoded ASN.1 SubjectPublicKeyInfo + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * subjectPublicKey = compressed format public key per ANSI X9.63 + * algorithm = ecPublicKey (1.2.840.10045.2.1) + * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g., + * prime256v1 (1.2.840.10045.3.1.7) + */ + + p = data; + + pkey = crypto_ec_parse_subpub_key((unsigned char *)p, data_len); + + if (!pkey) { + wpa_printf(MSG_DEBUG, + "DPP: Could not parse URI public-key SubjectPublicKeyInfo"); + return -1; + } + + if (!crypto_is_ec_key(pkey)) { + wpa_printf(MSG_DEBUG, + "DPP: SubjectPublicKeyInfo does not describe an EC key"); + crypto_ec_free_key(pkey); + return -1; + } + + group = crypto_ec_get_group_from_key(pkey); + if (!group) { + return -1; + } + id = crypto_ec_get_curve_id(group); + bi->curve = dpp_get_curve_group_id(id); + if (!bi->curve) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported SubjectPublicKeyInfo curve"); + goto fail; + } + + bi->pubkey = pkey; + return 0; +fail: + crypto_ec_free_key(pkey); + return -1; + +} + +int dpp_derive_bk_ke(struct dpp_authentication *auth) +{ + size_t nonce_len = auth->curve->nonce_len; + u8 nonces[2 * DPP_MAX_NONCE_LEN]; + const char *info_ke = "DPP Key"; + u8 prk[DPP_MAX_HASH_LEN]; + int res; + const u8 *addr[3]; + size_t len[3]; + size_t num_elem = 0; + unsigned int hash_len = auth->curve->hash_len; + + if (!auth->Mx_len || !auth->Nx_len) { + wpa_printf(MSG_DEBUG, + "DPP: Mx/Nx not available - cannot derive ke"); + return -1; + } + + /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */ + + /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */ + os_memcpy(nonces, auth->i_nonce, nonce_len); + os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len); + addr[num_elem] = auth->Mx; + len[num_elem] = auth->Mx_len; + num_elem++; + addr[num_elem] = auth->Nx; + len[num_elem] = auth->Nx_len; + num_elem++; + if (auth->peer_bi && auth->own_bi) { + if (!auth->Lx_len) { + wpa_printf(MSG_DEBUG, + "DPP: Lx not available - cannot derive ke"); + return -1; + } + addr[num_elem] = auth->Lx; + len[num_elem] = auth->secret_len; + num_elem++; + } + res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len, + num_elem, addr, len, prk); + if (res < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", + prk, hash_len); + + /* HKDF-Expand(PRK, info, L) */ + res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, auth->ke, hash_len); + forced_memzero(prk, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)", + auth->ke, hash_len); + return 0; +} + +struct wpabuf * dpp_get_pubkey_point(struct crypto_key *pkey, int prefix) +{ + int len, res; + struct wpabuf *buf; + unsigned char *pos = NULL; + + len = crypto_ec_get_publickey_buf(pkey, pos, 0); + if (len <= 0) { + wpa_printf(MSG_ERROR, + "DDP: Failed to determine public key encoding length"); + return NULL; + } + + buf = wpabuf_alloc(len); + if (!buf) { + return NULL; + } + + pos = wpabuf_put(buf, len); + + res = crypto_ec_get_publickey_buf(pkey, pos, len); + if (res != len) { + wpa_printf(MSG_ERROR, + "DDP: Failed to encode public key (res=%d/%d)", + res, len); + wpabuf_free(buf); + return NULL; + } + + if (!prefix) { + /* Remove 0x04 prefix to match DPP definition */ + pos = wpabuf_mhead(buf); + os_memmove(pos, pos + 1, len - 1); + buf->used--; + } + + return buf; +} + +int dpp_check_pubkey_match(struct crypto_key *pub, struct wpabuf *r_hash) +{ + struct wpabuf *uncomp; + int res; + u8 hash[SHA256_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + + if (wpabuf_len(r_hash) != SHA256_MAC_LEN) + return -1; + uncomp = dpp_get_pubkey_point(pub, 1); + if (!uncomp) + return -1; + addr[0] = wpabuf_head(uncomp); + len[0] = wpabuf_len(uncomp); + wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key", + addr[0], len[0]); + res = sha256_vector(1, addr, len, hash); + wpabuf_free(uncomp); + if (res < 0) + return -1; + if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Received hash value does not match calculated public key hash value"); + wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash", + hash, SHA256_MAC_LEN); + return -1; + } + return 0; +} + +enum dpp_status_error +dpp_process_signed_connector(struct dpp_signed_connector_info *info, + struct crypto_key *csign_pub, const char *connector) +{ + enum dpp_status_error ret = 255; + const char *pos, *end, *signed_start, *signed_end; + struct wpabuf *kid = NULL; + unsigned char *prot_hdr = NULL, *signature = NULL; + size_t prot_hdr_len = 0, signature_len = 0, signed_len; + struct crypto_bignum *r = NULL, *s = NULL; + const struct dpp_curve_params *curve; + const struct crypto_ec_group *group; + int id, hash_func = -1; + u8 *hash = NULL; + + group = crypto_ec_get_group_from_key(csign_pub); + if (!group) + goto fail; + id = crypto_ec_get_curve_id(group); + curve = dpp_get_curve_group_id(id); + if (!curve) + goto fail; + wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv); + os_memset(info, 0, sizeof(*info)); + + signed_start = pos = connector; + end = os_strchr(pos, '.'); + if (!end) { + wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector"); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len); + if (!prot_hdr) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to base64url decode signedConnector JWS Protected Header"); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, + "DPP: signedConnector - JWS Protected Header", + (u8 *)prot_hdr, prot_hdr_len); + kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &hash_func); + if (!kid) { + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + if (wpabuf_len(kid) != SHA256_MAC_LEN) { + wpa_printf(MSG_DEBUG, + "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)", + (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + + pos = end + 1; + end = os_strchr(pos, '.'); + if (!end) { + wpa_printf(MSG_DEBUG, + "DPP: Missing dot(2) in signedConnector"); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + signed_end = end - 1; + info->payload = base64_url_decode(pos, end - pos, &info->payload_len); + if (!info->payload) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to base64url decode signedConnector JWS Payload"); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, + "DPP: signedConnector - JWS Payload", + (u8 *)info->payload, info->payload_len); + pos = end + 1; + signature = base64_url_decode(pos, os_strlen(pos), &signature_len); + if (!signature) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to base64url decode signedConnector signature"); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature", + signature, signature_len); + + if (dpp_check_pubkey_match(csign_pub, kid) < 0) { + ret = DPP_STATUS_NO_MATCH; + goto fail; + } + + if (signature_len & 0x01) { + wpa_printf(MSG_DEBUG, + "DPP: Unexpected signedConnector signature length (%d)", + (int) signature_len); + ret = DPP_STATUS_INVALID_CONNECTOR; + goto fail; + } + + /* JWS Signature encodes the signature (r,s) as two octet strings. Need + * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */ + r = crypto_bignum_init_set(signature, signature_len / 2); + s = crypto_bignum_init_set(signature + signature_len / 2, signature_len / 2); + + signed_len = signed_end - signed_start + 1; + hash = os_malloc(curve->hash_len); + if (!hash) { + wpa_printf(MSG_ERROR, "malloc failed"); + goto fail; + } + + if (hash_func == CRYPTO_HASH_ALG_SHA256) { + if ((sha256_vector(1, (const u8 **) &signed_start, &signed_len, hash)) != 0) { + goto fail; + } + } else { + goto fail; + } + + if ((crypto_edcsa_sign_verify((unsigned char *)hash, r, s, + csign_pub, curve->hash_len)) != 0) { + goto fail; + } + + ret = DPP_STATUS_OK; +fail: + if (hash != NULL) { + os_free(hash); + } + os_free(prot_hdr); + wpabuf_free(kid); + os_free(signature); + crypto_bignum_deinit(r, 0); + crypto_bignum_deinit(s, 0); + return ret; +} + +enum dpp_status_error +dpp_check_signed_connector(struct dpp_signed_connector_info *info, + const u8 *csign_key, size_t csign_key_len, + const u8 *peer_connector, size_t peer_connector_len) +{ + struct crypto_key *csign; + char *signed_connector = NULL; + enum dpp_status_error res = DPP_STATUS_INVALID_CONNECTOR; + const unsigned char *p; + + p = csign_key; + csign = crypto_ec_parse_subpub_key(p, csign_key_len); + if (!csign) { + wpa_printf(MSG_ERROR, + "DPP: Failed to parse local C-sign-key information"); + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector", + (u8 *)peer_connector, peer_connector_len); + signed_connector = os_malloc(peer_connector_len + 1); + if (!signed_connector) + goto fail; + os_memcpy(signed_connector, peer_connector, peer_connector_len); + signed_connector[peer_connector_len] = '\0'; + + res = dpp_process_signed_connector(info, csign, signed_connector); +fail: + os_free(signed_connector); + crypto_ec_free_key(csign); + return res; + +} + +int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth) +{ + struct wpabuf *pix, *prx, *bix, *brx; + const u8 *addr[7]; + size_t len[7]; + size_t i, num_elem = 0; + size_t nonce_len; + u8 zero = 0; + int res = -1; + + /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ + nonce_len = auth->curve->nonce_len; + + if (auth->initiator) { + pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); + prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); + if (auth->own_bi) + bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); + else + bix = NULL; + brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); + } else { + pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); + prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); + if (auth->peer_bi) + bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); + else + bix = NULL; + brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); + } + if (!pix || !prx || !brx) + goto fail; + + addr[num_elem] = auth->i_nonce; + len[num_elem] = nonce_len; + num_elem++; + + addr[num_elem] = auth->r_nonce; + len[num_elem] = nonce_len; + num_elem++; + + addr[num_elem] = wpabuf_head(pix); + len[num_elem] = wpabuf_len(pix) / 2; + num_elem++; + + addr[num_elem] = wpabuf_head(prx); + len[num_elem] = wpabuf_len(prx) / 2; + num_elem++; + + if (bix) { + addr[num_elem] = wpabuf_head(bix); + len[num_elem] = wpabuf_len(bix) / 2; + num_elem++; + } + + addr[num_elem] = wpabuf_head(brx); + len[num_elem] = wpabuf_len(brx) / 2; + num_elem++; + + addr[num_elem] = &zero; + len[num_elem] = 1; + num_elem++; + + wpa_printf(MSG_DEBUG, "DPP: R-auth hash components"); + for (i = 0; i < num_elem; i++) + wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); + res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth); + if (res == 0) + wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth, + auth->curve->hash_len); +fail: + wpabuf_free(pix); + wpabuf_free(prx); + wpabuf_free(bix); + wpabuf_free(brx); + return res; +} + +int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth) +{ + struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL; + const u8 *addr[7]; + size_t len[7]; + size_t i, num_elem = 0; + size_t nonce_len; + u8 one = 1; + int res = -1; + + /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ + nonce_len = auth->curve->nonce_len; + + if (auth->initiator) { + pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); + prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); + if (auth->own_bi) + bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); + else + bix = NULL; + if (!auth->peer_bi) + goto fail; + brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); + } else { + pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); + prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); + if (auth->peer_bi) + bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); + else + bix = NULL; + if (!auth->own_bi) + goto fail; + brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); + } + if (!pix || !prx || !brx) + goto fail; + + addr[num_elem] = auth->r_nonce; + len[num_elem] = nonce_len; + num_elem++; + + addr[num_elem] = auth->i_nonce; + len[num_elem] = nonce_len; + num_elem++; + + addr[num_elem] = wpabuf_head(prx); + len[num_elem] = wpabuf_len(prx) / 2; + num_elem++; + + addr[num_elem] = wpabuf_head(pix); + len[num_elem] = wpabuf_len(pix) / 2; + num_elem++; + + addr[num_elem] = wpabuf_head(brx); + len[num_elem] = wpabuf_len(brx) / 2; + num_elem++; + + if (bix) { + addr[num_elem] = wpabuf_head(bix); + len[num_elem] = wpabuf_len(bix) / 2; + num_elem++; + } + + addr[num_elem] = &one; + len[num_elem] = 1; + num_elem++; + + wpa_printf(MSG_DEBUG, "DPP: I-auth hash components"); + for (i = 0; i < num_elem; i++) + wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); + res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth); + if (res == 0) + wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth, + auth->curve->hash_len); +fail: + wpabuf_free(pix); + wpabuf_free(prx); + wpabuf_free(bix); + wpabuf_free(brx); + return res; +} + +int dpp_bn2bin_pad(const struct crypto_bignum *bn, u8 *pos, size_t len) +{ + if (crypto_bignum_to_bin(bn, pos, len, 0) < 0) + return -1; + + return 0; +} + +int dpp_auth_derive_l_responder(struct dpp_authentication *auth) +{ + struct crypto_ec_group *group; + struct crypto_ec_point *l = NULL; + struct crypto_ec_point *BI_point; + struct crypto_bignum *lx, *sum, *q; + struct crypto_bignum *bR_bn, *pR_bn; + int ret = -1; + + /* L = ((bR + pR) modulo q) * BI */ + + sum = crypto_bignum_init(); + q = crypto_bignum_init(); + lx = crypto_bignum_init(); + if (!sum || !q || !lx) + goto fail; + + BI_point = crypto_ec_key_get_public_key(auth->peer_bi->pubkey); + group = crypto_ec_get_group_from_key(auth->peer_bi->pubkey); + bR_bn = crypto_ec_key_get_private_key(auth->own_bi->pubkey); + pR_bn = crypto_ec_key_get_private_key(auth->own_protocol_key); + + if (!bR_bn || !pR_bn) + goto fail; + + if ((crypto_get_order(group, q) != 0) || + (crypto_bignum_addmod(sum, bR_bn, pR_bn, q) != 0)) + goto fail; + + l = crypto_ec_point_init((struct crypto_ec *)group); + if (!l || (crypto_ec_point_mul((struct crypto_ec *)group, BI_point, sum, l) != 0) || + (crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0)) { + wpa_printf(MSG_ERROR, + "OpenSSL: failed: %s", __func__); + goto fail; + } + if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); + auth->Lx_len = auth->secret_len; + ret = 0; +fail: + crypto_ec_point_deinit(l, 1); + crypto_bignum_deinit(lx, 0); + crypto_bignum_deinit(sum, 0); + crypto_bignum_deinit(q, 0); + + return ret; +} + +int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) +{ + struct crypto_ec_group *group; + struct crypto_ec_point *l = NULL, *sum = NULL; + struct crypto_ec_point *BR_point, *PR_point; + struct crypto_bignum *lx; + struct crypto_bignum *bI_bn; + int ret = -1; + + /* L = bI * (BR + PR) */ + + lx = crypto_bignum_init(); + if (!lx) + goto fail; + BR_point = crypto_ec_key_get_public_key(auth->peer_bi->pubkey); + PR_point = crypto_ec_key_get_public_key(auth->peer_protocol_key); + + group = crypto_ec_get_group_from_key(auth->own_bi->pubkey); + bI_bn = crypto_ec_key_get_private_key(auth->own_bi->pubkey); + if (!group || !bI_bn) + goto fail; + sum = crypto_ec_point_init((struct crypto_ec *)group); + l = crypto_ec_point_init((struct crypto_ec *)group); + if (!sum || !l || + crypto_ec_point_add((struct crypto_ec *)group, BR_point, PR_point, sum) != 0 || + crypto_ec_point_mul((struct crypto_ec *)group, sum, bI_bn, l) != 0 || + crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0) { + wpa_printf(MSG_ERROR, + "OpenSSL: failed: %s", __func__); + goto fail; + } + + if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); + auth->Lx_len = auth->secret_len; + ret = 0; +fail: + crypto_ec_point_deinit(l, 1); + crypto_ec_point_deinit(sum, 1); + crypto_bignum_deinit(lx, 0); + + + return ret; +} + +int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, + unsigned int hash_len) +{ + u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; + const char *info = "DPP PMK"; + int res; + + /* PMK = HKDF(<>, "DPP PMK", N.x) */ + + /* HKDF-Extract(<>, N.x) */ + os_memset(salt, 0, hash_len); + if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", + prk, hash_len); + + /* HKDF-Expand(PRK, info, L) */ + res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len); + forced_memzero(prk, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)", + pmk, hash_len); + return 0; +} + +int dpp_derive_pmkid(const struct dpp_curve_params *curve, + struct crypto_key *own_key, struct crypto_key *peer_key, u8 *pmkid) +{ + struct wpabuf *nkx, *pkx; + int ret = -1, res; + const u8 *addr[2]; + size_t len[2]; + u8 hash[SHA256_MAC_LEN]; + + /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ + nkx = dpp_get_pubkey_point(own_key, 0); + pkx = dpp_get_pubkey_point(peer_key, 0); + if (!nkx || !pkx) + goto fail; + addr[0] = wpabuf_head(nkx); + len[0] = wpabuf_len(nkx) / 2; + addr[1] = wpabuf_head(pkx); + len[1] = wpabuf_len(pkx) / 2; + if (len[0] != len[1]) + goto fail; + if (os_memcmp(addr[0], addr[1], len[0]) > 0) { + addr[0] = wpabuf_head(pkx); + addr[1] = wpabuf_head(nkx); + } + wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]); + wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]); + res = sha256_vector(2, addr, len, hash); + if (res < 0) + goto fail; + wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN); + os_memcpy(pmkid, hash, PMKID_LEN); + wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN); + ret = 0; +fail: + wpabuf_free(nkx); + wpabuf_free(pkx); + return ret; +} + +#ifdef CONFIG_TESTING_OPTIONS +int dpp_test_gen_invalid_key(struct wpabuf *msg, + const struct dpp_curve_params *curve) +{ + return 0; +} + +char * dpp_corrupt_connector_signature(const char *connector) +{ + char *tmp, *pos, *signed3 = NULL; + unsigned char *signature = NULL; + size_t signature_len = 0, signed3_len; + + tmp = os_zalloc(os_strlen(connector) + 5); + if (!tmp) + goto fail; + os_memcpy(tmp, connector, os_strlen(connector)); + + pos = os_strchr(tmp, '.'); + if (!pos) + goto fail; + + pos = os_strchr(pos + 1, '.'); + if (!pos) + goto fail; + pos++; + + wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s", + pos); + signature = base64_url_decode(pos, os_strlen(pos), &signature_len); + if (!signature || signature_len == 0) + goto fail; + wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature", + signature, signature_len); + signature[signature_len - 1] ^= 0x01; + wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature", + signature, signature_len); + signed3 = base64_url_encode(signature, signature_len, &signed3_len); + if (!signed3) + goto fail; + os_memcpy(pos, signed3, signed3_len); + pos[signed3_len] = '\0'; + wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s", + pos); + +out: + os_free(signature); + os_free(signed3); + return tmp; +fail: + os_free(tmp); + tmp = NULL; + goto out; +} +#endif /* CONFIG_TESTING_OPTIONS */ diff --git a/components/wpa_supplicant/src/crypto/crypto.h b/components/wpa_supplicant/src/crypto/crypto.h index 7d7e458020..1181c4d148 100644 --- a/components/wpa_supplicant/src/crypto/crypto.h +++ b/components/wpa_supplicant/src/crypto/crypto.h @@ -798,7 +798,7 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e); */ /** - * crypto_ec_get_b - Get 'b' coeffiecient of an EC group's curve + * crypto_ec_get_b - Get 'b' coefficient of an EC group's curve * @e: EC context from crypto_ec_init() * Returns: 'b' coefficient (bignum) of the group */ @@ -949,19 +949,19 @@ int crypto_ec_get_publickey_buf(struct crypto_key *key, u8 *key_buf, int len); struct crypto_ec_group *crypto_ec_get_group_from_key(struct crypto_key *key); /** - * crypto_ec_get_private_key - Get EC private key (in bignum format) + * crypto_ec_key_get_private_key - Get EC private key (in bignum format) * @key: crypto key * Returns: Private key */ -struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key); +struct crypto_bignum *crypto_ec_key_get_private_key(struct crypto_key *key); /** - * crypto_ec_get_key - Read key from character stream + * crypto_ec_key_parse_priv - Read key from character stream * @privkey: Private key * @privkey_len: private key len * Returns: Crypto key */ -struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len); +struct crypto_key *crypto_ec_key_parse_priv(const u8 *privkey, size_t privkey_len); /** * crypto_ec_get_mbedtls_to_nist_group_id - get nist group from mbedtls internal group @@ -1029,14 +1029,14 @@ struct crypto_key *crypto_ec_parse_subpub_key(const unsigned char *p, size_t len int crypto_is_ec_key(struct crypto_key *key); /** - * crypto_ec_gen_keypair: generate crypto ec keypair + * crypto_ec_key_gen: generate crypto ec keypair * @ike_group: grpup * Return: crypto key */ -struct crypto_key * crypto_ec_gen_keypair(u16 ike_group); +struct crypto_key * crypto_ec_key_gen(u16 ike_group); /** - * crypto_ec_write_pub_key: return public key in charater buffer + * crypto_ec_write_pub_key: return public key in character buffer * @key: crypto key * @der_len: buffer len * Return: public key buffer @@ -1047,7 +1047,7 @@ int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf); * crypto_ec_set_pubkey_point: set bignum point on ec curve * @group: ec group * @buf: x,y coordinate - * @len: length of x and y coordiate + * @len: length of x and y coordinate * Return : crypto key */ struct crypto_key * crypto_ec_set_pubkey_point(const struct crypto_ec_group *group, @@ -1058,19 +1058,19 @@ struct crypto_key * crypto_ec_set_pubkey_point(const struct crypto_ec_group *gro */ void crypto_ec_free_key(struct crypto_key *key); /** - * crypto_debug_print_ec_key: print ec key + * crypto_ec_key_debug_print: print ec key * @title: title * @key: crypto key * Return: None */ -void crypto_debug_print_ec_key(const char *title, struct crypto_key *key); +void crypto_ec_key_debug_print(const char *title, struct crypto_key *key); /** - * crypto_ec_get_public_key: Public key from crypto key + * crypto_ec_key_get_public_key: Public key from crypto key * @key: crypto key * Return : Public key */ -struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key); +struct crypto_ec_point *crypto_ec_key_get_public_key(struct crypto_key *key); /** * crypto_get_order: free crypto key @@ -1079,7 +1079,7 @@ struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key); int crypto_get_order(struct crypto_ec_group *group, struct crypto_bignum *x); /** - * crypto_ec_get_affine_coordinates : get affine corrdinate of ec curve + * crypto_ec_get_affine_coordinates : get affine coordinate of ec curve * @e: ec curve * @pt: point * @x: x coordinate @@ -1105,7 +1105,7 @@ int crypto_key_compare(struct crypto_key *key1, struct crypto_key *key2); /* * crypto_write_pubkey_der: get public key in der format * @csign: key - * @key_buf: key buffer in charater format + * @key_buf: key buffer in character format * Return : len of char buffer if success */ int crypto_write_pubkey_der(struct crypto_key *csign, unsigned char **key_buf); @@ -1120,8 +1120,8 @@ void crypto_free_buffer(unsigned char *buf); /** * @crypto_ec_get_priv_key_der: get private key in der format * @key: key structure - * @key_data: key data in charater buffer - * @key_len = key length of charater buffer + * @key_data: key data in character buffer + * @key_len = key length of character buffer * Return : 0 if success */ int crypto_ec_get_priv_key_der(struct crypto_key *key, unsigned char **key_data, int *key_len);