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.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index dbfaf9c..b321c42 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -107,6 +107,11 @@
*/
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 @@
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 @@
#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 9777726..cce230b 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1632,6 +1632,12 @@
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 @@
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 @@
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 <unsupported>", prefix );
+ MBEDTLS_X509_SAFE_SNPRINTF;
+ }
+ else
+ {
+ ret = mbedtls_snprintf( p, n, "\n%s <malformed>", 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, " <unsupported>" );
- MBEDTLS_X509_SAFE_SNPRINTF;
- }
- else
- {
- ret = mbedtls_snprintf( p, n, " <malformed>" );
- 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 <unsupported>", prefix );
@@ -1805,102 +1794,53 @@
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 beec52c..b4e9802 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -303,8 +303,10 @@
/* 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 @@
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 */