diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 52fadad17..a98748cdc 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -370,6 +370,15 @@ int mbedtls_x509_write_names(unsigned char **p, unsigned char *start, int mbedtls_x509_write_sig(unsigned char **p, unsigned char *start, const char *oid, size_t oid_len, unsigned char *sig, size_t size); +int x509_get_ns_cert_type(unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type); +int x509_get_key_usage(unsigned char **p, + const unsigned char *end, + unsigned int *key_usage); +int x509_get_subject_alt_name(unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name); #define MBEDTLS_X509_SAFE_SNPRINTF \ do { \ diff --git a/include/mbedtls/x509_csr.h b/include/mbedtls/x509_csr.h index 50998c42b..216a0a2e9 100644 --- a/include/mbedtls/x509_csr.h +++ b/include/mbedtls/x509_csr.h @@ -58,6 +58,10 @@ typedef struct mbedtls_x509_csr { mbedtls_pk_context pk; /**< Container for the public key context. */ + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of raw entries of Subject Alternative Names extension (currently only dNSName and OtherName are listed). */ + mbedtls_x509_buf sig_oid; mbedtls_x509_buf MBEDTLS_PRIVATE(sig); mbedtls_md_type_t MBEDTLS_PRIVATE(sig_md); /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 033009797..e02d18e05 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -562,9 +562,9 @@ static int x509_get_basic_constraints(unsigned char **p, return 0; } -static int x509_get_ns_cert_type(unsigned char **p, - const unsigned char *end, - unsigned char *ns_cert_type) +int x509_get_ns_cert_type(unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_x509_bitstring bs = { 0, 0, NULL }; @@ -583,9 +583,9 @@ static int x509_get_ns_cert_type(unsigned char **p, return 0; } -static int x509_get_key_usage(unsigned char **p, - const unsigned char *end, - unsigned int *key_usage) +int x509_get_key_usage(unsigned char **p, + const unsigned char *end, + unsigned int *key_usage) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t i; @@ -660,9 +660,9 @@ static int x509_get_ext_key_usage(unsigned char **p, * NOTE: we list all types, but only use dNSName and otherName * of type HwModuleName, as defined in RFC 4108, at this point. */ -static int x509_get_subject_alt_name(unsigned char **p, - const unsigned char *end, - mbedtls_x509_sequence *subject_alt_name) +int x509_get_subject_alt_name(unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t len, tag_len; diff --git a/library/x509_csr.c b/library/x509_csr.c index 0c664d908..824d17a75 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -69,6 +69,153 @@ static int x509_csr_get_version(unsigned char **p, return 0; } +/* + * Parse CSR extension requests in DER format + */ +static int x509_csr_parse_extensions(mbedtls_x509_csr *csr, + unsigned char **p, const unsigned char *end) +{ + int ret; + size_t len; + unsigned char *end_ext_data; + + while (*p < end) { + mbedtls_x509_buf extn_oid = { 0, 0, NULL }; + int ext_type = 0; + + /* Read sequence tag */ + if ((ret = mbedtls_asn1_get_tag(p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + end_ext_data = *p + len; + + /* Get extension ID */ + if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len, + MBEDTLS_ASN1_OID)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + extn_oid.tag = MBEDTLS_ASN1_OID; + extn_oid.p = *p; + *p += extn_oid.len; + + /* Data should be octet string type */ + if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + if (*p + len != end_ext_data) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + + if (mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type) == 0) { + switch (ext_type) { + case MBEDTLS_X509_EXT_KEY_USAGE: + /* Parse key usage */ + if ((ret = x509_get_key_usage(p, end_ext_data, + &csr->key_usage)) != 0) { + return ret; + } + break; + + case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: + /* Parse subject alt name */ + if ((ret = x509_get_subject_alt_name(p, end_ext_data, + &csr->subject_alt_names)) != 0) { + return ret; + } + break; + + case MBEDTLS_X509_EXT_NS_CERT_TYPE: + /* Parse netscape certificate type */ + if ((ret = x509_get_ns_cert_type(p, end_ext_data, + &csr->ns_cert_type)) != 0) { + return ret; + } + break; + default: + break; + } + } + + *p = end_ext_data; + } + + if (*p != end) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + + return 0; +} + +/* + * Parse CSR attributes in DER format + */ +static int x509_csr_parse_attributes(mbedtls_x509_csr *csr, + const unsigned char *start, const unsigned char *end) +{ + int ret; + size_t len; + unsigned char *end_attr_data; + unsigned char **p = (unsigned char **) &start; + + while (*p < end) { + mbedtls_x509_buf attr_oid = { 0, 0, NULL }; + + if ((ret = mbedtls_asn1_get_tag(p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + end_attr_data = *p + len; + + /* Get attribute ID */ + if ((ret = mbedtls_asn1_get_tag(p, end_attr_data, &attr_oid.len, + MBEDTLS_ASN1_OID)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + attr_oid.tag = MBEDTLS_ASN1_OID; + attr_oid.p = *p; + *p += attr_oid.len; + + /* Check that this is an extension-request attribute */ + if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_CSR_EXT_REQ, &attr_oid) == 0) { + if ((ret = mbedtls_asn1_get_tag(p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + if ((ret = mbedtls_asn1_get_tag(p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != + 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + if ((ret = x509_csr_parse_extensions(csr, p, *p + len)) != 0) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret; + } + + if (*p != end_attr_data) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + } + + *p = end_attr_data; + } + + if (*p != end) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + } + + return 0; +} + /* * Parse a CSR in DER format */ @@ -197,6 +344,11 @@ int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr, return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); } + if ((ret = x509_csr_parse_attributes(csr, p, p + len)) != 0) { + mbedtls_x509_csr_free(csr); + return ret; + } + p += len; end = csr->raw.p + csr->raw.len;