Add 2 new functions in crypto.h that "wraps" around already defined signing function with (r,s) interface instead of DER Ecdsa-Sig-Value. Using those functions implies to compute the hash to sign manually before. Signed-off-by: Cedric Izoard <cedric.izoard@xxxxxxxxxxxx> --- src/common/dpp_crypto.c | 195 +++++++++++------------------------- src/crypto/crypto.h | 27 +++++ src/crypto/crypto_openssl.c | 106 ++++++++++++++++++++ 3 files changed, 194 insertions(+), 134 deletions(-) diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c index ef9aa14bc..1844ae7e7 100644 --- a/src/common/dpp_crypto.c +++ b/src/common/dpp_crypto.c @@ -29,24 +29,6 @@ LIBRESSL_VERSION_NUMBER < 0x20700000L) /* Compatibility wrappers for older versions. */ -static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) -{ - sig->r = r; - sig->s = s; - return 1; -} - - -static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, - const BIGNUM **ps) -{ - if (pr) - *pr = sig->r; - if (ps) - *ps = sig->s; -} - - static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_EC) @@ -710,7 +692,7 @@ fail: static struct wpabuf * dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, const u8 *prot_hdr, u16 prot_hdr_len, - const EVP_MD **ret_md) + int *hash_func) { struct json_token *root, *token; struct wpabuf *kid = NULL; @@ -757,16 +739,15 @@ dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, } if (os_strcmp(token->string, "ES256") == 0 || os_strcmp(token->string, "BS256") == 0) - *ret_md = EVP_sha256(); + *hash_func = CRYPTO_HASH_ALG_SHA256; else if (os_strcmp(token->string, "ES384") == 0 || os_strcmp(token->string, "BS384") == 0) - *ret_md = EVP_sha384(); + *hash_func = CRYPTO_HASH_ALG_SHA384; else if (os_strcmp(token->string, "ES512") == 0 || os_strcmp(token->string, "BS512") == 0) - *ret_md = EVP_sha512(); - else - *ret_md = NULL; - if (!*ret_md) { + *hash_func = CRYPTO_HASH_ALG_SHA512; + else { + *hash_func = -1; wpa_printf(MSG_DEBUG, "DPP: Unsupported JWS Protected Header alg=%s", token->string); @@ -827,27 +808,12 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, 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; - const EVP_MD *sign_md = NULL; - unsigned char *der = NULL; - int der_len; - int res; - EVP_MD_CTX *md_ctx = NULL; - ECDSA_SIG *sig = NULL; - BIGNUM *r = NULL, *s = NULL; + size_t prot_hdr_len = 0, signature_len = 0, signed_len; + int res, hash_func = -1; const struct dpp_curve_params *curve; - const EC_KEY *eckey; - const EC_GROUP *group; - int nid; + u8 *hash = NULL; - eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *)csign_pub); - if (!eckey) - goto fail; - group = EC_KEY_get0_group(eckey); - if (!group) - goto fail; - nid = EC_GROUP_get_curve_name(group); - curve = dpp_get_curve_nid(nid); + curve = dpp_get_curve_ike_group(crypto_ec_key_group(csign_pub)); if (!curve) goto fail; wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv); @@ -870,7 +836,7 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector - JWS Protected Header", prot_hdr, prot_hdr_len); - kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md); + kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &hash_func); if (!kid) { ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; @@ -926,57 +892,41 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, 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 = BN_bin2bn(signature, signature_len / 2, NULL); - s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL); - sig = ECDSA_SIG_new(); - if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1) + hash = os_malloc(curve->hash_len); + if (!hash) goto fail; - r = NULL; - s = NULL; - der_len = i2d_ECDSA_SIG(sig, &der); - if (der_len <= 0) { - wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature"); - goto fail; - } - wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len); - md_ctx = EVP_MD_CTX_create(); - if (!md_ctx) + signed_len = signed_end - signed_start + 1; + if (hash_func == CRYPTO_HASH_ALG_SHA256) + res = sha256_vector(1, (const u8**)&signed_start, &signed_len, hash); + else if (hash_func == CRYPTO_HASH_ALG_SHA384) + res = sha384_vector(1, (const u8**)&signed_start, &signed_len, hash); + else if (hash_func == CRYPTO_HASH_ALG_SHA512) + res = sha512_vector(1, (const u8**)&signed_start, &signed_len, hash); + else goto fail; - ERR_clear_error(); - if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, (EVP_PKEY *)csign_pub) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } - if (EVP_DigestVerifyUpdate(md_ctx, signed_start, - signed_end - signed_start + 1) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s", - ERR_error_string(ERR_get_error(), NULL)); + if (res) goto fail; - } - res = EVP_DigestVerifyFinal(md_ctx, der, der_len); + + res = crypto_ec_key_verify_signature_r_s(csign_pub, hash, curve->hash_len, + signature, signature_len / 2, + signature + signature_len / 2, + signature_len / 2); if (res != 1) { wpa_printf(MSG_DEBUG, - "DPP: EVP_DigestVerifyFinal failed (res=%d): %s", - res, ERR_error_string(ERR_get_error(), NULL)); + "DPP: signedConnector signature check failed (res=%d)", + res); ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } ret = DPP_STATUS_OK; fail: - EVP_MD_CTX_destroy(md_ctx); + os_free(hash); os_free(prot_hdr); wpabuf_free(kid); os_free(signature); - ECDSA_SIG_free(sig); - BN_free(r); - BN_free(s); - OPENSSL_free(der); return ret; } @@ -2036,78 +1986,55 @@ dpp_build_conn_signature(struct dpp_configurator *conf, size_t *signed3_len) { const struct dpp_curve_params *curve; + struct wpabuf *sig = NULL; char *signed3 = NULL; - unsigned char *signature = NULL; - const unsigned char *p; - size_t signature_len; - EVP_MD_CTX *md_ctx = NULL; - ECDSA_SIG *sig = NULL; char *dot = "."; - const EVP_MD *sign_md; - const BIGNUM *r, *s; + const u8 *vector[3]; + size_t vector_len[3]; + u8 *hash = NULL; + int ret; + + vector[0] = (const u8 *)signed1; + vector[1] = (const u8 *)dot; + vector[2] = (const u8 *)signed2; + vector_len[0] = signed1_len; + vector_len[1] = 1; + vector_len[2] = signed2_len; curve = conf->curve; + hash = os_malloc(curve->hash_len); + if (!hash) + goto fail; if (curve->hash_len == SHA256_MAC_LEN) { - sign_md = EVP_sha256(); + ret = sha256_vector(3, vector, vector_len, hash); } else if (curve->hash_len == SHA384_MAC_LEN) { - sign_md = EVP_sha384(); + ret = sha384_vector(3, vector, vector_len, hash); } else if (curve->hash_len == SHA512_MAC_LEN) { - sign_md = EVP_sha512(); + ret = sha512_vector(3, vector, vector_len, hash); } else { wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm"); goto fail; } - md_ctx = EVP_MD_CTX_create(); - if (!md_ctx) - goto fail; - - ERR_clear_error(); - if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, (EVP_PKEY *)conf->csign) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } - if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 || - EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 || - EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s", - ERR_error_string(ERR_get_error(), NULL)); + if (ret) { + wpa_printf(MSG_DEBUG, "DPP: Hash computation failed"); goto fail; } - if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } - signature = os_malloc(signature_len); - if (!signature) - goto fail; - if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) { - wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", - ERR_error_string(ERR_get_error(), NULL)); + wpa_hexdump(MSG_DEBUG, "HASH: ", hash, curve->hash_len); + + sig = crypto_ec_key_sign_r_s(conf->csign, hash, curve->hash_len); + if (!sig) { + wpa_printf(MSG_ERROR, "DPP: Signature computation failed"); goto fail; } - wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)", - signature, signature_len); - /* Convert to raw coordinates r,s */ - p = signature; - sig = d2i_ECDSA_SIG(NULL, &p, signature_len); - if (!sig) - goto fail; - ECDSA_SIG_get0(sig, &r, &s); - if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 || - dpp_bn2bin_pad(s, signature + curve->prime_len, - curve->prime_len) < 0) - goto fail; - signature_len = 2 * curve->prime_len; + wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)", - signature, signature_len); - signed3 = base64_url_encode(signature, signature_len, signed3_len); + wpabuf_head(sig), wpabuf_len(sig)); + signed3 = base64_url_encode(wpabuf_head(sig), wpabuf_len(sig), signed3_len); + fail: - EVP_MD_CTX_destroy(md_ctx); - ECDSA_SIG_free(sig); - os_free(signature); + os_free(hash); + wpabuf_free(sig); return signed3; } diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index c87cbcbe8..889d0ef0e 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -1090,6 +1090,18 @@ const struct crypto_bignum *crypto_ec_key_get_private_key(struct crypto_ec_key * struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, size_t len); +/** + * crypto_ec_key_sign_r_s - Sign a buffer with an EC key + * @key: EC key from crypto_ec_key_parse_priv() or crypto_ec_key_gen() + * @data: Data to sign + * @len: Length of @data buffer + * Returns: Buffer with r and s value concatenated in a buffer. Each value + * is in big endian byte order padded to the length of the prime defined the + * group of the key. + */ +struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, const u8 *data, + size_t len); + /** * crypto_ec_key_verify_signature - Verify signature * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_gen() @@ -1102,6 +1114,21 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, size_t len, const u8 *sig, size_t sig_len); +/** + * crypto_ec_key_verify_signature_r_s - Verify signature + * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_gen() + * @data: Data to signed + * @len: Length of @data buffer + * @r: Binary data, in big endian byte order, of the 'r' field of the ECDSA signature. + * @s: Binary data, in big endian byte order, of the 's' field of the ECDSA signature. + * @r_len: Length of @r buffer + * @s_len: Length of @s buffer + * Returns: 1 if signature is valid, 0 if signature is invalid and -1 on failure + */ +int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key, const u8 *data, + size_t len, const u8 *r, size_t r_len, + const u8 *s, size_t s_len); + /** * crypto_ec_key_group - Get IANA group identifier for an EC key * @key: EC key from crypto_ec_key_parse/set_pub/priv() or crypto_ec_key_gen() diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index bca512f6c..12b025593 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -88,6 +88,24 @@ static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) return NULL; return pkey->pkey.ec; } + + +static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + sig->r = r; + sig->s = s; + return 1; +} + + +static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, + const BIGNUM **ps) +{ + if (pr) + *pr = sig->r; + if (ps) + *ps = sig->s; +} #endif /* CONFIG_ECC */ #endif /* OpenSSL version < 1.1.0 */ @@ -2599,6 +2617,61 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, } +struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, const u8 *data, + size_t len) +{ + const EC_GROUP *group = NULL; + const EC_KEY *eckey = NULL; + BIGNUM *prime = NULL; + ECDSA_SIG *sig = NULL; + const BIGNUM *r, *s; + u8 *r_buf, *s_buf; + struct wpabuf *buf; + const unsigned char *p; + int prime_len; + + buf = crypto_ec_key_sign(key, data, len); + if (!buf) + return NULL; + + // Extract (r,s) from Ecdsa-Sig-Value + eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *)key); + if (!eckey) + goto fail; + group = EC_KEY_get0_group(eckey); + prime = BN_new(); + if (!prime || !group || + !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL)) + goto fail; + prime_len = BN_num_bytes(prime); + + p = wpabuf_head(buf); + sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf)); + if (!sig) + goto fail; + ECDSA_SIG_get0(sig, &r, &s); + + // re-use wpabuf returned by crypto_ec_key_sign + buf->used = 0; + r_buf = wpabuf_put(buf, prime_len); + s_buf = wpabuf_put(buf, prime_len); + + if (!r_buf || !s_buf || + (crypto_bignum_to_bin((const struct crypto_bignum *)r, r_buf, prime_len, prime_len) < 0) || + (crypto_bignum_to_bin((const struct crypto_bignum *)s, s_buf, prime_len, prime_len) < 0)) + goto fail; + +out: + BN_free(prime); + ECDSA_SIG_free(sig); + return buf; +fail: + wpabuf_clear_free(buf); + buf = NULL; + goto out; +} + + int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, size_t len, const u8 *sig, size_t sig_len) { @@ -2620,6 +2693,39 @@ int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data, return -1; } +int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key, const u8 *data, + size_t len, const u8 *r, size_t r_len, + const u8 *s, size_t s_len) +{ + ECDSA_SIG *sig = NULL; + BIGNUM *r_bn = NULL, *s_bn = NULL; + unsigned char *der = NULL; + int der_len; + int ret = -1; + + r_bn = BN_bin2bn(r, r_len, NULL); + s_bn = BN_bin2bn(s, s_len, NULL); + sig = ECDSA_SIG_new(); + if (!r_bn || !s_bn || !sig || ECDSA_SIG_set0(sig, r_bn, s_bn) != 1) + goto fail; + r_bn = NULL; + s_bn = NULL; + + der_len = i2d_ECDSA_SIG(sig, &der); + if (der_len <= 0) { + wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature"); + goto fail; + } + + ret = crypto_ec_key_verify_signature(key, data, len, der, der_len); + +fail: + OPENSSL_free(der); + BN_free(r_bn); + BN_free(s_bn); + ECDSA_SIG_free(sig); + return ret; +} int crypto_ec_key_group(struct crypto_ec_key *key) { -- 2.17.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap