From d6700fd0196fce3d892ce18a6a5ae1066778e0fb Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Tue, 15 Aug 2017 15:14:16 +0100 Subject: [PATCH] Add support for AuthorityInfoAccess X509 extension --- include/mbedtls/oid.h | 5 + include/mbedtls/x509.h | 2 + include/mbedtls/x509_crt.h | 2 + library/oid.c | 24 ++++- library/x509_crt.c | 213 +++++++++++++++++++++++++++++++++---- 5 files changed, 222 insertions(+), 24 deletions(-) diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index fcecdafdca..dd23926c4e 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -172,6 +172,9 @@ */ #define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ +#define MBEDTLS_OID_PE MBEDTLS_OID_PKIX "\x01" /**< id-pe OBJECT IDENTIFIER ::= { id-pkix 1 } */ +#define MBEDTLS_OID_AUTHORITY_INFO_ACCESS MBEDTLS_OID_PE "\x01" /**< id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } */ + #define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ #define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ #define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ @@ -525,6 +528,8 @@ int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_a */ int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc ); +int mbedtls_oid_get_authority_info_access( const mbedtls_asn1_buf *oid, const char **desc ); + /** * \brief Translate md_type into hash algorithm OID * diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index d7e318dfdc..f73842a58e 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -160,6 +160,8 @@ #define MBEDTLS_X509_EXT_NS_CERT_TYPE (1 << 16) +#define MBEDTLS_X509_EXT_AUTHORITY_INFO_ACCESS (1 << 17) + /* * Storage format identifiers * Recognized formats: PEM and DER diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 06166d8b18..52c0d54591 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -74,6 +74,8 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + mbedtls_x509_sequence auth_access_descs; /**< Authority Information Access access descriptors. */ + int ext_types; /**< Bit string containing detected and parsed extensions */ int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ diff --git a/library/oid.c b/library/oid.c index f13826ed74..7cdfe585e5 100644 --- a/library/oid.c +++ b/library/oid.c @@ -259,25 +259,29 @@ typedef struct { static const oid_x509_ext_t oid_x509_ext[] = { { - { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, + { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, }, { - { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, MBEDTLS_X509_EXT_KEY_USAGE, }, { - { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, }, { - { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, }, { - { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, MBEDTLS_X509_EXT_NS_CERT_TYPE, }, + { + { ADD_LEN( MBEDTLS_OID_AUTHORITY_INFO_ACCESS ), "id-pe-authorityInfoAccess", "Authority Information Access" }, + MBEDTLS_X509_EXT_AUTHORITY_INFO_ACCESS, + }, { { NULL, 0, NULL, NULL }, 0, @@ -300,6 +304,16 @@ static const mbedtls_oid_descriptor_t oid_ext_key_usage[] = FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage) FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description) + +static const mbedtls_oid_descriptor_t oid_authority_info_access[] = +{ + /* TODO: Add more access descriptors */ + { ADD_LEN( MBEDTLS_OID_OCSP ), "id-ad-ocsp", "OCSP" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, authority_info_access, oid_authority_info_access) +FN_OID_GET_ATTR1(mbedtls_oid_get_authority_info_access, mbedtls_oid_descriptor_t, authority_info_access, const char *, description) #endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ #if defined(MBEDTLS_MD_C) diff --git a/library/x509_crt.c b/library/x509_crt.c index c6209fb40d..7ca95e28de 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -350,6 +350,90 @@ static int x509_get_basic_constraints( unsigned char **p, return( 0 ); } +/* + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + */ +static int x509_get_authority_info_access( unsigned char **p, + const unsigned char *end, + int is_critical, + mbedtls_x509_sequence *descs ) +{ + int ret; + size_t len; + unsigned char seq_tag = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE; + mbedtls_asn1_buf *buf; + mbedtls_asn1_sequence *cur = descs; + + /* + * RFC 5280 Section 4.2.2.1: Conforming CAs MUST mark this extension as + * non-critical. + */ + if( is_critical != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, seq_tag ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* TODO: Check whether this would overflow */ + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Get AccessDescriptor sequence tag and len */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, seq_tag ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* + * TODO: We should check whether the accessMethod and accessLocation + * are acceptable values. + * TODO: Check that the accessMethod and accessLocation are well + * formed. For example, it is currently possible to have: + * accessLocation.len + accessMethod.len == len, but + * len(accessLocation) != accessLocation.len + */ + + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &( cur->buf ); + buf->tag = seq_tag; + buf->p = *p; + buf->len = len; + *p += buf->len; + } + + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + static int x509_get_ns_cert_type( unsigned char **p, const unsigned char *end, unsigned char *ns_cert_type) @@ -646,6 +730,13 @@ static int x509_get_crt_ext( unsigned char **p, return( ret ); break; + case MBEDTLS_X509_EXT_AUTHORITY_INFO_ACCESS: + /* Parse Authority Information Access */ + if( ( ret = x509_get_authority_info_access( p, end_ext_octet, + is_critical, &crt->auth_access_descs ) ) != 0 ) + return( ret ); + break; + default: return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); } @@ -1354,6 +1445,70 @@ static int x509_info_ext_key_usage( char **buf, size_t *size, return( 0 ); } + +static int x509_info_authority_info_access( char **buf, size_t *size, + const mbedtls_x509_sequence *descs ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *access_method; + char access_location[128]; + const mbedtls_x509_sequence *cur = descs; + mbedtls_x509_buf x509_buf; + const char *sep = ""; + unsigned char *pos, *end; + size_t len; + + /* + * TODO: Some of the checks below are redundant if the certificate is + * checked while parsing in x509_get_authority_info_access() + */ + while( cur != NULL ) + { + pos = cur->buf.p; + end = pos + cur->buf.len; + + /* Get accessMethod */ + if( ( ret = mbedtls_asn1_get_tag( &pos, end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + x509_buf.tag = MBEDTLS_ASN1_OID; + x509_buf.p = pos; + x509_buf.len = len; + + if( mbedtls_oid_get_authority_info_access( &x509_buf, &access_method ) != 0 ) + access_method = "???"; + + pos += len; + + /* Get accessLocation */ + if( ( ret = mbedtls_asn1_get_tag( &pos, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 6 ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( sizeof( access_location ) > len ) + { + memcpy( access_location, pos, len ); + access_location[len] = '\0'; + ret = mbedtls_snprintf( p, n, "%s[%s;%s]", sep, access_method, + access_location ); + } + else + ret = mbedtls_snprintf( p, n, "%s[%s;%s]", sep, access_method, + "...too long..." ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + /* * Return an informational string about the certificate. */ @@ -1378,41 +1533,44 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } - ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", - prefix, crt->version ); + ret = mbedtls_snprintf( p, n, "%s%-" BC "s: %d\n", + prefix, "cert. version", crt->version ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "%sserial number : ", - prefix ); + ret = mbedtls_snprintf( p, n, "%s%-" BC "s: ", + prefix, "serial number" ); MBEDTLS_X509_SAFE_SNPRINTF; ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "issuer name" ); MBEDTLS_X509_SAFE_SNPRINTF; ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "subject name" ); MBEDTLS_X509_SAFE_SNPRINTF; ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, "issued on", crt->valid_from.year, crt->valid_from.mon, crt->valid_from.day, crt->valid_from.hour, crt->valid_from.min, crt->valid_from.sec ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, "expires on", crt->valid_to.year, crt->valid_to.mon, crt->valid_to.day, crt->valid_to.hour, crt->valid_to.min, crt->valid_to.sec ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "signed using" ); MBEDTLS_X509_SAFE_SNPRINTF; ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, @@ -1426,8 +1584,9 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( ret ); } - ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, - (int) mbedtls_pk_get_bitlen( &crt->pk ) ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", + prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &crt->pk ) ); MBEDTLS_X509_SAFE_SNPRINTF; /* @@ -1436,8 +1595,9 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) { - ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, - crt->ca_istrue ? "true" : "false" ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: CA=%s", + prefix, "basic constraints", + crt->ca_istrue ? "true" : "false" ); MBEDTLS_X509_SAFE_SNPRINTF; if( crt->max_pathlen > 0 ) @@ -1449,7 +1609,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { - ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "subject alt name" ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = x509_info_subject_alt_name( &p, &n, @@ -1459,7 +1620,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) { - ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "cert. type" ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) @@ -1468,7 +1630,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) { - ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "key usage" ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) @@ -1477,7 +1640,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) { - ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "ext key usage" ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = x509_info_ext_key_usage( &p, &n, @@ -1485,6 +1649,17 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( ret ); } + if( crt->ext_types & MBEDTLS_X509_EXT_AUTHORITY_INFO_ACCESS ) + { + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: ", + prefix, "authority info access" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_authority_info_access( &p, &n, + &crt->auth_access_descs ) ) != 0 ) + return( ret ); + } + ret = mbedtls_snprintf( p, n, "\n" ); MBEDTLS_X509_SAFE_SNPRINTF;