diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index dbfaf9c08a..b321c4233c 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 9777726761..cce230bd26 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 beec52cc3d..b4e9802101 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 */