From b2dc3fa72ed519eb739e41ac25d49eb943bca7a1 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Thu, 21 Mar 2019 13:40:13 +0200 Subject: [PATCH 01/27] Suppport otherName of type hardware module name Add support of parsing of subject alternative name, of type otherName. Currently supports only hardware module name, as defined in rfc 4108. --- include/mbedtls/oid.h | 3 + include/mbedtls/x509.h | 22 ++ include/mbedtls/x509_crt.h | 61 +++- library/x509_crt.c | 305 ++++++++++++++++-- tests/data_files/Makefile | 6 + tests/data_files/multiple_san.crt | 12 + tests/data_files/server5-othername.crt | 11 + .../server5-unsupported_othername.crt | 12 + tests/data_files/test-ca.opensslconf | 19 ++ tests/suites/test_suite_x509parse.data | 36 ++- tests/suites/test_suite_x509parse.function | 108 +++++++ 11 files changed, 565 insertions(+), 30 deletions(-) create mode 100644 tests/data_files/multiple_san.crt create mode 100644 tests/data_files/server5-othername.crt create mode 100644 tests/data_files/server5-unsupported_othername.crt diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index 55f72c8eb..c516b7aaf 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -214,6 +214,9 @@ */ #define MBEDTLS_OID_WISUN_FAN MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01" +#define MBEDTLS_OID_ON MBEDTLS_OID_PKIX "\x08" /**< id-on OBJECT IDENTIFIER ::= { id-pkix 8 } */ +#define MBEDTLS_OID_ON_HW_MODULE_NAME MBEDTLS_OID_ON "\x04" /**< id-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-on 4 } */ + /* * PKCS definition OIDs */ diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index b63e864e3..054ff2ecc 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -109,6 +109,28 @@ /* \} name */ /* \} addtogroup x509_module */ +/* + * X.509 v3 Subject Alternative Name types. + * 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 + */ +#define MBEDTLS_X509_SAN_OTHER_NAME 0 +#define MBEDTLS_X509_SAN_RFC822_NAME 1 +#define MBEDTLS_X509_SAN_DNS_NAME 2 +#define MBEDTLS_X509_SAN_X400_ADDRESS_NAME 3 +#define MBEDTLS_X509_SAN_DIRECTORY_NAME 4 +#define MBEDTLS_X509_SAN_EDI_PARTY_NAME 5 +#define MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER 6 +#define MBEDTLS_X509_SAN_IP_ADDRESS 7 +#define MBEDTLS_X509_SAN_REGISTERED_ID 8 + /* * X.509 v3 Key Usage Extension flags * Reminder: update x509_info_key_usage() when adding new flags. diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index a0f32cb30..4a796173f 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -76,7 +76,7 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ - mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName and OtherName supported). */ int ext_types; /**< Bit string containing detected and parsed extensions */ int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ @@ -97,6 +97,44 @@ 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 } + */ +typedef struct mbedtls_x509_san_other_name +{ + mbedtls_x509_buf type_id; /**< The type id. */ + union + { + /* + * From RFC 4108 section 5: + * HardwareModuleName ::= SEQUENCE { + * hwType OBJECT IDENTIFIER, + * hwSerialNum OCTET STRING } + */ + mbedtls_x509_name hardware_module_name; + } + value; +} +mbedtls_x509_san_other_name; + +/* + * A structure for holding the parsed Subject Alternative Name, according to type + */ +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 */ + struct mbedtls_x509_subject_alternative_name *next; /**< The next SAN in the list. */ +} +mbedtls_x509_subject_alternative_name; + /** * Build flag from an algorithm/curve identifier (pk, md, ecp) * Since 0 is always XXX_NONE, ignore it. @@ -347,7 +385,26 @@ 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 Parses the subject alternative name list of a given certificate; + * + * \param crt The X509 certificate to parse. + * + * \param san A list holding the parsed certificate. + * + * \note Only "dnsName" and "otherName" of type hardware_module_name, + * as defined in RFC 4180 is supported. + * + * \note Any unsupported san type is ignored. + * + * \note The function allocates a list of mbedtls_x509_subject_alternative_name + * and it is the caller's responsibility to free it. + * + * \return Zero for success and negative + * value for any other failure. + */ +int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, + mbedtls_x509_subject_alternative_name **san ); /** * \brief Returns an informational string about the * certificate. diff --git a/library/x509_crt.c b/library/x509_crt.c index 97a06d5f1..f9cbed0a2 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -618,7 +618,8 @@ static int x509_get_ext_key_usage( unsigned char **p, * nameAssigner [0] DirectoryString OPTIONAL, * partyName [1] DirectoryString } * - * NOTE: we only parse and use dNSName at this point. + * NOTE: we only parse and use dNSName at this point, + * and otherName of type HwModuleName, as defined in RFC 4108. */ static int x509_get_subject_alt_name( unsigned char **p, const unsigned char *end, @@ -657,13 +658,6 @@ static int x509_get_subject_alt_name( unsigned char **p, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); } - /* Skip everything but DNS name */ - if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) - { - *p += tag_len; - continue; - } - /* Allocate and assign next pointer */ if( cur->buf.p != NULL ) { @@ -1435,32 +1429,195 @@ 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; + 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_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_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_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 = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( 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_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_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; + other_name->value.hardware_module_name.next = NULL; + other_name->value.hardware_module_name.next_merged = 0; + p += len; + if( p != end ) + { + mbedtls_platform_zeroize( other_name, + sizeof( other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + return( 0 ); +} + static int x509_info_subject_alt_name( char **buf, size_t *size, - const mbedtls_x509_sequence *subject_alt_name ) + const mbedtls_x509_sequence *subject_alt_name, + const char *prefix ) { size_t i; + int ret; size_t n = *size; char *p = *buf; const mbedtls_x509_sequence *cur = subject_alt_name; - const char *sep = ""; - size_t sep_len = 0; while( cur != NULL ) { - if( cur->buf.len + sep_len >= n ) + switch( cur->buf.tag & + ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) { - *p = '\0'; - return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + /* + * otherName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): + { + mbedtls_x509_san_other_name other_name; + + ret = x509_get_other_name( &cur->buf, &other_name ); + if( ret != 0 ) + { + /* + * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, + * then the "otherName" is of an unsupported type. Ignore. + */ + if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + ret = 0; + return( ret ); + } + + 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; + + if( other_name.value.hardware_module_name.val.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + for( i = 0; i < other_name.value.hardware_module_name.val.len; i++ ) + { + *p++ = other_name.value.hardware_module_name.val.p[i]; + } + n -= other_name.value.hardware_module_name.val.len; + + }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + } + break; + + /* + * dNSName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): + { + + ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + if( cur->buf.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + n -= cur->buf.len; + for( i = 0; i < cur->buf.len; i++ ) + *p++ = cur->buf.p[i]; + } + break; + + /* + * Type not supported, skip item. + */ + default: + break; } - n -= cur->buf.len + sep_len; - for( i = 0; i < sep_len; i++ ) - *p++ = sep[i]; - for( i = 0; i < cur->buf.len; i++ ) - *p++ = cur->buf.p[i]; - - sep = ", "; - sep_len = 2; cur = cur->next; } @@ -1473,6 +1630,105 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, return( 0 ); } +int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, + mbedtls_x509_subject_alternative_name **san ) +{ + int ret; + const mbedtls_x509_sequence *cur = &crt->subject_alt_names; + mbedtls_x509_subject_alternative_name *cur_san = *san, *prev_san = NULL; + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + if( cur_san != NULL ) + { + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } + + while( cur != NULL ) + { + switch( cur->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( &cur->buf, &other_name ); + if( ret != 0 ) + { + /* + * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, + * then the "otherName" is of an unsupported type. Ignore. + */ + if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + ret = 0; + cur = cur->next; + continue; + } + + cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) ); + if( cur_san == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + if( prev_san != NULL ) + prev_san->next = cur_san; + + cur_san->type = MBEDTLS_X509_SAN_OTHER_NAME; + memcpy( &cur_san->san.other_name, + &other_name, sizeof( other_name ) ); + + } + break; + + /* + * dNSName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): + { + cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) ); + if( cur_san == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + if( prev_san != NULL ) + prev_san->next = cur_san; + + memset( cur_san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); + cur_san->type = MBEDTLS_X509_SAN_DNS_NAME; + + memcpy( &cur_san->san.unstructured_name, + &cur->buf, sizeof( cur->buf ) ); + + } + break; + + /* + * Type not supported, skip item. + */ + default: + break; + } + + if( *san == NULL ) + *san = cur_san; + + if( cur_san != NULL ) + { + prev_san = cur_san; + cur_san = cur_san->next; + } + + cur = cur->next; + }/* while( cur != NULL ) */ + }/* crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME */ + return( 0 ); +} + #define PRINT_ITEM(i) \ { \ ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ @@ -1659,11 +1915,12 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { - ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%ssubject alt name :", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = x509_info_subject_alt_name( &p, &n, - &crt->subject_alt_names ) ) != 0 ) + &crt->subject_alt_names, + prefix) ) != 0 ) return( ret ); } diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile index 748514db1..6680c808f 100644 --- a/tests/data_files/Makefile +++ b/tests/data_files/Makefile @@ -142,6 +142,12 @@ server5-ss-forgeca.crt: server5.key $(FAKETIME) '2015-09-01 14:08:43' $(OPENSSL) req -x509 -new -subj "/C=UK/O=mbed TLS/CN=mbed TLS Test intermediate CA 3" -set_serial 77 -config $(test_ca_config_file) -extensions noext_ca -days 3650 -sha256 -key $< -out $@ all_final += server5-ss-forgeca.crt +server5-othername.crt: server5.key + $(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions othername_san -days 3650 -sha256 -key $< -out $@ + +server5-unsupported_othername.crt: server5.key + $(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS unsupported othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions unsupoported_othername_san -days 3650 -sha256 -key $< -out $@ + server10-badsign.crt: server10.crt { head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@ all_final += server10-badsign.crt diff --git a/tests/data_files/multiple_san.crt b/tests/data_files/multiple_san.crt new file mode 100644 index 000000000..8cdc73061 --- /dev/null +++ b/tests/data_files/multiple_san.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB2jCCAYCgAwIBAgIBBDAKBggqhkjOPQQDAjBKMQswCQYDVQQGEwJVSzERMA8G +A1UECgwITWJlZCBUTFMxKDAmBgNVBAMMH01iZWQgVExTIG11bHRpcGxlIG90aGVy +bmFtZSBTQU4wHhcNMTkwNDIyMTYxMDQ4WhcNMjkwNDE5MTYxMDQ4WjBKMQswCQYD +VQQGEwJVSzERMA8GA1UECgwITWJlZCBUTFMxKDAmBgNVBAMMH01iZWQgVExTIG11 +bHRpcGxlIG90aGVybmFtZSBTQU4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3 +zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqI +wmt3DVXNiioO+gHItO3/o1cwVTBTBgNVHREETDBKggtleGFtcGxlLmNvbaAfBggr +BgEFBQcIBKATMBEGBysGAQQBEQMEBjEyMzQ1NoILZXhhbXBsZS5uZXSCDSouZXhh +bXBsZS5vcmcwCgYIKoZIzj0EAwIDSAAwRQIhAMZUkp+pcuFQ3WWdgvV4Y+tIXOyS +L6p0RtEAOi/GgigVAiB50n3rIUKjapYstPp3yOpGZGyRxnc6uRdSiMH5wLA4yw== +-----END CERTIFICATE----- diff --git a/tests/data_files/server5-othername.crt b/tests/data_files/server5-othername.crt new file mode 100644 index 000000000..3be1a772c --- /dev/null +++ b/tests/data_files/server5-othername.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBnzCCAUWgAwIBAgIBTTAKBggqhkjOPQQDAjBBMQswCQYDVQQGEwJVSzERMA8G +A1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIG90aGVybmFtZSBTQU4w +HhcNMTkwMzI0MDkwNjAyWhcNMjkwMzIxMDkwNjAyWjBBMQswCQYDVQQGEwJVSzER +MA8GA1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIG90aGVybmFtZSBT +QU4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5 +BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqIwmt3DVXNiioO+gHItO3/oy4w +LDAqBgNVHREEIzAhoB8GCCsGAQUFBwgEoBMwEQYHKwYBBAERAwQGMTIzNDU2MAoG +CCqGSM49BAMCA0gAMEUCIQCijdm1AfArx2p4cLCVciHCTE8UXRiTm8f85k4aNzzf +sgIgCdmLyfZB9jsSPH3A3O1GATAR3O9OTtEDC+YSc+lvxSw= +-----END CERTIFICATE----- diff --git a/tests/data_files/server5-unsupported_othername.crt b/tests/data_files/server5-unsupported_othername.crt new file mode 100644 index 000000000..b46fc2d96 --- /dev/null +++ b/tests/data_files/server5-unsupported_othername.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVygAwIBAgIBTTAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJVSzERMA8G +A1UECgwITWJlZCBUTFMxKzApBgNVBAMMIk1iZWQgVExTIHVuc3VwcG9ydGVkIG90 +aGVybmFtZSBTQU4wHhcNMTkwNTAxMDkxMDM1WhcNMjkwNDI4MDkxMDM1WjBNMQsw +CQYDVQQGEwJVSzERMA8GA1UECgwITWJlZCBUTFMxKzApBgNVBAMMIk1iZWQgVExT +IHVuc3VwcG9ydGVkIG90aGVybmFtZSBTQU4wWTATBgcqhkjOPQIBBggqhkjOPQMB +BwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0 +XV0WvYqIwmt3DVXNiioO+gHItO3/oy0wKzApBgNVHREEIjAgoB4GAyoDBKAXDBVz +b21lIG90aGVyIGlkZW50aWZpZXIwCgYIKoZIzj0EAwIDSAAwRQIhANkj6n9qHYVi +FLfb0IRZpIsvvuNCjSgT8yBLVjJYQj3nAiBffQKZ7y/F6rfon6L1GZU0BBja8BLX +rXp8WpY7Bc8myQ== +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf index f66b39e3c..d345fe99e 100644 --- a/tests/data_files/test-ca.opensslconf +++ b/tests/data_files/test-ca.opensslconf @@ -12,6 +12,25 @@ subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always basicConstraints = CA:true +[othername_san] +subjectAltName=otherName:1.3.6.1.5.5.7.8.4;SEQ:hw_module_name + +[unsupoported_othername_san] +subjectAltName=otherName:1.2.3.4;UTF8:some other identifier + +[alt_names] +DNS.1=example.com +otherName.1=1.3.6.1.5.5.7.8.4;SEQ:hw_module_name +DNS.2=example.net +DNS.3=*.example.org + +[multiple_san] +subjectAltName=@alt_names + +[hw_module_name] +hwtype = OID:1.3.6.1.4.1.17.3 +hwserial = OCT:123456 + [noext_ca] basicConstraints = CA:true diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index edd3a6fc5..f53ea8232 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -94,6 +94,10 @@ X509 Certificate information EC, SHA512 Digest depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA512_C x509_cert_info:"data_files/server5-sha512.crt":"cert. version \: 3\nserial number \: 15\nissuer name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name \: C=NL, O=PolarSSL, CN=localhost\nissued on \: 2013-09-24 16\:21\:27\nexpires on \: 2023-09-22 16\:21\:27\nsigned using \: ECDSA with SHA512\nEC key size \: 256 bits\nbasic constraints \: CA=false\n" +X509 Certificate information EC, SHA256 Digest, hardware module name SAN +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/server5-othername.crt":"cert. version \: 3\nserial number \: 4D\nissuer name \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nsubject name \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nissued on \: 2019-03-24 09\:06\:02\nexpires on \: 2029-03-21 09\:06\:02\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\nsubject alt name \:\n otherName \:\n hardware module name \:\n hardware type \: 1.3.6.1.4.1.17.3\n hardware serial number \: 123456\n" + X509 Certificate information, NS Cert Type depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C x509_cert_info:"data_files/server1.cert_type.crt":"cert. version \: 3\nserial number \: 01\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2011-02-12 14\:44\:06\nexpires on \: 2021-02-12 14\:44\:06\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\ncert. type \: SSL Server\n" @@ -108,11 +112,15 @@ x509_cert_info:"data_files/keyUsage.decipherOnly.crt":"cert. version \: 3\ns X509 Certificate information, Subject Alt Name depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C -x509_cert_info:"data_files/cert_example_multi.crt":"cert. version \: 3\nserial number \: 11\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=www.example.com\nissued on \: 2012-05-10 13\:23\:41\nexpires on \: 2022-05-11 13\:23\:41\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \: example.com, example.net, *.example.org\n" +x509_cert_info:"data_files/cert_example_multi.crt":"cert. version \: 3\nserial number \: 11\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=www.example.com\nissued on \: 2012-05-10 13\:23\:41\nexpires on \: 2022-05-11 13\:23\:41\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \:\n dNSName \: example.com\n dNSName \: example.net\n dNSName \: *.example.org\n" + +X509 Certificate information, Multiple different Subject Alt Name +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/multiple_san.crt":"cert. version \: 3\nserial number \: 04\nissuer name \: C=UK, O=Mbed TLS, CN=Mbed TLS multiple othername SAN\nsubject name \: C=UK, O=Mbed TLS, CN=Mbed TLS multiple othername SAN\nissued on \: 2019-04-22 16\:10\:48\nexpires on \: 2029-04-19 16\:10\:48\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\nsubject alt name \:\n dNSName \: example.com\n otherName \:\n hardware module name \:\n hardware type \: 1.3.6.1.4.1.17.3\n hardware serial number \: 123456\n dNSName \: example.net\n dNSName \: *.example.org\n" X509 Certificate information, Subject Alt Name + Key Usage depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C -x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version \: 3\nserial number \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name \: C=NL\nsubject name \: C=NL\nissued on \: 2014-01-22 10\:04\:33\nexpires on \: 2024-01-22 10\:04\:33\nsigned using \: RSA with SHA1\nRSA key size \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name \: www.shotokan-braunschweig.de, www.massimo-abate.eu\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n" +x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version \: 3\nserial number \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name \: C=NL\nsubject name \: C=NL\nissued on \: 2014-01-22 10\:04\:33\nexpires on \: 2024-01-22 10\:04\:33\nsigned using \: RSA with SHA1\nRSA key size \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name \:\n dNSName \: www.shotokan-braunschweig.de\n dNSName \: www.massimo-abate.eu\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n" X509 Certificate information, Key Usage + Extended Key Usage depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C @@ -128,11 +136,31 @@ x509_cert_info:"data_files/server3.crt":"cert. version \: 3\nserial number X509 Certificate information Bitstring in subject name depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C -x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version \: 3\nserial number \: 02\nissuer name \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued on \: 2015-03-11 12\:06\:51\nexpires on \: 2025-03-08 12\:06\:51\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \: \next key usage \: TLS Web Client Authentication\n" +x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version \: 3\nserial number \: 02\nissuer name \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued on \: 2015-03-11 12\:06\:51\nexpires on \: 2025-03-08 12\:06\:51\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \:\next key usage \: TLS Web Client Authentication\n" X509 certificate v1 with extension depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3:MBEDTLS_SHA1_C -x509_cert_info:"data_files/cert_v1_with_ext.crt":"cert. version \: 1\nserial number \: BD\:ED\:44\:C7\:D2\:3E\:C2\:A4\nissuer name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nsubject name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nissued on \: 2013-07-04 16\:17\:02\nexpires on \: 2014-07-04 16\:17\:02\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nsubject alt name \: identity-check.org, www.identity-check.org\n" +x509_cert_info:"data_files/cert_v1_with_ext.crt":"cert. version \: 1\nserial number \: BD\:ED\:44\:C7\:D2\:3E\:C2\:A4\nissuer name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nsubject name \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nissued on \: 2013-07-04 16\:17\:02\nexpires on \: 2014-07-04 16\:17\:02\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nsubject alt name \:\n dNSName \: identity-check.org\n dNSName \: www.identity-check.org\n" + +X509 SAN parsing otherName +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_parse_san:"data_files/server5-othername.crt":"type \: 0\notherName \: hardware module name \: hardware type \: 1.3.6.1.4.1.17.3, hardware serial number \: 123456\n" + +X509 SAN parsing dNSName +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C +x509_parse_san:"data_files/cert_example_multi.crt":"type \: 2\ndNSName \: example.com\ntype \: 2\ndNSName \: example.net\ntype \: 2\ndNSName \: *.example.org\n" + +X509 SAN parsing Multiple different types +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_parse_san:"data_files/multiple_san.crt":"type \: 2\ndNSName \: example.com\ntype \: 0\notherName \: hardware module name \: hardware type \: 1.3.6.1.4.1.17.3, hardware serial number \: 123456\ntype \: 2\ndNSName \: example.net\ntype \: 2\ndNSName \: *.example.org\n" + +X509 SAN parsing, no subject alt name +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C +x509_parse_san:"data_files/server4.crt":"" + +X509 SAN parsing, unsupported otherName name +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_parse_san:"data_files/server5-unsupported_othername.crt":"" X509 CRL information #1 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA1_C:MBEDTLS_RSA_C diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index b11ab849a..beec52cc3 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -219,6 +219,79 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint return( 0 ); } + +int verify_parse_san( mbedtls_x509_subject_alternative_name *san, + char **buf, size_t *size ) +{ + int ret; + size_t i; + char *p = *buf; + size_t n = *size; + + ret = mbedtls_snprintf( p, n, "type : %u", san->type ); + MBEDTLS_X509_SAFE_SNPRINTF; + + switch( san->type ) + { + case( MBEDTLS_X509_SAN_OTHER_NAME ): + ret = mbedtls_snprintf( p, n, "\notherName :"); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, + &san->san.other_name.value.hardware_module_name.oid ) != 0 ) + { + ret = mbedtls_snprintf( p, n, " hardware module name :" ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, " hardware type : " ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_oid_get_numeric_string( p, n, + &san->san.other_name.value.hardware_module_name.oid ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, ", hardware serial number : " ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( san->san.other_name.value.hardware_module_name.val.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + for( i=0; i < san->san.other_name.value.hardware_module_name.val.len; i++ ) + { + *p++ = san->san.other_name.value.hardware_module_name.val.p[i]; + } + n -= san->san.other_name.value.hardware_module_name.val.len; + } + break;/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + case( MBEDTLS_X509_SAN_DNS_NAME ): + ret = mbedtls_snprintf( p, n, "\ndNSName : " ); + MBEDTLS_X509_SAFE_SNPRINTF; + if( san->san.unstructured_name.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + n -= san->san.unstructured_name.len; + for( i = 0; i < san->san.unstructured_name.len; i++ ) + *p++ = san->san.unstructured_name.p[i]; + break;/* MBEDTLS_X509_SAN_DNS_NAME */ + + default: + /* + * Should not happen. + */ + return( -1 ); + } + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + *size = n; + *buf = p; + + return( 0 ); +} #endif /* MBEDTLS_X509_CRT_PARSE_C */ /* END_HEADER */ @@ -227,6 +300,41 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint * END_DEPENDENCIES */ +/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ +void x509_parse_san( char * crt_file, char * result_str ) +{ + mbedtls_x509_crt crt; + mbedtls_x509_subject_alternative_name *cur, *next, *san = NULL; + char buf[2000]; + char *p = buf; + size_t n = sizeof( buf ); + + mbedtls_x509_crt_init( &crt ); + memset( buf, 0, 2000 ); + + TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_parse_subject_alternative_name( &crt, &san ) == 0 ); + cur = san; + while( cur != NULL ) + { + TEST_ASSERT( verify_parse_san( cur, &p, &n ) == 0 ); + cur = cur->next; + } + + TEST_ASSERT( strcmp( buf, result_str ) == 0 ); + +exit: + + for( cur = san; cur != NULL; cur = next ) + { + next = cur->next; + mbedtls_free( cur ); + } + + mbedtls_x509_crt_free( &crt ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ void x509_cert_info( char * crt_file, char * result_str ) { From 74d9acc144a398c6df238abd5ba154a9ae798a05 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Thu, 21 Mar 2019 14:00:03 +0200 Subject: [PATCH 02/27] Add support for certificate policies extension Add support for certificate policies, as defined in rfc 5280. Currently support only `anyPolicy` policy. --- include/mbedtls/x509_crt.h | 2 + library/x509_crt.c | 189 ++++++++++++++++++ tests/data_files/Makefile | 36 ++++ tests/data_files/test-ca-any_policy.crt | 19 ++ tests/data_files/test-ca-any_policy_ec.crt | 12 ++ .../test-ca-any_policy_with_qualifier.crt | 20 ++ .../test-ca-any_policy_with_qualifier_ec.crt | 13 ++ tests/data_files/test-ca-multi_policy.crt | 19 ++ tests/data_files/test-ca-multi_policy_ec.crt | 12 ++ .../data_files/test-ca-unsupported_policy.crt | 19 ++ .../test-ca-unsupported_policy_ec.crt | 12 ++ tests/data_files/test-ca.opensslconf | 20 ++ tests/suites/test_suite_x509parse.data | 32 +++ 13 files changed, 405 insertions(+) create mode 100644 tests/data_files/test-ca-any_policy.crt create mode 100644 tests/data_files/test-ca-any_policy_ec.crt create mode 100644 tests/data_files/test-ca-any_policy_with_qualifier.crt create mode 100644 tests/data_files/test-ca-any_policy_with_qualifier_ec.crt create mode 100644 tests/data_files/test-ca-multi_policy.crt create mode 100644 tests/data_files/test-ca-multi_policy_ec.crt create mode 100644 tests/data_files/test-ca-unsupported_policy.crt create mode 100644 tests/data_files/test-ca-unsupported_policy_ec.crt diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 4a796173f..acaafbe9f 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -78,6 +78,8 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName and OtherName supported). */ + mbedtls_x509_sequence certificate_policies; /**< Optional list of certificate4 policies (Only anyPolicy supported). */ + int ext_types; /**< Bit string containing detected and parsed extensions */ int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ diff --git a/library/x509_crt.c b/library/x509_crt.c index f9cbed0a2..f17c8b2ec 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -690,6 +690,139 @@ static int x509_get_subject_alt_name( unsigned char **p, return( 0 ); } +/* + * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } + * + * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } + * + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + * CertPolicyId ::= OBJECT IDENTIFIER + * + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * -- policyQualifierIds for Internet policy qualifiers + * + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * + * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) + * + * Qualifier ::= CHOICE { + * cPSuri CPSuri, + * userNotice UserNotice } + * + * CPSuri ::= IA5String + * + * UserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL } + * + * NoticeReference ::= SEQUENCE { + * organization DisplayText, + * noticeNumbers SEQUENCE OF INTEGER } + * + * DisplayText ::= CHOICE { + * ia5String IA5String (SIZE (1..200)), + * visibleString VisibleString (SIZE (1..200)), + * bmpString BMPString (SIZE (1..200)), + * utf8String UTF8String (SIZE (1..200)) } + * + * NOTE: we only parse and use anyPolicy without qualifiers at this point + * as defined in RFC 5280. + */ +static int x509_get_certificate_policies( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *certificate_policies ) +{ + int ret; + size_t len; + mbedtls_asn1_buf *buf; + mbedtls_asn1_sequence *cur = certificate_policies; + + /* Get main sequence tag */ + ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Cannot be an empty sequence. + */ + if( len == 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + mbedtls_x509_buf policy_oid; + const unsigned char *policy_end; + + /* + * Get the policy sequence + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + policy_end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + policy_oid.tag = MBEDTLS_ASN1_OID; + policy_oid.len = len; + policy_oid.p = *p; + + /* 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_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &( cur->buf ); + buf->tag = policy_oid.tag; + buf->p = policy_oid.p; + buf->len = policy_oid.len; + /* + * Skip the optional policy qualifiers, + * and set the pointer to the end of the policy. + */ + *p = (unsigned char *)policy_end; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + /* * X.509 v3 extensions * @@ -817,6 +950,13 @@ static int x509_get_crt_ext( unsigned char **p, return( ret ); break; + case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: + /* Parse certificate policies type */ + if( ( ret = x509_get_certificate_policies( p, end_ext_octet, + &crt->certificate_policies ) ) != 0 ) + return( ret ); + break; + default: /* * If this is a non-critical extension, which the oid layer @@ -1820,6 +1960,35 @@ static int x509_info_ext_key_usage( char **buf, size_t *size, return( 0 ); } +static int x509_info_cert_policies( char **buf, size_t *size, + const mbedtls_x509_sequence *certificate_policies ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = certificate_policies; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + /* * Return an informational string about the certificate. */ @@ -1952,6 +2121,16 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( ret ); } + if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES ) + { + ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_policies( &p, &n, + &crt->certificate_policies ) ) != 0 ) + return( ret ); + } + ret = mbedtls_snprintf( p, n, "\n" ); MBEDTLS_X509_SAFE_SNPRINTF; @@ -3078,6 +3257,16 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) mbedtls_free( seq_prv ); } + seq_cur = cert_cur->certificate_policies.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) { mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile index 6680c808f..d139bfa06 100644 --- a/tests/data_files/Makefile +++ b/tests/data_files/Makefile @@ -77,6 +77,42 @@ all_final += test-ca-good-alt.crt test_ca_crt_file_ec = test-ca2.crt test_ca_key_file_ec = test-ca2.key +test-ca-any_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@ +all_final += test-ca-any_policy.crt + +test-ca-any_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@ +all_final += test-ca-any_policy_ec.crt + +test-ca-any_policy_with_qualifier.crt: $(test_ca_key_file_rsa) test-ca.req.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_qualifier_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@ +all_final += test-ca-any_policy_with_qualifier.crt + +test-ca-any_policy_with_qualifier_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_qualifier_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@ +all_final += test-ca-any_policy_with_qualifier_ec.crt + +test-ca-multi_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_multi_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@ +all_final += test-ca-multi_policy.crt + +test-ca-multi_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_multi_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@ +all_final += test-ca-multi_policy_ec.crt + +test-ca-unsupported_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_unsupported_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@ +all_final += test-ca-unsupported_policy.crt + +test-ca-unsupported_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256 + $(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_unsupported_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@ +all_final += test-ca-unsupported_policy_ec.crt + +test-ca.req_ec.sha256: $(test_ca_key_file_ec) + $(MBEDTLS_CERT_REQ) output_file=$@ filename=$(test_ca_key_file_ec) subject_name="C=NL, O=PolarSSL, CN=Polarssl Test EC CA" md=SHA256 +all_intermediate += test-ca.req_ec.sha256 + test_ca_crt_cat12 = test-ca_cat12.crt $(test_ca_crt_cat12): $(test_ca_crt) $(test_ca_crt_file_ec) cat $(test_ca_crt) $(test_ca_crt_file_ec) > $@ diff --git a/tests/data_files/test-ca-any_policy.crt b/tests/data_files/test-ca-any_policy.crt new file mode 100644 index 000000000..af87439cf --- /dev/null +++ b/tests/data_files/test-ca-any_policy.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFDCCAfygAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER +MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN +MTkwMzIxMTY0MDU5WhcNMjkwMzIxMTY0MDU5WjA7MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx +mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny +50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n +YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL +R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu +KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj +IzAhMAwGA1UdEwQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEB +CwUAA4IBAQCHadUDZiIjJhcrG+rYrpOVgMu548rc5kHLC7zVSVfszfdOJq/TdXQT +Lbn9i+AAVRYJU2kHWKD2fvgOYIIBeEGFJKohlKZ82irWxt0Ltph31cuygLcpqNq9 +KRQ/dh3S0w9vn1A1ubYGKTzTnZGELTVzMlXZGTRbAOylMu4eWac6LHymE2EBqmOq +fPCuWdFB62ewQWRa+dRO92Aphh870u43/iLbw7hs4s8hokZP7Ewg6AHb4qjVePdF +jjxAO6x5VCj/WQRnw7muAy0P3l5AhYXAIUdnkdYca5Ja6LfdEJiVeTdE3IU6UJg+ +gAu9swDhUlEuIlCrOdC3tOPDslsOIgTV +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-any_policy_ec.crt b/tests/data_files/test-ca-any_policy_ec.crt new file mode 100644 index 000000000..821a92c45 --- /dev/null +++ b/tests/data_files/test-ca-any_policy_ec.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBzDCCAVGgAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN +MTkwMzI1MDkwMjQ1WhcNMjkwMzI1MDkwMjQ1WjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU +UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0 +X3WnR2/VGSlVaZpTOyC0ZhZgMx6jIzAhMAwGA1UdEwQFMAMBAf8wEQYDVR0gBAow +CDAGBgRVHSAAMAoGCCqGSM49BAMCA2kAMGYCMQDWHgmWMckbGLd7XREnJVAv+XRp +XANOCbWLDu+Fik6c28S+qR6zGEKKGiPHYeDpjRACMQDnYcFBwlfuAB6td3fteG0P +AWngOaGHmUFEA6h24b5Z6/GSFD9FK9rVRdxQc4Olz7U= +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-any_policy_with_qualifier.crt b/tests/data_files/test-ca-any_policy_with_qualifier.crt new file mode 100644 index 000000000..a052bc626 --- /dev/null +++ b/tests/data_files/test-ca-any_policy_with_qualifier.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER +MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN +MTkwNDI4MTMxNDMxWhcNMjkwNDI4MTMxNDMxWjA7MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx +mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny +50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n +YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL +R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu +KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj +QTA/MAwGA1UdEwQFMAMBAf8wLwYDVR0gBCgwJjAkBgRVHSAAMBwwGgYIKwYBBQUH +AgEWDkNQUyB1cmkgc3RyaW5nMA0GCSqGSIb3DQEBCwUAA4IBAQBo3CLwvTakVDWs +XUZz3ehGgk39KzmYOb3m9bBfMpOplDfE8Zaj8TDZZsxXpNCXT85GgbrAdr6pONQJ +Mqd3TzTXCs6tmmIOVDToOj6nKtm2nNSf+1TUuLRgeavgCoicoQZOtW5tAehw/RTE +4VQXSm+ZWotYwK1jvlHS0LaehUy53GsNxWBJHCc3exD+iyutXTZ89jczIKuWpEIN +pTdI/EYVD2r6r/IITRnJpGjNXOhGB4zvgFlwv88GeF5lG6Si9YD+swO8JuJP35q6 +7cPA/vtrjoiyM3kXmmN1LZGIfEMKNwEcyVhvl+d6sReomI3HAKOj9IIG7umFKi6t +axMwzK3Y +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt b/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt new file mode 100644 index 000000000..5e1491da7 --- /dev/null +++ b/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB6DCCAW+gAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN +MTkwNDI4MTAxNjA1WhcNMjkwNDI4MTAxNjA1WjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU +UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0 +X3WnR2/VGSlVaZpTOyC0ZhZgMx6jQTA/MAwGA1UdEwQFMAMBAf8wLwYDVR0gBCgw +JjAkBgRVHSAAMBwwGgYIKwYBBQUHAgEWDkNQUyB1cmkgc3RyaW5nMAoGCCqGSM49 +BAMCA2cAMGQCMDvi5bBVplU3Gct+iYRmRW9ewty5b+1OX0ggzA+ExXpL1Obo6A16 +a2h1kb7Oy4+BSAIwXZHYb6OEWkOngISfwSZxDiiNXOTwvCu2/oFGC8xTENn0B88m +2WwPzh4jnvXhNh0w +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-multi_policy.crt b/tests/data_files/test-ca-multi_policy.crt new file mode 100644 index 000000000..168e99f2e --- /dev/null +++ b/tests/data_files/test-ca-multi_policy.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgOgAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER +MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN +MTkwNDI4MTI1OTE5WhcNMjkwNDI4MTI1OTE5WjA7MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx +mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny +50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n +YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL +R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu +KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj +KjAoMAwGA1UdEwQFMAMBAf8wGAYDVR0gBBEwDzAFBgMqAwQwBgYEVR0gADANBgkq +hkiG9w0BAQsFAAOCAQEAPwOUmjnrcBA7dt5drCakEz9HOpj8gZQd1fyVGv221LCL +h2W1Ngd2WlcADhPQcTdqNx4Dk+KPiBjPEooE9M7d3K33Qn/dVkmOYiW6E/4wU2tM +cqFj7rg8Now4lBaEqEmBP+cpv+mYqavPcKy3tz4wn1SnA3MpT1hEazhNe4yInNAY +4YqRBbWuBGkePjbce6Lf+rTfaA7kJnyuC9SHguQRmWtV3xzNzLUFn+V/jYSqYvYU +2MjDFgCYCmW0xl5Wo8wMWWAvMbO2mRJ37OLUkSOkxgeEL6OihY1GPkbfxC2qV6mR +4VjmfclwXumiDAvVLhW8hWjCxg8gc69G7kCkVbljLA== +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-multi_policy_ec.crt b/tests/data_files/test-ca-multi_policy_ec.crt new file mode 100644 index 000000000..70ea2ebbd --- /dev/null +++ b/tests/data_files/test-ca-multi_policy_ec.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIB0zCCAVigAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN +MTkwNDI4MTI1OTUxWhcNMjkwNDI4MTI1OTUxWjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU +UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0 +X3WnR2/VGSlVaZpTOyC0ZhZgMx6jKjAoMAwGA1UdEwQFMAMBAf8wGAYDVR0gBBEw +DzAFBgMqAwQwBgYEVR0gADAKBggqhkjOPQQDAgNpADBmAjEAqyz2v+6i3xXF4qlr +o89qxwlpIn9sR0xU+qo9tgcM6Fa7IDdAU1lhweN8MpkJTtrGAjEAmgNI/08M8n6/ +sMM0Xutt5u9EUHb+4y0uyOfYMcEPr+pCUM4GPxBP6RdqI8Wu9OQf +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-unsupported_policy.crt b/tests/data_files/test-ca-unsupported_policy.crt new file mode 100644 index 000000000..bf47d9538 --- /dev/null +++ b/tests/data_files/test-ca-unsupported_policy.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER +MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN +MTkwNDI4MTMwMDEzWhcNMjkwNDI4MTMwMDEzWjA7MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx +mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny +50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n +YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL +R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu +KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj +IjAgMAwGA1UdEwQFMAMBAf8wEAYDVR0gBAkwBzAFBgMqAwQwDQYJKoZIhvcNAQEL +BQADggEBAGvARX2orRXDmc2a7nSrbRFkdw/7qbL8Y+wLeM94SsZVgzGcxzRx1KvG +2H5nBvPKgAzBqWVPU7eDPjrETIfsCxSu+yklBIg5QYRuOcprLtQPkFVfl+WLd31F +lS1uMgZkahIr57aHoJLYPrEjW4CBHoliT8xfrvVZi4+ym7i/vFqXL7IJ+PIklNF8 +2/b4SAB9hRI5oPw1TV9Q0v2PqMXL/0cp/9Roe+H28Tcrody6jTtEdsU2wbaxhxMd +YK4Ak1FkhKItumINbtAUnHgBVwO2IivGZgsYulC/9y1uh5NU1HxMzqh04UEMgre+ +9SeEjhwFkq16Njc5Cdt/7iFLeiaHcNU= +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca-unsupported_policy_ec.crt b/tests/data_files/test-ca-unsupported_policy_ec.crt new file mode 100644 index 000000000..161e83cc1 --- /dev/null +++ b/tests/data_files/test-ca-unsupported_policy_ec.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIByjCCAVCgAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN +MTkwNDI4MTMwMDE5WhcNMjkwNDI4MTMwMDE5WjA+MQswCQYDVQQGEwJOTDERMA8G +A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU +UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0 +X3WnR2/VGSlVaZpTOyC0ZhZgMx6jIjAgMAwGA1UdEwQFMAMBAf8wEAYDVR0gBAkw +BzAFBgMqAwQwCgYIKoZIzj0EAwIDaAAwZQIwKUY3aTL6UR2H1Q1OzIJw7vxUso4P +2PksCWb62kQeAnhYK85t1VGQiA49iHCXVKuXAjEAq+1qvlmwHX1E99ha/rvxcAYp +UmxXLmSb53RT0NvhEKnUVGGUp2pBNAVVJOH+G0NI +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf index d345fe99e..5f71532ce 100644 --- a/tests/data_files/test-ca.opensslconf +++ b/tests/data_files/test-ca.opensslconf @@ -31,6 +31,26 @@ subjectAltName=@alt_names hwtype = OID:1.3.6.1.4.1.17.3 hwserial = OCT:123456 +[v3_any_policy_ca] +basicConstraints = CA:true +certificatePolicies = 2.5.29.32.0 + +[v3_any_policy_qualifier_ca] +basicConstraints = CA:true +certificatePolicies = @policy_info + +[v3_multi_policy_ca] +basicConstraints = CA:true +certificatePolicies = 1.2.3.4,2.5.29.32.0 + +[v3_unsupported_policy_ca] +basicConstraints = CA:true +certificatePolicies = 1.2.3.4 + +[policy_info] +policyIdentifier = 2.5.29.32.0 +CPS.1 ="CPS uri string" + [noext_ca] basicConstraints = CA:true diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index f53ea8232..6fcf80564 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -122,6 +122,38 @@ X509 Certificate information, Subject Alt Name + Key Usage depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version \: 3\nserial number \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name \: C=NL\nsubject name \: C=NL\nissued on \: 2014-01-22 10\:04\:33\nexpires on \: 2024-01-22 10\:04\:33\nsigned using \: RSA with SHA1\nRSA key size \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name \:\n dNSName \: www.shotokan-braunschweig.de\n dNSName \: www.massimo-abate.eu\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n" +X509 Certificate information, RSA Certificate Policy any +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-any_policy.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued on \: 2019-03-21 16\:40\:59\nexpires on \: 2029-03-21 16\:40\:59\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n" + +X509 Certificate information, ECDSA Certificate Policy any +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-any_policy_ec.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued on \: 2019-03-25 09\:02\:45\nexpires on \: 2029-03-25 09\:02\:45\nsigned using \: ECDSA with SHA256\nEC key size \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n" + +X509 Certificate information, RSA Certificate Policy any with qualifier +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-any_policy_with_qualifier.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued on \: 2019-04-28 13\:14\:31\nexpires on \: 2029-04-28 13\:14\:31\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n" + +X509 Certificate information, ECDSA Certificate Policy any with qualifier +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-any_policy_with_qualifier_ec.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued on \: 2019-04-28 10\:16\:05\nexpires on \: 2029-04-28 10\:16\:05\nsigned using \: ECDSA with SHA256\nEC key size \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n" + +X509 Certificate information, RSA Certificate multiple Policies +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-multi_policy.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued on \: 2019-04-28 12\:59\:19\nexpires on \: 2029-04-28 12\:59\:19\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: ???, Any Policy\n" + +X509 Certificate information, ECDSA Certificate multiple Policies +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-multi_policy_ec.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued on \: 2019-04-28 12\:59\:51\nexpires on \: 2029-04-28 12\:59\:51\nsigned using \: ECDSA with SHA256\nEC key size \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: ???, Any Policy\n" + +X509 Certificate information, RSA Certificate unsupported policy +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-unsupported_policy.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued on \: 2019-04-28 13\:00\:13\nexpires on \: 2029-04-28 13\:00\:13\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: ???\n" + +X509 Certificate information, ECDSA Certificate unsupported policy +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/test-ca-unsupported_policy_ec.crt":"cert. version \: 3\nserial number \: 00\nissuer name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued on \: 2019-04-28 13\:00\:19\nexpires on \: 2029-04-28 13\:00\:19\nsigned using \: ECDSA with SHA256\nEC key size \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: ???\n" + X509 Certificate information, Key Usage + Extended Key Usage depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C x509_cert_info:"data_files/server1.ext_ku.crt":"cert. version \: 3\nserial number \: 21\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2014-04-01 14\:44\:43\nexpires on \: 2024-03-29 14\:44\:43\nsigned using \: RSA with SHA-256\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\next key usage \: TLS Web Server Authentication\n" From 226991e624a1d5e339cf6b7123b46e8c852b7223 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Sun, 24 Mar 2019 13:39:51 +0200 Subject: [PATCH 03/27] Add ChangeLog entry for new extensions change Add an entry for the new x509 extension parsing support. --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 58ff14734..ce50950a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -61,6 +61,10 @@ Features * Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites from the default list (enabled by default). See https://sweet32.info/SWEET32_CCS16.pdf. + * Add support for parsing subject alternative name, of type otherName, + HardwareModuleName, as defined in rfc 4108 section 5. + * Add support for parsing certificate policies extension, as defined in + rfc 5280 section 4.2.1.4. Currently only supports "Any Policy" policy. API Changes * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`. From 3c4734a2a569c538350758bd456bc6e55af1eb64 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 25 Mar 2019 14:05:23 +0200 Subject: [PATCH 04/27] Add Wisun Fan device certificate Add certificate with Wisun fan device extended key usage, support parsing it and add tests. --- include/mbedtls/oid.h | 2 +- tests/data_files/Makefile | 3 +++ tests/data_files/server5-fan.crt | 10 ++++++++++ tests/data_files/test-ca.opensslconf | 3 +++ tests/suites/test_suite_x509parse.data | 4 ++++ 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/data_files/server5-fan.crt diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index c516b7aaf..1e96856e2 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -212,7 +212,7 @@ * { iso(1) identified-organization(3) dod(6) internet(1) * private(4) enterprise(1) WiSUN(45605) FieldAreaNetwork(1) } */ -#define MBEDTLS_OID_WISUN_FAN MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01" +#define MBEDTLS_OID_WISUN_FAN MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01" #define MBEDTLS_OID_ON MBEDTLS_OID_PKIX "\x08" /**< id-on OBJECT IDENTIFIER ::= { id-pkix 8 } */ #define MBEDTLS_OID_ON_HW_MODULE_NAME MBEDTLS_OID_ON "\x04" /**< id-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-on 4 } */ diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile index d139bfa06..d1af18ce7 100644 --- a/tests/data_files/Makefile +++ b/tests/data_files/Makefile @@ -184,6 +184,9 @@ server5-othername.crt: server5.key server5-unsupported_othername.crt: server5.key $(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS unsupported othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions unsupoported_othername_san -days 3650 -sha256 -key $< -out $@ +server5-fan.crt: server5.key + $(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS FAN" -set_serial 77 -config $(test_ca_config_file) -extensions fan_cert -days 3650 -sha256 -key server5.key -out $@ + server10-badsign.crt: server10.crt { head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@ all_final += server10-badsign.crt diff --git a/tests/data_files/server5-fan.crt b/tests/data_files/server5-fan.crt new file mode 100644 index 000000000..dc1eb380c --- /dev/null +++ b/tests/data_files/server5-fan.crt @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBdTCCARugAwIBAgIBTTAKBggqhkjOPQQDAjA3MQswCQYDVQQGEwJVSzERMA8G +A1UECgwITWJlZCBUTFMxFTATBgNVBAMMDE1iZWQgVExTIEZBTjAeFw0xOTAzMjUw +OTAzNDZaFw0yOTAzMjIwOTAzNDZaMDcxCzAJBgNVBAYTAlVLMREwDwYDVQQKDAhN +YmVkIFRMUzEVMBMGA1UEAwwMTWJlZCBUTFMgRkFOMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/ +6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6MYMBYwFAYDVR0lBA0wCwYJKwYBBAGC +5CUBMAoGCCqGSM49BAMCA0gAMEUCIQDp/Q5FaVy3YNeJflQKLGycQZoH6V3FQnLq +ERUCeimLIAIgdyiA4KdHxkpQhC1L1KfmxG8YJqu31FBjmNw00Sv8J9k= +-----END CERTIFICATE----- diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf index 5f71532ce..d2c5c0630 100644 --- a/tests/data_files/test-ca.opensslconf +++ b/tests/data_files/test-ca.opensslconf @@ -51,6 +51,9 @@ certificatePolicies = 1.2.3.4 policyIdentifier = 2.5.29.32.0 CPS.1 ="CPS uri string" +[fan_cert] +extendedKeyUsage = 1.3.6.1.4.1.45605.1 + [noext_ca] basicConstraints = CA:true diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 6fcf80564..d3afe1f88 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -98,6 +98,10 @@ X509 Certificate information EC, SHA256 Digest, hardware module name SAN depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C x509_cert_info:"data_files/server5-othername.crt":"cert. version \: 3\nserial number \: 4D\nissuer name \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nsubject name \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nissued on \: 2019-03-24 09\:06\:02\nexpires on \: 2029-03-21 09\:06\:02\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\nsubject alt name \:\n otherName \:\n hardware module name \:\n hardware type \: 1.3.6.1.4.1.17.3\n hardware serial number \: 123456\n" +X509 Certificate information EC, SHA256 Digest, Wisun Fan device +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C +x509_cert_info:"data_files/server5-fan.crt":"cert. version \: 3\nserial number \: 4D\nissuer name \: C=UK, O=Mbed TLS, CN=Mbed TLS FAN\nsubject name \: C=UK, O=Mbed TLS, CN=Mbed TLS FAN\nissued on \: 2019-03-25 09\:03\:46\nexpires on \: 2029-03-22 09\:03\:46\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\next key usage \: Wi-SUN Alliance Field Area Network (FAN)\n" + X509 Certificate information, NS Cert Type depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C x509_cert_info:"data_files/server1.cert_type.crt":"cert. version \: 3\nserial number \: 01\nissuer name \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued on \: 2011-02-12 14\:44\:06\nexpires on \: 2021-02-12 14\:44\:06\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\ncert. type \: SSL Server\n" From 5091bec3ea5b29aa0a745bdd17438178f842175f Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 8 May 2019 15:23:08 +0100 Subject: [PATCH 05/27] Fix doxygen for new x509 structures The documentation for some new structures and members was only a C style comment and wasn't picked up by doxygen. This commit adds the missing asterisks. --- include/mbedtls/x509_crt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index acaafbe9f..c93fefa22 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -99,7 +99,7 @@ typedef struct mbedtls_x509_crt } mbedtls_x509_crt; -/* +/** * From RFC 5280 section 4.2.1.6: * OtherName ::= SEQUENCE { * type-id OBJECT IDENTIFIER, @@ -110,7 +110,7 @@ typedef struct mbedtls_x509_san_other_name mbedtls_x509_buf type_id; /**< The type id. */ union { - /* + /** * From RFC 4108 section 5: * HardwareModuleName ::= SEQUENCE { * hwType OBJECT IDENTIFIER, @@ -122,7 +122,7 @@ typedef struct mbedtls_x509_san_other_name } mbedtls_x509_san_other_name; -/* +/** * A structure for holding the parsed Subject Alternative Name, according to type */ typedef struct mbedtls_x509_subject_alternative_name From 11b41eb12beffb486f22e6fc34d7b0eed0b0026b Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Wed, 8 May 2019 15:26:49 +0100 Subject: [PATCH 06/27] Fix typos in x509_crt.h --- include/mbedtls/x509_crt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index c93fefa22..ad39400a5 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -386,12 +386,12 @@ int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ); * if partly successful or a specific X509 or PEM error code */ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); + #endif /* MBEDTLS_FS_IO */ /** - * \brief Parses the subject alternative name list of a given certificate; + * \brief Parses the subject alternative name list of a given certificate. * * \param crt The X509 certificate to parse. - * * \param san A list holding the parsed certificate. * * \note Only "dnsName" and "otherName" of type hardware_module_name, From ab23cd1eae1afe30f11c06cf26034a0c0ee3f006 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Thu, 9 May 2019 13:53:57 +0100 Subject: [PATCH 07/27] Remove unneeded checks from x509_get_other_name Lengths are aleady checked in mbedtls_asn1_get_len() which is called in mbedtls_asn1_get_tag(), therefore it is not necessary to check the lengths explicitly afterwards. Also with the previous flow data was left in the output buffer on some errors. --- library/x509_crt.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index f17c8b2ec..cfd3b9d13 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1584,7 +1584,7 @@ cleanup: static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, mbedtls_x509_san_other_name *other_name ) { - int ret; + int ret = 0; size_t len; unsigned char *p = subject_alt_name->p; const unsigned char *end = p + subject_alt_name->len; @@ -1616,12 +1616,6 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); } - if( p + len >= end ) - { - mbedtls_platform_zeroize( other_name, sizeof( other_name ) ); - return( 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 ) @@ -1638,30 +1632,31 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, 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_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_ERR_X509_INVALID_EXTENSIONS + ret ); + goto cleanup; 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; other_name->value.hardware_module_name.next = NULL; other_name->value.hardware_module_name.next_merged = 0; + p += len; if( p != end ) { - mbedtls_platform_zeroize( other_name, - sizeof( other_name ) ); - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; } + +cleanup: + + if( ret != 0 ) + { + memset( other_name, 0, sizeof( *other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + return( 0 ); } From 22f605fbab03c36f3ce32f0fdd681dbec480917c Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 10 May 2019 10:37:17 +0100 Subject: [PATCH 08/27] Print unparseable SubjectAlternativeNames In x509_info_subject_alt_name() we silently dropped names that we couldn't parse because they are not supported or are malformed. (Being malformed might mean damaged file, but can be a sign of incompatibility between applications.) This commit adds code notifying the user that there is something, but we can't parse it. --- library/x509_crt.c | 34 +++++++++++++++----------- tests/suites/test_suite_x509parse.data | 4 +-- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index cfd3b9d13..54b42854b 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1682,21 +1682,27 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, { mbedtls_x509_san_other_name other_name; - ret = x509_get_other_name( &cur->buf, &other_name ); - if( ret != 0 ) - { - /* - * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, - * then the "otherName" is of an unsupported type. Ignore. - */ - if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) - ret = 0; - return( ret ); - } + int parse_ret = x509_get_other_name( &cur->buf, &other_name ); ret = mbedtls_snprintf( p, n, "\n%s otherName :", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; + if( parse_ret != 0 ) + { + if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + { + ret = mbedtls_snprintf( p, n, " " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + else + { + ret = mbedtls_snprintf( p, n, " " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + break; + } + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, &other_name.value.hardware_module_name.oid ) != 0 ) { @@ -1732,7 +1738,6 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, */ case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): { - ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; if( cur->buf.len >= n ) @@ -1747,13 +1752,14 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, break; /* - * Type not supported, skip item. + * Type not supported. */ default: + ret = mbedtls_snprintf( p, n, "\n%s ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; break; } - cur = cur->next; } diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index d3afe1f88..99dd0833f 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -124,7 +124,7 @@ x509_cert_info:"data_files/multiple_san.crt":"cert. version \: 3\nserial num X509 Certificate information, Subject Alt Name + Key Usage depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C -x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version \: 3\nserial number \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name \: C=NL\nsubject name \: C=NL\nissued on \: 2014-01-22 10\:04\:33\nexpires on \: 2024-01-22 10\:04\:33\nsigned using \: RSA with SHA1\nRSA key size \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name \:\n dNSName \: www.shotokan-braunschweig.de\n dNSName \: www.massimo-abate.eu\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n" +x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version \: 3\nserial number \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name \: C=NL\nsubject name \: C=NL\nissued on \: 2014-01-22 10\:04\:33\nexpires on \: 2024-01-22 10\:04\:33\nsigned using \: RSA with SHA1\nRSA key size \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name \:\n dNSName \: www.shotokan-braunschweig.de\n dNSName \: www.massimo-abate.eu\n \n \nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n" X509 Certificate information, RSA Certificate Policy any depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C @@ -172,7 +172,7 @@ x509_cert_info:"data_files/server3.crt":"cert. version \: 3\nserial number X509 Certificate information Bitstring in subject name depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C -x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version \: 3\nserial number \: 02\nissuer name \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued on \: 2015-03-11 12\:06\:51\nexpires on \: 2025-03-08 12\:06\:51\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \:\next key usage \: TLS Web Client Authentication\n" +x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version \: 3\nserial number \: 02\nissuer name \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued on \: 2015-03-11 12\:06\:51\nexpires on \: 2025-03-08 12\:06\:51\nsigned using \: RSA with SHA1\nRSA key size \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name \:\n \next key usage \: TLS Web Client Authentication\n" X509 certificate v1 with extension depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3:MBEDTLS_SHA1_C From 2f0ec1e3bf4a02d64251826231284044972f7f4f Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 10 May 2019 11:06:31 +0100 Subject: [PATCH 09/27] Tidy up style in x509_info_subject_alt_name --- library/x509_crt.c | 122 ++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 52 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 54b42854b..a01b53c3c 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1661,7 +1661,8 @@ cleanup: } static int x509_info_subject_alt_name( char **buf, size_t *size, - const mbedtls_x509_sequence *subject_alt_name, + const mbedtls_x509_sequence + *subject_alt_name, const char *prefix ) { size_t i; @@ -1679,77 +1680,94 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, * otherName */ case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): - { - mbedtls_x509_san_other_name other_name; - - int parse_ret = x509_get_other_name( &cur->buf, &other_name ); - - ret = mbedtls_snprintf( p, n, "\n%s otherName :", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - - if( parse_ret != 0 ) { - if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + mbedtls_x509_san_other_name other_name; + + int parse_ret = x509_get_other_name( &cur->buf, + &other_name ); + + ret = mbedtls_snprintf( p, n, "\n%s otherName :", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( parse_ret != 0 ) { - ret = mbedtls_snprintf( p, n, " " ); - MBEDTLS_X509_SAFE_SNPRINTF; - } - else - { - ret = mbedtls_snprintf( p, n, " " ); - MBEDTLS_X509_SAFE_SNPRINTF; + if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + { + ret = mbedtls_snprintf( p, n, " " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + else + { + ret = mbedtls_snprintf( p, n, " " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + break; } - break; + 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; + + if( other_name.value.hardware_module_name.val.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + for( i = 0; + i < other_name.value.hardware_module_name.val.len; + i++ ) + { + *p++ = + other_name.value.hardware_module_name.val.p[i]; + } + n -= other_name.value.hardware_module_name.val.len; + + }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + } - - 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; - - if( other_name.value.hardware_module_name.val.len >= n ) - { - *p = '\0'; - return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); - } - - for( i = 0; i < other_name.value.hardware_module_name.val.len; i++ ) - { - *p++ = other_name.value.hardware_module_name.val.p[i]; - } - n -= other_name.value.hardware_module_name.val.len; - - }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ - } - break; + break; /* * dNSName */ case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): - { ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; + if( cur->buf.len >= n ) { *p = '\0'; return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); } + n -= cur->buf.len; for( i = 0; i < cur->buf.len; i++ ) *p++ = cur->buf.p[i]; - } - break; + + break; /* * Type not supported. From 6c379b4b8091ede8d28becc6bf36c7a7c59c3b37 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 10 May 2019 14:17:16 +0100 Subject: [PATCH 10/27] Propogate error when parsing SubjectAltNames The previous behaviour of mbedtls_x509_parse_subject_alternative_name() was to silently ignore errors coming from x509_get_other_name(). The current commit fixes it and returns with an error. --- library/x509_crt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index a01b53c3c..047e4e6e2 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1823,8 +1823,9 @@ int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, * then the "otherName" is of an unsupported type. Ignore. */ - if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) - ret = 0; + if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + return MBEDTLS_ERR_X509_INVALID_FORMAT; + cur = cur->next; continue; } From 293c3dae6dce53b03b5149f097009c147644e0e3 Mon Sep 17 00:00:00 2001 From: Janos Follath Date: Fri, 10 May 2019 15:53:03 +0100 Subject: [PATCH 11/27] Remove redundant memset() The preceding calloc() already zeroizes that memory area, therfore the memset() is not necessary. Compilers are likely to optimize this out, but it still can be confusing to readers. --- library/x509_crt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 047e4e6e2..f58b15694 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1858,7 +1858,6 @@ int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, if( prev_san != NULL ) prev_san->next = cur_san; - memset( cur_san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); cur_san->type = MBEDTLS_X509_SAN_DNS_NAME; memcpy( &cur_san->san.unstructured_name, From 26cfd1361dd7e92aff4fd7cb6a951c1b0181c629 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 13 May 2019 15:48:38 +0300 Subject: [PATCH 12/27] Rephrase changeLog entries Rephrase the changeLog entries for clarity and capitalize RFC. --- ChangeLog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ce50950a3..f942ebbf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -61,10 +61,11 @@ Features * Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites from the default list (enabled by default). See https://sweet32.info/SWEET32_CCS16.pdf. - * Add support for parsing subject alternative name, of type otherName, - HardwareModuleName, as defined in rfc 4108 section 5. + * Add support for parsing otherName entries in the Subject Alternative Name + X.509 certificate extension, as defined in RFC 4108 section 5. * Add support for parsing certificate policies extension, as defined in - rfc 5280 section 4.2.1.4. Currently only supports "Any Policy" policy. + RFC 5280 section 4.2.1.4. Currently, only the "Any Policy" policy is + supported. API Changes * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`. From 78c3040347b5bdcbbaeeeafe9cfb587e8a9eccad Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 13 May 2019 15:49:53 +0300 Subject: [PATCH 13/27] Rephrase x509_crt extension member description Rephrase doxygen comments for subject alternative name and certificate policies. --- include/mbedtls/x509_crt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index ad39400a5..dbfaf9c08 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -76,9 +76,9 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ - mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName and OtherName supported). */ + 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_sequence certificate_policies; /**< Optional list of certificate4 policies (Only anyPolicy supported). */ + mbedtls_x509_sequence certificate_policies; /**< Optional list of certificate policies (Only anyPolicy supported). */ int ext_types; /**< Bit string containing detected and parsed extensions */ int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ From 0806379e3e359d5d6f67e354767812dfc848c0e8 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 13 May 2019 16:38:39 +0300 Subject: [PATCH 14/27] Add length checking in certificate policy parsing Change the extension parsing to `policy_end` and verify that the policy and qualifiers length don't exceed the end of the extension. --- library/x509_crt.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index f58b15694..977772676 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -779,7 +779,7 @@ static int x509_get_certificate_policies( unsigned char **p, policy_end = *p + len; - if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); @@ -806,11 +806,27 @@ static int x509_get_certificate_policies( unsigned char **p, buf->tag = policy_oid.tag; buf->p = policy_oid.p; buf->len = policy_oid.len; - /* - * Skip the optional policy qualifiers, - * and set the pointer to the end of the policy. - */ - *p = (unsigned char *)policy_end; + + *p += len; + + /* + * If there is an optional qualifier, then *p < policy_end + * Check the Qualifier len to verify it doesn't exceed policy_end. + */ + if( *p < policy_end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + /* + * Skip the optional policy qualifiers. + */ + *p += len; + } + + if( *p != policy_end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } /* Set final sequence entry's next pointer to NULL */ From 890819a597bd7a67f0b8185a4409733504f792b3 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 13 May 2019 19:03:04 +0300 Subject: [PATCH 15/27] Change mbedtls_x509_subject_alternative_name Make `mbedtls_x509_subject_alternative_name` to be a single item rather than a list. Adapt the subject alternative name parsing function, to receive a signle `mbedtls_x509_buf` item from the subject_alt_names sequence of the certificate. --- include/mbedtls/x509_crt.h | 34 ++- library/x509_crt.c | 284 ++++++++------------- tests/suites/test_suite_x509parse.function | 29 ++- 3 files changed, 151 insertions(+), 196 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index dbfaf9c08..b321c4233 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -107,6 +107,11 @@ mbedtls_x509_crt; */ typedef struct mbedtls_x509_san_other_name { + /** + * The type_id is an OID as deifned 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 { @@ -133,7 +138,6 @@ typedef struct mbedtls_x509_subject_alternative_name mbedtls_x509_buf unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */ } san; /**< A union of the supported SAN types */ - struct mbedtls_x509_subject_alternative_name *next; /**< The next SAN in the list. */ } mbedtls_x509_subject_alternative_name; @@ -389,24 +393,30 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); #endif /* MBEDTLS_FS_IO */ /** - * \brief Parses the subject alternative name list of a given certificate. + * \brief Parses a subject alternative name item + * to an identified structure; * - * \param crt The X509 certificate to parse. - * \param san A list holding the parsed certificate. + * \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 Any unsupported san type is ignored. + * \note This function should be called on a single raw data of + * subject alternative name. For example, after successfult + * certificate parsing, one must iterate on every item in the + * \p crt->subject_alt_names sequence, and send it as parameter + * to this function. * - * \note The function allocates a list of mbedtls_x509_subject_alternative_name - * and it is the caller's responsibility to free it. - * - * \return Zero for success and negative - * value for any other failure. + * \return \c 0 on success + * \return #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported + * SAN type + * \return Negative value for any other failure. */ -int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, - mbedtls_x509_subject_alternative_name **san ); +int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san ); /** * \brief Returns an informational string about the * certificate. diff --git a/library/x509_crt.c b/library/x509_crt.c index 977772676..cce230bd2 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1632,6 +1632,12 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); } + if( p + len >= end ) + { + mbedtls_platform_zeroize( other_name, sizeof( other_name ) ); + return( 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 ) @@ -1648,31 +1654,30 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, 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_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 ) - goto cleanup; + return( 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; other_name->value.hardware_module_name.next = NULL; other_name->value.hardware_module_name.next_merged = 0; - p += len; if( p != end ) { - ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + mbedtls_platform_zeroize( other_name, + sizeof( other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } - -cleanup: - - if( ret != 0 ) - { - memset( other_name, 0, sizeof( *other_name ) ); - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - } - return( 0 ); } @@ -1686,107 +1691,91 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, 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 ) { - switch( cur->buf.tag & - ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) + 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_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): + 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 ) { - mbedtls_x509_san_other_name other_name; - - int parse_ret = x509_get_other_name( &cur->buf, - &other_name ); - - ret = mbedtls_snprintf( p, n, "\n%s otherName :", - prefix ); + 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; - if( parse_ret != 0 ) - { - if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) - { - ret = mbedtls_snprintf( p, n, " " ); - MBEDTLS_X509_SAFE_SNPRINTF; - } - else - { - ret = mbedtls_snprintf( p, n, " " ); - MBEDTLS_X509_SAFE_SNPRINTF; - } + ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid ); + MBEDTLS_X509_SAFE_SNPRINTF; - break; + ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( other_name->value.hardware_module_name.val.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); } - if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, - &other_name.value.hardware_module_name.oid ) - != 0 ) + for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ ) { - 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; + *p++ = other_name->value.hardware_module_name.val.p[i]; + } + n -= other_name->value.hardware_module_name.val.len; - 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; - - if( other_name.value.hardware_module_name.val.len >= n ) - { - *p = '\0'; - return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); - } - - for( i = 0; - i < other_name.value.hardware_module_name.val.len; - i++ ) - { - *p++ = - other_name.value.hardware_module_name.val.p[i]; - } - n -= other_name.value.hardware_module_name.val.len; - - }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ - - } - break; + }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + } + break; /* * dNSName */ - case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): + case( MBEDTLS_X509_SAN_DNS_NAME ): + { ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; - - if( cur->buf.len >= n ) + if( san.san.unstructured_name.len >= n ) { *p = '\0'; return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); } - - n -= cur->buf.len; - for( i = 0; i < cur->buf.len; i++ ) - *p++ = cur->buf.p[i]; - - break; + n -= san.san.unstructured_name.len; + for( i = 0; i < san.san.unstructured_name.len; i++ ) + *p++ = san.san.unstructured_name.p[i]; + } + break; /* - * Type not supported. + * Type not supported, skip item. */ default: ret = mbedtls_snprintf( p, n, "\n%s ", prefix ); @@ -1805,102 +1794,53 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, return( 0 ); } -int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, - mbedtls_x509_subject_alternative_name **san ) +int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san ) { int ret; - const mbedtls_x509_sequence *cur = &crt->subject_alt_names; - mbedtls_x509_subject_alternative_name *cur_san = *san, *prev_san = NULL; - - if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + switch( san_buf->tag & + ( MBEDTLS_ASN1_TAG_CLASS_MASK | + MBEDTLS_ASN1_TAG_VALUE_MASK ) ) { - if( cur_san != NULL ) + /* + * otherName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): { - return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + 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; - while( cur != NULL ) + /* + * dNSName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): { - switch( cur->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; + memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); + san->type = MBEDTLS_X509_SAN_DNS_NAME; - ret = x509_get_other_name( &cur->buf, &other_name ); - if( ret != 0 ) - { - /* - * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, - * then the "otherName" is of an unsupported type. Ignore. - */ - if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) - return MBEDTLS_ERR_X509_INVALID_FORMAT; + memcpy( &san->san.unstructured_name, + san_buf, sizeof( *san_buf ) ); - cur = cur->next; - continue; - } + } + break; - cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) ); - if( cur_san == NULL ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - - if( prev_san != NULL ) - prev_san->next = cur_san; - - cur_san->type = MBEDTLS_X509_SAN_OTHER_NAME; - memcpy( &cur_san->san.other_name, - &other_name, sizeof( other_name ) ); - - } - break; - - /* - * dNSName - */ - case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): - { - cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) ); - if( cur_san == NULL ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - - if( prev_san != NULL ) - prev_san->next = cur_san; - - cur_san->type = MBEDTLS_X509_SAN_DNS_NAME; - - memcpy( &cur_san->san.unstructured_name, - &cur->buf, sizeof( cur->buf ) ); - - } - break; - - /* - * Type not supported, skip item. - */ - default: - break; - } - - if( *san == NULL ) - *san = cur_san; - - if( cur_san != NULL ) - { - prev_san = cur_san; - cur_san = cur_san->next; - } - - cur = cur->next; - }/* while( cur != NULL ) */ - }/* crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME */ + /* + * Type not supported + */ + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } return( 0 ); } diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index beec52cc3..b4e980210 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -303,8 +303,10 @@ int verify_parse_san( mbedtls_x509_subject_alternative_name *san, /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ void x509_parse_san( char * crt_file, char * result_str ) { + int ret; mbedtls_x509_crt crt; - mbedtls_x509_subject_alternative_name *cur, *next, *san = NULL; + mbedtls_x509_subject_alternative_name san; + mbedtls_x509_sequence *cur = NULL; char buf[2000]; char *p = buf; size_t n = sizeof( buf ); @@ -313,24 +315,27 @@ void x509_parse_san( char * crt_file, char * result_str ) memset( buf, 0, 2000 ); TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); - TEST_ASSERT( mbedtls_x509_parse_subject_alternative_name( &crt, &san ) == 0 ); - cur = san; - while( cur != NULL ) + + if( crt.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { - TEST_ASSERT( verify_parse_san( cur, &p, &n ) == 0 ); - cur = cur->next; + cur = &crt.subject_alt_names; + while( cur != NULL ) + { + ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san ); + TEST_ASSERT( ret == 0 || ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + /* + * If san type not supported, ignore. + */ + if( ret == 0) + TEST_ASSERT( verify_parse_san( &san, &p, &n ) == 0 ); + cur = cur->next; + } } TEST_ASSERT( strcmp( buf, result_str ) == 0 ); exit: - for( cur = san; cur != NULL; cur = next ) - { - next = cur->next; - mbedtls_free( cur ); - } - mbedtls_x509_crt_free( &crt ); } /* END_CASE */ From f05f594acbd405104150f47b349e423cc1ba0241 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 13 May 2019 19:11:31 +0300 Subject: [PATCH 16/27] change the type of hardware_module_name member Change the type of `hardware_module_name` struct from `mbedtls_x509_name` to a unique struct, to distinguish it from the named data type. --- include/mbedtls/x509_crt.h | 7 ++++++- library/x509_crt.c | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index b321c4233..81a2de2be 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -121,7 +121,12 @@ typedef struct mbedtls_x509_san_other_name * hwType OBJECT IDENTIFIER, * hwSerialNum OCTET STRING } */ - mbedtls_x509_name hardware_module_name; + struct + { + mbedtls_x509_buf oid; /**< The object identifier. */ + mbedtls_x509_buf val; /**< The named value. */ + } + hardware_module_name; } value; } diff --git a/library/x509_crt.c b/library/x509_crt.c index cce230bd2..9bc869652 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1668,8 +1668,6 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, 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; - other_name->value.hardware_module_name.next = NULL; - other_name->value.hardware_module_name.next_merged = 0; p += len; if( p != end ) { From cc45cd177f89883ff54f1c54bbfc8f03a7cf8ef6 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 15 May 2019 10:20:09 +0300 Subject: [PATCH 17/27] Update SAN parsing documentation 1) Fix typo in `mbedtls_x509_parse_subject_alt_name()` documentation. 2) Add a not in `mbedtls_x509_parse_subject_alt_name()` documentation, stating that the lifetime of the target structure is restricted by the lifetime ofthe parsed certificate. --- include/mbedtls/x509_crt.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 81a2de2be..a5deb95e0 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -410,11 +410,15 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); * 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 successfult + * subject alternative name. For example, after successful * certificate parsing, one must iterate on every item in the * \p crt->subject_alt_names sequence, and send it as parameter * to this function. * + * \note 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 From 8b0c3c91e63fee5d62c965f10cc35a760d5fea7f Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 15 May 2019 12:20:00 +0300 Subject: [PATCH 18/27] Fail in case critical crt policy not supported In case the certificate policy is not of type `AnyPolicy` set the returned error code to `MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE` and continue parsing. If the extension is critical, return error anyway, unless `MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION` is configured. Fail parsing on any other error. --- library/x509_crt.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 9bc869652..3b68f01aa 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -743,7 +743,7 @@ static int x509_get_certificate_policies( unsigned char **p, const unsigned char *end, mbedtls_x509_sequence *certificate_policies ) { - int ret; + int ret, parse_ret = 0; size_t len; mbedtls_asn1_buf *buf; mbedtls_asn1_sequence *cur = certificate_policies; @@ -787,6 +787,19 @@ static int x509_get_certificate_policies( unsigned char **p, policy_oid.len = len; policy_oid.p = *p; + /* + * Only AnyPolicy is currently supported when enforcing policy. + */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_POLICY, &policy_oid ) != 0 ) + { + /* + * Set the parsing return code but continue parsing, in case this + * extension is critical and MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * is configured. + */ + parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; + } + /* Allocate and assign next pointer */ if( cur->buf.p != NULL ) { @@ -836,7 +849,7 @@ static int x509_get_certificate_policies( unsigned char **p, return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - return( 0 ); + return( parse_ret ); } /* @@ -970,7 +983,21 @@ static int x509_get_crt_ext( unsigned char **p, /* Parse certificate policies type */ if( ( ret = x509_get_certificate_policies( p, end_ext_octet, &crt->certificate_policies ) ) != 0 ) - return( ret ); + { +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + return( ret ); + else +#endif + /* + * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, the we cannot + * interpret or enforce the policy. However, it is up to the user + * to choose how to enforce the policies, + * unless the extension is critical. + */ + if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + return( ret ); + } break; default: From 2e06a9fb24871d3c5473f2a4f0b2e67eaca133e6 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 15 May 2019 15:14:46 +0300 Subject: [PATCH 19/27] Fix ChangeLog entry Move the ChangeLog entries to correct location, and mention sppecifically the support for hardware module name othername. --- ChangeLog | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f942ebbf5..f6763fc2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,12 @@ Features Contributed by Jack Lloyd and Fortanix Inc. * Add the Wi-SUN Field Area Network (FAN) device extended key usage. * Add the oid certificate policy x509 extension. + * Add support for parsing otherName entries in the Subject Alternative Name + X.509 certificate extension, specifically type hardware module name, + as defined in RFC 4108 section 5. + * Add support for parsing certificate policies extension, as defined in + RFC 5280 section 4.2.1.4. Currently, only the "Any Policy" policy is + supported. Bugfix * Fix private key DER output in the key_app_writer example. File contents @@ -61,11 +67,6 @@ Features * Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites from the default list (enabled by default). See https://sweet32.info/SWEET32_CCS16.pdf. - * Add support for parsing otherName entries in the Subject Alternative Name - X.509 certificate extension, as defined in RFC 4108 section 5. - * Add support for parsing certificate policies extension, as defined in - RFC 5280 section 4.2.1.4. Currently, only the "Any Policy" policy is - supported. API Changes * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`. From c8b5f3f520b97dc1580f09b2850012bda184de5d Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 15 May 2019 15:15:55 +0300 Subject: [PATCH 20/27] Documentation fixes Rephrase documentation of the SAN to make it clearer. --- include/mbedtls/x509_crt.h | 18 +++++++++--------- library/x509_crt.c | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index a5deb95e0..cd3be09e0 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -78,7 +78,7 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ 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_sequence certificate_policies; /**< Optional list of certificate policies (Only anyPolicy supported). */ + mbedtls_x509_sequence certificate_policies; /**< Optional list of certificate policies (Only anyPolicy is printed and enforced, however the rest of the policies are still listed). */ int ext_types; /**< Bit string containing detected and parsed extensions */ int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ @@ -398,31 +398,31 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); #endif /* MBEDTLS_FS_IO */ /** - * \brief Parses a subject alternative name item - * to an identified structure; + * \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, + * \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 send it as parameter - * to this function. + * \p crt->subject_alt_names sequence, and pass it to + * this function. * - * \note The target structure contains pointers to the raw data of the + * \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 Negative value for any other failure. + * 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 ); diff --git a/library/x509_crt.c b/library/x509_crt.c index 3b68f01aa..701b0142d 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -618,8 +618,8 @@ static int x509_get_ext_key_usage( unsigned char **p, * nameAssigner [0] DirectoryString OPTIONAL, * partyName [1] DirectoryString } * - * NOTE: we only parse and use dNSName at this point, - * and otherName of type HwModuleName, as defined in RFC 4108. + * 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, From dbbd96652ceff314a45f23be40b3820dbd540347 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Wed, 15 May 2019 15:46:03 +0300 Subject: [PATCH 21/27] Check that SAN is not malformed when parsing Add a call to `mbedtls_x509_parse_subject_alt_name()` during certificate parsing, to verify the certificate is not malformed. --- library/x509_crt.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index 701b0142d..754a65fdf 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -642,6 +642,9 @@ static int x509_get_subject_alt_name( unsigned char **p, while( *p < end ) { + mbedtls_x509_subject_alternative_name dummy_san_buf; + memset( &dummy_san_buf, 0, sizeof( dummy_san_buf ) ); + if( ( end - *p ) < 1 ) return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); @@ -658,6 +661,29 @@ static int x509_get_subject_alt_name( unsigned char **p, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); } + /* + * Check that the SAN are structured correct. + */ + 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_x509_sequence *seq_cur = subject_alt_name->next; + mbedtls_x509_sequence *seq_prv; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + return( ret ); + } + /* Allocate and assign next pointer */ if( cur->buf.p != NULL ) { From e269537b807ce066cc31fe10f5c8d975f19c8362 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Thu, 16 May 2019 11:52:57 +0300 Subject: [PATCH 22/27] Add ChangeLog entry about listing all SAN Add a ChangeLog entry that indicates that all SAN types are now listed in the corresponding certificate field. --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index f6763fc2c..959904a33 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,8 @@ Features * Add support for parsing certificate policies extension, as defined in RFC 5280 section 4.2.1.4. Currently, only the "Any Policy" policy is supported. + * List all SAN types in the subject_alt_names field of the certificate. + Resolves #459. Bugfix * Fix private key DER output in the key_app_writer example. File contents From a29139177596aab29ea605c1f7e4fe482e63c343 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Thu, 16 May 2019 16:17:38 +0300 Subject: [PATCH 23/27] Fix minor issues 1. Typo fix. 2. Change byte by byte coipy to `memcpy`. 3. Remove parenthesis in switch cases. --- library/x509_crt.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 754a65fdf..8200374cd 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1016,9 +1016,9 @@ static int x509_get_crt_ext( unsigned char **p, else #endif /* - * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, the we cannot - * interpret or enforce the policy. However, it is up to the user - * to choose how to enforce the policies, + * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we + * cannot interpret or enforce the policy. However, it is up to + * the user to choose how to enforce the policies, * unless the extension is critical. */ if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) @@ -1737,7 +1737,6 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, *subject_alt_name, const char *prefix ) { - size_t i; int ret; size_t n = *size; char *p = *buf; @@ -1770,7 +1769,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, /* * otherName */ - case( MBEDTLS_X509_SAN_OTHER_NAME ): + case MBEDTLS_X509_SAN_OTHER_NAME: { mbedtls_x509_san_other_name *other_name = &san.san.other_name; @@ -1797,10 +1796,10 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); } - for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ ) - { - *p++ = other_name->value.hardware_module_name.val.p[i]; - } + memcpy( p, other_name->value.hardware_module_name.val.p, + other_name->value.hardware_module_name.val.len ); + p += other_name->value.hardware_module_name.val.len; + n -= other_name->value.hardware_module_name.val.len; }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ @@ -1810,7 +1809,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, /* * dNSName */ - case( MBEDTLS_X509_SAN_DNS_NAME ): + case MBEDTLS_X509_SAN_DNS_NAME: { ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; @@ -1819,9 +1818,10 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, *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; - for( i = 0; i < san.san.unstructured_name.len; i++ ) - *p++ = san.san.unstructured_name.p[i]; } break; From 11818f2c172c995d072760c0eb5b77327dc78c52 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Thu, 16 May 2019 18:17:02 +0300 Subject: [PATCH 24/27] Add some negative test cases Add some invalid certificate tests for certifiate policies extension. --- tests/suites/test_suite_x509parse.data | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 99dd0833f..e331d6184 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -1198,6 +1198,18 @@ X509 Certificate ASN1 (TBSCertificate v3, first ext invalid tag) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C x509parse_crt:"30819030818da0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba3043002310000":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG +X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, bool len missing) +depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d2001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA + +X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data missing) +depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d20042801010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA + +X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data not oid) +depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a302a0603551d200101FF0420301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA + X509 Certificate ASN1 (TBSCertificate v3, ext BasicContraint tag, bool len missing) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d1301010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA From 8a59d6b964add89108482c8235980cbdc23fd042 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Sun, 19 May 2019 12:32:15 +0300 Subject: [PATCH 25/27] Update test data Update the test data for the negative certificate policies extension tests with correct lengths, to test the correct behaviour. Add another test. --- tests/suites/test_suite_x509parse.data | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index e331d6184..e0ab4050b 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -1200,15 +1200,19 @@ x509parse_crt:"30819030818da0030201028204deadbeef300d06092a864886f70d01010205003 X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, bool len missing) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C -x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d2001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300730050603551d2001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data missing) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C -x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d20042801010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30080603551d2004010001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data not oid) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C -x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a302a0603551d200101FF0420301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30270603551d200420301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA + +X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, qualifier not complete) +depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a301F0603551d2004183020301F0603551D200418301630140604551D2000300C300A06082B0601050507020101010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA X509 Certificate ASN1 (TBSCertificate v3, ext BasicContraint tag, bool len missing) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C From 76a9c4a81fd61c48a7551b505623b5e5662a4eb5 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 20 May 2019 11:58:59 +0300 Subject: [PATCH 26/27] Fix test data Fix test data to test what it actually intends to test. --- tests/suites/test_suite_x509parse.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index e0ab4050b..ab3880a05 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -1204,11 +1204,11 @@ x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d01010205003 X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data missing) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C -x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30080603551d2004010001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG +x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30b300930070603551d20040001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data not oid) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C -x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30270603551d200420301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA +x509parse_crt:"3081bc3081b9a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba32e302c30290603551d2004223020301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, qualifier not complete) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C From 6aeae9e962b665c826fc349538eb61b90c1f69c0 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Mon, 20 May 2019 12:00:36 +0300 Subject: [PATCH 27/27] Style fix Add whitespace before parenthesis. --- library/x509_crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 8200374cd..708dbf771 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2115,7 +2115,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( ( ret = x509_info_subject_alt_name( &p, &n, &crt->subject_alt_names, - prefix) ) != 0 ) + prefix ) ) != 0 ) return( ret ); }