]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Update connector signing to use crypto.h
authorCedric Izoard <cedric.izoard@ceva-dsp.com>
Mon, 28 Jun 2021 16:25:31 +0000 (18:25 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 26 Oct 2021 21:08:36 +0000 (00:08 +0300)
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>
src/common/dpp_crypto.c
src/crypto/crypto.h
src/crypto/crypto_openssl.c

index d1bc850c6949f27aaca59063aa86653f17f5c4b2..cb75b78540ec5276a94019b4ac3c24edd9a4e0d9 100644 (file)
         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)
+       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));
+       if (res)
                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));
-               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;
        }
-
-       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));
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "DPP: Hash computation failed");
                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));
+       wpa_hexdump(MSG_DEBUG, "DPP: Hash value for Connector signature",
+                   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;
 }
 
index bd56fe8eaec404b4f52e9ef31eac342078cf2c8c..3e10601cba3121dca88f0bd0b7f9ceceb82f1450 100644 (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()
index 2da796d7186c5be8ad40a8a55bc4ea6e5ab0363e..dc2a8c06c4710bbb08d7a33a899d6f2ba864c446 100644 (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;