]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Move CSR routines to use crypto.h
authorCedric Izoard <cedric.izoard@ceva-dsp.com>
Mon, 28 Jun 2021 16:25:37 +0000 (18:25 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 27 Oct 2021 21:39:56 +0000 (00:39 +0300)
Add basic CSR API in crypto.h.

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 b90e4db4273f188ec71b37fa4f4e547c62009628..ceb621a0b0ed07c64ddd3dd10c459bc54737a984 100644 (file)
@@ -21,6 +21,7 @@
 #include "crypto/random.h"
 #include "crypto/sha384.h"
 #include "crypto/sha512.h"
+#include "tls/asn1.h"
 #include "dpp.h"
 #include "dpp_i.h"
 
@@ -2156,19 +2157,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 */
 
@@ -2182,22 +2179,12 @@ 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, name))
+               goto fail;
 
        /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
        if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
@@ -2208,134 +2195,75 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
                        cp, DPP_CP_LEN);
        password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
        forced_memzero(cp, DPP_CP_LEN);
-       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 (!password ||
+           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;
 }
 
 
-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;
+       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(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");
+                          "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");
@@ -2366,7 +2294,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;
 }
 
index 9c18971d8c5c17a8ec3cc7d90cfcfb1475472957..a59a812626721667687c64ab19dee7be0ca220cc 100644 (file)
@@ -1173,4 +1173,106 @@ int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2);
 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(void);
+
+/**
+ * crypto_csr_verify - Initialize CSR from CertificationRequest
+ * @req: DER encoding of ASN.1 CertificationRequest
+ *
+ * Returns: Pointer to CSR data or %NULL on failure or if signature is invalid
+ */
+struct crypto_csr * crypto_csr_verify(const struct wpabuf *req);
+
+/**
+ * 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 entry in CSR SubjectName
+ * @csr: CSR structure from @crypto_csr_init()
+ * @type: Name type  to add into the CSR SubjectName
+ * @name: UTF-8 string to write in the CSR SubjectName
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+                       const char *name);
+
+/**
+ * crypto_csr_set_attribute - Set attribute in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @attr: Attribute 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 attribute 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 */
index 73e5c635deef260fd63c425474abd4929abab234..96ce493e324d90d808939453bbbb8cdcfb77c75a 100644 (file)
@@ -111,6 +111,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)
@@ -2896,4 +2900,184 @@ fail:
        return pem;
 }
 
+
+struct crypto_csr * crypto_csr_init()
+{
+       return (struct crypto_csr *)X509_REQ_new();
+}
+
+
+struct crypto_csr * crypto_csr_verify(const struct wpabuf *req)
+{
+       X509_REQ *csr;
+       EVP_PKEY *pkey = NULL;
+       const u8 *der = wpabuf_head(req);
+
+       csr = d2i_X509_REQ(NULL, &der, wpabuf_len(req));
+       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 char *name)
+{
+       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,
+                                       (const unsigned char *) name,
+                                       os_strlen(name), -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);
+       if (!attrib_type)
+               return NULL;
+       *type = ASN1_TYPE_get(attrib_type);
+       data = X509_ATTRIBUTE_get0_data(attrib, 0, *type, NULL);
+       if (!data)
+               return 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;
+       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 */