mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-12-24 12:55:41 +00:00
Implement v3 Extension parsing through ASN.1 SEQUENCE OF traversal
This commit rewrites the v3 ext parsing routine `x509_crt_get_ext_cb()` in terms of the generic ASN.1 SEQUENCE traversal routine.
This commit is contained in:
parent
c7c638eddd
commit
f1b39bf18c
|
@ -393,7 +393,7 @@ static int x509_get_basic_constraints( unsigned char **p,
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
|
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
|
||||||
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
return( ret );
|
||||||
|
|
||||||
if( *p == end )
|
if( *p == end )
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
@ -404,7 +404,7 @@ static int x509_get_basic_constraints( unsigned char **p,
|
||||||
ret = mbedtls_asn1_get_int( p, end, ca_istrue );
|
ret = mbedtls_asn1_get_int( p, end, ca_istrue );
|
||||||
|
|
||||||
if( ret != 0 )
|
if( ret != 0 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
return( ret );
|
||||||
|
|
||||||
if( *ca_istrue != 0 )
|
if( *ca_istrue != 0 )
|
||||||
*ca_istrue = 1;
|
*ca_istrue = 1;
|
||||||
|
@ -414,11 +414,10 @@ static int x509_get_basic_constraints( unsigned char **p,
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 )
|
if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
return( ret );
|
||||||
|
|
||||||
if( *p != end )
|
if( *p != end )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
||||||
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
|
|
||||||
(*max_pathlen)++;
|
(*max_pathlen)++;
|
||||||
|
|
||||||
|
@ -433,11 +432,10 @@ static int x509_get_ns_cert_type( unsigned char **p,
|
||||||
mbedtls_x509_bitstring bs = { 0, 0, NULL };
|
mbedtls_x509_bitstring bs = { 0, 0, NULL };
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
|
if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
return( ret );
|
||||||
|
|
||||||
if( bs.len != 1 )
|
if( bs.len != 1 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
|
||||||
MBEDTLS_ERR_ASN1_INVALID_LENGTH );
|
|
||||||
|
|
||||||
/* Get actual bitstring */
|
/* Get actual bitstring */
|
||||||
*ns_cert_type = *bs.p;
|
*ns_cert_type = *bs.p;
|
||||||
|
@ -453,11 +451,10 @@ static int x509_get_key_usage( unsigned char **p,
|
||||||
mbedtls_x509_bitstring bs = { 0, 0, NULL };
|
mbedtls_x509_bitstring bs = { 0, 0, NULL };
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
|
if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
return( ret );
|
||||||
|
|
||||||
if( bs.len < 1 )
|
if( bs.len < 1 )
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
|
||||||
MBEDTLS_ERR_ASN1_INVALID_LENGTH );
|
|
||||||
|
|
||||||
/* Get actual bitstring */
|
/* Get actual bitstring */
|
||||||
*key_usage = 0;
|
*key_usage = 0;
|
||||||
|
@ -478,17 +475,8 @@ static int x509_get_ext_key_usage( unsigned char **p,
|
||||||
const unsigned char *end,
|
const unsigned char *end,
|
||||||
mbedtls_x509_sequence *ext_key_usage)
|
mbedtls_x509_sequence *ext_key_usage)
|
||||||
{
|
{
|
||||||
int ret;
|
return( mbedtls_asn1_get_sequence_of( p, end, ext_key_usage,
|
||||||
|
MBEDTLS_ASN1_OID ) );
|
||||||
if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
|
||||||
|
|
||||||
/* Sequence length must be >= 1 */
|
|
||||||
if( ext_key_usage->buf.p == NULL )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
|
||||||
MBEDTLS_ERR_ASN1_INVALID_LENGTH );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -546,162 +534,202 @@ static int x509_get_subject_alt_name( unsigned char *p,
|
||||||
const unsigned char *end,
|
const unsigned char *end,
|
||||||
mbedtls_x509_sequence *subject_alt_name )
|
mbedtls_x509_sequence *subject_alt_name )
|
||||||
{
|
{
|
||||||
int ret;
|
return( mbedtls_asn1_traverse_sequence_of( &p, end,
|
||||||
ret = mbedtls_asn1_traverse_sequence_of( &p, end,
|
MBEDTLS_ASN1_TAG_CLASS_MASK,
|
||||||
MBEDTLS_ASN1_TAG_CLASS_MASK,
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC,
|
||||||
MBEDTLS_ASN1_CONTEXT_SPECIFIC,
|
MBEDTLS_ASN1_TAG_VALUE_MASK,
|
||||||
MBEDTLS_ASN1_TAG_VALUE_MASK,
|
2 /* SubjectAlt DNS */,
|
||||||
2 /* SubjectAlt DNS */,
|
x509_get_subject_alt_name_cb,
|
||||||
x509_get_subject_alt_name_cb,
|
(void*) &subject_alt_name ) );
|
||||||
(void*) &subject_alt_name );
|
|
||||||
if( ret != 0 )
|
|
||||||
ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
|
|
||||||
return( ret );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* X.509 v3 extensions
|
* X.509 v3 extensions
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int x509_get_crt_ext( unsigned char **p,
|
static int x509_crt_get_ext_cb( void *ctx,
|
||||||
const unsigned char *end,
|
int tag,
|
||||||
mbedtls_x509_crt *crt )
|
unsigned char *p,
|
||||||
|
size_t ext_len )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
mbedtls_x509_crt *crt = (mbedtls_x509_crt *) ctx;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char *end_ext_data, *end_ext_octet;
|
unsigned char *end, *end_ext_octet;
|
||||||
|
mbedtls_x509_buf extn_oid = { 0, 0, NULL };
|
||||||
|
int is_critical = 0; /* DEFAULT FALSE */
|
||||||
|
int ext_type = 0;
|
||||||
|
|
||||||
if( *p == end )
|
((void) tag);
|
||||||
return( 0 );
|
|
||||||
|
|
||||||
if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
|
/*
|
||||||
return( ret );
|
* Extension ::= SEQUENCE {
|
||||||
|
* extnID OBJECT IDENTIFIER,
|
||||||
|
* critical BOOLEAN DEFAULT FALSE,
|
||||||
|
* extnValue OCTET STRING }
|
||||||
|
*/
|
||||||
|
|
||||||
end = crt->v3_ext.p + crt->v3_ext.len;
|
end = p + ext_len;
|
||||||
while( *p < end )
|
|
||||||
|
/* Get extension ID */
|
||||||
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &extn_oid.len,
|
||||||
|
MBEDTLS_ASN1_OID ) ) != 0 )
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
extn_oid.tag = MBEDTLS_ASN1_OID;
|
||||||
|
extn_oid.p = p;
|
||||||
|
p += extn_oid.len;
|
||||||
|
|
||||||
|
/* Get optional critical */
|
||||||
|
if( ( ret = mbedtls_asn1_get_bool( &p, end, &is_critical ) ) != 0 &&
|
||||||
|
( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) )
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Data should be octet string type */
|
||||||
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
|
||||||
|
MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
end_ext_octet = p + len;
|
||||||
|
if( end_ext_octet != end )
|
||||||
{
|
{
|
||||||
/*
|
ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
|
||||||
* Extension ::= SEQUENCE {
|
goto err;
|
||||||
* extnID OBJECT IDENTIFIER,
|
}
|
||||||
* critical BOOLEAN DEFAULT FALSE,
|
|
||||||
* extnValue OCTET STRING }
|
|
||||||
*/
|
|
||||||
mbedtls_x509_buf extn_oid = {0, 0, NULL};
|
|
||||||
int is_critical = 0; /* DEFAULT FALSE */
|
|
||||||
int ext_type = 0;
|
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
|
|
||||||
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
|
||||||
|
|
||||||
end_ext_data = *p + len;
|
|
||||||
|
|
||||||
/* Get extension ID */
|
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len,
|
|
||||||
MBEDTLS_ASN1_OID ) ) != 0 )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
|
||||||
|
|
||||||
extn_oid.tag = MBEDTLS_ASN1_OID;
|
|
||||||
extn_oid.p = *p;
|
|
||||||
*p += extn_oid.len;
|
|
||||||
|
|
||||||
/* Get optional critical */
|
|
||||||
if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 &&
|
|
||||||
( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
|
||||||
|
|
||||||
/* Data should be octet string type */
|
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len,
|
|
||||||
MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
|
|
||||||
|
|
||||||
end_ext_octet = *p + len;
|
|
||||||
|
|
||||||
if( end_ext_octet != end_ext_data )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
|
||||||
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Detect supported extensions
|
|
||||||
*/
|
|
||||||
ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type );
|
|
||||||
|
|
||||||
if( ret != 0 )
|
|
||||||
{
|
|
||||||
/* No parser found, skip extension */
|
|
||||||
*p = end_ext_octet;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect supported extensions
|
||||||
|
*/
|
||||||
|
ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type );
|
||||||
|
if( ret != 0 )
|
||||||
|
{
|
||||||
#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
|
#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
|
||||||
if( is_critical )
|
if( is_critical )
|
||||||
{
|
|
||||||
/* Data is marked as critical: fail */
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
|
||||||
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forbid repeated extensions */
|
|
||||||
if( ( crt->ext_types & ext_type ) != 0 )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
|
|
||||||
|
|
||||||
crt->ext_types |= ext_type;
|
|
||||||
|
|
||||||
switch( ext_type )
|
|
||||||
{
|
{
|
||||||
|
/* Data is marked as critical: fail */
|
||||||
|
ret = MBEDTLS_ERR_ASN1_UNEXPECTED_TAG;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forbid repeated extensions */
|
||||||
|
if( ( crt->ext_types & ext_type ) != 0 )
|
||||||
|
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
|
||||||
|
|
||||||
|
crt->ext_types |= ext_type;
|
||||||
|
switch( ext_type )
|
||||||
|
{
|
||||||
case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
|
case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
|
||||||
|
{
|
||||||
|
int ca_istrue;
|
||||||
|
int max_pathlen;
|
||||||
|
|
||||||
/* Parse basic constraints */
|
/* Parse basic constraints */
|
||||||
if( ( ret = x509_get_basic_constraints( p, end_ext_octet,
|
ret = x509_get_basic_constraints( &p, end_ext_octet,
|
||||||
&crt->ca_istrue, &crt->max_pathlen ) ) != 0 )
|
&ca_istrue,
|
||||||
return( ret );
|
&max_pathlen );
|
||||||
|
if( ret != 0 )
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
crt->ca_istrue = ca_istrue;
|
||||||
|
crt->max_pathlen = max_pathlen;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MBEDTLS_X509_EXT_KEY_USAGE:
|
case MBEDTLS_X509_EXT_KEY_USAGE:
|
||||||
/* Parse key usage */
|
/* Parse key usage */
|
||||||
if( ( ret = x509_get_key_usage( p, end_ext_octet,
|
ret = x509_get_key_usage( &p, end_ext_octet,
|
||||||
&crt->key_usage ) ) != 0 )
|
&crt->key_usage );
|
||||||
|
if( ret != 0 )
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
|
||||||
|
/* Copy reference to raw subject alt name data. */
|
||||||
|
crt->subject_alt_raw.p = p;
|
||||||
|
crt->subject_alt_raw.len = end_ext_octet - p;
|
||||||
|
if( ( ret = x509_get_subject_alt_name( p, end_ext_octet,
|
||||||
|
&crt->subject_alt_names ) ) != 0 )
|
||||||
|
{
|
||||||
return( ret );
|
return( ret );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
|
case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
|
||||||
/* Parse extended key usage */
|
/* Parse extended key usage */
|
||||||
crt->ext_key_usage_raw.p = *p;
|
crt->ext_key_usage_raw.p = p;
|
||||||
crt->ext_key_usage_raw.len = end_ext_octet - *p;
|
crt->ext_key_usage_raw.len = end_ext_octet - p;
|
||||||
if( ( ret = x509_get_ext_key_usage( p, end_ext_octet,
|
if( ( ret = x509_get_ext_key_usage( &p, end_ext_octet,
|
||||||
&crt->ext_key_usage ) ) != 0 )
|
&crt->ext_key_usage ) ) != 0 )
|
||||||
return( ret );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
|
|
||||||
/* Parse subject alt name */
|
|
||||||
crt->subject_alt_raw.p = *p;
|
|
||||||
crt->subject_alt_raw.len = end_ext_octet - *p;
|
|
||||||
if( ( ret = x509_get_subject_alt_name( *p, end_ext_octet,
|
|
||||||
&crt->subject_alt_names ) ) != 0 )
|
|
||||||
{
|
{
|
||||||
return( ret );
|
return( ret );
|
||||||
}
|
}
|
||||||
*p = end_ext_octet;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBEDTLS_X509_EXT_NS_CERT_TYPE:
|
case MBEDTLS_X509_EXT_NS_CERT_TYPE:
|
||||||
/* Parse netscape certificate type */
|
/* Parse netscape certificate type */
|
||||||
if( ( ret = x509_get_ns_cert_type( p, end_ext_octet,
|
ret = x509_get_ns_cert_type( &p, end_ext_octet,
|
||||||
&crt->ns_cert_type ) ) != 0 )
|
&crt->ns_cert_type );
|
||||||
return( ret );
|
if( ret != 0 )
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
|
/*
|
||||||
}
|
* If this is a non-critical extension, which the oid layer
|
||||||
|
* supports, but there isn't an X.509 parser for it,
|
||||||
|
* skip the extension.
|
||||||
|
*/
|
||||||
|
#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
|
||||||
|
if( is_critical )
|
||||||
|
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
|
||||||
|
#endif
|
||||||
|
p = end_ext_octet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( *p != end )
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
|
|
||||||
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
|
||||||
|
err:
|
||||||
|
return( ret );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int x509_get_crt_ext( unsigned char **p,
|
||||||
|
unsigned char *end,
|
||||||
|
mbedtls_x509_crt *crt )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if( *p == end )
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
ret = mbedtls_asn1_get_tag( p, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 );
|
||||||
|
if( ret != 0 )
|
||||||
|
{
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = *p + len;
|
||||||
|
ret = mbedtls_asn1_traverse_sequence_of( p, end,
|
||||||
|
0xFF, MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED,
|
||||||
|
0, 0, x509_crt_get_ext_cb, crt );
|
||||||
|
if( ret != 0 )
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err:
|
||||||
|
|
||||||
|
if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
|
||||||
|
return( ret );
|
||||||
|
if( ret == MBEDTLS_ERR_X509_INVALID_EXTENSIONS )
|
||||||
|
return( ret );
|
||||||
|
|
||||||
|
if( ret != 0 )
|
||||||
|
ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
|
||||||
|
|
||||||
|
return( ret );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue