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
{
/**
* 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.

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 );
}
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 <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 @@ 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 );
}

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 */
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 */