[PATCH 20/21] dpp: csr rewrote to use crypto.h

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


Add basic CSR API in crypto.h.

Signed-off-by: Cedric Izoard <cedric.izoard at ceva-dsp.com>
---
Probably not the best place to add this.

---
 src/common/dpp_crypto.c     | 143 +++++++---------------------
 src/crypto/crypto.h         | 101 ++++++++++++++++++++
 src/crypto/crypto_openssl.c | 180 ++++++++++++++++++++++++++++++++++++
 3 files changed, 316 insertions(+), 108 deletions(-)

diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 4b387f6b0..5092e98e3 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -19,6 +19,7 @@
 #include "crypto/random.h"
 #include "crypto/sha384.h"
 #include "crypto/sha512.h"
+#include "tls/asn1.h"
 #include "dpp.h"
 #include "dpp_i.h"

@@ -2030,19 +2031,15 @@ void dpp_pfs_free(struct dpp_pfs *pfs)

 struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
 {
-	X509_REQ *req = NULL;
+	struct crypto_csr *csr = NULL;
 	struct wpabuf *buf = NULL;
-	unsigned char *der;
-	int der_len;
 	struct crypto_ec_key *key;
-	const EVP_MD *sign_md;
 	unsigned int hash_len = auth->curve->hash_len;
 	struct wpabuf * priv_key;
-	BIO *out = NULL;
 	u8 cp[DPP_CP_LEN];
-	char *password;
+	char *password = NULL;
 	size_t password_len;
-	int res;
+	int hash_sign_algo;

 	/* TODO: use auth->csrattrs */

@@ -2056,22 +2053,13 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
 	wpabuf_free(auth->priv_key);
 	auth->priv_key = priv_key;

-	req = X509_REQ_new();
-	if (!req || !X509_REQ_set_pubkey(req, (EVP_PKEY *)key))
+	csr = crypto_csr_init();
+	if (!csr || crypto_csr_set_ec_public_key(csr, key))
 		goto fail;

-	if (name) {
-		X509_NAME *n;
-
-		n = X509_REQ_get_subject_name(req);
-		if (!n)
-			goto fail;
-
-		if (X509_NAME_add_entry_by_txt(
-			    n, "CN", MBSTRING_UTF8,
-			    (const unsigned char *) name, -1, -1, 0) != 1)
-			goto fail;
-	}
+	if (name && crypto_csr_set_name(csr, CSR_NAME_CN, (const u8 *)name,
+					os_strlen(name)))
+		goto fail;

 	/* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
 	if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
@@ -2085,43 +2073,31 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
 	if (!password)
 		goto fail;

-	res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
-					V_ASN1_UTF8STRING,
-					(const unsigned char *) password,
-					password_len);
-	bin_clear_free(password, password_len);
-	if (!res)
+	if (crypto_csr_set_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
+				     ASN1_TAG_UTF8STRING, (const u8*) password,
+				     password_len))
 		goto fail;

-	/* TODO */
-
 	/* TODO: hash func selection based on csrAttrs */
 	if (hash_len == SHA256_MAC_LEN) {
-		sign_md = EVP_sha256();
+		hash_sign_algo = CRYPTO_HASH_ALG_SHA256;
 	} else if (hash_len == SHA384_MAC_LEN) {
-		sign_md = EVP_sha384();
+		hash_sign_algo = CRYPTO_HASH_ALG_SHA384;
 	} else if (hash_len == SHA512_MAC_LEN) {
-		sign_md = EVP_sha512();
+		hash_sign_algo = CRYPTO_HASH_ALG_SHA512;
 	} else {
 		wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
 		goto fail;
 	}

-	if (!X509_REQ_sign(req, (EVP_PKEY *)key, sign_md))
+	buf = crypto_csr_sign(csr, key, hash_sign_algo);
+	if (!buf)
 		goto fail;
-
-	der = NULL;
-	der_len = i2d_X509_REQ(req, &der);
-	if (der_len < 0)
-		goto fail;
-	buf = wpabuf_alloc_copy(der, der_len);
-	OPENSSL_free(der);
-
 	wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);

 fail:
-	BIO_free_all(out);
-	X509_REQ_free(req);
+	bin_clear_free(password, password_len);
+	crypto_csr_deinit(csr);
 	return buf;
 }

@@ -2214,90 +2190,41 @@ fail:
 }


-int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csrbuf)
 {
-	X509_REQ *req;
-	const unsigned char *pos;
-	EVP_PKEY *pkey;
-	int res, loc, ret = -1;
-	X509_ATTRIBUTE *attr;
-	ASN1_TYPE *type;
-	ASN1_STRING *str;
-	unsigned char *utf8 = NULL;
+	struct crypto_csr *csr = NULL;
+	const u8 *attr;
+	size_t attr_len;
+	int attr_type;
 	unsigned char *cp = NULL;
 	size_t cp_len;
 	u8 exp_cp[DPP_CP_LEN];
 	unsigned int hash_len = auth->curve->hash_len;
+	int ret = -1;

-	pos = wpabuf_head(csr);
-	req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
-	if (!req) {
-		wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
-		return -1;
-	}
-
-	pkey = X509_REQ_get_pubkey(req);
-	if (!pkey) {
-		wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
-		goto fail;
-	}
-
-	res = X509_REQ_verify(req, pkey);
-	EVP_PKEY_free(pkey);
-	if (res != 1) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: CSR does not have a valid signature");
-		goto fail;
-	}
-
-	loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
-	if (loc < 0) {
+	csr = crypto_csr_verify(wpabuf_head(csrbuf), wpabuf_len(csrbuf));
+	if (!csr) {
 		wpa_printf(MSG_DEBUG,
-			   "DPP: CSR does not include challengePassword");
+			   "DPP: CSR invalid or invalid signature");
 		goto fail;
 	}

-	attr = X509_REQ_get_attr(req, loc);
+	attr = crypto_csr_get_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD, &attr_len, &attr_type);
 	if (!attr) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Could not get challengePassword attribute");
-		goto fail;
-	}
-
-	type = X509_ATTRIBUTE_get0_type(attr, 0);
-	if (!type) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Could not get challengePassword attribute type");
+		wpa_printf(MSG_DEBUG, "DPP: CSR does not include challengePassword");
 		goto fail;
 	}
-
-	res = ASN1_TYPE_get(type);
 	/* This is supposed to be UTF8String, but allow other strings as well
 	 * since challengePassword is using ASCII (base64 encoded). */
-	if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
-	    res != V_ASN1_IA5STRING) {
+	if (attr_type != ASN1_TAG_UTF8STRING && attr_type != ASN1_TAG_PRINTABLESTRING &&
+	    attr_type != ASN1_TAG_IA5STRING) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Unexpected challengePassword attribute type %d",
-			   res);
-		goto fail;
-	}
-
-	str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
-	if (!str) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Could not get ASN.1 string for challengePassword");
-		goto fail;
-	}
-
-	res = ASN1_STRING_to_UTF8(&utf8, str);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG,
-			   "DPP: Could not get UTF8 version of challengePassword");
+			   attr_type);
 		goto fail;
 	}

-	cp = base64_decode((const char *) utf8, res, &cp_len);
-	OPENSSL_free(utf8);
+	cp = base64_decode((const char *)attr, attr_len, &cp_len);
 	if (!cp) {
 		wpa_printf(MSG_DEBUG,
 			   "DPP: Could not base64 decode challengePassword");
@@ -2328,7 +2255,7 @@ int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
 	ret = 0;
 fail:
 	os_free(cp);
-	X509_REQ_free(req);
+	crypto_csr_deinit(csr);
 	return ret;
 }

diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 78e7045ca..b5c5f0c36 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1169,4 +1169,105 @@ void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
 			       const char *title);


+/**
+ * struct crypto_csr - Certification Signing Request
+ *
+ * Internal data structure for CSR. The contents is specific to the used
+ * crypto library.
+ * For now it is assumed that only an EC public key can be used
+ */
+struct crypto_csr;
+
+/**
+ * enum crypto_csr_name - CSR name type
+ */
+enum crypto_csr_name {
+	CSR_NAME_CN,
+	CSR_NAME_SN,
+	CSR_NAME_C,
+	CSR_NAME_O,
+	CSR_NAME_OU,
+};
+
+/**
+ * enum crypto_csr_attr - CSR attribute
+ */
+enum crypto_csr_attr {
+	CSR_ATTR_CHALLENGE_PASSWORD,
+};
+
+/**
+ * crypto_csr_init - Initialize empty CSR
+ * Returns: Pointer to CSR data or %NULL on failure
+ */
+struct crypto_csr * crypto_csr_init();
+
+/**
+ * crypto_csr_verify - Initialize CSR from CertificationRequest
+ * @req: DER encoding of ASN.1 CertificationRequest
+ * @len: Length of @req buffer
+ *
+ * Returns: Pointer to CSR data or %NULL on failure or if signature is invalid
+ */
+struct crypto_csr * crypto_csr_verify(const u8 *req, size_t len);
+
+/**
+ * crypto_csr_deinit - Free CSR structure
+ * @csr: CSR structure from @crypto_csr_init() or crypto_csr_verify()
+ */
+void crypto_csr_deinit(struct crypto_csr *csr);
+
+/**
+ * crypto_csr_set_ec_public_key - Set public Key in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @key: EC Public key to set as Public key in the CSR
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_ec_public_key(struct crypto_csr *csr, struct crypto_ec_key *key);
+
+/**
+ * crypto_csr_set_name - Set name in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @type: Name to add in the EC Public key to set as Public key in the CSR
+ * @name: UTF8 string to write in the CSR
+ * @len: length of @name buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+			const u8 *name, size_t len);
+
+/**
+ * crypto_csr_set_attribute - Set attribute in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @attr: Atribute identifier
+ * @attr_type: ASN.1 type of @value buffer
+ * @value: Attribute value
+ * @len: length of @value buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
+			     int attr_type, const u8 *value, size_t len);
+
+/**
+ * crypto_csr_get_attribute - Get attribute from CSR
+ * @csr: CSR structure from @crypto_csr_verify()
+ * @attr: Updated with atribute identifier
+ * @len: Updated with length of returned buffer
+ * @type: ASN.1 type of the attribute buffer
+ * Returns: Type, length and Pointer on atrtibute value or %NULL on failure
+ */
+const u8 *crypto_csr_get_attribute(struct crypto_csr *csr,
+				   enum crypto_csr_attr attr,
+				   size_t *len, int *type);
+
+/**
+ * crypto_csr_sign - Sign CSR and return ASN.1 CertificationRequest
+ * @csr: CSR structure from @crypto_csr_init()
+ * @key: Private key to sign the CSR (for now ony EC key are supported)
+ * @algo: Hash algorithm to use for the signature
+ * Returns: DER encoding of ASN.1 CertificationRequest for the CSR or %NULL on failure
+ */
+struct wpabuf *crypto_csr_sign(struct crypto_csr *csr, struct crypto_ec_key *key,
+			       enum crypto_hash_alg algo);
+
 #endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 26705ff50..abcfeef38 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -108,6 +108,10 @@ static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
 }
 #endif /* CONFIG_ECC */

+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+	return ASN1_STRING_data((ASN1_STRING *) x);
+}
 #endif /* OpenSSL version < 1.1.0 */

 static BIGNUM * get_group5_prime(void)
@@ -2829,4 +2833,180 @@ void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
 	BIO_free(out);
 }

+
+struct crypto_csr * crypto_csr_init()
+{
+	return (struct crypto_csr *)X509_REQ_new();
+}
+
+
+struct crypto_csr * crypto_csr_verify(const u8 *req, size_t len)
+{
+	X509_REQ *csr;
+	EVP_PKEY *pkey = NULL;
+	const u8 *der = req;
+
+	csr = d2i_X509_REQ(NULL, &der, len);
+	if (!csr)
+		return NULL;
+
+	pkey = X509_REQ_get_pubkey((X509_REQ *)csr);
+	if (!pkey)
+		goto fail;
+
+	if (X509_REQ_verify((X509_REQ *)csr, pkey) != 1)
+		goto fail;
+
+	return (struct crypto_csr *)csr;
+fail:
+	X509_REQ_free(csr);
+	return NULL;
+}
+
+
+void crypto_csr_deinit(struct crypto_csr *csr)
+{
+	X509_REQ_free((X509_REQ *)csr);
+}
+
+
+int crypto_csr_set_ec_public_key(struct crypto_csr *csr, struct crypto_ec_key *key)
+{
+	if (!X509_REQ_set_pubkey((X509_REQ *)csr, (EVP_PKEY *)key))
+		return -1;
+
+	return 0;
+}
+
+
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+			const u8 *name, size_t len)
+{
+	X509_NAME *n;
+	int nid;
+
+	switch (type) {
+	case CSR_NAME_CN:
+		nid = NID_commonName;
+		break;
+	case CSR_NAME_SN:
+		nid = NID_surname;
+		break;
+	case CSR_NAME_C:
+		nid = NID_countryName;
+		break;
+	case CSR_NAME_O:
+		nid = NID_organizationName;
+		break;
+	case CSR_NAME_OU:
+		nid = NID_organizationalUnitName;
+		break;
+	default:
+		return -1;
+	}
+
+	n = X509_REQ_get_subject_name((X509_REQ *)csr);
+	if (!n)
+		return -1;
+
+	if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_UTF8,
+					name, len, -1, 0))
+		return -1;
+
+	return 0;
+}
+
+
+int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
+			     int attr_type, const u8 *value, size_t len)
+{
+	int nid;
+
+	switch(attr) {
+	case CSR_ATTR_CHALLENGE_PASSWORD:
+		nid = NID_pkcs9_challengePassword;
+		break;
+	default:
+		return -1;
+	}
+
+	if (!X509_REQ_add1_attr_by_NID((X509_REQ *)csr, nid, attr_type, value, len))
+		return -1;
+
+	return 0;
+}
+
+
+const u8 *crypto_csr_get_attribute(struct crypto_csr *csr,
+				   enum crypto_csr_attr attr,
+				   size_t *len, int *type)
+{
+	X509_ATTRIBUTE *attrib;
+	ASN1_TYPE *attrib_type;
+	ASN1_STRING *data;
+	int loc;
+	int nid;
+
+	switch(attr) {
+	case CSR_ATTR_CHALLENGE_PASSWORD:
+		nid = NID_pkcs9_challengePassword;
+		break;
+	default:
+		return NULL;
+	}
+
+	loc = X509_REQ_get_attr_by_NID((X509_REQ *)csr, nid, -1);
+	if (loc < 0) {
+		return NULL;
+	}
+
+	attrib = X509_REQ_get_attr((X509_REQ *)csr, loc);
+	if (!attrib) {
+		return NULL;
+	}
+
+
+	attrib_type = X509_ATTRIBUTE_get0_type(attrib, 0);
+	*type = ASN1_TYPE_get(attrib_type);
+	data = X509_ATTRIBUTE_get0_data(attrib, 0, *type, NULL);
+	*len = ASN1_STRING_length(data);
+	return ASN1_STRING_get0_data(data);
+}
+
+
+struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, struct crypto_ec_key *key,
+				enum crypto_hash_alg algo)
+{
+	const EVP_MD *sign_md;
+	struct wpabuf *buf = NULL;
+	unsigned char *der = NULL;
+	int der_len;
+
+	switch(algo) {
+	case CRYPTO_HASH_ALG_SHA256:
+		sign_md = EVP_sha256();
+		break;
+	case CRYPTO_HASH_ALG_SHA384:
+		sign_md = EVP_sha384();
+		break;
+	case CRYPTO_HASH_ALG_SHA512:
+		sign_md = EVP_sha512();
+		break;
+	default:
+		return NULL;
+	}
+
+	if (!X509_REQ_sign((X509_REQ *)csr, (EVP_PKEY *)key, sign_md))
+		return NULL;
+
+	der_len = i2d_X509_REQ((X509_REQ *)csr, &der);
+	if (der_len < 0)
+		return NULL;
+
+	buf = wpabuf_alloc_copy(der, der_len);
+	OPENSSL_free(der);
+
+	return buf;
+}
+
 #endif /* CONFIG_ECC */
--
2.17.0




More information about the Hostap mailing list