diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index abd36b8eec..aa1cd084ee 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -250,6 +250,56 @@ typedef struct mbedtls_x509_time { } mbedtls_x509_time; +/** + * From RFC 5280 section 4.2.1.6: + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * Future versions of the library may add new fields to this structure or + * to its embedded union and structure. + */ +typedef struct mbedtls_x509_san_other_name { + /** + * The type_id is an OID as defined in RFC 5280. + * To check the value of the type id, you should use + * \p MBEDTLS_OID_CMP with a known OID mbedtls_x509_buf. + */ + mbedtls_x509_buf type_id; /**< The type id. */ + union { + /** + * From RFC 4108 section 5: + * HardwareModuleName ::= SEQUENCE { + * hwType OBJECT IDENTIFIER, + * hwSerialNum OCTET STRING } + */ + struct { + mbedtls_x509_buf oid; /**< The object identifier. */ + mbedtls_x509_buf val; /**< The named value. */ + } + hardware_module_name; + } + value; +} +mbedtls_x509_san_other_name; + +/** + * A structure for holding the parsed Subject Alternative Name, + * according to type. + * + * Future versions of the library may add new fields to this structure or + * to its embedded union and structure. + */ +typedef struct mbedtls_x509_subject_alternative_name { + int type; /**< The SAN type, value of MBEDTLS_X509_SAN_XXX. */ + union { + mbedtls_x509_san_other_name other_name; /**< The otherName supported type. */ + mbedtls_x509_buf unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */ + } + san; /**< A union of the supported SAN types */ +} +mbedtls_x509_subject_alternative_name; + /** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ /** @@ -326,6 +376,36 @@ int mbedtls_x509_time_is_past(const mbedtls_x509_time *to); */ int mbedtls_x509_time_is_future(const mbedtls_x509_time *from); +/** + * \brief This function parses an item in the SubjectAlternativeNames + * extension. + * + * \param san_buf The buffer holding the raw data item of the subject + * alternative name. + * \param san The target structure to populate with the parsed presentation + * of the subject alternative name encoded in \p san_raw. + * + * \note Only "dnsName" and "otherName" of type hardware_module_name + * as defined in RFC 4180 is supported. + * + * \note This function should be called on a single raw data of + * subject alternative name. For example, after successful + * certificate parsing, one must iterate on every item in the + * \p crt->subject_alt_names sequence, and pass it to + * this function. + * + * \warning The target structure contains pointers to the raw data of the + * parsed certificate, and its lifetime is restricted by the + * lifetime of the certificate. + * + * \return \c 0 on success + * \return #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported + * SAN type. + * \return Another negative value for any other failure. + */ +int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san); + /** \} addtogroup x509_module */ /* diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 661f8aa7b8..2060835022 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -102,56 +102,6 @@ typedef struct mbedtls_x509_crt { } mbedtls_x509_crt; -/** - * From RFC 5280 section 4.2.1.6: - * OtherName ::= SEQUENCE { - * type-id OBJECT IDENTIFIER, - * value [0] EXPLICIT ANY DEFINED BY type-id } - * - * Future versions of the library may add new fields to this structure or - * to its embedded union and structure. - */ -typedef struct mbedtls_x509_san_other_name { - /** - * The type_id is an OID as defined in RFC 5280. - * To check the value of the type id, you should use - * \p MBEDTLS_OID_CMP with a known OID mbedtls_x509_buf. - */ - mbedtls_x509_buf type_id; /**< The type id. */ - union { - /** - * From RFC 4108 section 5: - * HardwareModuleName ::= SEQUENCE { - * hwType OBJECT IDENTIFIER, - * hwSerialNum OCTET STRING } - */ - struct { - mbedtls_x509_buf oid; /**< The object identifier. */ - mbedtls_x509_buf val; /**< The named value. */ - } - hardware_module_name; - } - value; -} -mbedtls_x509_san_other_name; - -/** - * A structure for holding the parsed Subject Alternative Name, - * according to type. - * - * Future versions of the library may add new fields to this structure or - * to its embedded union and structure. - */ -typedef struct mbedtls_x509_subject_alternative_name { - int type; /**< The SAN type, value of MBEDTLS_X509_SAN_XXX. */ - union { - mbedtls_x509_san_other_name other_name; /**< The otherName supported type. */ - mbedtls_x509_buf unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */ - } - san; /**< A union of the supported SAN types */ -} -mbedtls_x509_subject_alternative_name; - /** * Build flag from an algorithm/curve identifier (pk, md, ecp) * Since 0 is always XXX_NONE, ignore it. @@ -589,36 +539,6 @@ int mbedtls_x509_crt_parse_file(mbedtls_x509_crt *chain, const char *path); int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *chain, const char *path); #endif /* MBEDTLS_FS_IO */ -/** - * \brief This function parses an item in the SubjectAlternativeNames - * extension. - * - * \param san_buf The buffer holding the raw data item of the subject - * alternative name. - * \param san The target structure to populate with the parsed presentation - * of the subject alternative name encoded in \p san_raw. - * - * \note Only "dnsName" and "otherName" of type hardware_module_name - * as defined in RFC 4180 is supported. - * - * \note This function should be called on a single raw data of - * subject alternative name. For example, after successful - * certificate parsing, one must iterate on every item in the - * \p crt->subject_alt_names sequence, and pass it to - * this function. - * - * \warning The target structure contains pointers to the raw data of the - * parsed certificate, and its lifetime is restricted by the - * lifetime of the certificate. - * - * \return \c 0 on success - * \return #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported - * SAN type. - * \return Another negative value for any other failure. - */ -int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf, - mbedtls_x509_subject_alternative_name *san); - #if !defined(MBEDTLS_X509_REMOVE_INFO) /** * \brief Returns an informational string about the diff --git a/library/x509.c b/library/x509.c index 1b3701cda8..9869b05e5e 100644 --- a/library/x509.c +++ b/library/x509.c @@ -1107,4 +1107,490 @@ int mbedtls_x509_time_is_future(const mbedtls_x509_time *from) return 0; } #endif /* MBEDTLS_HAVE_TIME_DATE */ + +/* Common functions for parsing CRT and CSR. */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) || defined(MBEDTLS_X509_CSR_PARSE_C) +/* + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * HardwareModuleName ::= SEQUENCE { + * hwType OBJECT IDENTIFIER, + * hwSerialNum OCTET STRING } + * + * NOTE: we currently only parse and use otherName of type HwModuleName, + * as defined in RFC 4108. + */ +static int x509_get_other_name(const mbedtls_x509_buf *subject_alt_name, + mbedtls_x509_san_other_name *other_name) +{ + int ret = 0; + size_t len; + unsigned char *p = subject_alt_name->p; + const unsigned char *end = p + subject_alt_name->len; + mbedtls_x509_buf cur_oid; + + if ((subject_alt_name->tag & + (MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK)) != + (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME)) { + /* + * The given subject alternative name is not of type "othername". + */ + return MBEDTLS_ERR_X509_BAD_INPUT_DATA; + } + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_OID)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + cur_oid.tag = MBEDTLS_ASN1_OID; + cur_oid.p = p; + cur_oid.len = len; + + /* + * Only HwModuleName is currently supported. + */ + if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid) != 0) { + return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; + } + + if (p + len >= end) { + mbedtls_platform_zeroize(other_name, sizeof(*other_name)); + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + p += len; + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != + 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID; + other_name->value.hardware_module_name.oid.p = p; + other_name->value.hardware_module_name.oid.len = len; + + if (p + len >= end) { + mbedtls_platform_zeroize(other_name, sizeof(*other_name)); + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + p += len; + if ((ret = mbedtls_asn1_get_tag(&p, end, &len, + MBEDTLS_ASN1_OCTET_STRING)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING; + other_name->value.hardware_module_name.val.p = p; + other_name->value.hardware_module_name.val.len = len; + p += len; + if (p != end) { + mbedtls_platform_zeroize(other_name, + sizeof(*other_name)); + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + return 0; +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: we list all types, but only use dNSName and otherName + * of type HwModuleName, as defined in RFC 4108, at this point. + */ +int mbedtls_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; + mbedtls_asn1_buf *buf; + unsigned char tag; + mbedtls_asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if ((ret = mbedtls_asn1_get_tag(p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if (*p + len != end) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + + while (*p < end) { + mbedtls_x509_subject_alternative_name dummy_san_buf; + memset(&dummy_san_buf, 0, sizeof(dummy_san_buf)); + + tag = **p; + (*p)++; + if ((ret = mbedtls_asn1_get_len(p, end, &tag_len)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if ((tag & MBEDTLS_ASN1_TAG_CLASS_MASK) != + MBEDTLS_ASN1_CONTEXT_SPECIFIC) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); + } + + /* + * Check that the SAN is structured correctly. + */ + ret = mbedtls_x509_parse_subject_alt_name(&(cur->buf), &dummy_san_buf); + /* + * In case the extension is malformed, return an error, + * and clear the allocated sequences. + */ + if (ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { + mbedtls_asn1_sequence_free(subject_alt_name->next); + subject_alt_name->next = NULL; + return ret; + } + + /* Allocate and assign next pointer */ + if (cur->buf.p != NULL) { + if (cur->next != NULL) { + return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; + } + + cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence)); + + if (cur->next == NULL) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_ALLOC_FAILED); + } + + cur = cur->next; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if (*p != end) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + + return 0; +} + +int mbedtls_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 }; + + if ((ret = mbedtls_asn1_get_bitstring(p, end, &bs)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if (bs.len == 0) { + *ns_cert_type = 0; + return 0; + } + + if (bs.len != 1) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_INVALID_LENGTH); + } + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return 0; +} + +int mbedtls_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; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if ((ret = mbedtls_asn1_get_bitstring(p, end, &bs)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } + + if (bs.len == 0) { + *key_usage = 0; + return 0; + } + + if (bs.len < 1) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, + MBEDTLS_ERR_ASN1_INVALID_LENGTH); + } + + /* Get actual bitstring */ + *key_usage = 0; + for (i = 0; i < bs.len && i < sizeof(unsigned int); i++) { + *key_usage |= (unsigned int) bs.p[i] << (8*i); + } + + return 0; +} + +int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + switch (san_buf->tag & + (MBEDTLS_ASN1_TAG_CLASS_MASK | + MBEDTLS_ASN1_TAG_VALUE_MASK)) { + /* + * otherName + */ + case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME): + { + mbedtls_x509_san_other_name other_name; + + ret = x509_get_other_name(san_buf, &other_name); + if (ret != 0) { + return ret; + } + + memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name)); + san->type = MBEDTLS_X509_SAN_OTHER_NAME; + memcpy(&san->san.other_name, + &other_name, sizeof(other_name)); + + } + break; + + /* + * dNSName + */ + case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME): + { + memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name)); + san->type = MBEDTLS_X509_SAN_DNS_NAME; + + memcpy(&san->san.unstructured_name, + san_buf, sizeof(*san_buf)); + + } + break; + + /* + * Type not supported + */ + default: + return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; + } + return 0; +} + +#if !defined(MBEDTLS_X509_REMOVE_INFO) +int mbedtls_x509_info_subject_alt_name(char **buf, size_t *size, + const mbedtls_x509_sequence + *subject_alt_name, + const char *prefix) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + mbedtls_x509_subject_alternative_name san; + int parse_ret; + + while (cur != NULL) { + memset(&san, 0, sizeof(san)); + parse_ret = mbedtls_x509_parse_subject_alt_name(&cur->buf, &san); + if (parse_ret != 0) { + if (parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { + ret = mbedtls_snprintf(p, n, "\n%s ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + } else { + ret = mbedtls_snprintf(p, n, "\n%s ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + } + cur = cur->next; + continue; + } + + switch (san.type) { + /* + * otherName + */ + case MBEDTLS_X509_SAN_OTHER_NAME: + { + mbedtls_x509_san_other_name *other_name = &san.san.other_name; + + ret = mbedtls_snprintf(p, n, "\n%s otherName :", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + + if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME, + &other_name->value.hardware_module_name.oid) != 0) { + ret = mbedtls_snprintf(p, n, "\n%s hardware module name :", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = + mbedtls_snprintf(p, n, "\n%s hardware type : ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_oid_get_numeric_string(p, + n, + &other_name->value.hardware_module_name.oid); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = + mbedtls_snprintf(p, n, "\n%s hardware serial number : ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + + for (i = 0; i < other_name->value.hardware_module_name.val.len; i++) { + ret = mbedtls_snprintf(p, + n, + "%02X", + other_name->value.hardware_module_name.val.p[i]); + MBEDTLS_X509_SAFE_SNPRINTF; + } + }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + } + break; + + /* + * dNSName + */ + case MBEDTLS_X509_SAN_DNS_NAME: + { + ret = mbedtls_snprintf(p, n, "\n%s dNSName : ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + if (san.san.unstructured_name.len >= n) { + *p = '\0'; + return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; + } + + memcpy(p, san.san.unstructured_name.p, san.san.unstructured_name.len); + p += san.san.unstructured_name.len; + n -= san.san.unstructured_name.len; + } + break; + + /* + * Type not supported, skip item. + */ + default: + ret = mbedtls_snprintf(p, n, "\n%s ", prefix); + MBEDTLS_X509_SAFE_SNPRINTF; + break; + } + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + return 0; +} + +#define PRINT_ITEM(i) \ + { \ + ret = mbedtls_snprintf(p, n, "%s" i, sep); \ + MBEDTLS_X509_SAFE_SNPRINTF; \ + sep = ", "; \ + } + +#define CERT_TYPE(type, name) \ + if (ns_cert_type & (type)) \ + PRINT_ITEM(name); + +int mbedtls_x509_info_cert_type(char **buf, size_t *size, + unsigned char ns_cert_type) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA"); + CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA"); + + *size = n; + *buf = p; + + return 0; +} + +#define KEY_USAGE(code, name) \ + if (key_usage & (code)) \ + PRINT_ITEM(name); + +int mbedtls_x509_info_key_usage(char **buf, size_t *size, + unsigned int key_usage) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + KEY_USAGE(MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature"); + KEY_USAGE(MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation"); + KEY_USAGE(MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment"); + KEY_USAGE(MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment"); + KEY_USAGE(MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement"); + KEY_USAGE(MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign"); + KEY_USAGE(MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign"); + KEY_USAGE(MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only"); + KEY_USAGE(MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only"); + + *size = n; + *buf = p; + + return 0; +} +#endif /* MBEDTLS_X509_REMOVE_INFO */ +#endif /* MBEDTLS_X509_CRT_PARSE_C || MBEDTLS_X509_CSR_PARSE_C */ #endif /* MBEDTLS_X509_USE_C */ diff --git a/library/x509_crt.c b/library/x509_crt.c index f77991eb5c..5997c87468 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -562,63 +562,6 @@ static int x509_get_basic_constraints(unsigned char **p, return 0; } -int mbedtls_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 }; - - if ((ret = mbedtls_asn1_get_bitstring(p, end, &bs)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if (bs.len == 0) { - *ns_cert_type = 0; - return 0; - } - - if (bs.len != 1) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_INVALID_LENGTH); - } - - /* Get actual bitstring */ - *ns_cert_type = *bs.p; - return 0; -} - -int mbedtls_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; - mbedtls_x509_bitstring bs = { 0, 0, NULL }; - - if ((ret = mbedtls_asn1_get_bitstring(p, end, &bs)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if (bs.len == 0) { - *key_usage = 0; - return 0; - } - - if (bs.len < 1) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_INVALID_LENGTH); - } - - /* Get actual bitstring */ - *key_usage = 0; - for (i = 0; i < bs.len && i < sizeof(unsigned int); i++) { - *key_usage |= (unsigned int) bs.p[i] << (8*i); - } - - return 0; -} - /* * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId * @@ -643,118 +586,6 @@ static int x509_get_ext_key_usage(unsigned char **p, return 0; } -/* - * SubjectAltName ::= GeneralNames - * - * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName - * - * GeneralName ::= CHOICE { - * otherName [0] OtherName, - * rfc822Name [1] IA5String, - * dNSName [2] IA5String, - * x400Address [3] ORAddress, - * directoryName [4] Name, - * ediPartyName [5] EDIPartyName, - * uniformResourceIdentifier [6] IA5String, - * iPAddress [7] OCTET STRING, - * registeredID [8] OBJECT IDENTIFIER } - * - * OtherName ::= SEQUENCE { - * type-id OBJECT IDENTIFIER, - * value [0] EXPLICIT ANY DEFINED BY type-id } - * - * EDIPartyName ::= SEQUENCE { - * nameAssigner [0] DirectoryString OPTIONAL, - * partyName [1] DirectoryString } - * - * NOTE: we list all types, but only use dNSName and otherName - * of type HwModuleName, as defined in RFC 4108, at this point. - */ -int mbedtls_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; - mbedtls_asn1_buf *buf; - unsigned char tag; - mbedtls_asn1_sequence *cur = subject_alt_name; - - /* Get main sequence tag */ - if ((ret = mbedtls_asn1_get_tag(p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if (*p + len != end) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - - while (*p < end) { - mbedtls_x509_subject_alternative_name dummy_san_buf; - memset(&dummy_san_buf, 0, sizeof(dummy_san_buf)); - - tag = **p; - (*p)++; - if ((ret = mbedtls_asn1_get_len(p, end, &tag_len)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if ((tag & MBEDTLS_ASN1_TAG_CLASS_MASK) != - MBEDTLS_ASN1_CONTEXT_SPECIFIC) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); - } - - /* - * Check that the SAN is structured correctly. - */ - ret = mbedtls_x509_parse_subject_alt_name(&(cur->buf), &dummy_san_buf); - /* - * In case the extension is malformed, return an error, - * and clear the allocated sequences. - */ - if (ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { - mbedtls_asn1_sequence_free(subject_alt_name->next); - subject_alt_name->next = NULL; - return ret; - } - - /* Allocate and assign next pointer */ - if (cur->buf.p != NULL) { - if (cur->next != NULL) { - return MBEDTLS_ERR_X509_INVALID_EXTENSIONS; - } - - cur->next = mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence)); - - if (cur->next == NULL) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_ALLOC_FAILED); - } - - cur = cur->next; - } - - buf = &(cur->buf); - buf->tag = tag; - buf->p = *p; - buf->len = tag_len; - *p += buf->len; - } - - /* Set final sequence entry's next pointer to NULL */ - cur->next = NULL; - - if (*p != end) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - - return 0; -} - /* * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } * @@ -1713,319 +1544,7 @@ cleanup: } #endif /* MBEDTLS_FS_IO */ -/* - * OtherName ::= SEQUENCE { - * type-id OBJECT IDENTIFIER, - * value [0] EXPLICIT ANY DEFINED BY type-id } - * - * HardwareModuleName ::= SEQUENCE { - * hwType OBJECT IDENTIFIER, - * hwSerialNum OCTET STRING } - * - * NOTE: we currently only parse and use otherName of type HwModuleName, - * as defined in RFC 4108. - */ -static int x509_get_other_name(const mbedtls_x509_buf *subject_alt_name, - mbedtls_x509_san_other_name *other_name) -{ - int ret = 0; - size_t len; - unsigned char *p = subject_alt_name->p; - const unsigned char *end = p + subject_alt_name->len; - mbedtls_x509_buf cur_oid; - - if ((subject_alt_name->tag & - (MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK)) != - (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME)) { - /* - * The given subject alternative name is not of type "othername". - */ - return MBEDTLS_ERR_X509_BAD_INPUT_DATA; - } - - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_OID)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - cur_oid.tag = MBEDTLS_ASN1_OID; - cur_oid.p = p; - cur_oid.len = len; - - /* - * Only HwModuleName is currently supported. - */ - if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid) != 0) { - return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; - } - - if (p + len >= end) { - mbedtls_platform_zeroize(other_name, sizeof(*other_name)); - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - p += len; - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != - 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID; - other_name->value.hardware_module_name.oid.p = p; - other_name->value.hardware_module_name.oid.len = len; - - if (p + len >= end) { - mbedtls_platform_zeroize(other_name, sizeof(*other_name)); - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - p += len; - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_OCTET_STRING)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); - } - - other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING; - other_name->value.hardware_module_name.val.p = p; - other_name->value.hardware_module_name.val.len = len; - p += len; - if (p != end) { - mbedtls_platform_zeroize(other_name, - sizeof(*other_name)); - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - return 0; -} - -int mbedtls_x509_parse_subject_alt_name(const mbedtls_x509_buf *san_buf, - mbedtls_x509_subject_alternative_name *san) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - switch (san_buf->tag & - (MBEDTLS_ASN1_TAG_CLASS_MASK | - MBEDTLS_ASN1_TAG_VALUE_MASK)) { - /* - * otherName - */ - case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME): - { - mbedtls_x509_san_other_name other_name; - - ret = x509_get_other_name(san_buf, &other_name); - if (ret != 0) { - return ret; - } - - memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name)); - san->type = MBEDTLS_X509_SAN_OTHER_NAME; - memcpy(&san->san.other_name, - &other_name, sizeof(other_name)); - - } - break; - - /* - * dNSName - */ - case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME): - { - memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name)); - san->type = MBEDTLS_X509_SAN_DNS_NAME; - - memcpy(&san->san.unstructured_name, - san_buf, sizeof(*san_buf)); - - } - break; - - /* - * Type not supported - */ - default: - return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; - } - return 0; -} - #if !defined(MBEDTLS_X509_REMOVE_INFO) -int mbedtls_x509_info_subject_alt_name(char **buf, size_t *size, - const mbedtls_x509_sequence - *subject_alt_name, - const char *prefix) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t i; - size_t n = *size; - char *p = *buf; - const mbedtls_x509_sequence *cur = subject_alt_name; - mbedtls_x509_subject_alternative_name san; - int parse_ret; - - while (cur != NULL) { - memset(&san, 0, sizeof(san)); - parse_ret = mbedtls_x509_parse_subject_alt_name(&cur->buf, &san); - if (parse_ret != 0) { - if (parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { - ret = mbedtls_snprintf(p, n, "\n%s ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - } else { - ret = mbedtls_snprintf(p, n, "\n%s ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - } - cur = cur->next; - continue; - } - - switch (san.type) { - /* - * otherName - */ - case MBEDTLS_X509_SAN_OTHER_NAME: - { - mbedtls_x509_san_other_name *other_name = &san.san.other_name; - - ret = mbedtls_snprintf(p, n, "\n%s otherName :", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - - if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME, - &other_name->value.hardware_module_name.oid) != 0) { - ret = mbedtls_snprintf(p, n, "\n%s hardware module name :", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = - mbedtls_snprintf(p, n, "\n%s hardware type : ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = mbedtls_oid_get_numeric_string(p, - n, - &other_name->value.hardware_module_name.oid); - MBEDTLS_X509_SAFE_SNPRINTF; - - ret = - mbedtls_snprintf(p, n, "\n%s hardware serial number : ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - - for (i = 0; i < other_name->value.hardware_module_name.val.len; i++) { - ret = mbedtls_snprintf(p, - n, - "%02X", - other_name->value.hardware_module_name.val.p[i]); - MBEDTLS_X509_SAFE_SNPRINTF; - } - }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ - } - break; - - /* - * dNSName - */ - case MBEDTLS_X509_SAN_DNS_NAME: - { - ret = mbedtls_snprintf(p, n, "\n%s dNSName : ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - if (san.san.unstructured_name.len >= n) { - *p = '\0'; - return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; - } - - memcpy(p, san.san.unstructured_name.p, san.san.unstructured_name.len); - p += san.san.unstructured_name.len; - n -= san.san.unstructured_name.len; - } - break; - - /* - * Type not supported, skip item. - */ - default: - ret = mbedtls_snprintf(p, n, "\n%s ", prefix); - MBEDTLS_X509_SAFE_SNPRINTF; - break; - } - - cur = cur->next; - } - - *p = '\0'; - - *size = n; - *buf = p; - - return 0; -} - -#define PRINT_ITEM(i) \ - { \ - ret = mbedtls_snprintf(p, n, "%s" i, sep); \ - MBEDTLS_X509_SAFE_SNPRINTF; \ - sep = ", "; \ - } - -#define CERT_TYPE(type, name) \ - if (ns_cert_type & (type)) \ - PRINT_ITEM(name); - -int mbedtls_x509_info_cert_type(char **buf, size_t *size, - unsigned char ns_cert_type) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n = *size; - char *p = *buf; - const char *sep = ""; - - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA"); - CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA"); - - *size = n; - *buf = p; - - return 0; -} - -#define KEY_USAGE(code, name) \ - if (key_usage & (code)) \ - PRINT_ITEM(name); - -int mbedtls_x509_info_key_usage(char **buf, size_t *size, - unsigned int key_usage) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n = *size; - char *p = *buf; - const char *sep = ""; - - KEY_USAGE(MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature"); - KEY_USAGE(MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation"); - KEY_USAGE(MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment"); - KEY_USAGE(MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment"); - KEY_USAGE(MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement"); - KEY_USAGE(MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign"); - KEY_USAGE(MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign"); - KEY_USAGE(MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only"); - KEY_USAGE(MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only"); - - *size = n; - *buf = p; - - return 0; -} - static int x509_info_ext_key_usage(char **buf, size_t *size, const mbedtls_x509_sequence *extended_key_usage) {