[PATCH 14/21] dpp: Update connector signing to use crypto.h

Cedric Izoard cedric.izoard at ceva-dsp.com
Mon Jun 28 09:25:31 PDT 2021


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 at ceva-dsp.com>
---
 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




More information about the Hostap mailing list