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.
This commit is contained in:
Ron Eldor 2019-05-13 19:03:04 +03:00
parent 0806379e3e
commit 890819a597
3 changed files with 151 additions and 196 deletions

View File

@ -107,6 +107,11 @@ mbedtls_x509_crt;
*/ */
typedef struct mbedtls_x509_san_other_name 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. */ mbedtls_x509_buf type_id; /**< The type id. */
union 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 */ mbedtls_x509_buf unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */
} }
san; /**< A union of the supported SAN types */ 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; 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 */ #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_buf The buffer holding the raw data item of the subject
* \param san A list holding the parsed certificate. * 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. * 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 * \return \c 0 on success
* and it is the caller's responsibility to free it. * \return #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported
* * SAN type
* \return Zero for success and negative * \return Negative value for any other failure.
* value for any other failure.
*/ */
int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf,
mbedtls_x509_subject_alternative_name **san ); mbedtls_x509_subject_alternative_name *san );
/** /**
* \brief Returns an informational string about the * \brief Returns an informational string about the
* certificate. * certificate.

View File

@ -1632,6 +1632,12 @@ static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name,
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); 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; p += len;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) 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.p = p;
other_name->value.hardware_module_name.oid.len = len; 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; p += len;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) 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.tag = MBEDTLS_ASN1_OCTET_STRING;
other_name->value.hardware_module_name.val.p = p; other_name->value.hardware_module_name.val.p = p;
other_name->value.hardware_module_name.val.len = len; other_name->value.hardware_module_name.val.len = len;
other_name->value.hardware_module_name.next = NULL; other_name->value.hardware_module_name.next = NULL;
other_name->value.hardware_module_name.next_merged = 0; other_name->value.hardware_module_name.next_merged = 0;
p += len; p += len;
if( p != end ) 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 ); return( 0 );
} }
@ -1686,107 +1691,91 @@ static int x509_info_subject_alt_name( char **buf, size_t *size,
size_t n = *size; size_t n = *size;
char *p = *buf; char *p = *buf;
const mbedtls_x509_sequence *cur = subject_alt_name; const mbedtls_x509_sequence *cur = subject_alt_name;
mbedtls_x509_subject_alternative_name san;
int parse_ret;
while( cur != NULL ) while( cur != NULL )
{ {
switch( cur->buf.tag & memset( &san, 0, sizeof( san ) );
( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) 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 * 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; ret = mbedtls_snprintf( p, n, "\n%s hardware module name :", prefix );
MBEDTLS_X509_SAFE_SNPRINTF;
int parse_ret = x509_get_other_name( &cur->buf, ret = mbedtls_snprintf( p, n, "\n%s hardware type : ", prefix );
&other_name );
ret = mbedtls_snprintf( p, n, "\n%s otherName :",
prefix );
MBEDTLS_X509_SAFE_SNPRINTF; MBEDTLS_X509_SAFE_SNPRINTF;
if( parse_ret != 0 ) ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid );
{ MBEDTLS_X509_SAFE_SNPRINTF;
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;
}
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, for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ )
&other_name.value.hardware_module_name.oid )
!= 0 )
{ {
ret = mbedtls_snprintf( p, n, "\n%s " *p++ = other_name->value.hardware_module_name.val.p[i];
"hardware module name :", }
prefix ); n -= other_name->value.hardware_module_name.val.len;
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, }/* MBEDTLS_OID_ON_HW_MODULE_NAME */
&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 );
}
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 * 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 ); ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix );
MBEDTLS_X509_SAFE_SNPRINTF; MBEDTLS_X509_SAFE_SNPRINTF;
if( san.san.unstructured_name.len >= n )
if( cur->buf.len >= n )
{ {
*p = '\0'; *p = '\0';
return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
} }
n -= san.san.unstructured_name.len;
n -= cur->buf.len; for( i = 0; i < san.san.unstructured_name.len; i++ )
for( i = 0; i < cur->buf.len; i++ ) *p++ = san.san.unstructured_name.p[i];
*p++ = cur->buf.p[i]; }
break;
break;
/* /*
* Type not supported. * Type not supported, skip item.
*/ */
default: default:
ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix ); ret = mbedtls_snprintf( p, n, "\n%s <unsupported>", prefix );
@ -1805,102 +1794,53 @@ static int x509_info_subject_alt_name( char **buf, size_t *size,
return( 0 ); return( 0 );
} }
int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt, int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf,
mbedtls_x509_subject_alternative_name **san ) mbedtls_x509_subject_alternative_name *san )
{ {
int ret; int ret;
const mbedtls_x509_sequence *cur = &crt->subject_alt_names; switch( san_buf->tag &
mbedtls_x509_subject_alternative_name *cur_san = *san, *prev_san = NULL; ( MBEDTLS_ASN1_TAG_CLASS_MASK |
MBEDTLS_ASN1_TAG_VALUE_MASK ) )
if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
{ {
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 & memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) );
( MBEDTLS_ASN1_TAG_CLASS_MASK | san->type = MBEDTLS_X509_SAN_DNS_NAME;
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 ); memcpy( &san->san.unstructured_name,
if( ret != 0 ) san_buf, sizeof( *san_buf ) );
{
/*
* 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;
cur = cur->next; }
continue; break;
}
cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) ); /*
if( cur_san == NULL ) * Type not supported
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + */
MBEDTLS_ERR_ASN1_ALLOC_FAILED ); default:
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
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 */
return( 0 ); return( 0 );
} }

View File

@ -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 */ /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
void x509_parse_san( char * crt_file, char * result_str ) void x509_parse_san( char * crt_file, char * result_str )
{ {
int ret;
mbedtls_x509_crt crt; 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 buf[2000];
char *p = buf; char *p = buf;
size_t n = sizeof( buf ); size_t n = sizeof( buf );
@ -313,24 +315,27 @@ void x509_parse_san( char * crt_file, char * result_str )
memset( buf, 0, 2000 ); memset( buf, 0, 2000 );
TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
TEST_ASSERT( mbedtls_x509_parse_subject_alternative_name( &crt, &san ) == 0 );
cur = san; if( crt.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
while( cur != NULL )
{ {
TEST_ASSERT( verify_parse_san( cur, &p, &n ) == 0 ); cur = &crt.subject_alt_names;
cur = cur->next; 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 ); TEST_ASSERT( strcmp( buf, result_str ) == 0 );
exit: exit:
for( cur = san; cur != NULL; cur = next )
{
next = cur->next;
mbedtls_free( cur );
}
mbedtls_x509_crt_free( &crt ); mbedtls_x509_crt_free( &crt );
} }
/* END_CASE */ /* END_CASE */