[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