DPP: Update connector signing to use crypto.h

Add two new functions in crypto.h that "wrap" 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@ceva-dsp.com>
This commit is contained in:
Cedric Izoard 2021-06-28 18:25:31 +02:00 committed by Jouni Malinen
parent da63d30997
commit eac41656ee
3 changed files with 216 additions and 144 deletions

View file

@ -31,24 +31,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)
@ -837,7 +819,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;
@ -883,17 +865,16 @@ dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
goto fail;
}
if (os_strcmp(token->string, "ES256") == 0 ||
os_strcmp(token->string, "BS256") == 0)
*ret_md = EVP_sha256();
else if (os_strcmp(token->string, "ES384") == 0 ||
os_strcmp(token->string, "BS384") == 0)
*ret_md = EVP_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) {
os_strcmp(token->string, "BS256") == 0) {
*hash_func = CRYPTO_HASH_ALG_SHA256;
} else if (os_strcmp(token->string, "ES384") == 0 ||
os_strcmp(token->string, "BS384") == 0) {
*hash_func = CRYPTO_HASH_ALG_SHA384;
} else if (os_strcmp(token->string, "ES512") == 0 ||
os_strcmp(token->string, "BS512") == 0) {
*hash_func = CRYPTO_HASH_ALG_SHA512;
} else {
*hash_func = -1;
wpa_printf(MSG_DEBUG,
"DPP: Unsupported JWS Protected Header alg=%s",
token->string);
@ -956,27 +937,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);
@ -999,7 +965,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;
@ -1055,58 +1021,45 @@ 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)
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)
hash = os_malloc(curve->hash_len);
if (!hash)
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));
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;
}
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;
}
@ -2161,79 +2114,56 @@ 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;
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;
}
if (ret) {
wpa_printf(MSG_DEBUG, "DPP: Hash computation failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Hash value for Connector signature",
hash, curve->hash_len);
md_ctx = EVP_MD_CTX_create();
if (!md_ctx)
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;
}
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));
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));
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;
}

View file

@ -1084,6 +1084,18 @@ crypto_ec_key_get_private_key(struct crypto_ec_key *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 the concatenated r and s values. Each value is in big
* endian byte order padded to the length of the prime defining 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 ECDSA signature
* @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_gen()
@ -1096,6 +1108,24 @@ 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, or -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()

View file

@ -82,12 +82,32 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
#ifdef CONFIG_ECC
static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
{
if (pkey->type != EVP_PKEY_EC)
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 */
@ -2556,6 +2576,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;
const EC_KEY *eckey;
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 (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)
{
@ -2578,6 +2653,43 @@ int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
}
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;
BIGNUM *r_bn, *s_bn;
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,
"OpenSSL: 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)
{
const EC_KEY *eckey;