DPP: Move CSR routines to use crypto.h
Add basic CSR API in crypto.h. Signed-off-by: Cedric Izoard <cedric.izoard@ceva-dsp.com>
This commit is contained in:
parent
d56352b551
commit
d51939f2c4
3 changed files with 324 additions and 110 deletions
|
@ -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,23 +2179,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)
|
||||
if (name && crypto_csr_set_name(csr, CSR_NAME_CN, name))
|
||||
goto fail;
|
||||
|
||||
if (X509_NAME_add_entry_by_txt(
|
||||
n, "CN", MBSTRING_UTF8,
|
||||
(const unsigned char *) name, -1, -1, 0) != 1)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
|
||||
if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
|
||||
"CSR challengePassword", cp, DPP_CP_LEN) < 0)
|
||||
|
@ -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)
|
||||
if (!password ||
|
||||
crypto_csr_set_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
|
||||
ASN1_TAG_UTF8STRING, (const u8 *) password,
|
||||
password_len))
|
||||
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)
|
||||
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) {
|
||||
csr = crypto_csr_verify(csrbuf);
|
||||
if (!csr) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: CSR does not have a valid signature");
|
||||
"DPP: CSR invalid or invalid signature");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
|
||||
if (loc < 0) {
|
||||
attr = crypto_csr_get_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
|
||||
&attr_len, &attr_type);
|
||||
if (!attr) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: CSR does not include challengePassword");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
attr = X509_REQ_get_attr(req, loc);
|
||||
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");
|
||||
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);
|
||||
attr_type);
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue