From cd03bb2048884fb8015d758c081ac69198456e4e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 15 Feb 2019 17:15:53 +0000 Subject: [PATCH 001/140] Introduce helper functions to free X.509 names and sequences `mbedtls_x509_name` and `mbedtls_x509_sequence` are dynamically allocated linked lists that need a loop to free properly. Introduce a static helper function to do that and use it in `mbedtls_x509_crt_free()`, where the CRT's issuer and subject names (of type `mbedtls_x509_name`) and the SubjectAlternativeName and ExtendedKeyUsage extensions (of type `mbedtls_x509_sequence`) need freeing. Increases code-clarity and saves a few bytes of flash. --- library/x509_crt.c | 68 ++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index e4a35f64d..93729986f 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2641,14 +2641,33 @@ void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) /* * Unallocate all certificate data */ + +static void x509_free_sequence( mbedtls_x509_sequence *seq ) +{ + while( seq != NULL ) + { + mbedtls_x509_sequence *next = seq->next; + mbedtls_platform_zeroize( seq, sizeof( *seq ) ); + mbedtls_free( seq ); + seq = next; + } +} + +static void x509_free_name( mbedtls_x509_name *name ) +{ + while( name != NULL ) + { + mbedtls_x509_name *next = name->next; + mbedtls_platform_zeroize( name, sizeof( *name ) ); + mbedtls_free( name ); + name = next; + } +} + void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { mbedtls_x509_crt *cert_cur = crt; mbedtls_x509_crt *cert_prv; - mbedtls_x509_name *name_cur; - mbedtls_x509_name *name_prv; - mbedtls_x509_sequence *seq_cur; - mbedtls_x509_sequence *seq_prv; if( crt == NULL ) return; @@ -2661,43 +2680,10 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) mbedtls_free( cert_cur->sig_opts ); #endif - name_cur = cert_cur->issuer.next; - while( name_cur != NULL ) - { - name_prv = name_cur; - name_cur = name_cur->next; - mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); - mbedtls_free( name_prv ); - } - - name_cur = cert_cur->subject.next; - while( name_cur != NULL ) - { - name_prv = name_cur; - name_cur = name_cur->next; - mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); - mbedtls_free( name_prv ); - } - - seq_cur = cert_cur->ext_key_usage.next; - while( seq_cur != NULL ) - { - seq_prv = seq_cur; - seq_cur = seq_cur->next; - mbedtls_platform_zeroize( seq_prv, - sizeof( mbedtls_x509_sequence ) ); - mbedtls_free( seq_prv ); - } - - seq_cur = cert_cur->subject_alt_names.next; - while( seq_cur != NULL ) - { - seq_prv = seq_cur; - seq_cur = seq_cur->next; - mbedtls_platform_zeroize( seq_prv, - sizeof( mbedtls_x509_sequence ) ); - mbedtls_free( seq_prv ); - } + x509_free_name( cert_cur->issuer.next ); + x509_free_name( cert_cur->subject.next ); + x509_free_sequence( cert_cur->ext_key_usage.next ); + x509_free_sequence( cert_cur->subject_alt_names.next ); if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) { From 81bb4d0378e2bc8161a311cd3cac75f6c4665609 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sat, 16 Feb 2019 11:03:48 +0000 Subject: [PATCH 002/140] Simplify server-side ssl_decrypt_encrypted_pms() The server-side routine `ssl_decrypt_encrypted_pms()` is responsible for decrypting the RSA-encrypted PMS in case of an RSA-based ciphersuite. Previously, the code checked that the length of the PMS sent by the client matches the bit length of the RSA key. This commit removes this check -- thereby removing the need to access the server's own CRT -- because the RSA decryption routine performs this check itself, too. --- library/ssl_srv.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index a8821f319..e886cd36a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3607,9 +3607,8 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, size_t peer_pmssize ) { int ret; + size_t len = (size_t)( end - p ); /* Cast is safe because p <= end. */ mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl ); - mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; - size_t len = mbedtls_pk_get_len( public_key ); #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /* If we have already started decoding the message and there is an ongoing @@ -3627,12 +3626,17 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, */ #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_SSL3) if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ { - if ( p + 2 > end ) { + if( len < 2 ) + { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); } + len -= 2; + if( *p++ != ( ( len >> 8 ) & 0xFF ) || *p++ != ( ( len ) & 0xFF ) ) { @@ -3642,12 +3646,6 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, } #endif - if( p + len != end ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); - } - /* * Decrypt the premaster secret */ From 74b89f605116fec08bc9f67746639e2b5fe82c24 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sun, 17 Feb 2019 21:22:07 +0000 Subject: [PATCH 003/140] Use private key to check suitability of PK type when picking srv CRT The server-side routine `ssl_pick_cert()` is responsible for picking a suitable CRT from the list of CRTs configured on the server. For that, it previously used the public key context from the certificate to check whether its type (including the curve type for ECC keys) suits the ciphersuite and the client's preferences. This commit changes the code to instead use the PK context holding the corresponding private key. For inferring the type of the key, this makes no difference, and it removes a PK-from-CRT extraction step which, if CRTs are stored raw, is costly in terms of computation and memory: CRTs need to be parsed, and memory needs to be allocated for the PK context. --- library/ssl_srv.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index e886cd36a..8ac7dd49b 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -797,10 +797,19 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, for( cur = list; cur != NULL; cur = cur->next ) { - MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", - cur->cert ); +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /* ASYNC_PRIVATE may use a NULL entry for the opaque private key, so + * we have to use the public key context to infer the capabilities + * of the key. */ + mbedtls_pk_context *pk = &cur->cert->pk; +#else + /* Outside of ASYNC_PRIVATE, use private key context directly + * instead of querying for the public key context from the + * certificate, so save a few bytes of code. */ + mbedtls_pk_context *pk = cur->key; +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ - if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) ) + if( ! mbedtls_pk_can_do( pk, pk_alg ) ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); continue; @@ -824,7 +833,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ECDSA_C) if( pk_alg == MBEDTLS_PK_ECDSA && - ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 ) + ssl_check_key_curve( pk, ssl->handshake->curves ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); continue; From ace04a6dc3dd079935163ce4d566ef960fd3d1d9 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 09:35:34 +0000 Subject: [PATCH 004/140] Move bounds check into ASN.1 parsing function `x509_get_attr_type_value()` checks for the presence of a tag byte and reads and stores it before calling `mbedtls_asn1_get_tag()` which fails if either the tag byte is not present or not as expected. Therefore, the manual check can be removed and left to `mbedtls_asn1_get_tag()`, and the tag can be hardcoded after the call succeeded. This saves a few bytes of code. --- library/x509.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/x509.c b/library/x509.c index 858dd904e..2e7bd5710 100644 --- a/library/x509.c +++ b/library/x509.c @@ -362,17 +362,12 @@ static int x509_get_attr_type_value( unsigned char **p, return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); end = *p + len; - - if( ( end - *p ) < 1 ) - return( MBEDTLS_ERR_X509_INVALID_NAME + - MBEDTLS_ERR_ASN1_OUT_OF_DATA ); - oid = &cur->oid; - oid->tag = **p; if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + oid->tag = MBEDTLS_ASN1_OID; oid->p = *p; *p += oid->len; From b40dc58a831284dce9f85104409c73f4574d6d0d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 09:38:45 +0000 Subject: [PATCH 005/140] Introduce a helper macro to check for ASN.1 string tags This commit introduces a macro `MBEDTLS_ASN1_IS_STRING_TAG` that can be used to check if an ASN.1 tag is among the list of string tags: - MBEDTLS_ASN1_BMP_STRING - MBEDTLS_ASN1_UTF8_STRING - MBEDTLS_ASN1_T61_STRING - MBEDTLS_ASN1_IA5_STRING - MBEDTLS_ASN1_UNIVERSAL_STRING - MBEDTLS_ASN1_PRINTABLE_STRING - MBEDTLS_ASN1_BIT_STRING --- include/mbedtls/asn1.h | 12 ++++++++++++ library/x509.c | 7 +++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h index 96c1c9a8a..2fb6de0a5 100644 --- a/include/mbedtls/asn1.h +++ b/include/mbedtls/asn1.h @@ -89,6 +89,18 @@ #define MBEDTLS_ASN1_CONSTRUCTED 0x20 #define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80 +/* Slightly smaller way to check if tag is a string tag + * compared to canonical implementation. */ +#define MBEDTLS_ASN1_IS_STRING_TAG( tag ) \ + ( ( tag ) < 32u && ( \ + ( ( 1u << ( tag ) ) & ( ( 1u << MBEDTLS_ASN1_BMP_STRING ) | \ + ( 1u << MBEDTLS_ASN1_UTF8_STRING ) | \ + ( 1u << MBEDTLS_ASN1_T61_STRING ) | \ + ( 1u << MBEDTLS_ASN1_IA5_STRING ) | \ + ( 1u << MBEDTLS_ASN1_UNIVERSAL_STRING ) | \ + ( 1u << MBEDTLS_ASN1_PRINTABLE_STRING ) | \ + ( 1u << MBEDTLS_ASN1_BIT_STRING ) ) ) != 0 ) ) + /* * Bit masks for each of the components of an ASN.1 tag as specified in * ITU X.690 (08/2015), section 8.1 "General rules for encoding", diff --git a/library/x509.c b/library/x509.c index 2e7bd5710..9d9db2341 100644 --- a/library/x509.c +++ b/library/x509.c @@ -375,12 +375,11 @@ static int x509_get_attr_type_value( unsigned char **p, return( MBEDTLS_ERR_X509_INVALID_NAME + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); - if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && - **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && - **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && - **p != MBEDTLS_ASN1_BIT_STRING ) + if( !MBEDTLS_ASN1_IS_STRING_TAG( **p ) ) + { return( MBEDTLS_ERR_X509_INVALID_NAME + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } val = &cur->val; val->tag = *(*p)++; From 3470d592ce2df8affc9d1bb07a298811646c14a0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 09:45:17 +0000 Subject: [PATCH 006/140] Simplify implementation of mbedtls_x509_get_name() X.509 names in ASN.1 are encoded as ASN.1 SEQUENCEs of ASN.1 SETs of Attribute-Value pairs, one for each component in the name. (For example, there could be an Attribute-Value pair for "DN=www.mbedtls.org"). So far, `mbedtls_x509_get_name()` parsed such names by two nested loops, the outer one traversing the outer ASN.1 SEQUENCE and the inner one the ASN.1 SETs. This commit introduces a helper function `x509_set_sequence_iterate()` which implements an iterator through an ASN.1 name buffer; the state of the iterator is a triple consisting of - the current read pointer - the end of the current SET - the end of the name buffer The iteration step reads a new SET if the current read pointer has reached the end of the current SET, and afterwards reads the next AttributeValue pair. This way, iteration through the X.509 name data can be implemented in a single loop, which increases readability and slightly reduces the code-size. --- library/x509.c | 84 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/library/x509.c b/library/x509.c index 9d9db2341..8f809ab55 100644 --- a/library/x509.c +++ b/library/x509.c @@ -350,30 +350,31 @@ int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, */ static int x509_get_attr_type_value( unsigned char **p, const unsigned char *end, - mbedtls_x509_name *cur ) + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val ) { int ret; size_t len; - mbedtls_x509_buf *oid; - mbedtls_x509_buf *val; if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); end = *p + len; - oid = &cur->oid; - if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) + ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ); + if( ret != 0 ) return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); oid->tag = MBEDTLS_ASN1_OID; oid->p = *p; *p += oid->len; - if( ( end - *p ) < 1 ) + if( *p == end ) + { return( MBEDTLS_ERR_X509_INVALID_NAME + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + } if( !MBEDTLS_ASN1_IS_STRING_TAG( **p ) ) { @@ -381,7 +382,6 @@ static int x509_get_attr_type_value( unsigned char **p, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); } - val = &cur->val; val->tag = *(*p)++; if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) @@ -395,9 +395,6 @@ static int x509_get_attr_type_value( unsigned char **p, return( MBEDTLS_ERR_X509_INVALID_NAME + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } - - cur->next = NULL; - return( 0 ); } @@ -424,57 +421,62 @@ static int x509_get_attr_type_value( unsigned char **p, * same set so that they are "merged" together in the functions that consume * this list, eg mbedtls_x509_dn_gets(). */ -int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, - mbedtls_x509_name *cur ) +static int x509_set_sequence_iterate( unsigned char **p, + unsigned char const **end_set, + unsigned char const *end, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val ) + { int ret; size_t set_len; - const unsigned char *end_set; - /* don't use recursion, we'd risk stack overflow if not optimized */ - while( 1 ) + if( *p == *end_set ) { - /* - * parse SET - */ - if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) + /* Parse next TLV of ASN.1 SET structure. */ + ret = mbedtls_asn1_get_tag( p, end, &set_len, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ); + if( ret != 0 ) return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); - end_set = *p + set_len; + *end_set = *p + set_len; + } - while( 1 ) - { - if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) - return( ret ); + return( x509_get_attr_type_value( p, *end_set, oid, val ) ); +} - if( *p == end_set ) - break; +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + const unsigned char *end_set; - /* Mark this item as being no the only one in a set */ + end_set = *p; + while( 1 ) + { + ret = x509_set_sequence_iterate( p, &end_set, end, + &cur->oid, &cur->val ); + if( ret != 0 ) + return( ret ); + + if( *p != end_set ) cur->next_merged = 1; - cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); - - if( cur->next == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); - - cur = cur->next; + if( *p == end ) + { + cur->next = NULL; + break; } - /* - * continue until end of SEQUENCE is reached - */ - if( *p == end ) - return( 0 ); - cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); - if( cur->next == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); cur = cur->next; } + + return( 0 ); } static int x509_parse_int( unsigned char **p, size_t n, int *res ) From 30cb1ac23eac08bd3dafc331262dfe589ecf28b8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 11:30:29 +0000 Subject: [PATCH 007/140] Reduce code-size of mbedtls_x509_get_name() Consider the following code-template: int beef(); static int foo() { /* ... */ ret = beef(); if( ret != 0 ) return( ret + HIGH_LEVEL ); /* ... */ } int bar() { /* ... */ ret = foo(); if( ret != 0 ) ... /* ... */ } This leads to slightly larger code than expected, because when the compiler inlines foo() into bar(), the sequence of return sequences cannot be squashed, because compiler might not have knowledge that the wrapping `ret + HIGH_LEVEL` of the return value of beef() doesn't lead to foo() returning 0. This can be avoided by performing error code wrapping in nested functions calls at the top of the call chain. This commit applies this slight optimization to mbedtls_x509_get_name(). It also moves various return statements into a single exit section, again with the intend to save code. --- library/x509.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/library/x509.c b/library/x509.c index 8f809ab55..aeabdd3fa 100644 --- a/library/x509.c +++ b/library/x509.c @@ -356,15 +356,17 @@ static int x509_get_attr_type_value( unsigned char **p, int ret; size_t len; - if( ( ret = mbedtls_asn1_get_tag( p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + goto exit; end = *p + len; ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ); if( ret != 0 ) - return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + goto exit; oid->tag = MBEDTLS_ASN1_OID; oid->p = *p; @@ -372,30 +374,30 @@ static int x509_get_attr_type_value( unsigned char **p, if( *p == end ) { - return( MBEDTLS_ERR_X509_INVALID_NAME + - MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + ret = MBEDTLS_ERR_ASN1_OUT_OF_DATA; + goto exit; } if( !MBEDTLS_ASN1_IS_STRING_TAG( **p ) ) { - return( MBEDTLS_ERR_X509_INVALID_NAME + - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + ret = MBEDTLS_ERR_ASN1_UNEXPECTED_TAG; + goto exit; } val->tag = *(*p)++; - if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + ret = mbedtls_asn1_get_len( p, end, &val->len ); + if( ret != 0 ) + goto exit; val->p = *p; *p += val->len; if( *p != end ) - { - return( MBEDTLS_ERR_X509_INVALID_NAME + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - } - return( 0 ); + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + +exit: + return( ret ); } /* @@ -438,12 +440,15 @@ static int x509_set_sequence_iterate( unsigned char **p, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ); if( ret != 0 ) - return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + goto exit; *end_set = *p + set_len; } - return( x509_get_attr_type_value( p, *end_set, oid, val ) ); + ret = x509_get_attr_type_value( p, *end_set, oid, val ); + +exit: + return( ret ); } int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, @@ -458,7 +463,7 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, ret = x509_set_sequence_iterate( p, &end_set, end, &cur->oid, &cur->val ); if( ret != 0 ) - return( ret ); + return( ret + MBEDTLS_ERR_X509_INVALID_NAME ); if( *p != end_set ) cur->next_merged = 1; From b5419867cdc84acd58b750f1278806287a14caa1 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 14:20:45 +0000 Subject: [PATCH 008/140] Reduce code-size of mbedtls_asn1_get_alg() The previous code - checked that at least 1 byte of ASN.1 tag data is available, - read and stored that ASN.1 tag, - called the ASN.1 parsing function, part of which is checking that enough space is available and that the ASN.1 tag matches the expected value MBEDTLS_ASN1_OID. Since the ASN.1 parsing function includes bounds checks, this can be streamlined to: - call the ASN.1 parsing function directly, - on success, store MBEDTLS_ASN1_OID in the tag field. This commit applies this simplification to mbedtls_asn1_get_alg(). --- library/asn1parse.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/asn1parse.c b/library/asn1parse.c index 171c340b8..b844fc69e 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -295,15 +295,12 @@ int mbedtls_asn1_get_alg( unsigned char **p, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( ret ); - if( ( end - *p ) < 1 ) - return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); - - alg->tag = **p; end = *p + len; if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) return( ret ); + alg->tag = MBEDTLS_ASN1_OID; alg->p = *p; *p += alg->len; From f226998fa25f5a3cd17eb48b542fa36907dc8b37 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 14:43:55 +0000 Subject: [PATCH 009/140] Reduce code-size of mbedtls_asn1_get_sequence_of() Reduce nesting of branches and remove unnecessary check at the end of the routine. --- library/asn1parse.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/library/asn1parse.c b/library/asn1parse.c index b844fc69e..dffc67fb3 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -251,7 +251,7 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p, if( *p + len != end ) return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - while( *p < end ) + while( 1 ) { buf = &(cur->buf); buf->tag = **p; @@ -262,25 +262,20 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p, buf->p = *p; *p += buf->len; - /* Allocate and assign next pointer */ - if( *p < end ) + if( *p == end ) { - cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, - sizeof( mbedtls_asn1_sequence ) ); - - if( cur->next == NULL ) - return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - - cur = cur->next; + cur->next = NULL; + break; } + + cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, + sizeof( mbedtls_asn1_sequence ) ); + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; } - /* Set final sequence entry's next pointer to NULL */ - cur->next = NULL; - - if( *p != end ) - return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - return( 0 ); } From 83cd8676faa81d1a4e5e66e2877a0d1322b653f7 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 17:13:46 +0000 Subject: [PATCH 010/140] Remove `sig_oid` parameter from mbedtls_x509_sig_alg_gets() The function `mbedtls_x509_sig_alg_gets()` previously needed the raw ASN.1 OID string even though it is implicit in the PK and MD parameters. This commit modifies `mbedtls_x509_sig_alg_gets()` to infer the OID and remove it from the parameters. This will be needed for the new X.509 CRT structure which will likely not store the signature OID. Care has to be taken to handle the case of RSASSA-PSS correctly, where the hash algorithm in the OID list is set to MBEDTLS_MD_NONE because it's only determined by the algorithm parameters. --- include/mbedtls/x509.h | 3 ++- library/x509.c | 28 +++++++++++++++++++++------- library/x509_crl.c | 4 ++-- library/x509_crt.c | 4 ++-- library/x509_csr.c | 4 ++-- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index ff06d13b3..6a6fd028b 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -305,8 +305,9 @@ int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); + #if !defined(MBEDTLS_X509_REMOVE_INFO) -int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, const void *sig_opts ); #endif diff --git a/library/x509.c b/library/x509.c index aeabdd3fa..58cd871be 100644 --- a/library/x509.c +++ b/library/x509.c @@ -841,20 +841,34 @@ int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *se /* * Helper for writing signature algorithms */ -int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, - mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, - const void *sig_opts ) +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, mbedtls_pk_type_t pk_alg, + mbedtls_md_type_t md_alg, const void *sig_opts ) { int ret; char *p = buf; size_t n = size; const char *desc = NULL; + mbedtls_x509_buf sig_oid; + mbedtls_md_type_t tmp_md_alg = md_alg; - ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); - if( ret != 0 ) - ret = mbedtls_snprintf( p, n, "???" ); - else +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + /* The hash for RSASSA is determined by the algorithm parameters; + * in the OID list, the hash is set to MBEDTLS_MD_NONE. */ + if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) + tmp_md_alg = MBEDTLS_MD_NONE; +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + sig_oid.tag = MBEDTLS_ASN1_OID; + ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, tmp_md_alg, + (const char**) &sig_oid.p, + &sig_oid.len ); + if( ret == 0 && + mbedtls_oid_get_sig_alg_desc( &sig_oid, &desc ) == 0 ) + { ret = mbedtls_snprintf( p, n, "%s", desc ); + } + else + ret = mbedtls_snprintf( p, n, "???" ); MBEDTLS_X509_SAFE_SNPRINTF; #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) diff --git a/library/x509_crl.c b/library/x509_crl.c index 4f5507f0e..a56d5e3e8 100644 --- a/library/x509_crl.c +++ b/library/x509_crl.c @@ -690,8 +690,8 @@ int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md, - crl->sig_opts ); + ret = mbedtls_x509_sig_alg_gets( p, n, crl->sig_pk, + crl->sig_md, crl->sig_opts ); MBEDTLS_X509_SAFE_SNPRINTF; ret = mbedtls_snprintf( p, n, "\n" ); diff --git a/library/x509_crt.c b/library/x509_crt.c index 93729986f..f1f5473ff 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1606,8 +1606,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, - crt->sig_md, crt->sig_opts ); + ret = mbedtls_x509_sig_alg_gets( p, n, sig_info.sig_pk, + sig_info.sig_md, sig_info.sig_opts ); MBEDTLS_X509_SAFE_SNPRINTF; /* Key size */ diff --git a/library/x509_csr.c b/library/x509_csr.c index aa519fb93..d1a276041 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -357,8 +357,8 @@ int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md, - csr->sig_opts ); + ret = mbedtls_x509_sig_alg_gets( p, n, csr->sig_pk, + csr->sig_md, csr->sig_opts ); MBEDTLS_X509_SAFE_SNPRINTF; if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, From 88de342c9521a80f58a12ab332aa826244f21cc6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 12:41:55 +0000 Subject: [PATCH 011/140] Move x509_name_cmp() from x509_crt.c to x509.c This is to prepare a subsequent rewrite of `x509_name_cmp()` in terms of the X.509 name traversal helper `x509_set_sequence_iterate()` from `x509.c`. --- include/mbedtls/x509.h | 3 ++ library/x509.c | 99 +++++++++++++++++++++++++++++++++++++ library/x509_crt.c | 109 +++-------------------------------------- 3 files changed, 108 insertions(+), 103 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 6a6fd028b..e6781b699 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -303,6 +303,9 @@ int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, mbedtls_x509_time *t ); int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial ); +int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, + const mbedtls_x509_name *b ); +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); diff --git a/library/x509.c b/library/x509.c index 58cd871be..fd9274743 100644 --- a/library/x509.c +++ b/library/x509.c @@ -484,6 +484,105 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, return( 0 ); } +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, + const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + mbedtls_x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, + const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + static int x509_parse_int( unsigned char **p, size_t n, int *res ) { *res = 0; diff --git a/library/x509_crt.c b/library/x509_crt.c index f1f5473ff..6bec4d024 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -227,35 +227,6 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, return( -1 ); } -/* - * Like memcmp, but case-insensitive and always returns -1 if different - */ -static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) -{ - size_t i; - unsigned char diff; - const unsigned char *n1 = s1, *n2 = s2; - - for( i = 0; i < len; i++ ) - { - diff = n1[i] ^ n2[i]; - - if( diff == 0 ) - continue; - - if( diff == 32 && - ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || - ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) - { - continue; - } - - return( -1 ); - } - - return( 0 ); -} - /* * Return 0 if name matches wildcard, -1 otherwise */ @@ -281,7 +252,7 @@ static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) return( -1 ); if( cn_len - cn_idx == name->len - 1 && - x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + mbedtls_x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) { return( 0 ); } @@ -289,74 +260,6 @@ static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) return( -1 ); } -/* - * Compare two X.509 strings, case-insensitive, and allowing for some encoding - * variations (but not all). - * - * Return 0 if equal, -1 otherwise. - */ -static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) -{ - if( a->tag == b->tag && - a->len == b->len && - memcmp( a->p, b->p, b->len ) == 0 ) - { - return( 0 ); - } - - if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && - ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && - a->len == b->len && - x509_memcasecmp( a->p, b->p, b->len ) == 0 ) - { - return( 0 ); - } - - return( -1 ); -} - -/* - * Compare two X.509 Names (aka rdnSequence). - * - * See RFC 5280 section 7.1, though we don't implement the whole algorithm: - * we sometimes return unequal when the full algorithm would return equal, - * but never the other way. (In particular, we don't do Unicode normalisation - * or space folding.) - * - * Return 0 if equal, -1 otherwise. - */ -static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) -{ - /* Avoid recursion, it might not be optimised by the compiler */ - while( a != NULL || b != NULL ) - { - if( a == NULL || b == NULL ) - return( -1 ); - - /* type */ - if( a->oid.tag != b->oid.tag || - a->oid.len != b->oid.len || - memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) - { - return( -1 ); - } - - /* value */ - if( x509_string_cmp( &a->val, &b->val ) != 0 ) - return( -1 ); - - /* structure of the list of sets */ - if( a->next_merged != b->next_merged ) - return( -1 ); - - a = a->next; - b = b->next; - } - - /* a == NULL == b */ - return( 0 ); -} - /* * Reset (init or clear) a verify_chain */ @@ -1838,7 +1741,7 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, while( crl_list != NULL ) { if( crl_list->version == 0 || - x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) + mbedtls_x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) { crl_list = crl_list->next; continue; @@ -1959,7 +1862,7 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, int need_ca_bit; /* Parent must be the issuer */ - if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + if( mbedtls_x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) return( -1 ); /* Parent must have the basicConstraints CA bit set as a general rule */ @@ -2225,7 +2128,7 @@ static int x509_crt_check_ee_locally_trusted( mbedtls_x509_crt *cur; /* must be self-issued */ - if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) + if( mbedtls_x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) return( -1 ); /* look for an exact match with trusted cert */ @@ -2390,7 +2293,7 @@ find_parent: * These can occur with some strategies for key rollover, see [SIRO], * and should be excluded from max_pathlen checks. */ if( ver_chain->len != 1 && - x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + mbedtls_x509_name_cmp( &child->issuer, &child->subject ) == 0 ) { self_cnt++; } @@ -2435,7 +2338,7 @@ static int x509_crt_check_cn( const mbedtls_x509_buf *name, { /* try exact match */ if( name->len == cn_len && - x509_memcasecmp( cn, name->p, cn_len ) == 0 ) + mbedtls_x509_memcasecmp( cn, name->p, cn_len ) == 0 ) { return( 0 ); } From a3a2ca1333a47e5c19a1a7a5282f2cc4530233b6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 12:42:07 +0000 Subject: [PATCH 012/140] Provide X.509 name comparison based on raw ASN.1 data This commit provides a new function `mbedtls_x509_name_cmp_raw()` to x509.c for comparing to X.509 names by traversing the raw ASN.1 data (as opposed to using the dynamically allocated linked list of `mbedtls_x509_name` structures). It has external linkage because it will be needed in `x509_crt` and `x509_crl`, but is marked internal and hence not part of the public API. --- include/mbedtls/x509.h | 2 ++ library/x509.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index e6781b699..13067b8f3 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -305,6 +305,8 @@ int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial ); int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ); +int mbedtls_x509_name_cmp_raw( const mbedtls_x509_buf_raw *a, + const mbedtls_x509_buf_raw *b ); int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); diff --git a/library/x509.c b/library/x509.c index fd9274743..d27c42327 100644 --- a/library/x509.c +++ b/library/x509.c @@ -583,6 +583,57 @@ int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, return( 0 ); } +int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, + mbedtls_x509_buf_raw const *b ) +{ + int ret; + + unsigned char *p_a, *end_a, *set_a; + unsigned char *p_b, *end_b, *set_b; + + p_a = set_a = (unsigned char*) a->p; + p_b = set_b = (unsigned char*) b->p; + + end_a = p_a + a->len; + end_b = p_b + b->len; + + while( 1 ) + { + mbedtls_x509_buf oid_a, val_a, oid_b, val_b; + + ret = x509_set_sequence_iterate( &p_a, (const unsigned char **) &set_a, + end_a, &oid_a, &val_a ); + if( ret != 0 ) + goto exit; + + ret = x509_set_sequence_iterate( &p_b, (const unsigned char **) &set_b, + end_b, &oid_b, &val_b ); + if( ret != 0 ) + goto exit; + + if( oid_a.len != oid_b.len || + memcmp( oid_a.p, oid_b.p, oid_b.len ) != 0 ) + { + return( 1 ); + } + + if( x509_string_cmp( &val_a, &val_b ) != 0 ) + return( 1 ); + + if( ( set_a == p_a ) != ( set_b == p_b ) ) + return( 1 ); + + if( p_a == end_a && p_b == end_b ) + break; + } + +exit: + if( ret < 0 ) + ret += MBEDTLS_ERR_X509_INVALID_NAME; + + return( ret ); +} + static int x509_parse_int( unsigned char **p, size_t n, int *res ) { *res = 0; From a632e3638cbeeb32240cd1e4468b699f5694e7a7 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 13:44:36 +0000 Subject: [PATCH 013/140] Add buffer with raw issuer data to CRL structure To make use of the X.509 name comparison function based on raw ASN.1 data that was introduced in the previous commit, this commit adds an ASN.1 buffer field `issuer_raw_no_hdr` to `mbedtls_x509_crl` which delimits the raw contents of the CRLs `Issuer` field. The previous field `issuer_raw` isn't suitable for that because it includes the ASN.1 header. --- include/mbedtls/x509.h | 9 +++++++++ include/mbedtls/x509_crl.h | 3 ++- library/x509_crl.c | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 13067b8f3..152e4b683 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -183,6 +183,15 @@ extern "C" { * \{ */ +/** + * Basic length-value buffer structure + */ +typedef struct mbedtls_x509_buf_raw +{ + unsigned char *p; /*!< The address of the first byte in the buffer. */ + size_t len; /*!< The number of Bytes in the buffer. */ +} mbedtls_x509_buf_raw; + /** * Type-length-value structure that allows for ASN1 using DER. */ diff --git a/include/mbedtls/x509_crl.h b/include/mbedtls/x509_crl.h index 2bb95de16..b035c6c4f 100644 --- a/include/mbedtls/x509_crl.h +++ b/include/mbedtls/x509_crl.h @@ -75,7 +75,8 @@ typedef struct mbedtls_x509_crl int version; /**< CRL version (1=v1, 2=v2) */ mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ - mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */ + mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). */ + mbedtls_x509_buf_raw issuer_raw_no_hdr; mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ diff --git a/library/x509_crl.c b/library/x509_crl.c index a56d5e3e8..f07784128 100644 --- a/library/x509_crl.c +++ b/library/x509_crl.c @@ -428,6 +428,7 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, mbedtls_x509_crl_free( crl ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } + crl->issuer_raw_no_hdr.p = p; if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) { @@ -435,6 +436,7 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, return( ret ); } + crl->issuer_raw_no_hdr.len = p - crl->issuer_raw_no_hdr.p; crl->issuer_raw.len = p - crl->issuer_raw.p; /* From f8a42862b72206be38b425f1c45a2232184d2def Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 20 Feb 2019 13:45:16 +0000 Subject: [PATCH 014/140] Add buffers with raw issuer/subject data to CRT structure --- include/mbedtls/x509_crt.h | 3 +++ library/x509_crt.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 09ba69f39..6e07ac6f2 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -64,6 +64,9 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + mbedtls_x509_buf_raw subject_raw_no_hdr; + mbedtls_x509_buf_raw issuer_raw_no_hdr; + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 6bec4d024..a05ea9ff4 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -848,6 +848,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, mbedtls_x509_crt_free( crt ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } + crt->issuer_raw_no_hdr.p = p; if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) { @@ -855,6 +856,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, return( ret ); } + crt->issuer_raw_no_hdr.len = p - crt->issuer_raw_no_hdr.p; crt->issuer_raw.len = p - crt->issuer_raw.p; /* @@ -882,12 +884,15 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } + crt->subject_raw_no_hdr.p = p; + if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) { mbedtls_x509_crt_free( crt ); return( ret ); } + crt->subject_raw_no_hdr.len = p - crt->subject_raw_no_hdr.p; crt->subject_raw.len = p - crt->subject_raw.p; /* From 7dee12a38c2a2d27573898632a474d8aab5c6adb Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 13:58:38 +0000 Subject: [PATCH 015/140] Make use of raw comparison function in CRT verification This commit replaces the previous calls to `mbedtls_x509_name_cmp()` during CRT verification (to match child and parent, to check whether a CRT is self-issued, and to match CRLs and CAs) by calls to the new `mbedtls_x509_name_cmp_raw()` using the raw ASN.1 data; it passes the raw buffers introduced in the last commits. The previous name comparison function mbedtls_x509_name_cmp() is now both unused and unneeded, and is removed. --- include/mbedtls/x509.h | 2 -- library/x509.c | 46 +++++++++--------------------------------- library/x509_crt.c | 16 +++++++++++---- 3 files changed, 22 insertions(+), 42 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 152e4b683..ba7a17419 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -312,8 +312,6 @@ int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, mbedtls_x509_time *t ); int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial ); -int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, - const mbedtls_x509_name *b ); int mbedtls_x509_name_cmp_raw( const mbedtls_x509_buf_raw *a, const mbedtls_x509_buf_raw *b ); int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); diff --git a/library/x509.c b/library/x509.c index d27c42327..f74d474a9 100644 --- a/library/x509.c +++ b/library/x509.c @@ -541,48 +541,22 @@ static int x509_string_cmp( const mbedtls_x509_buf *a, } /* - * Compare two X.509 Names (aka rdnSequence). + * Compare two X.509 Names (aka rdnSequence) given as raw ASN.1 data. * * See RFC 5280 section 7.1, though we don't implement the whole algorithm: - * we sometimes return unequal when the full algorithm would return equal, + * We sometimes return unequal when the full algorithm would return equal, * but never the other way. (In particular, we don't do Unicode normalisation * or space folding.) * - * Return 0 if equal, -1 otherwise. + * Returns: + * - 0 if both sequences are well-formed and present the same X.509 name. + * - 1 if a difference was detected. + * - A negative error code if a parsing error occurred in either + * of the two buffers. + * + * This function can be used to verify that a buffer contains a well-formed + * ASN.1 encoded X.509 name by calling it with equal parameters. */ -int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, - const mbedtls_x509_name *b ) -{ - /* Avoid recursion, it might not be optimised by the compiler */ - while( a != NULL || b != NULL ) - { - if( a == NULL || b == NULL ) - return( -1 ); - - /* type */ - if( a->oid.tag != b->oid.tag || - a->oid.len != b->oid.len || - memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) - { - return( -1 ); - } - - /* value */ - if( x509_string_cmp( &a->val, &b->val ) != 0 ) - return( -1 ); - - /* structure of the list of sets */ - if( a->next_merged != b->next_merged ) - return( -1 ); - - a = a->next; - b = b->next; - } - - /* a == NULL == b */ - return( 0 ); -} - int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, mbedtls_x509_buf_raw const *b ) { diff --git a/library/x509_crt.c b/library/x509_crt.c index a05ea9ff4..ad70a201b 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1746,7 +1746,8 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, while( crl_list != NULL ) { if( crl_list->version == 0 || - mbedtls_x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) + mbedtls_x509_name_cmp_raw( &crl_list->issuer_raw_no_hdr, + &ca->subject_raw_no_hdr ) != 0 ) { crl_list = crl_list->next; continue; @@ -1867,8 +1868,11 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, int need_ca_bit; /* Parent must be the issuer */ - if( mbedtls_x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + if( mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, + &parent->subject_raw_no_hdr ) != 0 ) + { return( -1 ); + } /* Parent must have the basicConstraints CA bit set as a general rule */ need_ca_bit = 1; @@ -2133,8 +2137,11 @@ static int x509_crt_check_ee_locally_trusted( mbedtls_x509_crt *cur; /* must be self-issued */ - if( mbedtls_x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) + if( mbedtls_x509_name_cmp_raw( &crt->issuer_raw_no_hdr, + &crt->subject_raw_no_hdr ) != 0 ) + { return( -1 ); + } /* look for an exact match with trusted cert */ for( cur = trust_ca; cur != NULL; cur = cur->next ) @@ -2298,7 +2305,8 @@ find_parent: * These can occur with some strategies for key rollover, see [SIRO], * and should be excluded from max_pathlen checks. */ if( ver_chain->len != 1 && - mbedtls_x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, + &child->subject_raw_no_hdr ) == 0 ) { self_cnt++; } From 67284cce00147d1e803b51169dfe19c88e86f3ca Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 14:31:51 +0000 Subject: [PATCH 016/140] Add abort condition callback to `mbedtls_x509_name_cmp_raw()` There are three operations that need to be performed on an X.509 name: 1 Initial traversal to check well-formedness of the ASN.1 structure. 2 Comparison between two X.509 name sequences. 3 Checking whether an X.509 name matches a client's ServerName request. Each of these tasks involves traversing the nested ASN.1 structure, In the interest of saving code, we aim to provide a single function which can perform all of the above tasks. The existing comparison function is already suitable not only for task 2, but also for 1: One can simply pass two equal ASN.1 name buffers, in which case the function will succeed if and only if that buffer is a well-formed ASN.1 name. This commit further adds a callback to `mbedtls_x509_name_cmp_raw()` which is called after each successful step in the simultaneous name traversal and comparison; it may perform any operation on the current name and potentially signal that the comparison should be aborted. With that, task 3 can be implemented by passing equal names and a callback which aborts as soon as it finds the desired name component. --- include/mbedtls/x509.h | 8 ++++++-- library/x509.c | 24 +++++++++++++++++++++--- library/x509_crt.c | 12 ++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index ba7a17419..c7b8cc4c5 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -312,8 +312,12 @@ int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, mbedtls_x509_time *t ); int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial ); -int mbedtls_x509_name_cmp_raw( const mbedtls_x509_buf_raw *a, - const mbedtls_x509_buf_raw *b ); +int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, + mbedtls_x509_buf_raw const *b, + int (*check)( void *ctx, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val ), + void *check_ctx ); int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); diff --git a/library/x509.c b/library/x509.c index f74d474a9..b49ecf3a7 100644 --- a/library/x509.c +++ b/library/x509.c @@ -548,9 +548,16 @@ static int x509_string_cmp( const mbedtls_x509_buf *a, * but never the other way. (In particular, we don't do Unicode normalisation * or space folding.) * + * Further, this function allows to pass a callback to be triggered for every + * pair of well-formed and equal entries in the two input name lists. + * * Returns: - * - 0 if both sequences are well-formed and present the same X.509 name. - * - 1 if a difference was detected. + * - 0 if both sequences are well-formed, present the same X.509 name, + * and the callback (if provided) hasn't returned a non-zero value + * on any of the name components. + * - 1 if a difference was detected in the name components. + * - A non-zero error code if the abort callback returns a non-zero value. + * In this case, the returned error code is the error code from the callback. * - A negative error code if a parsing error occurred in either * of the two buffers. * @@ -558,7 +565,11 @@ static int x509_string_cmp( const mbedtls_x509_buf *a, * ASN.1 encoded X.509 name by calling it with equal parameters. */ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, - mbedtls_x509_buf_raw const *b ) + mbedtls_x509_buf_raw const *b, + int (*abort_check)( void *ctx, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val ), + void *abort_check_ctx ) { int ret; @@ -597,6 +608,13 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, if( ( set_a == p_a ) != ( set_b == p_b ) ) return( 1 ); + if( abort_check != NULL ) + { + ret = abort_check( abort_check_ctx, &oid_a, &val_a ); + if( ret != 0 ) + return( ret ); + } + if( p_a == end_a && p_b == end_b ) break; } diff --git a/library/x509_crt.c b/library/x509_crt.c index ad70a201b..85bccedcb 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1747,7 +1747,8 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, { if( crl_list->version == 0 || mbedtls_x509_name_cmp_raw( &crl_list->issuer_raw_no_hdr, - &ca->subject_raw_no_hdr ) != 0 ) + &ca->subject_raw_no_hdr, + NULL, NULL ) != 0 ) { crl_list = crl_list->next; continue; @@ -1869,7 +1870,8 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, /* Parent must be the issuer */ if( mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, - &parent->subject_raw_no_hdr ) != 0 ) + &parent->subject_raw_no_hdr, + NULL, NULL ) != 0 ) { return( -1 ); } @@ -2138,7 +2140,8 @@ static int x509_crt_check_ee_locally_trusted( /* must be self-issued */ if( mbedtls_x509_name_cmp_raw( &crt->issuer_raw_no_hdr, - &crt->subject_raw_no_hdr ) != 0 ) + &crt->subject_raw_no_hdr, + NULL, NULL ) != 0 ) { return( -1 ); } @@ -2306,7 +2309,8 @@ find_parent: * and should be excluded from max_pathlen checks. */ if( ver_chain->len != 1 && mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, - &child->subject_raw_no_hdr ) == 0 ) + &child->subject_raw_no_hdr, + NULL, NULL ) == 0 ) { self_cnt++; } From 8b543b3ca8defdba08e64a6f3ba359fd05ba5bda Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 11:50:44 +0000 Subject: [PATCH 017/140] Make use of abort condition callback in CN comparison The previous CN name comparison function x509_crt_verify_name() traversed the dynamically allocated linked list presentation of the CRT's subject, comparing each entry to the desired hostname configured by the application code. Eventually, we want to get rid of the linked list presentation of the CRT's subject to save both code and RAM usage, and hence need to rewrite the CN verification routine in a way that builds on the raw ASN.1 subject data only. In order to avoid duplicating the code for the parsing of the nested ASN.1 name structure, this commit performs the name search by using the existing name traversal function mbedtls_x509_name_cmp_raw(), passing to it a callback which checks whether the current name component matches the desired hostname. --- library/x509_crt.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 85bccedcb..1d5bedc78 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2369,6 +2369,26 @@ static int x509_crt_check_cn( const mbedtls_x509_buf *name, return( -1 ); } +/* Returns 1 on a match and 0 on a mismatch. + * This is because this function is used as a callback for + * mbedtls_x509_name_cmp_raw(), which continues the name + * traversal as long as the callback returns 0. */ +static int x509_crt_check_name( void *ctx, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val ) +{ + char const *cn = (char const*) ctx; + size_t cn_len = strlen( cn ); + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, oid ) == 0 && + x509_crt_check_cn( val, cn, cn_len ) == 0 ) + { + return( 1 ); + } + + return( 0 ); +} + /* * Verify the requested CN - only call this if cn is not NULL! */ @@ -2376,7 +2396,6 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, const char *cn, uint32_t *flags ) { - const mbedtls_x509_name *name; const mbedtls_x509_sequence *cur; size_t cn_len = strlen( cn ); @@ -2393,16 +2412,11 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, } else { - for( name = &crt->subject; name != NULL; name = name->next ) - { - if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && - x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) - { - break; - } - } - - if( name == NULL ) + int ret; + ret = mbedtls_x509_name_cmp_raw( &crt->subject_raw_no_hdr, + &crt->subject_raw_no_hdr, + x509_crt_check_name, (void*) cn ); + if( ret != 1 ) *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; } } From 7ec9c368f1552dcdff474af2bb4ba7ded314c4d8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 14:24:05 +0000 Subject: [PATCH 018/140] Add buffer holding raw ExtKeyUsage extension data to CRT struct The previous commits replace the use of dynamically allocated linked lists for X.509 name inspection. This commit is the first in a series which attempts the same for the `ExtendedKeyUsage` extension. So far, when a CRT is parsed, the extension is traversed and converted into a dynamically allocated linked list, which is then search through whenever the usage of a CRT needs to be checked through `mbedtls_x509_check_extended_key_usage()`. As a first step, this commit introduces a raw buffer holding the bounds of the `ExtendedKeyUsage` extension to the `mbedtls_x509_crt` structure. --- include/mbedtls/x509_crt.h | 3 ++- library/x509_crt.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 6e07ac6f2..0c71dae18 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -87,7 +87,8 @@ typedef struct mbedtls_x509_crt unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ - mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + mbedtls_x509_buf_raw ext_key_usage_raw; /**< Raw data of ExtendedKeyUsage extensions. */ unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 1d5bedc78..afc707bb6 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -697,6 +697,8 @@ static int x509_get_crt_ext( unsigned char **p, case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: /* Parse extended key usage */ + crt->ext_key_usage_raw.p = *p; + crt->ext_key_usage_raw.len = end_ext_octet - *p; if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, &crt->ext_key_usage ) ) != 0 ) return( ret ); From e1956af05758ac16ce3f39d9fdbce8cf3e185400 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 14:28:12 +0000 Subject: [PATCH 019/140] Check for extended key usage by traversing raw extension data This commit re-implements `mbedtls_x509_crt_check_extended_key_usage()` to not use the dynamically allocated linked list presentation of the `ExtendedKeyUsage` but to search for the required usage by traversing the raw ASN.1 data. --- include/mbedtls/asn1.h | 4 +++ library/x509_crt.c | 63 ++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h index 2fb6de0a5..b49fe5ad4 100644 --- a/include/mbedtls/asn1.h +++ b/include/mbedtls/asn1.h @@ -131,6 +131,10 @@ ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \ memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 ) +#define MBEDTLS_OID_CMP_RAW(oid_str, oid_buf, oid_buf_len) \ + ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf_len) ) || \ + memcmp( (oid_str), (oid_buf), (oid_buf_len) ) != 0 ) + #ifdef __cplusplus extern "C" { #endif diff --git a/library/x509_crt.c b/library/x509_crt.c index afc707bb6..46d6434a9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1677,33 +1677,66 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, - const char *usage_oid, - size_t usage_len ) + const char *usage_oid, + size_t usage_len ) { - const mbedtls_x509_sequence *cur; + int ret; + size_t len; + unsigned ext_types; + unsigned char *p, *end; /* Extension is not mandatory, absent means no restriction */ - if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + ext_types = crt->ext_types; + if( ( ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) return( 0 ); - /* - * Look for the requested usage (or wildcard ANY) in our list - */ - for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) - { - const mbedtls_x509_buf *cur_oid = &cur->buf; + p = crt->ext_key_usage_raw.p; + end = p + crt->ext_key_usage_raw.len; - if( cur_oid->len == usage_len && - memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + goto exit; + + if( end != p + len ) + { + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto exit; + } + + if( len == 0 ) + { + ret = MBEDTLS_ERR_ASN1_INVALID_LENGTH; + goto exit; + } + + while( p < end ) + { + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_OID ); + if( ret != 0 ) + goto exit; + + if( usage_oid != NULL ) { - return( 0 ); + if( len == usage_len && memcmp( p, usage_oid, len ) == 0 ) + return( 0 ); + + if( MBEDTLS_OID_CMP_RAW( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, + p, len ) == 0 ) + { + return( 0 ); + } } - if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) - return( 0 ); + p += len; } return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + +exit: + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); } #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ From ded167e18cf7f82fecb5f0d08a356e241056db5d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 14:34:46 +0000 Subject: [PATCH 020/140] Add raw buffer holding SubjectAlternativeName ext to CRT structure This is analogous to a previous commit for the `ExtendedKeyUsage` extension: We aim at not using dynamically allocated linked lists to represent the components of the `SubjectAlternativeName` extension, but to traverse the raw ASN.1 data when needed. This commit adds a field to `mbedtls_x509_crt` containing the raw ASN.1 buffer bounds of the `SubjectAlternativeNames` extension. --- include/mbedtls/x509_crt.h | 1 + library/x509_crt.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 0c71dae18..76d829bed 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -80,6 +80,7 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ 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_buf_raw subject_alt_raw; /**< Raw data for SubjectAlternativeNames extension. */ 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. */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 46d6434a9..243373ea7 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -706,6 +706,8 @@ static int x509_get_crt_ext( unsigned char **p, 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 ); From 2492622289039005536e6e949c0000ce13b52f72 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 13:10:55 +0000 Subject: [PATCH 021/140] Pass raw data to x509_check_wildcard() and `x509_crt_check_cn()` In preparation for rewriting the `SubjectAlternativeName` search routine to use raw ASN.1 data, this commit changes `x509_check_wildcard()` and `x509_check_cn()`, responsible for checking whether a name matches a wildcard pattern, to take a raw buffer pointer and length as parameters instead of an `mbedtls_x509_buf` instance. --- library/x509_crt.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 243373ea7..c628e812a 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -230,13 +230,16 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, /* * Return 0 if name matches wildcard, -1 otherwise */ -static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) +static int x509_check_wildcard( char const *cn, + size_t cn_len, + unsigned char const *buf, + size_t buf_len ) { size_t i; - size_t cn_idx = 0, cn_len = strlen( cn ); + size_t cn_idx = 0; /* We can't have a match if there is no wildcard to match */ - if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + if( buf_len < 3 || buf[0] != '*' || buf[1] != '.' ) return( -1 ); for( i = 0; i < cn_len; ++i ) @@ -251,8 +254,8 @@ static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) if( cn_idx == 0 ) return( -1 ); - if( cn_len - cn_idx == name->len - 1 && - mbedtls_x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + if( cn_len - cn_idx == buf_len - 1 && + mbedtls_x509_memcasecmp( buf + 1, cn + cn_idx, buf_len - 1 ) == 0 ) { return( 0 ); } @@ -2387,18 +2390,20 @@ find_parent: /* * Check for CN match */ -static int x509_crt_check_cn( const mbedtls_x509_buf *name, - const char *cn, size_t cn_len ) +static int x509_crt_check_cn( unsigned char const *buf, + size_t buflen, + const char *cn, + size_t cn_len ) { - /* try exact match */ - if( name->len == cn_len && - mbedtls_x509_memcasecmp( cn, name->p, cn_len ) == 0 ) + /* Try exact match */ + if( buflen == cn_len && + mbedtls_x509_memcasecmp( cn, buf, cn_len ) == 0 ) { return( 0 ); } /* try wildcard match */ - if( x509_check_wildcard( cn, name ) == 0 ) + if( x509_check_wildcard( cn, cn_len, buf, buflen ) == 0 ) { return( 0 ); } @@ -2418,7 +2423,7 @@ static int x509_crt_check_name( void *ctx, size_t cn_len = strlen( cn ); if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, oid ) == 0 && - x509_crt_check_cn( val, cn, cn_len ) == 0 ) + x509_crt_check_cn( val->p, val->len, cn, cn_len ) == 0 ) { return( 1 ); } @@ -2440,7 +2445,8 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, { for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) { - if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 ) + if( x509_crt_check_cn( cur->buf.p, cur->buf.len, + cn, cn_len ) == 0 ) break; } From 2c6cc045c27318157792f6944044ee83b1486a7a Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 13:30:50 +0000 Subject: [PATCH 022/140] Add function to traverse raw SubjectAltName extension This commit adds a new function `x509_subject_alt_name_traverse()` which allows to traverse the raw ASN.1 data of a `SubjectAlternativeNames` extension. The `SubjectAlternativeNames` extension needs to be traversed in the following situations: 1 Initial traversal to check well-formedness of ASN.1 data 2 Traversal to check for a particular name component 3 Building the legacy linked list presentation Analogously to how multiple tasks related to X.509 name comparison are implemented through the workhorse `mbedtlS_x509_name_cmp_raw()`, the new function `x509_subject_alt_name_traverse()` allows to pass an arbitrary callback which is called on any component of the `SubjectAlternativeNames` extension found. This way, the above three tasks can be implemented by passing 1 a NULL callback, 2 a name comparison callback 3 a linked list building callback. --- library/x509_crt.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index c628e812a..a38f74981 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -517,6 +517,56 @@ static int x509_get_ext_key_usage( unsigned char **p, * * NOTE: we only parse and use dNSName at this point. */ +static int x509_subject_alt_name_traverse( unsigned char *p, + const unsigned char *end, + int (*cb)( void *ctx, + int tag, + unsigned char *data, + size_t data_len ), + void *ctx ) +{ + int ret; + size_t len; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + if( p + len != end ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + while( p < end ) + { + unsigned char const tag = *p++; + if( ( ret = mbedtls_asn1_get_len( &p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( cb != NULL ) + { + ret = cb( ctx, tag, p, len ); + if( ret != 0 ) + return( ret ); + } + + p += len; + } + + return( 0 ); +} + static int x509_get_subject_alt_name( unsigned char **p, const unsigned char *end, mbedtls_x509_sequence *subject_alt_name ) From da410828f4f63a6480c25e7cb7239ae1d16372af Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 13:36:59 +0000 Subject: [PATCH 023/140] Add callback to search through SubjectAltNames extension The current CN name verification x509_crt_verify_name() traverses the dynamically allocated linked list presentation of the subject alternative name extension, searching for an alternative name that matches the desired hostname configured by the application. Eventually, we want to remove this dynamically allocated linked list for the benefit of reduced code size and RAM usage, and hence need to rewrite x509_crt_verify_name() in a way that builds on the raw ASN.1 buffer holding the SubjectAlternativeNames extension. This commit does this by using the existing SubjectAlternativeNames traversal routine x509_subject_alt_name_traverse(), passing to it a callback which compares the current alternative name component to the desired hostname configured by the application. --- library/x509_crt.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index a38f74981..8541d1139 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2481,6 +2481,28 @@ static int x509_crt_check_name( void *ctx, return( 0 ); } +/* Returns 1 on a match and 0 on a mismatch. + * This is because this function is used as a callback for + * mbedtls_asn1_traverse_sequence_of(), which continues the + * traversal as long as the callback returns 0. */ +static int x509_crt_subject_alt_check_name( void *ctx, + int tag, + unsigned char *data, + size_t data_len ) +{ + char const *cn = (char const*) ctx; + size_t cn_len = strlen( cn ); + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + return( 0 ); + + if( x509_crt_check_cn( data, data_len, cn, cn_len ) == 0 ) + return( 1 ); + + return( 0 ); +} + /* * Verify the requested CN - only call this if cn is not NULL! */ @@ -2488,30 +2510,27 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, const char *cn, uint32_t *flags ) { - const mbedtls_x509_sequence *cur; - size_t cn_len = strlen( cn ); + int ret; if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { - for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) - { - if( x509_crt_check_cn( cur->buf.p, cur->buf.len, - cn, cn_len ) == 0 ) - break; - } + const unsigned char *end = + crt->subject_alt_raw.p + crt->subject_alt_raw.len; - if( cur == NULL ) - *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + ret = x509_subject_alt_name_traverse( crt->subject_alt_raw.p, + end, + x509_crt_subject_alt_check_name, + (void*) cn ); } else { - int ret; ret = mbedtls_x509_name_cmp_raw( &crt->subject_raw_no_hdr, &crt->subject_raw_no_hdr, x509_crt_check_name, (void*) cn ); - if( ret != 1 ) - *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; } + + if( ret != 1 ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; } /* From ad46219a881d163420c369e058818dabe0f2573c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 13:32:31 +0000 Subject: [PATCH 024/140] Add cb to build dynamic linked list representation of SubjectAltName This commit adds a callback for use with `x509_subject_alt_name_traverse()` which builds the legacy dynamically allocated linked list presentation of the `SubjectAlternativeNames` extension while traversing the raw data. --- library/x509_crt.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index 8541d1139..5d43a4487 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -517,6 +517,38 @@ static int x509_get_ext_key_usage( unsigned char **p, * * NOTE: we only parse and use dNSName at this point. */ +static int x509_get_subject_alt_name_cb( void *ctx, + int tag, + unsigned char *data, + size_t data_len ) +{ + mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx; + mbedtls_asn1_sequence *cur = *cur_ptr; + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + return( 0 ); + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + 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; + } + + cur->buf.tag = tag; + cur->buf.p = data; + cur->buf.len = data_len; + + *cur_ptr = cur; + return( 0 ); +} + static int x509_subject_alt_name_traverse( unsigned char *p, const unsigned char *end, int (*cb)( void *ctx, From 5984d30f4b0e2bb697e08ad3821e7afe8a959d01 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 14:46:54 +0000 Subject: [PATCH 025/140] Make use of cb to build linked list presentation of SubjectAltName --- library/x509_crt.c | 80 +++++----------------------------------------- 1 file changed, 8 insertions(+), 72 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 5d43a4487..3dfa86379 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -599,80 +599,13 @@ static int x509_subject_alt_name_traverse( unsigned char *p, return( 0 ); } -static int x509_get_subject_alt_name( unsigned char **p, +static int x509_get_subject_alt_name( unsigned char *p, const unsigned char *end, mbedtls_x509_sequence *subject_alt_name ) { - int ret; - size_t len, tag_len; - mbedtls_asn1_buf *buf; - unsigned char tag; - mbedtls_asn1_sequence *cur = subject_alt_name; - - /* Get main sequence tag */ - if( ( ret = mbedtls_asn1_get_tag( p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - - 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 ); - - tag = **p; - (*p)++; - if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - - if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != - MBEDTLS_ASN1_CONTEXT_SPECIFIC ) - { - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); - } - - /* Skip everything but DNS name */ - if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) - { - *p += tag_len; - continue; - } - - /* Allocate and assign next pointer */ - 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 = tag; - buf->p = *p; - buf->len = tag_len; - *p += buf->len; - } - - /* Set final sequence entry's next pointer to NULL */ - cur->next = NULL; - - if( *p != end ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - - return( 0 ); + return( x509_subject_alt_name_traverse( p, end, + x509_get_subject_alt_name_cb, + (void*) &subject_alt_name ) ); } /* @@ -793,9 +726,12 @@ static int x509_get_crt_ext( unsigned char **p, /* 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, + if( ( ret = x509_get_subject_alt_name( *p, end_ext_octet, &crt->subject_alt_names ) ) != 0 ) + { return( ret ); + } + *p = end_ext_octet; break; case MBEDTLS_X509_EXT_NS_CERT_TYPE: From 8730610ae062661598168caf0d54e9817e8ad974 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 20:52:09 +0000 Subject: [PATCH 026/140] Introduce ASN.1 API for traversing ASN.1 SEQUENCEs This commit adds a new function `mbedtls_asn1_traverse_sequence_of()` which traverses an ASN.1 SEQUENCE and calls a user-provided callback for each entry. It allows to put the following constraints on the tags allowed in the SEQUENCE: - A tag mask and mandatory tag value w.r.t. that mask. A non-matching tag leads to an MBEDTLS_ERR_ASN1_UNEXPECTED_TAG error. For example, it the mask if 0xFF, this means that only a single tag will be allowed in the SEQUENCE. - A tag mask and optional tag value w.r.t. that mask. A non-matching tag is silently ignored. The main use for this flexibility is the traversal of the `SubjectAlternativeNames` extension, where some parts of the tag are fixed but some are flexible to indicate which type of name the entry describes. --- include/mbedtls/asn1.h | 52 +++++++++++++++++ library/asn1parse.c | 130 +++++++++++++++++++++++++++++------------ 2 files changed, 144 insertions(+), 38 deletions(-) diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h index b49fe5ad4..5b7b2b82d 100644 --- a/include/mbedtls/asn1.h +++ b/include/mbedtls/asn1.h @@ -291,6 +291,58 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p, mbedtls_asn1_sequence *cur, int tag); +/** + * \brief Traverse an ASN.1 SEQUENCE container and + * call a callback for each entry. + * + * \warning This function is still experimental and may change + * at any time. + * + * \param p The address of the pointer to the beginning of + * the ASN.1 SEQUENCE header. This is updated to + * point to the end of the ASN.1 SEQUENCE container + * on a successful invocation. + * \param end The end of the ASN.1 SEQUENCE container. + * \param tag_must_mask A mask to be applied to the ASN.1 tags found within + * the SEQUENCE before comparing to \p tag_must_value. + * \param tag_must_val The required value of each ASN.1 tag found in the + * SEQUENCE, after masking with \p tag_must_mask. + * Mismatching tags lead to an error. + * For example, a value of \c 0 for both \p tag_must_mask + * and \p tag_must_val means that every tag is allowed, + * while a value of \c 0xFF for \p tag_must_mask means + * that \p tag_must_val is the only allowed tag. + * \param tag_may_mask A mask to be applied to the ASN.1 tags found within + * the SEQUENCE before comparing to \p tag_may_value. + * \param tag_may_val The desired value of each ASN.1 tag found in the + * SEQUENCE, after masking with \p tag_may_mask. + * Mismatching tags will be silently ignored. + * For example, a value of \c 0 for \p tag_may_mask and + * \p tag_may_val means that any tag will be considered, + * while a value of \c 0xFF for \p tag_may_mask means + * that all tags with value different from \p tag_may_val + * will be ignored. + * \param cb The callback to trigger for each component + * in the ASN.1 SEQUENCE. If the callback returns + * a non-zero value, the function stops immediately, + * forwarding the callback's return value. + * \param ctx The context to be passed to the callback \p cb. + * + * \return \c 0 if successful the entire ASN.1 SEQUENCE + * was traversed without parsing or callback errors. + * \return A negative ASN.1 error code on a parsing failure. + * \return A non-zero error code forwarded from the callback + * \p cb in case the latter returns a non-zero value. + */ +int mbedtls_asn1_traverse_sequence_of( + unsigned char **p, + const unsigned char *end, + uint8_t tag_must_mask, uint8_t tag_must_val, + uint8_t tag_may_mask, uint8_t tag_may_val, + int (*cb)( void *ctx, int tag, + unsigned char* start, size_t len ), + void *ctx ); + #if defined(MBEDTLS_BIGNUM_C) /** * \brief Retrieve a MPI value from an integer ASN.1 tag. diff --git a/library/asn1parse.c b/library/asn1parse.c index dffc67fb3..f24fee69f 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -230,6 +230,93 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end } +/* + * Traverse an ASN.1 "SEQUENCE OF " + * and call a callback for each entry found. + */ +int mbedtls_asn1_traverse_sequence_of( + unsigned char **p, + const unsigned char *end, + uint8_t tag_must_mask, uint8_t tag_must_val, + uint8_t tag_may_mask, uint8_t tag_may_val, + int (*cb)( void *ctx, int tag, + unsigned char *start, size_t len ), + void *ctx ) +{ + int ret; + size_t len; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( ret ); + } + + if( *p + len != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + unsigned char const tag = *(*p)++; + + if( ( tag & tag_must_mask ) != tag_must_val ) + return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( tag & tag_may_mask ) == tag_may_val ) + { + if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 ) + return( ret ); + + if( cb != NULL ) + { + ret = cb( ctx, tag, *p, len ); + if( ret != 0 ) + return( ret ); + } + } + + *p += len; + } + + return( 0 ); +} + +typedef struct +{ + int tag; + mbedtls_asn1_sequence *cur; +} asn1_get_sequence_of_cb_ctx_t; + +static int asn1_get_sequence_of_cb( void *ctx, + int tag, + unsigned char *start, + size_t len ) +{ + asn1_get_sequence_of_cb_ctx_t *cb_ctx = + (asn1_get_sequence_of_cb_ctx_t *) ctx; + mbedtls_asn1_sequence *cur = + cb_ctx->cur; + + if( cur->buf.p != NULL ) + { + cur->next = + mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + cur->buf.p = start; + cur->buf.len = len; + cur->buf.tag = tag; + + cb_ctx->cur = cur; + return( 0 ); +} + /* * Parses and splits an ASN.1 "SEQUENCE OF " @@ -239,44 +326,11 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p, mbedtls_asn1_sequence *cur, int tag) { - int ret; - size_t len; - mbedtls_asn1_buf *buf; - - /* Get main sequence tag */ - if( ( ret = mbedtls_asn1_get_tag( p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - return( ret ); - - if( *p + len != end ) - return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - - while( 1 ) - { - buf = &(cur->buf); - buf->tag = **p; - - if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) - return( ret ); - - buf->p = *p; - *p += buf->len; - - if( *p == end ) - { - cur->next = NULL; - break; - } - - cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, - sizeof( mbedtls_asn1_sequence ) ); - if( cur->next == NULL ) - return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - - cur = cur->next; - } - - return( 0 ); + asn1_get_sequence_of_cb_ctx_t cb_ctx = { tag, cur }; + memset( cur, 0, sizeof( mbedtls_asn1_sequence ) ); + return( mbedtls_asn1_traverse_sequence_of( + p, end, 0xFF, tag, 0, 0, + asn1_get_sequence_of_cb, &cb_ctx ) ); } int mbedtls_asn1_get_alg( unsigned char **p, From 90b9408dd0b799f4429c5df7fd9d0fdea07944b4 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 21:13:21 +0000 Subject: [PATCH 027/140] Implement SubjectAltName traversal via ASN.1 SEQUENCE OF traversal This commit re-implements the `SubjectAlternativeName` traversal routine in terms of the generic ASN.1 SEQUENCE traversal routine. --- library/x509_crt.c | 91 +++++++++++----------------------------------- 1 file changed, 22 insertions(+), 69 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3dfa86379..6d5bb6fad 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -525,19 +525,12 @@ static int x509_get_subject_alt_name_cb( void *ctx, mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx; mbedtls_asn1_sequence *cur = *cur_ptr; - /* Skip everything but DNS name */ - if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) - return( 0 ); - /* Allocate and assign next pointer */ if( cur->buf.p != NULL ) { cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); if( cur->next == NULL ) - { - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - } + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); cur = cur->next; } @@ -549,63 +542,21 @@ static int x509_get_subject_alt_name_cb( void *ctx, return( 0 ); } -static int x509_subject_alt_name_traverse( unsigned char *p, - const unsigned char *end, - int (*cb)( void *ctx, - int tag, - unsigned char *data, - size_t data_len ), - void *ctx ) -{ - int ret; - size_t len; - - /* Get main sequence tag */ - if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - { - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - } - - if( p + len != end ) - { - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - } - - while( p < end ) - { - unsigned char const tag = *p++; - if( ( ret = mbedtls_asn1_get_len( &p, end, &len ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); - - if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != - MBEDTLS_ASN1_CONTEXT_SPECIFIC ) - { - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); - } - - if( cb != NULL ) - { - ret = cb( ctx, tag, p, len ); - if( ret != 0 ) - return( ret ); - } - - p += len; - } - - return( 0 ); -} - static int x509_get_subject_alt_name( unsigned char *p, const unsigned char *end, mbedtls_x509_sequence *subject_alt_name ) { - return( x509_subject_alt_name_traverse( p, end, - x509_get_subject_alt_name_cb, - (void*) &subject_alt_name ) ); + int ret; + ret = mbedtls_asn1_traverse_sequence_of( &p, end, + MBEDTLS_ASN1_TAG_CLASS_MASK, + MBEDTLS_ASN1_CONTEXT_SPECIFIC, + MBEDTLS_ASN1_TAG_VALUE_MASK, + 2 /* SubjectAlt DNS */, + x509_get_subject_alt_name_cb, + (void*) &subject_alt_name ); + if( ret != 0 ) + ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS; + return( ret ); } /* @@ -2460,10 +2411,7 @@ static int x509_crt_subject_alt_check_name( void *ctx, { char const *cn = (char const*) ctx; size_t cn_len = strlen( cn ); - - /* Skip everything but DNS name */ - if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) - return( 0 ); + ((void) tag); if( x509_crt_check_cn( data, data_len, cn, cn_len ) == 0 ) return( 1 ); @@ -2482,13 +2430,18 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { + unsigned char *p = + crt->subject_alt_raw.p; const unsigned char *end = crt->subject_alt_raw.p + crt->subject_alt_raw.len; - ret = x509_subject_alt_name_traverse( crt->subject_alt_raw.p, - end, - x509_crt_subject_alt_check_name, - (void*) cn ); + ret = mbedtls_asn1_traverse_sequence_of( &p, end, + MBEDTLS_ASN1_TAG_CLASS_MASK, + MBEDTLS_ASN1_CONTEXT_SPECIFIC, + MBEDTLS_ASN1_TAG_VALUE_MASK, + 2 /* SubjectAlt DNS */, + x509_crt_subject_alt_check_name, + (void*) cn ); } else { From c7c638eddd19b6b9e544237d102c2ba8bc41bb68 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 21 Feb 2019 21:10:51 +0000 Subject: [PATCH 028/140] Implement ExtKeyUsage traversal via ASN.1 SEQUENCE OF traversal This commit re-implements the `ExtendedKeyUsage` traversal routine in terms of the generic ASN.1 SEQUENCE traversal routine. --- library/x509_crt.c | 80 +++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 6d5bb6fad..ae82e92a7 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1650,14 +1650,44 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, #endif #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +typedef struct +{ + const char *oid; + size_t oid_len; +} x509_crt_check_ext_key_usage_cb_ctx_t; + +static int x509_crt_check_ext_key_usage_cb( void *ctx, + int tag, + unsigned char *data, + size_t data_len ) +{ + x509_crt_check_ext_key_usage_cb_ctx_t *cb_ctx = + (x509_crt_check_ext_key_usage_cb_ctx_t *) ctx; + ((void) tag); + + if( MBEDTLS_OID_CMP_RAW( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, + data, data_len ) == 0 ) + { + return( 1 ); + } + + if( data_len == cb_ctx->oid_len && memcmp( data, cb_ctx->oid, + data_len ) == 0 ) + { + return( 1 ); + } + + return( 0 ); +} + int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, const char *usage_oid, size_t usage_len ) { int ret; - size_t len; unsigned ext_types; unsigned char *p, *end; + x509_crt_check_ext_key_usage_cb_ctx_t cb_ctx = { usage_oid, usage_len }; /* Extension is not mandatory, absent means no restriction */ ext_types = crt->ext_types; @@ -1667,50 +1697,14 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, p = crt->ext_key_usage_raw.p; end = p + crt->ext_key_usage_raw.len; - ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | - MBEDTLS_ASN1_SEQUENCE ); - if( ret != 0 ) - goto exit; - - if( end != p + len ) - { - ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; - goto exit; - } - - if( len == 0 ) - { - ret = MBEDTLS_ERR_ASN1_INVALID_LENGTH; - goto exit; - } - - while( p < end ) - { - ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_OID ); - if( ret != 0 ) - goto exit; - - if( usage_oid != NULL ) - { - if( len == usage_len && memcmp( p, usage_oid, len ) == 0 ) - return( 0 ); - - if( MBEDTLS_OID_CMP_RAW( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, - p, len ) == 0 ) - { - return( 0 ); - } - } - - p += len; - } + ret = mbedtls_asn1_traverse_sequence_of( &p, end, + 0xFF, MBEDTLS_ASN1_OID, 0, 0, + x509_crt_check_ext_key_usage_cb, + &cb_ctx ); + if( ret == 1 ) + return( 0 ); return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); - -exit: - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); } #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ From f1b39bf18c33d594cbe0647fb162a3f94b9f5481 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 11:09:48 +0000 Subject: [PATCH 029/140] 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. --- library/x509_crt.c | 304 +++++++++++++++++++++++++-------------------- 1 file changed, 166 insertions(+), 138 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index ae82e92a7..c9bc16321 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -393,7 +393,7 @@ static int x509_get_basic_constraints( unsigned char **p, if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + return( ret ); if( *p == end ) return( 0 ); @@ -404,7 +404,7 @@ static int x509_get_basic_constraints( unsigned char **p, ret = mbedtls_asn1_get_int( p, end, ca_istrue ); if( ret != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + return( ret ); if( *ca_istrue != 0 ) *ca_istrue = 1; @@ -414,11 +414,10 @@ static int x509_get_basic_constraints( unsigned char **p, return( 0 ); if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + return( ret ); if( *p != end ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); (*max_pathlen)++; @@ -433,11 +432,10 @@ static int x509_get_ns_cert_type( unsigned char **p, mbedtls_x509_bitstring bs = { 0, 0, NULL }; if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + return( ret ); if( bs.len != 1 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); /* Get actual bitstring */ *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 }; if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + return( ret ); if( bs.len < 1 ) - return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + - MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); /* Get actual bitstring */ *key_usage = 0; @@ -478,17 +475,8 @@ static int x509_get_ext_key_usage( unsigned char **p, const unsigned char *end, mbedtls_x509_sequence *ext_key_usage) { - int ret; - - 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 ); + return( mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, + MBEDTLS_ASN1_OID ) ); } /* @@ -546,162 +534,202 @@ static int x509_get_subject_alt_name( unsigned char *p, const unsigned char *end, mbedtls_x509_sequence *subject_alt_name ) { - int ret; - ret = mbedtls_asn1_traverse_sequence_of( &p, end, - MBEDTLS_ASN1_TAG_CLASS_MASK, - MBEDTLS_ASN1_CONTEXT_SPECIFIC, - MBEDTLS_ASN1_TAG_VALUE_MASK, - 2 /* SubjectAlt DNS */, - x509_get_subject_alt_name_cb, - (void*) &subject_alt_name ); - if( ret != 0 ) - ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS; - return( ret ); + return( mbedtls_asn1_traverse_sequence_of( &p, end, + MBEDTLS_ASN1_TAG_CLASS_MASK, + MBEDTLS_ASN1_CONTEXT_SPECIFIC, + MBEDTLS_ASN1_TAG_VALUE_MASK, + 2 /* SubjectAlt DNS */, + x509_get_subject_alt_name_cb, + (void*) &subject_alt_name ) ); } /* * X.509 v3 extensions * */ -static int x509_get_crt_ext( unsigned char **p, - const unsigned char *end, - mbedtls_x509_crt *crt ) +static int x509_crt_get_ext_cb( void *ctx, + int tag, + unsigned char *p, + size_t ext_len ) { int ret; + mbedtls_x509_crt *crt = (mbedtls_x509_crt *) ctx; 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 ) - return( 0 ); + ((void) tag); - 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; - while( *p < end ) + end = p + ext_len; + + /* 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 ) { - /* - * Extension ::= SEQUENCE { - * 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; + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto err; + } + /* + * 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( 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 ) + if( is_critical ) { + /* 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: + { + int ca_istrue; + int max_pathlen; + /* Parse basic constraints */ - if( ( ret = x509_get_basic_constraints( p, end_ext_octet, - &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) - return( ret ); + ret = x509_get_basic_constraints( &p, end_ext_octet, + &ca_istrue, + &max_pathlen ); + if( ret != 0 ) + goto err; + + crt->ca_istrue = ca_istrue; + crt->max_pathlen = max_pathlen; break; + } case MBEDTLS_X509_EXT_KEY_USAGE: /* Parse key usage */ - if( ( ret = x509_get_key_usage( p, end_ext_octet, - &crt->key_usage ) ) != 0 ) + ret = x509_get_key_usage( &p, end_ext_octet, + &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 ); + } break; case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: /* Parse extended key usage */ - crt->ext_key_usage_raw.p = *p; - crt->ext_key_usage_raw.len = end_ext_octet - *p; - if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, - &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 ) + crt->ext_key_usage_raw.p = p; + crt->ext_key_usage_raw.len = end_ext_octet - p; + if( ( ret = x509_get_ext_key_usage( &p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) { return( ret ); } - *p = end_ext_octet; break; case MBEDTLS_X509_EXT_NS_CERT_TYPE: /* Parse netscape certificate type */ - if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, - &crt->ns_cert_type ) ) != 0 ) - return( ret ); + ret = x509_get_ns_cert_type( &p, end_ext_octet, + &crt->ns_cert_type ); + if( ret != 0 ) + goto err; break; 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 ); + +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 ); } /* From b3def1d341129db4ab4d19df44fcf05ece13df76 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 11:46:06 +0000 Subject: [PATCH 030/140] Move length check into mbedtls_x509_memcasecmp() At every occasion where we're using `mbedtls_x509_memcasecmp()` we're checking that the two buffer lengths coincide before making the call. This commit saves a few bytes of code by moving this length check to `mbedtls_x509_memcasecmp()`. --- include/mbedtls/x509.h | 3 ++- library/x509.c | 12 ++++++++---- library/x509_crt.c | 9 +++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index c7b8cc4c5..c02c7c8ba 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -318,7 +318,8 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, mbedtls_x509_buf *oid, mbedtls_x509_buf *val ), void *check_ctx ); -int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, + size_t len1, size_t lend2 ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); diff --git a/library/x509.c b/library/x509.c index b49ecf3a7..f2b6c7b7e 100644 --- a/library/x509.c +++ b/library/x509.c @@ -487,13 +487,17 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, /* * Like memcmp, but case-insensitive and always returns -1 if different */ -int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ) +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, + size_t len1, size_t len2 ) { size_t i; unsigned char diff; const unsigned char *n1 = s1, *n2 = s2; - for( i = 0; i < len; i++ ) + if( len1 != len2 ) + return( -1 ); + + for( i = 0; i < len1; i++ ) { diff = n1[i] ^ n2[i]; @@ -531,8 +535,8 @@ static int x509_string_cmp( const mbedtls_x509_buf *a, if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && - a->len == b->len && - mbedtls_x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + mbedtls_x509_memcasecmp( a->p, b->p, + a->len, b->len ) == 0 ) { return( 0 ); } diff --git a/library/x509_crt.c b/library/x509_crt.c index c9bc16321..5959c0afa 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -254,8 +254,8 @@ static int x509_check_wildcard( char const *cn, if( cn_idx == 0 ) return( -1 ); - if( cn_len - cn_idx == buf_len - 1 && - mbedtls_x509_memcasecmp( buf + 1, cn + cn_idx, buf_len - 1 ) == 0 ) + if( mbedtls_x509_memcasecmp( buf + 1, cn + cn_idx, + buf_len - 1, cn_len - cn_idx ) == 0 ) { return( 0 ); } @@ -2387,11 +2387,8 @@ static int x509_crt_check_cn( unsigned char const *buf, size_t cn_len ) { /* Try exact match */ - if( buflen == cn_len && - mbedtls_x509_memcasecmp( cn, buf, cn_len ) == 0 ) - { + if( mbedtls_x509_memcasecmp( cn, buf, buflen, cn_len ) == 0 ) return( 0 ); - } /* try wildcard match */ if( x509_check_wildcard( cn, cn_len, buf, buflen ) == 0 ) From c84fd1cd95160520089eecd075eefe6baee4bfef Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 15:01:03 +0000 Subject: [PATCH 031/140] Check whether CRT is revoked by passing its serial number only CRLs reference revoked CRTs through their serial number only. --- library/x509_crt.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 5959c0afa..c6d310d0b 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1740,14 +1740,16 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, /* * Return 1 if the certificate is revoked, or 0 otherwise. */ -int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) +static int x509_serial_is_revoked( unsigned char const *serial, + size_t serial_len, + const mbedtls_x509_crl *crl ) { const mbedtls_x509_crl_entry *cur = &crl->entry; while( cur != NULL && cur->serial.len != 0 ) { - if( crt->serial.len == cur->serial.len && - memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + if( serial_len == cur->serial.len && + memcmp( serial, cur->serial.p, serial_len ) == 0 ) { if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) return( 1 ); @@ -1759,11 +1761,21 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509 return( 0 ); } +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, + const mbedtls_x509_crl *crl ) +{ + return( x509_serial_is_revoked( crt->serial.p, + crt->serial.len, + crl ) ); +} + /* * Check that the given certificate is not revoked according to the CRL. * Skip validation if no CRL for the given CA is present. */ -static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, +static int x509_crt_verifycrl( unsigned char *crt_serial, + size_t crt_serial_len, + mbedtls_x509_crt *ca, mbedtls_x509_crl *crl_list, const mbedtls_x509_crt_profile *profile ) { @@ -1837,7 +1849,8 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, /* * Check if certificate is revoked */ - if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) + if( x509_serial_is_revoked( crt_serial, crt_serial_len, + crl_list ) ) { flags |= MBEDTLS_X509_BADCERT_REVOKED; break; @@ -2365,7 +2378,9 @@ find_parent: #if defined(MBEDTLS_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the given crt */ - *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); + *flags |= x509_crt_verifycrl( child->serial.p, + child->serial.len, + parent, ca_crl, profile ); #else (void) ca_crl; #endif From 1898b68f09c77aacc6fe04331f82aa446ddf690b Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 16:03:29 +0000 Subject: [PATCH 032/140] Allow NULL pointer in mbedtls_x509_get_sig_alg if params not needed Also, set `sig_opts` pointer to `NULL` if no signature algorithm parameters are given (to reflect exactly that). --- library/x509.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/x509.c b/library/x509.c index f2b6c7b7e..be170bb46 100644 --- a/library/x509.c +++ b/library/x509.c @@ -811,9 +811,6 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50 { int ret; - if( *sig_opts != NULL ) - return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); - if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); @@ -836,7 +833,10 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50 return( ret ); } - *sig_opts = (void *) pss_opts; + if( sig_opts != NULL ) + *sig_opts = (void *) pss_opts; + else + mbedtls_free( pss_opts ); } else #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ @@ -844,7 +844,10 @@ int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x50 /* Make sure parameters are absent or NULL */ if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || sig_params->len != 0 ) - return( MBEDTLS_ERR_X509_INVALID_ALG ); + return( MBEDTLS_ERR_X509_INVALID_ALG ); + + if( sig_opts != NULL ) + *sig_opts = NULL; } return( 0 ); From b59d3f1692b6df35ab5ebf40aa21bfab114f6498 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 17:49:34 +0000 Subject: [PATCH 033/140] Add single function to parse ASN.1 AlgorithmIdentifier to x509.c --- include/mbedtls/x509.h | 4 ++++ library/x509.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index c02c7c8ba..8297910cc 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -305,6 +305,10 @@ int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, int *salt_len ); #endif int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg, + void **sig_opts ); int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, void **sig_opts ); diff --git a/library/x509.c b/library/x509.c index be170bb46..05d995c59 100644 --- a/library/x509.c +++ b/library/x509.c @@ -802,6 +802,21 @@ int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x return( 0 ); } +int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg, + void **sig_opts ) +{ + int ret; + mbedtls_asn1_buf alg, params; + ret = mbedtls_asn1_get_alg( p, end, &alg, ¶ms ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( mbedtls_x509_get_sig_alg( &alg, ¶ms, md_alg, + pk_alg, sig_opts ) ); +} + /* * Get signature algorithm from alg OID and optional parameters */ From 10e6b9b2b5a1b338cb1f395b101fe1a4965ce81c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 22 Feb 2019 17:56:43 +0000 Subject: [PATCH 034/140] Move point of re-entry for restartable X.509 verification --- library/x509_crt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index c6d310d0b..72c04736c 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2275,8 +2275,6 @@ static int x509_crt_verify_chain( /* restore derived state */ cur = &ver_chain->items[ver_chain->len - 1]; child = cur->crt; - flags = &cur->flags; - goto find_parent; } #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ @@ -2292,6 +2290,11 @@ static int x509_crt_verify_chain( cur->crt = child; cur->flags = 0; ver_chain->len++; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +find_parent: +#endif + flags = &cur->flags; /* Check time-validity (all certificates) */ @@ -2319,9 +2322,6 @@ static int x509_crt_verify_chain( return( 0 ); } -#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) -find_parent: -#endif /* Look for a parent in trusted CAs or up the chain */ ret = x509_crt_find_parent( child, trust_ca, &parent, &parent_is_trusted, &signature_is_good, From 6b37812a45be3321ae98e7dea346f4ec383db132 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sat, 23 Feb 2019 10:20:14 +0000 Subject: [PATCH 035/140] Add `next_merged` field to X.509 name comparison abort callback --- include/mbedtls/x509.h | 3 +- library/x509.c | 80 +++++++++++++++++++++++------------------- library/x509_crt.c | 4 ++- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 8297910cc..f7987a9ed 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -320,7 +320,8 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, mbedtls_x509_buf_raw const *b, int (*check)( void *ctx, mbedtls_x509_buf *oid, - mbedtls_x509_buf *val ), + mbedtls_x509_buf *val, + int next_merged ), void *check_ctx ); int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len1, size_t lend2 ); diff --git a/library/x509.c b/library/x509.c index 05d995c59..8b63572a2 100644 --- a/library/x509.c +++ b/library/x509.c @@ -451,39 +451,6 @@ exit: return( ret ); } -int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, - mbedtls_x509_name *cur ) -{ - int ret; - const unsigned char *end_set; - - end_set = *p; - while( 1 ) - { - ret = x509_set_sequence_iterate( p, &end_set, end, - &cur->oid, &cur->val ); - if( ret != 0 ) - return( ret + MBEDTLS_ERR_X509_INVALID_NAME ); - - if( *p != end_set ) - cur->next_merged = 1; - - if( *p == end ) - { - cur->next = NULL; - break; - } - - cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); - if( cur->next == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); - - cur = cur->next; - } - - return( 0 ); -} - /* * Like memcmp, but case-insensitive and always returns -1 if different */ @@ -572,7 +539,8 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, mbedtls_x509_buf_raw const *b, int (*abort_check)( void *ctx, mbedtls_x509_buf *oid, - mbedtls_x509_buf *val ), + mbedtls_x509_buf *val, + int next_merged ), void *abort_check_ctx ) { int ret; @@ -588,7 +556,8 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, while( 1 ) { - mbedtls_x509_buf oid_a, val_a, oid_b, val_b; + int next_merged; + mbedtls_x509_buf oid_a, val_a, oid_b, val_b; ret = x509_set_sequence_iterate( &p_a, (const unsigned char **) &set_a, end_a, &oid_a, &val_a ); @@ -609,12 +578,14 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, if( x509_string_cmp( &val_a, &val_b ) != 0 ) return( 1 ); - if( ( set_a == p_a ) != ( set_b == p_b ) ) + next_merged = ( set_a != p_a ); + if( next_merged != ( set_b != p_b ) ) return( 1 ); if( abort_check != NULL ) { - ret = abort_check( abort_check_ctx, &oid_a, &val_a ); + ret = abort_check( abort_check_ctx, &oid_a, &val_a, + next_merged ); if( ret != 0 ) return( ret ); } @@ -630,6 +601,41 @@ exit: return( ret ); } + +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + const unsigned char *end_set; + + end_set = *p; + while( 1 ) + { + ret = x509_set_sequence_iterate( p, &end_set, end, + &cur->oid, &cur->val ); + if( ret != 0 ) + return( ret + MBEDTLS_ERR_X509_INVALID_NAME ); + + if( *p != end_set ) + cur->next_merged = 1; + + if( *p == end ) + { + cur->next = NULL; + break; + } + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } + + return( 0 ); +} + + static int x509_parse_int( unsigned char **p, size_t n, int *res ) { *res = 0; diff --git a/library/x509_crt.c b/library/x509_crt.c index 72c04736c..77056c07f 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2420,10 +2420,12 @@ static int x509_crt_check_cn( unsigned char const *buf, * traversal as long as the callback returns 0. */ static int x509_crt_check_name( void *ctx, mbedtls_x509_buf *oid, - mbedtls_x509_buf *val ) + mbedtls_x509_buf *val, + int next_merged ) { char const *cn = (char const*) ctx; size_t cn_len = strlen( cn ); + ((void) next_merged); if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, oid ) == 0 && x509_crt_check_cn( val->p, val->len, cn, cn_len ) == 0 ) From c6573a27a193ce33971ec2912c02d69305bf954a Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sat, 23 Feb 2019 09:13:17 +0000 Subject: [PATCH 036/140] Convert X.509 name buffer to linked list via name traversal callback --- library/x509.c | 58 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/library/x509.c b/library/x509.c index 8b63572a2..72cadd088 100644 --- a/library/x509.c +++ b/library/x509.c @@ -601,41 +601,47 @@ exit: return( ret ); } +static int x509_get_name_cb( void *ctx, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val, + int next_merged ) +{ + mbedtls_x509_name **cur_ptr = (mbedtls_x509_name**) ctx; + mbedtls_x509_name *cur = *cur_ptr; + + if( cur->oid.p != NULL ) + { + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + cur->oid = *oid; + cur->val = *val; + cur->next_merged = next_merged; + + *cur_ptr = cur; + return( 0 ); +} int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, mbedtls_x509_name *cur ) { int ret; - const unsigned char *end_set; - - end_set = *p; - while( 1 ) - { - ret = x509_set_sequence_iterate( p, &end_set, end, - &cur->oid, &cur->val ); - if( ret != 0 ) - return( ret + MBEDTLS_ERR_X509_INVALID_NAME ); - - if( *p != end_set ) - cur->next_merged = 1; - - if( *p == end ) - { - cur->next = NULL; - break; - } - - cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); - if( cur->next == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); - - cur = cur->next; - } + mbedtls_x509_buf_raw name_buf = { *p, end - *p }; + memset( cur, 0, sizeof( mbedtls_x509_name ) ); + ret = mbedtls_x509_name_cmp_raw( &name_buf, &name_buf, + x509_get_name_cb, + &cur ); + if( ret != 0 ) + return( ret ); + *p = (unsigned char*) end; return( 0 ); } - static int x509_parse_int( unsigned char **p, size_t n, int *res ) { *res = 0; From 21f55675716cefccec43790c604dc00d4979ec71 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 15 Feb 2019 15:27:59 +0000 Subject: [PATCH 037/140] Introduce X.509 CRT frame structure This commit restructures the parsing of X.509 CRTs in the following way: First, it introduces a 'frame' structure `mbedtls_x509_crt_frame`, which contains pointers to some structured fields of a CRT as well as copies of primitive fields. For example, there's a pointer-length pair delimiting the raw public key data in the CRT, but there's a C-uint8 to store the CRT version (not a pointer-length pair delimiting the ASN.1 structure holding the version). Setting up a frame from a raw CRT buffer does not require any memory outside of the frame structure itself; it's just attaches a 'template' to the buffer that allows to inspect the structured parts of the CRT afterwards. Note that the frame structure does not correspond to a particular ASN.1 structure; for example, it contains pointers to delimit the three parts of a CRT (TBS, SignatureAlgorithm, Signature), but also pointers to the fields of the TBS, and pointers into the Extensions substructure of the TBS. Further, the commit introduces an internal function `x509_crt_parse_frame()` which sets up a frame from a raw CRT buffer, as well as several small helper functions which help setting up the more complex structures (Subject, Issuer, PK) from the frame. These functions are then put to use to rewrite the existing parsing function `mbedtls_x509_crt_parse_der_core()` by setting up a CRT frame from the input buffer, residing on the stack, and afterwards copying the respective fields to the actual `mbedtls_x509_crt` structure and performing the deeper parsing through the various helper functions. --- include/mbedtls/x509_crt.h | 52 +++ library/x509_crt.c | 779 ++++++++++++++++++++++++------------- 2 files changed, 567 insertions(+), 264 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 76d829bed..25e807743 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -47,6 +47,58 @@ extern "C" { * \{ */ +typedef struct mbedtls_x509_crt_frame +{ + /* Keep these 8-bit fields at the front of the structure to allow them to + * be fetched in a single instruction on Thumb2; putting them at the back + * requires an intermediate address calculation. */ + + uint8_t version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ + uint8_t ca_istrue; /**< Optional Basic Constraint extension value: + * 1 if this certificate belongs to a CA, 0 otherwise. */ + uint8_t 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+ */ + uint8_t ns_cert_type; /**< Optional Netscape certificate type extension value: + * See the values in x509.h */ + + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + uint32_t ext_types; /**< Bitfield indicating which extensions are present. + * See the values in x509.h. */ + + mbedtls_md_type_t sig_md; /**< The hash algorithm used to hash CRT before signing. */ + mbedtls_pk_type_t sig_pk; /**< The signature algorithm used to sign the CRT hash. */ + + mbedtls_x509_time valid_from; /**< The start time of certificate validity. */ + mbedtls_x509_time valid_to; /**< The end time of certificate validity. */ + + mbedtls_x509_buf_raw raw; /**< The raw certificate data in DER. */ + mbedtls_x509_buf_raw tbs; /**< The part of the CRT that is [T]o [B]e [S]igned. */ + + mbedtls_x509_buf_raw serial; /**< The unique ID for certificate issued by a specific CA. */ + + mbedtls_x509_buf_raw pubkey_raw; /**< The raw public key data (DER). */ + + mbedtls_x509_buf_raw issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + + mbedtls_x509_buf_raw subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf_raw subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + mbedtls_x509_buf_raw sig; /**< Signature: hash of the tbs part signed with the private key. */ + mbedtls_x509_buf_raw sig_alg; /**< The signature algorithm used for \p sig. */ + + mbedtls_x509_buf_raw v3_ext; /**< The raw data for the extension list in the certificate. + * Might be useful for manual inspection of extensions that + * Mbed TLS doesn't yet support. */ + mbedtls_x509_buf_raw subject_alt_raw; /**< The raw data for the SubjectAlternativeNames extension. */ + mbedtls_x509_buf_raw ext_key_usage_raw; /**< The raw data for the ExtendedKeyUsage extension. */ + + mbedtls_x509_buf_raw issuer_raw_with_hdr; + mbedtls_x509_buf_raw subject_raw_with_hdr; + +} mbedtls_x509_crt_frame; + /** * Container for an X.509 certificate. The certificate may be chained. */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 77056c07f..3d50b20b8 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -78,6 +78,18 @@ #endif /* !_WIN32 || EFIX64 || EFI32 */ #endif +static int x509_crt_parse_frame( unsigned char *start, + unsigned char *end, + mbedtls_x509_crt_frame *frame ); +static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_name *subject ); +static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_name *issuer ); +static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_sequence *subject_alt ); +static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_sequence *ext_key_usage ); + /* * Item in a verification chain: cert and flags for it */ @@ -553,7 +565,7 @@ static int x509_crt_get_ext_cb( void *ctx, size_t ext_len ) { int ret; - mbedtls_x509_crt *crt = (mbedtls_x509_crt *) ctx; + mbedtls_x509_crt_frame *frame = (mbedtls_x509_crt_frame *) ctx; size_t len; unsigned char *end, *end_ext_octet; mbedtls_x509_buf extn_oid = { 0, 0, NULL }; @@ -615,10 +627,10 @@ static int x509_crt_get_ext_cb( void *ctx, } /* Forbid repeated extensions */ - if( ( crt->ext_types & ext_type ) != 0 ) + if( ( frame->ext_types & ext_type ) != 0 ) return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); - crt->ext_types |= ext_type; + frame->ext_types |= ext_type; switch( ext_type ) { case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: @@ -633,45 +645,57 @@ static int x509_crt_get_ext_cb( void *ctx, if( ret != 0 ) goto err; - crt->ca_istrue = ca_istrue; - crt->max_pathlen = max_pathlen; + frame->ca_istrue = ca_istrue; + frame->max_pathlen = max_pathlen; break; } case MBEDTLS_X509_EXT_KEY_USAGE: /* Parse key usage */ ret = x509_get_key_usage( &p, end_ext_octet, - &crt->key_usage ); + &frame->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 ); - } + frame->subject_alt_raw.p = p; + frame->subject_alt_raw.len = end_ext_octet - p; + + ret = mbedtls_asn1_traverse_sequence_of( &p, end_ext_octet, + MBEDTLS_ASN1_TAG_CLASS_MASK, + MBEDTLS_ASN1_CONTEXT_SPECIFIC, + MBEDTLS_ASN1_TAG_VALUE_MASK, + 2 /* SubjectAlt DNS */, + NULL, NULL ); + if( ret != 0 ) + goto err; break; case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: /* Parse extended key usage */ - crt->ext_key_usage_raw.p = p; - crt->ext_key_usage_raw.len = end_ext_octet - p; - if( ( ret = x509_get_ext_key_usage( &p, end_ext_octet, - &crt->ext_key_usage ) ) != 0 ) + frame->ext_key_usage_raw.p = p; + frame->ext_key_usage_raw.len = end_ext_octet - p; + if( frame->ext_key_usage_raw.len == 0 ) { - return( ret ); + ret = MBEDTLS_ERR_ASN1_INVALID_LENGTH; + goto err; } + + /* Check structural sanity of extension. */ + ret = mbedtls_asn1_traverse_sequence_of( &p, end_ext_octet, + 0xFF, MBEDTLS_ASN1_OID, + 0, 0, NULL, NULL ); + if( ret != 0 ) + goto err; + break; case MBEDTLS_X509_EXT_NS_CERT_TYPE: /* Parse netscape certificate type */ ret = x509_get_ns_cert_type( &p, end_ext_octet, - &crt->ns_cert_type ); + &frame->ns_cert_type ); if( ret != 0 ) goto err; break; @@ -695,31 +719,18 @@ err: return( ret ); } -static int x509_get_crt_ext( unsigned char **p, - unsigned char *end, - mbedtls_x509_crt *crt ) +static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame ) { int ret; - size_t len; + unsigned char *p = frame->v3_ext.p; + unsigned char *end = p + frame->v3_ext.len; - if( *p == end ) + 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, + 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: + 0, 0, x509_crt_get_ext_cb, frame ); if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) return( ret ); @@ -732,6 +743,363 @@ err: return( ret ); } +static int x509_crt_parse_frame( unsigned char *start, + unsigned char *end, + mbedtls_x509_crt_frame *frame ) +{ + int ret; + unsigned char *p; + size_t len; + + mbedtls_x509_buf tmp; + unsigned char *tbs_start; + + mbedtls_x509_buf outer_sig_alg; + size_t inner_sig_alg_len; + unsigned char *inner_sig_alg_start; + + memset( frame, 0, sizeof( *frame ) ); + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * + */ + p = start; + + frame->raw.p = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + /* NOTE: We are currently not checking that the `Certificate` + * structure spans the entire buffer. */ + end = p + len; + frame->raw.len = end - frame->raw.p; + + /* + * TBSCertificate ::= SEQUENCE { ... + */ + frame->tbs.p = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + tbs_start = p; + + /* Breadth-first parsing: Jump over TBS for now. */ + p += len; + frame->tbs.len = p - frame->tbs.p; + + /* + * AlgorithmIdentifier ::= SEQUENCE { ... + */ + outer_sig_alg.p = p; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + } + p += len; + outer_sig_alg.len = p - outer_sig_alg.p; + + /* + * signatureValue BIT STRING + */ + ret = mbedtls_x509_get_sig( &p, end, &tmp ); + if( ret != 0 ) + return( ret ); + frame->sig.p = tmp.p; + frame->sig.len = tmp.len; + + /* Check that we consumed the entire `Certificate` structure. */ + if( p != end ) + { + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* Parse TBSCertificate structure + * + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version MUST be v3 + * } + */ + end = frame->tbs.p + frame->tbs.len; + p = tbs_start; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + { + int version; + ret = x509_get_version( &p, end, &version ); + if( ret != 0 ) + return( ret ); + + if( version < 0 || version > 2 ) + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + + frame->version = version + 1; + } + + /* + * CertificateSerialNumber ::= INTEGER + */ + ret = mbedtls_x509_get_serial( &p, end, &tmp ); + if( ret != 0 ) + return( ret ); + + frame->serial.p = tmp.p; + frame->serial.len = tmp.len; + + /* + * signature AlgorithmIdentifier + */ + inner_sig_alg_start = p; + ret = mbedtls_x509_get_sig_alg_raw( &p, end, &frame->sig_md, + &frame->sig_pk, NULL ); + if( ret != 0 ) + return( ret ); + inner_sig_alg_len = p - inner_sig_alg_start; + + frame->sig_alg.p = inner_sig_alg_start; + frame->sig_alg.len = inner_sig_alg_len; + + /* Consistency check: + * Inner and outer AlgorithmIdentifier structures must coincide: + * + * Quoting RFC 5280, Section 4.1.1.2: + * This field MUST contain the same algorithm identifier as the + * signature field in the sequence tbsCertificate (Section 4.1.2.3). + */ + if( outer_sig_alg.len != inner_sig_alg_len || + memcmp( outer_sig_alg.p, inner_sig_alg_start, inner_sig_alg_len ) != 0 ) + { + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + /* + * issuer Name + * + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + */ + frame->issuer_raw_with_hdr.p = p; + + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT ); + frame->issuer_raw.p = p; + frame->issuer_raw.len = len; + p += len; + + ret = mbedtls_x509_name_cmp_raw( &frame->issuer_raw, + &frame->issuer_raw, + NULL, NULL ); + if( ret != 0 ) + return( ret ); + + frame->issuer_raw_with_hdr.len = p - frame->issuer_raw_with_hdr.p; + + /* + * Validity ::= SEQUENCE { ... + */ + ret = x509_get_dates( &p, end, &frame->valid_from, &frame->valid_to ); + if( ret != 0 ) + return( ret ); + + /* + * subject Name + * + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + */ + frame->subject_raw_with_hdr.p = p; + + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT ); + frame->subject_raw.p = p; + frame->subject_raw.len = len; + p += len; + + ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw, + &frame->subject_raw, + NULL, NULL ); + if( ret != 0 ) + return( ret ); + + frame->subject_raw_with_hdr.len = p - frame->subject_raw_with_hdr.p; + + /* + * SubjectPublicKeyInfo + */ + frame->pubkey_raw.p = p; + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + return( ret + MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + p += len; + frame->pubkey_raw.len = p - frame->pubkey_raw.p; + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + */ + if( frame->version == 2 || frame->version == 3 ) + { + ret = x509_get_uid( &p, end, &tmp, 1 /* implicit tag */ ); + if( ret != 0 ) + return( ret ); + + frame->issuer_id.p = tmp.p; + frame->issuer_id.len = tmp.len; + } + + /* + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + */ + if( frame->version == 2 || frame->version == 3 ) + { + ret = x509_get_uid( &p, end, &tmp, 2 /* implicit tag */ ); + if( ret != 0 ) + return( ret ); + + frame->subject_id.p = tmp.p; + frame->subject_id.len = tmp.len; + } + + /* + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ +#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + if( frame->version == 3 ) +#endif + { + if( p != end ) + { + ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 3 ); + if( len == 0 ) + ret = MBEDTLS_ERR_ASN1_OUT_OF_DATA; + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + frame->v3_ext.p = p; + frame->v3_ext.len = len; + + p += len; + } + + ret = x509_crt_frame_parse_ext( frame ); + if( ret != 0 ) + return( ret ); + } + + /* Wrapup: Check that we consumed the entire `TBSCertificate` structure. */ + if( p != end ) + { + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_name *subject ) +{ + unsigned char *p = frame->subject_raw.p; + unsigned char *end = p + frame->subject_raw.len; + + return( mbedtls_x509_get_name( &p, end, subject ) ); +} + +static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_name *issuer ) +{ + unsigned char *p = frame->issuer_raw.p; + unsigned char *end = p + frame->issuer_raw.len; + + return( mbedtls_x509_get_name( &p, end, issuer ) ); +} + +static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_sequence *subject_alt ) +{ + int ret; + unsigned char *p = frame->subject_alt_raw.p; + unsigned char *end = p + frame->subject_alt_raw.len; + + memset( subject_alt, 0, sizeof( *subject_alt ) ); + + if( ( frame->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) == 0 ) + return( 0 ); + + ret = x509_get_subject_alt_name( p, end, subject_alt ); + if( ret != 0 ) + ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS; + return( ret ); +} + +static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_x509_sequence *ext_key_usage ) +{ + int ret; + unsigned char *p = frame->ext_key_usage_raw.p; + unsigned char *end = p + frame->ext_key_usage_raw.len; + + memset( ext_key_usage, 0, sizeof( *ext_key_usage ) ); + + if( ( frame->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + return( 0 ); + + ret = x509_get_ext_key_usage( &p, end, ext_key_usage ); + if( ret != 0 ) + { + ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS; + return( ret ); + } + + return( 0 ); +} + +static int x509_crt_pk_from_frame( mbedtls_x509_crt_frame *frame, + mbedtls_pk_context *pk ) +{ + unsigned char *p = frame->pubkey_raw.p; + unsigned char *end = p + frame->pubkey_raw.len; + return( mbedtls_pk_parse_subpubkey( &p, end, pk ) ); +} + /* * Parse and fill a single X.509 certificate in DER format */ @@ -741,261 +1109,144 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, int make_copy ) { int ret; - size_t len; - unsigned char *p, *end, *crt_end; - mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + mbedtls_x509_crt_frame frame; - memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); - memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); - memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); - - /* - * Check for valid input - */ if( crt == NULL || buf == NULL ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); - /* Use the original buffer until we figure out actual length. */ - p = (unsigned char*) buf; - len = buflen; - end = p + len; - - /* - * Certificate ::= SEQUENCE { - * tbsCertificate TBSCertificate, - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING } - */ - if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + if( make_copy == 0 ) { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT ); - } - - end = crt_end = p + len; - crt->raw.len = crt_end - buf; - if( make_copy != 0 ) - { - /* Create and populate a new buffer for the raw field. */ - crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); - if( crt->raw.p == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); - - memcpy( crt->raw.p, buf, crt->raw.len ); - crt->own_buffer = 1; - - p += crt->raw.len - len; - end = crt_end = p + len; + crt->raw.p = (unsigned char*) buf; + crt->raw.len = buflen; + crt->own_buffer = 0; } else { - crt->raw.p = (unsigned char*) buf; - crt->own_buffer = 0; + crt->raw.p = mbedtls_calloc( 1, buflen ); + if( crt->raw.p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + crt->raw.len = buflen; + memcpy( crt->raw.p, buf, buflen ); + + crt->own_buffer = 1; } - /* - * TBSCertificate ::= SEQUENCE { + /* Parse CRT frame. + * This omits: + * - Issuer, Subject + * - ExtKeyUsage, SubjectAltNames, + * - Time + * - PK */ - crt->tbs.p = p; + ret = x509_crt_parse_frame( crt->raw.p, + crt->raw.p + crt->raw.len, + &frame ); + if( ret != 0 ) + goto exit; - if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); - } - - end = p + len; - crt->tbs.len = end - crt->tbs.p; - - /* - * Version ::= INTEGER { v1(0), v2(1), v3(2) } + /* Currently, we accept DER encoded CRTs with trailing garbage + * and promise to not account for the garbage in the `raw` field. * - * CertificateSerialNumber ::= INTEGER - * - * signature AlgorithmIdentifier - */ - if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || - ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || - ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, - &sig_params1 ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } + * Note that this means that `crt->raw.len` is not necessarily the + * full size of the heap buffer allocated at `crt->raw.p` in case + * of copy-mode, but this is not a problem: freeing the buffer doesn't + * need the size, and the garbage data doesn't need zeroization. */ + crt->raw.len = frame->raw.len; - if( crt->version < 0 || crt->version > 2 ) - { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); - } - - crt->version++; - - if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, - &crt->sig_md, &crt->sig_pk, - &crt->sig_opts ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } + /* Copy frame to legacy CRT structure -- that's inefficient, but if + * memory matters, the new CRT structure should be used anyway. */ + crt->tbs.p = frame.tbs.p; + crt->tbs.len = frame.tbs.len; + crt->serial.p = frame.serial.p; + crt->serial.len = frame.serial.len; + crt->issuer_raw.p = frame.issuer_raw_with_hdr.p; + crt->issuer_raw.len = frame.issuer_raw_with_hdr.len; + crt->subject_raw.p = frame.subject_raw_with_hdr.p; + crt->subject_raw.len = frame.subject_raw_with_hdr.len; + crt->issuer_raw_no_hdr = frame.issuer_raw; + crt->subject_raw_no_hdr = frame.subject_raw; + crt->issuer_id.p = frame.issuer_id.p; + crt->issuer_id.len = frame.issuer_id.len; + crt->subject_id.p = frame.subject_id.p; + crt->subject_id.len = frame.subject_id.len; + crt->pk_raw.p = frame.pubkey_raw.p; + crt->pk_raw.len = frame.pubkey_raw.len; + crt->ext_key_usage_raw = frame.ext_key_usage_raw; + crt->subject_alt_raw = frame.subject_alt_raw; + crt->sig.p = frame.sig.p; + crt->sig.len = frame.sig.len; + crt->valid_from = frame.valid_from; + crt->valid_to = frame.valid_to; + crt->v3_ext.p = frame.v3_ext.p; + crt->v3_ext.len = frame.v3_ext.len; + crt->version = frame.version; + crt->ca_istrue = frame.ca_istrue; + crt->max_pathlen = frame.max_pathlen; + crt->ext_types = frame.ext_types; + crt->key_usage = frame.key_usage; + crt->ns_cert_type = frame.ns_cert_type; /* - * issuer Name + * Obtain the remaining fields from the frame. */ - crt->issuer_raw.p = p; - if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); - } - crt->issuer_raw_no_hdr.p = p; + /* sig_oid: Previously, needed for convenience in + * mbedtls_x509_crt_info(), now pure legacy burden. */ + unsigned char *tmp = frame.sig_alg.p; + unsigned char *end = tmp + frame.sig_alg.len; + mbedtls_x509_buf sig_oid, sig_params; - if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - - crt->issuer_raw_no_hdr.len = p - crt->issuer_raw_no_hdr.p; - crt->issuer_raw.len = p - crt->issuer_raw.p; - - /* - * Validity ::= SEQUENCE { - * notBefore Time, - * notAfter Time } - * - */ - if( ( ret = x509_get_dates( &p, end, &crt->valid_from, - &crt->valid_to ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - - /* - * subject Name - */ - crt->subject_raw.p = p; - - if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); - } - - crt->subject_raw_no_hdr.p = p; - - if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - - crt->subject_raw_no_hdr.len = p - crt->subject_raw_no_hdr.p; - crt->subject_raw.len = p - crt->subject_raw.p; - - /* - * SubjectPublicKeyInfo - */ - crt->pk_raw.p = p; - if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - crt->pk_raw.len = p - crt->pk_raw.p; - - /* - * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - * extensions [3] EXPLICIT Extensions OPTIONAL - * -- If present, version shall be v3 - */ - if( crt->version == 2 || crt->version == 3 ) - { - ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + ret = mbedtls_x509_get_alg( &tmp, end, + &sig_oid, &sig_params ); if( ret != 0 ) { - mbedtls_x509_crt_free( crt ); - return( ret ); + /* This should never happen, because we check + * the sanity of the AlgorithmIdentifier structure + * during frame parsing. */ + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto exit; + } + crt->sig_oid = sig_oid; + + /* Signature parameters */ + tmp = frame.sig_alg.p; + ret = mbedtls_x509_get_sig_alg_raw( &tmp, end, + &crt->sig_md, &crt->sig_pk, + &crt->sig_opts ); + if( ret != 0 ) + { + /* Again, this should never happen. */ + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto exit; } } - if( crt->version == 2 || crt->version == 3 ) - { - ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); - if( ret != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - } + ret = x509_crt_pk_from_frame( &frame, &crt->pk ); + if( ret != 0 ) + goto exit; -#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) - if( crt->version == 3 ) -#endif - { - ret = x509_get_crt_ext( &p, end, crt ); - if( ret != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - } + ret = x509_crt_subject_from_frame( &frame, &crt->subject ); + if( ret != 0 ) + goto exit; - if( p != end ) - { + ret = x509_crt_issuer_from_frame( &frame, &crt->issuer ); + if( ret != 0 ) + goto exit; + + ret = x509_crt_subject_alt_from_frame( &frame, &crt->subject_alt_names ); + if( ret != 0 ) + goto exit; + + ret = x509_crt_ext_key_usage_from_frame( &frame, &crt->ext_key_usage ); + if( ret != 0 ) + goto exit; + +exit: + if( ret != 0 ) mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - } - end = crt_end; - - /* - * } - * -- end of TBSCertificate - * - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING - */ - if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - - if( crt->sig_oid.len != sig_oid2.len || - memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || - sig_params1.len != sig_params2.len || - ( sig_params1.len != 0 && - memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) - { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_SIG_MISMATCH ); - } - - if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) - { - mbedtls_x509_crt_free( crt ); - return( ret ); - } - - if( p != end ) - { - mbedtls_x509_crt_free( crt ); - return( MBEDTLS_ERR_X509_INVALID_FORMAT + - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); - } - - return( 0 ); + return( ret ); } /* From 337088aa2d872876514e88a76d613345a60c1ade Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 14:53:14 +0000 Subject: [PATCH 038/140] Add internal API for acquire/release of CRT frames and PKs The goal of the subsequent commits is to remove all direct uses of the existing `mbedtls_x509_crt` apart from the `raw` buffer and the linked list `next` pointer. The approach is the following: Whenever a code-path needs to inspect a CRT, it can request a frame for the CRT through the API `x509_crt_frame_acquire()`. On success, this function returns a pointer to a frame structure for the CRT (the origin of which is flexible and need not concern the caller) that can be used to inspect the desired fields. Once done, the caller hands back the frame through an explicit call to `x509_crt_frame_release()`. This commit also adds an inefficient dummy implementation for `x509_crt_frame_acquire()` which always allocates a new `mbedtls_x509_crt_frame` structure on the heap and parses it from the raw data underlying the CRT. This will change in subsequent commits, but it constitutes a valid implementation to test against. Ultimately, `x509_crt_frame_acquire()` is to compute a frame for the given CRT only once, and cache it for subsequent calls. The need for `x509_crt_frame_release()` is the following: When implementing `x509_crt_frame_acquire()` through a flushable cache as indicated above, it must be ensured that no thread destroys a cached frame structure for the time it is needed by another thread. The `acquire/release` pair allows to explicitly delimit the lifetime requirements for the returned frame structure. The frame pointer must not be used after the `release` call anymore; and in fact, the dummy implementation shows that it would immediately lead to a memory failure. Analogously to `x509_crt_frame_{acquire|release}()`, there's also `x509_crt_pk_{acquire|release}()` which allows to acquire/release a PK context setup from the public key contained within the CRT. --- library/x509_crt.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3d50b20b8..218461d20 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -90,6 +90,51 @@ static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_sequence *ext_key_usage ); +static void x509_free_sequence( mbedtls_x509_sequence *seq ); +static void x509_free_name( mbedtls_x509_name *name ); + +static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame **frame_ptr ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + + frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) ); + if( frame == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + ret = x509_crt_parse_frame( crt->raw.p, crt->raw.p + crt->raw.len, + frame ); + if( ret != 0 ) + return( ret ); + + *frame_ptr = frame; + return( 0 ); +} + +static void x509_crt_frame_release( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame *frame ) +{ + ((void) crt); + if( frame == NULL ) + return; + mbedtls_free( frame ); +} +static int x509_crt_pk_acquire( mbedtls_x509_crt *crt, + mbedtls_pk_context **pk ) +{ + *pk = &crt->pk; + return( 0 ); +} + +static void x509_crt_pk_release( mbedtls_x509_crt *crt, + mbedtls_pk_context *pk ) +{ + ((void) crt); + ((void) pk); + return; +} + /* * Item in a verification chain: cert and flags for it */ From 1e0677acc10f30a1c96b918082139b019b49f647 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 14:58:22 +0000 Subject: [PATCH 039/140] Make use of CRT acquire/release for child in CRT chain verification During CRT verification, `x509_crt_check_signature()` checks whether a candidate parent CRT correctly signs the current child CRT. This commit rewrites this function to use the new acquire/release framework for using CRTs. --- library/x509_crt.c | 113 +++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 35 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 218461d20..29938c232 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2162,38 +2162,66 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, /* * Check the signature of a certificate by its parent */ -static int x509_crt_check_signature( const mbedtls_x509_crt *child, +static int x509_crt_check_signature( const mbedtls_x509_crt_frame *child, mbedtls_x509_crt *parent, mbedtls_x509_crt_restart_ctx *rs_ctx ) { - const mbedtls_md_info_t *md_info; + int ret; + size_t hash_len; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; - md_info = mbedtls_md_info_from_type( child->sig_md ); - if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) + mbedtls_md_type_t sig_md; + mbedtls_pk_type_t sig_pk; + void *sig_opts; + + const mbedtls_md_info_t *md_info; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) { - /* Note: this can't happen except after an internal error */ - return( -1 ); + /* Get signature options -- currently only + * necessary for RSASSA-PSS. */ + unsigned char *p = child->sig_alg.p; + unsigned char *end = p + child->sig_alg.len; + ret = mbedtls_x509_get_sig_alg_raw( &p, end, &sig_md, + &sig_pk, &sig_opts ); + if( ret != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } } +#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + sig_md = child->sig_md; + sig_pk = child->sig_pk; + sig_opts = NULL; +#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + md_info = mbedtls_md_info_from_type( sig_md ); + if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) + return( -1 ); + + hash_len = mbedtls_md_get_size( md_info ); /* Skip expensive computation on obvious mismatch */ - if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) ) + if( ! mbedtls_pk_can_do( &parent->pk, sig_pk ) ) return( -1 ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) { return( mbedtls_pk_verify_restartable( &parent->pk, - child->sig_md, hash, mbedtls_md_get_size( md_info ), + sig_md, hash, mbedtls_md_get_size( md_info ), child->sig.p, child->sig.len, &rs_ctx->pk ) ); } #else (void) rs_ctx; #endif - return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, - child->sig_md, hash, mbedtls_md_get_size( md_info ), - child->sig.p, child->sig.len ) ); + ret = mbedtls_pk_verify_ext( sig_pk, sig_opts, &parent->pk, + sig_md, hash, hash_len, + child->sig.p, child->sig.len ); + mbedtls_free( sig_opts ); + return( ret ); } /* @@ -2202,14 +2230,14 @@ static int x509_crt_check_signature( const mbedtls_x509_crt *child, * * top means parent is a locally-trusted certificate */ -static int x509_crt_check_parent( const mbedtls_x509_crt *child, +static int x509_crt_check_parent( const mbedtls_x509_crt_frame *child, const mbedtls_x509_crt *parent, int top ) { int need_ca_bit; /* Parent must be the issuer */ - if( mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, + if( mbedtls_x509_name_cmp_raw( &child->issuer_raw, &parent->subject_raw_no_hdr, NULL, NULL ) != 0 ) { @@ -2281,7 +2309,7 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child, * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise */ static int x509_crt_find_parent_in( - mbedtls_x509_crt *child, + mbedtls_x509_crt_frame const *child, mbedtls_x509_crt *candidates, mbedtls_x509_crt **r_parent, int *r_signature_is_good, @@ -2406,7 +2434,8 @@ check_signature: * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise */ static int x509_crt_find_parent( - mbedtls_x509_crt *child, + mbedtls_x509_crt_frame const *child, + mbedtls_x509_crt *rest, mbedtls_x509_crt *trust_ca, mbedtls_x509_crt **parent, int *parent_is_trusted, @@ -2430,7 +2459,7 @@ static int x509_crt_find_parent( #endif while( 1 ) { - search_list = *parent_is_trusted ? trust_ca : child->next; + search_list = *parent_is_trusted ? trust_ca : rest; ret = x509_crt_find_parent_in( child, search_list, parent, signature_is_good, @@ -2473,14 +2502,14 @@ static int x509_crt_find_parent( * check for self-issued as self-signatures are not checked) */ static int x509_crt_check_ee_locally_trusted( - mbedtls_x509_crt *crt, - mbedtls_x509_crt *trust_ca ) + mbedtls_x509_crt_frame const *crt, + mbedtls_x509_crt const *trust_ca ) { - mbedtls_x509_crt *cur; + mbedtls_x509_crt const *cur; /* must be self-issued */ - if( mbedtls_x509_name_cmp_raw( &crt->issuer_raw_no_hdr, - &crt->subject_raw_no_hdr, + if( mbedtls_x509_name_cmp_raw( &crt->issuer_raw, + &crt->subject_raw, NULL, NULL ) != 0 ) { return( -1 ); @@ -2553,7 +2582,7 @@ static int x509_crt_verify_chain( int ret; uint32_t *flags; mbedtls_x509_crt_verify_chain_item *cur; - mbedtls_x509_crt *child; + mbedtls_x509_crt *child_crt; mbedtls_x509_crt *parent; int parent_is_trusted; int child_is_trusted; @@ -2570,20 +2599,24 @@ static int x509_crt_verify_chain( /* restore derived state */ cur = &ver_chain->items[ver_chain->len - 1]; - child = cur->crt; + child_crt = cur->crt; + + child_is_trusted = 0; goto find_parent; } #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ - child = crt; + child_crt = crt; self_cnt = 0; parent_is_trusted = 0; child_is_trusted = 0; while( 1 ) { + mbedtls_x509_crt_frame *child; + /* Add certificate to the verification chain */ cur = &ver_chain->items[ver_chain->len]; - cur->crt = child; + cur->crt = child_crt; cur->flags = 0; ver_chain->len++; @@ -2591,6 +2624,10 @@ static int x509_crt_verify_chain( find_parent: #endif + ret = x509_crt_frame_acquire( child_crt, &child ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + flags = &cur->flags; /* Check time-validity (all certificates) */ @@ -2602,7 +2639,7 @@ find_parent: /* Stop here for trusted roots (but not for trusted EE certs) */ if( child_is_trusted ) - return( 0 ); + goto release; /* Check signature algorithm: MD & PK algs */ if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) @@ -2615,13 +2652,13 @@ find_parent: if( ver_chain->len == 1 && x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) { - return( 0 ); + goto release; } /* Look for a parent in trusted CAs or up the chain */ ret = x509_crt_find_parent( child, trust_ca, &parent, - &parent_is_trusted, &signature_is_good, - ver_chain->len - 1, self_cnt, rs_ctx ); + &parent_is_trusted, &signature_is_good, + ver_chain->len - 1, self_cnt, rs_ctx ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) @@ -2631,7 +2668,7 @@ find_parent: rs_ctx->self_cnt = self_cnt; rs_ctx->ver_chain = *ver_chain; /* struct copy */ - return( ret ); + goto release; } #else (void) ret; @@ -2641,15 +2678,15 @@ find_parent: if( parent == NULL ) { *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - return( 0 ); + goto release; } /* Count intermediate self-issued (not necessarily self-signed) certs. * These can occur with some strategies for key rollover, see [SIRO], * and should be excluded from max_pathlen checks. */ if( ver_chain->len != 1 && - mbedtls_x509_name_cmp_raw( &child->issuer_raw_no_hdr, - &child->subject_raw_no_hdr, + mbedtls_x509_name_cmp_raw( &child->issuer_raw, + &child->subject_raw, NULL, NULL ) == 0 ) { self_cnt++; @@ -2661,7 +2698,8 @@ find_parent: ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) { /* return immediately to avoid overflow the chain array */ - return( MBEDTLS_ERR_X509_FATAL_ERROR ); + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto release; } /* signature was checked while searching parent */ @@ -2682,11 +2720,16 @@ find_parent: #endif /* prepare for next iteration */ - child = parent; + x509_crt_frame_release( child_crt, child ); + child_crt = parent; parent = NULL; child_is_trusted = parent_is_trusted; signature_is_good = 0; } + +release: + x509_crt_frame_release( child_crt, child ); + return( ret ); } /* From a788cab46d267d53f5c76bf867f85a19848b8e82 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sun, 24 Feb 2019 17:47:46 +0000 Subject: [PATCH 040/140] Check validity of potential parent before checking signature The function `x509_crt_find_parent_in()` traverses a list of CRTs to find a potential parent to a given CRT. So far, the logic was the following: For each candidate, - check basic parenting skills (mostly name match) - verify signature - verify validity This order is insuitable for the new acquire/release layer of indirection when dealing with CRTs, because we either have to query the candidate's CRT frame twice, or query frame and PK simultaneously. This commit moves the validity check to the beginning of the routine to allow querying for the frame and then for the PK. The entry point for restartable ECC needs to be moved for that to not forget the validity-flag while pausing ECC computations. --- library/x509_crt.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 29938c232..efacf9ba9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2346,21 +2346,35 @@ static int x509_crt_find_parent_in( for( parent = candidates; parent != NULL; parent = parent->next ) { - /* basic parenting skills (name, CA bit, key usage) */ - if( x509_crt_check_parent( child, parent, top ) != 0 ) - continue; + int parent_valid, parent_match, path_len_ok; - /* +1 because stored max_pathlen is 1 higher that the actual value */ - if( parent->max_pathlen > 0 && - (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) - { - continue; - } - - /* Signature */ #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) check_signature: #endif + + parent_valid = parent_match = path_len_ok = 0; + + if( mbedtls_x509_time_is_past( &parent->valid_from ) && + mbedtls_x509_time_is_future( &parent->valid_to ) ) + { + parent_valid = 1; + } + + /* basic parenting skills (name, CA bit, key usage) */ + if( x509_crt_check_parent( child, parent, top ) == 0 ) + parent_match = 1; + + /* +1 because stored max_pathlen is 1 higher that the actual value */ + if( !( parent->max_pathlen > 0 && + (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) ) + { + path_len_ok = 1; + } + + if( parent_match == 0 || path_len_ok == 0 ) + continue; + + /* Signature */ ret = x509_crt_check_signature( child, parent, rs_ctx ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) @@ -2382,8 +2396,7 @@ check_signature: continue; /* optional time check */ - if( mbedtls_x509_time_is_past( &parent->valid_to ) || - mbedtls_x509_time_is_future( &parent->valid_from ) ) + if( !parent_valid ) { if( fallback_parent == NULL ) { From 5299cf87d41ebe1b7aba65ed37ac7a073421438c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 13:50:41 +0000 Subject: [PATCH 041/140] Add structure holding X.509 CRT signature information This commit introduces an internal structure `mbedtls_x509_crt_sig_info` containing all information that has to be kept from a child CRT when searching for a potential parent: - The issuer name - The signature type - The signature - The hash of the CRT The structure can be obtained from a CRT frame via `x509_crt_get_sig_info()` and freed via `x509_crt_free_sig_info()`. The purpose of this is to reduce the amount of RAM used during CRT chain verification; once we've extracted the signature info structure from the current child CRT, we can free all cached data for that CRT (frame and PK) before searching for a suitable parent. This way, there will ultimately not be more than one frame needed at a single point during the verification. --- library/x509_crt.c | 275 +++++++++++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 110 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index efacf9ba9..cfe082113 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -93,6 +93,15 @@ static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, static void x509_free_sequence( mbedtls_x509_sequence *seq ); static void x509_free_name( mbedtls_x509_name *name ); +static int x509_crt_pk_acquire( mbedtls_x509_crt *crt, + mbedtls_pk_context **pk ); +static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame **frame ); +static void x509_crt_pk_release( mbedtls_x509_crt *crt, + mbedtls_pk_context *pk ); +static void x509_crt_frame_release( mbedtls_x509_crt *crt, + mbedtls_pk_context *pk ); + static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame **frame_ptr ) { @@ -2162,66 +2171,33 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, /* * Check the signature of a certificate by its parent */ -static int x509_crt_check_signature( const mbedtls_x509_crt_frame *child, +static int x509_crt_check_signature( const mbedtls_x509_crt_sig_info *sig_info, mbedtls_x509_crt *parent, mbedtls_x509_crt_restart_ctx *rs_ctx ) { - int ret; - size_t hash_len; - unsigned char hash[MBEDTLS_MD_MAX_SIZE]; - - mbedtls_md_type_t sig_md; - mbedtls_pk_type_t sig_pk; - void *sig_opts; - - const mbedtls_md_info_t *md_info; - -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) - { - /* Get signature options -- currently only - * necessary for RSASSA-PSS. */ - unsigned char *p = child->sig_alg.p; - unsigned char *end = p + child->sig_alg.len; - ret = mbedtls_x509_get_sig_alg_raw( &p, end, &sig_md, - &sig_pk, &sig_opts ); - if( ret != 0 ) - { - /* Note: this can't happen except after an internal error */ - return( -1 ); - } - } -#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - sig_md = child->sig_md; - sig_pk = child->sig_pk; - sig_opts = NULL; -#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - - md_info = mbedtls_md_info_from_type( sig_md ); - if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) - return( -1 ); - - hash_len = mbedtls_md_get_size( md_info ); - /* Skip expensive computation on obvious mismatch */ - if( ! mbedtls_pk_can_do( &parent->pk, sig_pk ) ) + if( ! mbedtls_pk_can_do( &parent->pk, sig_info->sig_pk ) ) return( -1 ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) { return( mbedtls_pk_verify_restartable( &parent->pk, - sig_md, hash, mbedtls_md_get_size( md_info ), - child->sig.p, child->sig.len, &rs_ctx->pk ) ); + sig_info->sig_md, + sig_info->crt_hash, sig_info->crt_hash_len, + sig_info->sig.p, sig_info->sig.len, + &rs_ctx->pk ) ); } #else (void) rs_ctx; #endif - ret = mbedtls_pk_verify_ext( sig_pk, sig_opts, &parent->pk, - sig_md, hash, hash_len, - child->sig.p, child->sig.len ); - mbedtls_free( sig_opts ); - return( ret ); + return( mbedtls_pk_verify_ext( sig_info->sig_pk, + sig_info->sig_opts, + &parent->pk, + sig_info->sig_md, + sig_info->crt_hash, sig_info->crt_hash_len, + sig_info->sig.p, sig_info->sig.len ) ); } /* @@ -2230,14 +2206,14 @@ static int x509_crt_check_signature( const mbedtls_x509_crt_frame *child, * * top means parent is a locally-trusted certificate */ -static int x509_crt_check_parent( const mbedtls_x509_crt_frame *child, +static int x509_crt_check_parent( const mbedtls_x509_crt_sig_info *child_sig, const mbedtls_x509_crt *parent, int top ) { int need_ca_bit; /* Parent must be the issuer */ - if( mbedtls_x509_name_cmp_raw( &child->issuer_raw, + if( mbedtls_x509_name_cmp_raw( &child_sig->issuer_raw, &parent->subject_raw_no_hdr, NULL, NULL ) != 0 ) { @@ -2265,6 +2241,71 @@ static int x509_crt_check_parent( const mbedtls_x509_crt_frame *child, return( 0 ); } +typedef struct mbedtls_x509_crt_sig_info +{ + mbedtls_md_type_t sig_md; + mbedtls_pk_type_t sig_pk; + void *sig_opts; + uint8_t crt_hash[MBEDTLS_MD_MAX_SIZE]; + size_t crt_hash_len; + mbedtls_x509_buf_raw sig; + mbedtls_x509_buf_raw issuer_raw; +} mbedtls_x509_crt_sig_info; + +static void x509_crt_free_sig_info( mbedtls_x509_crt_sig_info *info ) +{ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( info->sig_opts ); +#else + ((void) info); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +} + +static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, + mbedtls_x509_crt_sig_info *info ) +{ + const mbedtls_md_info_t *md_info; + + md_info = mbedtls_md_info_from_type( frame->sig_md ); + if( mbedtls_md( md_info, frame->tbs.p, frame->tbs.len, + info->crt_hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + + info->crt_hash_len = mbedtls_md_get_size( md_info ); + + /* Make sure that this function leaves the target structure + * ready to be freed, regardless of success of failure. */ + info->sig_opts = NULL; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + { + int ret; + unsigned char *alg_start = frame->sig_alg.p; + unsigned char *alg_end = alg_start + frame->sig_alg.len; + + /* Get signature options -- currently only + * necessary for RSASSA-PSS. */ + ret = mbedtls_x509_get_sig_alg_raw( &alg_start, alg_end, &info->sig_md, + &info->sig_pk, &info->sig_opts ); + if( ret != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + } +#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + info->sig_md = frame->sig_md; + info->sig_pk = frame->sig_pk; +#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + info->issuer_raw = frame->issuer_raw; + info->sig = frame->sig; + return( 0 ); +} + /* * Find a suitable parent for child in candidates, or return NULL. * @@ -2309,7 +2350,7 @@ static int x509_crt_check_parent( const mbedtls_x509_crt_frame *child, * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise */ static int x509_crt_find_parent_in( - mbedtls_x509_crt_frame const *child, + mbedtls_x509_crt_sig_info const *child_sig, mbedtls_x509_crt *candidates, mbedtls_x509_crt **r_parent, int *r_signature_is_good, @@ -2361,7 +2402,7 @@ check_signature: } /* basic parenting skills (name, CA bit, key usage) */ - if( x509_crt_check_parent( child, parent, top ) == 0 ) + if( x509_crt_check_parent( child_sig, parent, top ) == 0 ) parent_match = 1; /* +1 because stored max_pathlen is 1 higher that the actual value */ @@ -2375,7 +2416,7 @@ check_signature: continue; /* Signature */ - ret = x509_crt_check_signature( child, parent, rs_ctx ); + ret = x509_crt_check_signature( child_sig, parent, rs_ctx ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) @@ -2447,7 +2488,7 @@ check_signature: * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise */ static int x509_crt_find_parent( - mbedtls_x509_crt_frame const *child, + mbedtls_x509_crt_sig_info const *child_sig, mbedtls_x509_crt *rest, mbedtls_x509_crt *trust_ca, mbedtls_x509_crt **parent, @@ -2474,7 +2515,7 @@ static int x509_crt_find_parent( while( 1 ) { search_list = *parent_is_trusted ? trust_ca : rest; - ret = x509_crt_find_parent_in( child, search_list, + ret = x509_crt_find_parent_in( child_sig, search_list, parent, signature_is_good, *parent_is_trusted, path_cnt, self_cnt, rs_ctx ); @@ -2520,14 +2561,6 @@ static int x509_crt_check_ee_locally_trusted( { mbedtls_x509_crt const *cur; - /* must be self-issued */ - if( mbedtls_x509_name_cmp_raw( &crt->issuer_raw, - &crt->subject_raw, - NULL, NULL ) != 0 ) - { - return( -1 ); - } - /* look for an exact match with trusted cert */ for( cur = trust_ca; cur != NULL; cur = cur->next ) { @@ -2625,7 +2658,10 @@ static int x509_crt_verify_chain( child_is_trusted = 0; while( 1 ) { - mbedtls_x509_crt_frame *child; +#if defined(MBEDTLS_X509_CRL_PARSE_C) + mbedtls_x509_buf_raw child_serial; +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + int self_issued; /* Add certificate to the verification chain */ cur = &ver_chain->items[ver_chain->len]; @@ -2637,41 +2673,72 @@ static int x509_crt_verify_chain( find_parent: #endif - ret = x509_crt_frame_acquire( child_crt, &child ); - if( ret != 0 ) - return( MBEDTLS_ERR_X509_FATAL_ERROR ); - flags = &cur->flags; - /* Check time-validity (all certificates) */ - if( mbedtls_x509_time_is_past( &child->valid_to ) ) - *flags |= MBEDTLS_X509_BADCERT_EXPIRED; - - if( mbedtls_x509_time_is_future( &child->valid_from ) ) - *flags |= MBEDTLS_X509_BADCERT_FUTURE; - - /* Stop here for trusted roots (but not for trusted EE certs) */ - if( child_is_trusted ) - goto release; - - /* Check signature algorithm: MD & PK algs */ - if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_MD; - - if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_PK; - - /* Special case: EE certs that are locally trusted */ - if( ver_chain->len == 1 && - x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) { - goto release; - } + mbedtls_x509_crt_sig_info child_sig; + { + mbedtls_x509_crt_frame *child; - /* Look for a parent in trusted CAs or up the chain */ - ret = x509_crt_find_parent( child, trust_ca, &parent, - &parent_is_trusted, &signature_is_good, - ver_chain->len - 1, self_cnt, rs_ctx ); + ret = x509_crt_frame_acquire( child_crt, &child ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + /* Check time-validity (all certificates) */ + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + /* Stop here for trusted roots (but not for trusted EE certs) */ + if( child_is_trusted ) + { + x509_crt_frame_release( child_crt, child ); + return( 0 ); + } + + self_issued = 0; + if( mbedtls_x509_name_cmp_raw( &child->issuer_raw, + &child->subject_raw, + NULL, NULL ) == 0 ) + { + self_issued = 1; + } + + /* Check signature algorithm: MD & PK algs */ + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + /* Special case: EE certs that are locally trusted */ + if( ver_chain->len == 1 && self_issued && + x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) + { + x509_crt_frame_release( child_crt, child ); + return( 0 ); + } + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + child_serial = child->serial; +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + + ret = x509_crt_get_sig_info( child, &child_sig ); + + x509_crt_frame_release( child_crt, child ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + } + + /* Look for a parent in trusted CAs or up the chain */ + ret = x509_crt_find_parent( &child_sig, child_crt->next, + trust_ca, &parent, + &parent_is_trusted, &signature_is_good, + ver_chain->len - 1, self_cnt, rs_ctx ); + + x509_crt_free_sig_info( &child_sig ); + } #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) @@ -2680,8 +2747,7 @@ find_parent: rs_ctx->in_progress = x509_crt_rs_find_parent; rs_ctx->self_cnt = self_cnt; rs_ctx->ver_chain = *ver_chain; /* struct copy */ - - goto release; + return( ret ); } #else (void) ret; @@ -2691,19 +2757,14 @@ find_parent: if( parent == NULL ) { *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - goto release; + return( 0 ); } /* Count intermediate self-issued (not necessarily self-signed) certs. * These can occur with some strategies for key rollover, see [SIRO], * and should be excluded from max_pathlen checks. */ - if( ver_chain->len != 1 && - mbedtls_x509_name_cmp_raw( &child->issuer_raw, - &child->subject_raw, - NULL, NULL ) == 0 ) - { + if( ver_chain->len != 1 && self_issued ) self_cnt++; - } /* path_cnt is 0 for the first intermediate CA, * and if parent is trusted it's not an intermediate CA */ @@ -2711,8 +2772,7 @@ find_parent: ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) { /* return immediately to avoid overflow the chain array */ - ret = MBEDTLS_ERR_X509_FATAL_ERROR; - goto release; + return( MBEDTLS_ERR_X509_FATAL_ERROR ); } /* signature was checked while searching parent */ @@ -2725,24 +2785,19 @@ find_parent: #if defined(MBEDTLS_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the given crt */ - *flags |= x509_crt_verifycrl( child->serial.p, - child->serial.len, + *flags |= x509_crt_verifycrl( child_serial.p, + child_serial.len, parent, ca_crl, profile ); #else (void) ca_crl; #endif /* prepare for next iteration */ - x509_crt_frame_release( child_crt, child ); child_crt = parent; parent = NULL; child_is_trusted = parent_is_trusted; signature_is_good = 0; } - -release: - x509_crt_frame_release( child_crt, child ); - return( ret ); } /* From e449e2d846f6e8ee6262e53e484e662ab7428a03 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 14:45:31 +0000 Subject: [PATCH 042/140] Make use of CRT acquire/release for X.509 CRT signature checking --- library/x509_crt.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index cfe082113..3a026a2b2 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2175,29 +2175,45 @@ static int x509_crt_check_signature( const mbedtls_x509_crt_sig_info *sig_info, mbedtls_x509_crt *parent, mbedtls_x509_crt_restart_ctx *rs_ctx ) { - /* Skip expensive computation on obvious mismatch */ - if( ! mbedtls_pk_can_do( &parent->pk, sig_info->sig_pk ) ) - return( -1 ); + int ret; + mbedtls_pk_context *pk; -#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) - if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) + ret = x509_crt_pk_acquire( parent, &pk ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + /* Skip expensive computation on obvious mismatch */ + if( ! mbedtls_pk_can_do( pk, sig_info->sig_pk ) ) { - return( mbedtls_pk_verify_restartable( &parent->pk, + ret = -1; + goto exit; + } + +#if !( defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) ) + ((void) rs_ctx); +#else + if( rs_ctx != NULL && sig_info->sig_pk == MBEDTLS_PK_ECDSA ) + { + ret = mbedtls_pk_verify_restartable( pk, sig_info->sig_md, sig_info->crt_hash, sig_info->crt_hash_len, sig_info->sig.p, sig_info->sig.len, - &rs_ctx->pk ) ); + &rs_ctx->pk ); } -#else - (void) rs_ctx; + else #endif + { + ret = mbedtls_pk_verify_ext( sig_info->sig_pk, + sig_info->sig_opts, + pk, + sig_info->sig_md, + sig_info->crt_hash, sig_info->crt_hash_len, + sig_info->sig.p, sig_info->sig.len ); + } - return( mbedtls_pk_verify_ext( sig_info->sig_pk, - sig_info->sig_opts, - &parent->pk, - sig_info->sig_md, - sig_info->crt_hash, sig_info->crt_hash_len, - sig_info->sig.p, sig_info->sig.len ) ); +exit: + x509_crt_pk_release( parent, pk ); + return( ret ); } /* From 43bf900018e86aa397520ccd59eca416d5a331af Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 14:46:49 +0000 Subject: [PATCH 043/140] Make use of CRT acquire/release searching for issuer in CRT verif. This commit continues rewriting the CRT chain verification to use the new acquire/release framework for CRTs. Specifically, it replaces all member accesses of the current _parent_ CRT by accesses to the respective frame. --- library/x509_crt.c | 64 +++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3a026a2b2..95cea46f8 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2222,15 +2222,15 @@ exit: * * top means parent is a locally-trusted certificate */ -static int x509_crt_check_parent( const mbedtls_x509_crt_sig_info *child_sig, - const mbedtls_x509_crt *parent, +static int x509_crt_check_parent( const mbedtls_x509_crt_sig_info *sig_info, + const mbedtls_x509_crt_frame *parent, int top ) { int need_ca_bit; /* Parent must be the issuer */ - if( mbedtls_x509_name_cmp_raw( &child_sig->issuer_raw, - &parent->subject_raw_no_hdr, + if( mbedtls_x509_name_cmp_raw( &sig_info->issuer_raw, + &parent->subject_raw, NULL, NULL ) != 0 ) { return( -1 ); @@ -2248,7 +2248,8 @@ static int x509_crt_check_parent( const mbedtls_x509_crt_sig_info *child_sig, #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) if( need_ca_bit && - mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) + x509_crt_check_key_usage_frame( parent, + MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) { return( -1 ); } @@ -2376,7 +2377,7 @@ static int x509_crt_find_parent_in( mbedtls_x509_crt_restart_ctx *rs_ctx ) { int ret; - mbedtls_x509_crt *parent, *fallback_parent; + mbedtls_x509_crt *parent_crt, *fallback_parent; int signature_is_good, fallback_signature_is_good; #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) @@ -2384,7 +2385,7 @@ static int x509_crt_find_parent_in( if( rs_ctx != NULL && rs_ctx->parent != NULL ) { /* restore saved state */ - parent = rs_ctx->parent; + parent_crt = rs_ctx->parent; fallback_parent = rs_ctx->fallback_parent; fallback_signature_is_good = rs_ctx->fallback_signature_is_good; @@ -2401,7 +2402,8 @@ static int x509_crt_find_parent_in( fallback_parent = NULL; fallback_signature_is_good = 0; - for( parent = candidates; parent != NULL; parent = parent->next ) + for( parent_crt = candidates; parent_crt != NULL; + parent_crt = parent_crt->next ) { int parent_valid, parent_match, path_len_ok; @@ -2410,35 +2412,45 @@ check_signature: #endif parent_valid = parent_match = path_len_ok = 0; - - if( mbedtls_x509_time_is_past( &parent->valid_from ) && - mbedtls_x509_time_is_future( &parent->valid_to ) ) { - parent_valid = 1; - } + mbedtls_x509_crt_frame *parent; - /* basic parenting skills (name, CA bit, key usage) */ - if( x509_crt_check_parent( child_sig, parent, top ) == 0 ) - parent_match = 1; + ret = x509_crt_frame_acquire( parent_crt, &parent ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); - /* +1 because stored max_pathlen is 1 higher that the actual value */ - if( !( parent->max_pathlen > 0 && - (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) ) - { - path_len_ok = 1; + if( mbedtls_x509_time_is_past( &parent->valid_from ) && + mbedtls_x509_time_is_future( &parent->valid_to ) ) + { + parent_valid = 1; + } + + /* basic parenting skills (name, CA bit, key usage) */ + if( x509_crt_check_parent( child_sig, parent, top ) == 0 ) + parent_match = 1; + + /* +1 because the stored max_pathlen is 1 higher + * than the actual value */ + if( !( parent->max_pathlen > 0 && + (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) ) + { + path_len_ok = 1; + } + + x509_crt_frame_release( parent_crt, parent ); } if( parent_match == 0 || path_len_ok == 0 ) continue; /* Signature */ - ret = x509_crt_check_signature( child_sig, parent, rs_ctx ); + ret = x509_crt_check_signature( child_sig, parent_crt, rs_ctx ); #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) { /* save state */ - rs_ctx->parent = parent; + rs_ctx->parent = parent_crt; rs_ctx->fallback_parent = fallback_parent; rs_ctx->fallback_signature_is_good = fallback_signature_is_good; @@ -2457,7 +2469,7 @@ check_signature: { if( fallback_parent == NULL ) { - fallback_parent = parent; + fallback_parent = parent_crt; fallback_signature_is_good = signature_is_good; } @@ -2467,9 +2479,9 @@ check_signature: break; } - if( parent != NULL ) + if( parent_crt != NULL ) { - *r_parent = parent; + *r_parent = parent_crt; *r_signature_is_good = signature_is_good; } else From 45eedf1ace042c55ea940aa17b827d0c8be9d0cb Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 13:55:33 +0000 Subject: [PATCH 044/140] Make use of CRT acquire/release in mbedtls_x509_crt_check_key_usage --- library/x509_crt.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 95cea46f8..aa82c2cb2 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1958,8 +1958,8 @@ int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, #endif /* !MBEDTLS_X509_REMOVE_INFO */ #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) -int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, - unsigned int usage ) +static int x509_crt_check_key_usage_frame( const mbedtls_x509_crt_frame *crt, + unsigned int usage ) { unsigned int usage_must, usage_may; unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY @@ -1980,6 +1980,21 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, return( 0 ); } + +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + ret = x509_crt_frame_acquire( crt, (mbedtls_x509_crt_frame**) &frame ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + ret = x509_crt_check_key_usage_frame( frame, usage ); + x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame ); + + return( ret ); +} #endif #if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) From 343fec08ad9648d9867c8f38b3bcc3088f195923 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sat, 23 Feb 2019 12:12:46 +0000 Subject: [PATCH 045/140] Add version of MBEDTLS_X509_SAFE_SNPRINTF supporting cleanup section This will be needed in debugging functions that maintain heap allocated state, and which hence needs to be freed in case an `snprintf()` call fails. --- include/mbedtls/x509.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index f7987a9ed..583bc1228 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -355,6 +355,18 @@ int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, p += (size_t) ret; \ } while( 0 ) +#define MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + { \ + ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; \ + goto cleanup; \ + } \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + #ifdef __cplusplus } #endif From 4f869eda64e2c6c4e02bfef74448bca4bf80279f Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sun, 24 Feb 2019 16:47:57 +0000 Subject: [PATCH 046/140] Make use of CRT acquire/release in mbedtls_x509_crt_info() This commit adapts `mbedtls_x509_crt_info()` to no longer access structure fields from `mbedtls_x509_crt` directly, but to instead query for a `mbedtls_x509_crt_frame` and `mbedtls_pk_context` and use these to extract the required CRT information. --- library/x509_crt.c | 265 ++++++++++++++++++++++++++++----------------- 1 file changed, 168 insertions(+), 97 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index aa82c2cb2..63823d300 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1762,81 +1762,204 @@ static int x509_info_ext_key_usage( char **buf, size_t *size, return( 0 ); } +typedef struct mbedtls_x509_crt_sig_info +{ + mbedtls_md_type_t sig_md; + mbedtls_pk_type_t sig_pk; + void *sig_opts; + uint8_t crt_hash[MBEDTLS_MD_MAX_SIZE]; + size_t crt_hash_len; + mbedtls_x509_buf_raw sig; + mbedtls_x509_buf_raw issuer_raw; +} mbedtls_x509_crt_sig_info; + +static void x509_crt_free_sig_info( mbedtls_x509_crt_sig_info *info ) +{ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( info->sig_opts ); +#else + ((void) info); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +} + +static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, + mbedtls_x509_crt_sig_info *info ) +{ + const mbedtls_md_info_t *md_info; + + md_info = mbedtls_md_info_from_type( frame->sig_md ); + if( mbedtls_md( md_info, frame->tbs.p, frame->tbs.len, + info->crt_hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + + info->crt_hash_len = mbedtls_md_get_size( md_info ); + + /* Make sure that this function leaves the target structure + * ready to be freed, regardless of success of failure. */ + info->sig_opts = NULL; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + { + int ret; + unsigned char *alg_start = frame->sig_alg.p; + unsigned char *alg_end = alg_start + frame->sig_alg.len; + + /* Get signature options -- currently only + * necessary for RSASSA-PSS. */ + ret = mbedtls_x509_get_sig_alg_raw( &alg_start, alg_end, &info->sig_md, + &info->sig_pk, &info->sig_opts ); + if( ret != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + } +#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + info->sig_md = frame->sig_md; + info->sig_pk = frame->sig_pk; +#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + info->issuer_raw = frame->issuer_raw; + info->sig = frame->sig; + return( 0 ); +} + /* * Return an informational string about the certificate. */ #define BEFORE_COLON 18 #define BC "18" int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, - const mbedtls_x509_crt *crt ) + const mbedtls_x509_crt *crt_raw ) { int ret; size_t n; char *p; char key_size_str[BEFORE_COLON]; + mbedtls_x509_crt_frame *crt; + mbedtls_pk_context *pk; + + mbedtls_x509_name issuer, subject; + mbedtls_x509_sequence ext_key_usage, subject_alt_names; + mbedtls_x509_crt_sig_info sig_info; p = buf; n = size; - if( NULL == crt ) + memset( &sig_info, 0, sizeof( mbedtls_x509_crt_sig_info ) ); + if( NULL == crt_raw ) { ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; return( (int) ( size - n ) ); } + ret = x509_crt_frame_acquire( crt_raw, &crt ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + ret = x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_get_sig_info( crt, &sig_info ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_subject_from_frame( crt, &subject ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_issuer_from_frame( crt, &issuer ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_subject_alt_from_frame( crt, &subject_alt_names ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_ext_key_usage_from_frame( crt, &ext_key_usage ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", prefix, crt->version ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_snprintf( p, n, "%sserial number : ", - prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); - MBEDTLS_X509_SAFE_SNPRINTF; + { + mbedtls_x509_buf serial; + serial.p = crt->serial.p; + serial.len = crt->serial.len; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + ret = mbedtls_x509_serial_gets( p, n, &serial ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + } ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + ret = mbedtls_x509_dn_gets( p, n, &issuer ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; - ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + ret = mbedtls_x509_dn_gets( p, n, &subject ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, 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; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, 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; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_x509_sig_alg_gets( p, n, sig_info.sig_pk, sig_info.sig_md, sig_info.sig_opts ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; /* Key size */ if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, - mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) + mbedtls_pk_get_name( pk ) ) ) != 0 ) { return( ret ); } 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; + (int) mbedtls_pk_get_bitlen( pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; /* * Optional extensions @@ -1846,29 +1969,29 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, { ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, crt->ca_istrue ? "true" : "false" ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( crt->max_pathlen > 0 ) { ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; } } if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_subject_alt_name( &p, &n, - &crt->subject_alt_names ) ) != 0 ) + &subject_alt_names ) ) != 0 ) return( ret ); } if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) { ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) return( ret ); @@ -1877,7 +2000,7 @@ 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 ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) return( ret ); @@ -1886,17 +2009,30 @@ 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 ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_ext_key_usage( &p, &n, - &crt->ext_key_usage ) ) != 0 ) + &ext_key_usage ) ) != 0 ) return( ret ); } ret = mbedtls_snprintf( p, n, "\n" ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - return( (int) ( size - n ) ); + ret = (int) ( size - n ); + +cleanup: + + x509_crt_frame_release( crt_raw, crt ); + x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk ); + + x509_crt_free_sig_info( &sig_info ); + x509_free_name( issuer.next ); + x509_free_name( subject.next ); + x509_free_sequence( ext_key_usage.next ); + x509_free_sequence( subject_alt_names.next ); + + return( ret ); } struct x509_crt_verify_string { @@ -2273,71 +2409,6 @@ static int x509_crt_check_parent( const mbedtls_x509_crt_sig_info *sig_info, return( 0 ); } -typedef struct mbedtls_x509_crt_sig_info -{ - mbedtls_md_type_t sig_md; - mbedtls_pk_type_t sig_pk; - void *sig_opts; - uint8_t crt_hash[MBEDTLS_MD_MAX_SIZE]; - size_t crt_hash_len; - mbedtls_x509_buf_raw sig; - mbedtls_x509_buf_raw issuer_raw; -} mbedtls_x509_crt_sig_info; - -static void x509_crt_free_sig_info( mbedtls_x509_crt_sig_info *info ) -{ -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) - mbedtls_free( info->sig_opts ); -#else - ((void) info); -#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ -} - -static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, - mbedtls_x509_crt_sig_info *info ) -{ - const mbedtls_md_info_t *md_info; - - md_info = mbedtls_md_info_from_type( frame->sig_md ); - if( mbedtls_md( md_info, frame->tbs.p, frame->tbs.len, - info->crt_hash ) != 0 ) - { - /* Note: this can't happen except after an internal error */ - return( -1 ); - } - - info->crt_hash_len = mbedtls_md_get_size( md_info ); - - /* Make sure that this function leaves the target structure - * ready to be freed, regardless of success of failure. */ - info->sig_opts = NULL; - -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) - { - int ret; - unsigned char *alg_start = frame->sig_alg.p; - unsigned char *alg_end = alg_start + frame->sig_alg.len; - - /* Get signature options -- currently only - * necessary for RSASSA-PSS. */ - ret = mbedtls_x509_get_sig_alg_raw( &alg_start, alg_end, &info->sig_md, - &info->sig_pk, &info->sig_opts ); - if( ret != 0 ) - { - /* Note: this can't happen except after an internal error */ - return( -1 ); - } - } -#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - info->sig_md = frame->sig_md; - info->sig_pk = frame->sig_pk; -#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - - info->issuer_raw = frame->issuer_raw; - info->sig = frame->sig; - return( 0 ); -} - /* * Find a suitable parent for child in candidates, or return NULL. * From 371e0e45730bc40147ddda550db55855e90929fe Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:08:59 +0000 Subject: [PATCH 047/140] Determine whether CRT is initialized or not through raw data pointer Previously, `mbedtls_x509_crt_der_internal()` used the `version` field (which is `0` after initialization but strictly greater than 0 once a CRT has successfully been parsed) to determine whether an `mbedtls_x509_crt` instance had already been setup. Preparating for the removal of `version` from the structure, this commit modifies the code to instead peek at the raw data pointer, which is NULL as long as the CRT structure hasn't been setup with a CRT, and will be kept in the new CRT structure. --- library/ssl_srv.c | 2 +- library/x509_crt.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 8ac7dd49b..9aef69a0f 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2955,7 +2955,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) #endif crt = ssl->conf->ca_chain; - while( crt != NULL && crt->version != 0 ) + while( crt != NULL && crt->raw.p != NULL ) { dn_size = crt->subject_raw.len; diff --git a/library/x509_crt.c b/library/x509_crt.c index 63823d300..060c0158b 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1321,7 +1321,7 @@ static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, if( crt == NULL || buf == NULL ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); - while( crt->version != 0 && crt->next != NULL ) + while( crt->raw.p != NULL && crt->next != NULL ) { prev = crt; crt = crt->next; @@ -1330,7 +1330,7 @@ static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, /* * Add new certificate on the end of the chain if needed. */ - if( crt->version != 0 && crt->next == NULL ) + if( crt->raw.p != NULL && crt->next == NULL ) { crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); From e9718b451a4b327158121e48bfb376d978f00e45 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:11:42 +0000 Subject: [PATCH 048/140] Make use of CRT acquire/release in ExtKeyUsage checking --- library/x509_crt.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 060c0158b..d7abb9b3f 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2169,26 +2169,34 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, size_t usage_len ) { int ret; + mbedtls_x509_crt_frame *frame; unsigned ext_types; unsigned char *p, *end; x509_crt_check_ext_key_usage_cb_ctx_t cb_ctx = { usage_oid, usage_len }; + ret = x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + /* Extension is not mandatory, absent means no restriction */ - ext_types = crt->ext_types; - if( ( ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) - return( 0 ); + ext_types = frame->ext_types; + if( ( ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) != 0 ) + { + p = frame->ext_key_usage_raw.p; + end = p + frame->ext_key_usage_raw.len; - p = crt->ext_key_usage_raw.p; - end = p + crt->ext_key_usage_raw.len; + ret = mbedtls_asn1_traverse_sequence_of( &p, end, + 0xFF, MBEDTLS_ASN1_OID, 0, 0, + x509_crt_check_ext_key_usage_cb, + &cb_ctx ); + if( ret == 1 ) + ret = 0; + else + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; + } - ret = mbedtls_asn1_traverse_sequence_of( &p, end, - 0xFF, MBEDTLS_ASN1_OID, 0, 0, - x509_crt_check_ext_key_usage_cb, - &cb_ctx ); - if( ret == 1 ) - return( 0 ); - - return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + x509_crt_frame_release( crt, frame ); + return( ret ); } #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ From 79ae5b68e723de81146a11a9e61906dc8e03bb50 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:12:00 +0000 Subject: [PATCH 049/140] Make use of CRT acquire/release in x509_serial_is_revoked() --- library/x509_crt.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index d7abb9b3f..bd3a7da21 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2228,9 +2228,18 @@ static int x509_serial_is_revoked( unsigned char const *serial, int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) { - return( x509_serial_is_revoked( crt->serial.p, - crt->serial.len, - crl ) ); + int ret; + mbedtls_x509_crt_frame *frame; + + ret = x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + ret = x509_serial_is_revoked( frame->serial.p, + frame->serial.len, + crl ); + x509_crt_frame_release( crt, frame ); + return( ret ); } /* From bb26613d32db21a0e7601d7c77d3871252448a61 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:12:46 +0000 Subject: [PATCH 050/140] Make use of CRT acquire/release in x509_crt_verifycrl() --- library/x509_crt.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index bd3a7da21..3c1221c83 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2248,23 +2248,48 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, */ static int x509_crt_verifycrl( unsigned char *crt_serial, size_t crt_serial_len, - mbedtls_x509_crt *ca, + mbedtls_x509_crt *ca_crt, mbedtls_x509_crl *crl_list, const mbedtls_x509_crt_profile *profile ) { + int ret; int flags = 0; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; const mbedtls_md_info_t *md_info; + mbedtls_x509_buf_raw ca_subject; + mbedtls_pk_context *pk; + int can_sign; - if( ca == NULL ) + if( ca_crt == NULL ) return( flags ); + { + mbedtls_x509_crt_frame *ca; + ret = x509_crt_frame_acquire( ca_crt, &ca ); + if( ret != 0 ) + return( MBEDTLS_X509_BADCRL_NOT_TRUSTED ); + + ca_subject = ca->subject_raw; + + can_sign = 0; + if( x509_crt_check_key_usage_frame( ca, + MBEDTLS_X509_KU_CRL_SIGN ) == 0 ) + { + can_sign = 1; + } + + x509_crt_frame_release( ca_crt, ca ); + } + + ret = x509_crt_pk_acquire( ca_crt, &pk ); + if( ret != 0 ) + return( MBEDTLS_X509_BADCRL_NOT_TRUSTED ); + while( crl_list != NULL ) { if( crl_list->version == 0 || mbedtls_x509_name_cmp_raw( &crl_list->issuer_raw_no_hdr, - &ca->subject_raw_no_hdr, - NULL, NULL ) != 0 ) + &ca_subject, NULL, NULL ) != 0 ) { crl_list = crl_list->next; continue; @@ -2274,8 +2299,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, * Check if the CA is configured to sign CRLs */ #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) - if( mbedtls_x509_crt_check_key_usage( ca, - MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) + if( !can_sign ) { flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; break; @@ -2299,10 +2323,10 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, break; } - if( x509_profile_check_key( profile, &ca->pk ) != 0 ) + if( x509_profile_check_key( profile, pk ) != 0 ) flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, + if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, pk, crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), crl_list->sig.p, crl_list->sig.len ) != 0 ) { @@ -2332,6 +2356,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, crl_list = crl_list->next; } + x509_crt_pk_release( ca_crt, pk ); return( flags ); } #endif /* MBEDTLS_X509_CRL_PARSE_C */ From 58c35646df15ebf27d5452f699ab75bbdc3a60be Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:13:46 +0000 Subject: [PATCH 051/140] Make use of CRT acquire/release in CRT chain verification #2 --- library/x509_crt.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3c1221c83..2a0bde055 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2785,7 +2785,7 @@ static int x509_crt_verify_chain( uint32_t *flags; mbedtls_x509_crt_verify_chain_item *cur; mbedtls_x509_crt *child_crt; - mbedtls_x509_crt *parent; + mbedtls_x509_crt *parent_crt; int parent_is_trusted; int child_is_trusted; int signature_is_good; @@ -2889,7 +2889,7 @@ find_parent: /* Look for a parent in trusted CAs or up the chain */ ret = x509_crt_find_parent( &child_sig, child_crt->next, - trust_ca, &parent, + trust_ca, &parent_crt, &parent_is_trusted, &signature_is_good, ver_chain->len - 1, self_cnt, rs_ctx ); @@ -2910,7 +2910,7 @@ find_parent: #endif /* No parent? We're done here */ - if( parent == NULL ) + if( parent_crt == NULL ) { *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; return( 0 ); @@ -2935,22 +2935,31 @@ find_parent: if( ! signature_is_good ) *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - /* check size of signing key */ - if( x509_profile_check_key( profile, &parent->pk ) != 0 ) - *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + { + mbedtls_pk_context *parent_pk; + ret = x509_crt_pk_acquire( parent_crt, &parent_pk ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + /* check size of signing key */ + if( x509_profile_check_key( profile, parent_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + x509_crt_pk_release( parent_crt, parent_pk ); + } #if defined(MBEDTLS_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the given crt */ *flags |= x509_crt_verifycrl( child_serial.p, child_serial.len, - parent, ca_crl, profile ); + parent_crt, ca_crl, profile ); #else (void) ca_crl; #endif /* prepare for next iteration */ - child_crt = parent; - parent = NULL; + child_crt = parent_crt; + parent_crt = NULL; child_is_trusted = parent_is_trusted; signature_is_good = 0; } From 082435c011e60db02056af64bbe8153ddd3d912c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:14:40 +0000 Subject: [PATCH 052/140] Make use of CRT acquire/release in x509_crt_verify_name() This commit modifies the static function `x509_crt_verify_name()` to use the acquire/release API to access the given CRTs `subject` field. This function is solely called from the beginning of the CRT chain verification routine, which also needs to access the child's CRT frame. It should therefore be considered - for a later commit - to collapse the two acquire/release pairs to one, thereby saving some code. --- library/x509_crt.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 2a0bde055..6dba6a1c9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -3030,18 +3030,23 @@ static int x509_crt_subject_alt_check_name( void *ctx, /* * Verify the requested CN - only call this if cn is not NULL! */ -static void x509_crt_verify_name( const mbedtls_x509_crt *crt, - const char *cn, - uint32_t *flags ) +static int x509_crt_verify_name( const mbedtls_x509_crt *crt, + const char *cn, + uint32_t *flags ) { int ret; + mbedtls_x509_crt_frame *frame; - if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + ret = x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + if( frame->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { unsigned char *p = - crt->subject_alt_raw.p; + frame->subject_alt_raw.p; const unsigned char *end = - crt->subject_alt_raw.p + crt->subject_alt_raw.len; + frame->subject_alt_raw.p + frame->subject_alt_raw.len; ret = mbedtls_asn1_traverse_sequence_of( &p, end, MBEDTLS_ASN1_TAG_CLASS_MASK, @@ -3053,13 +3058,23 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt, } else { - ret = mbedtls_x509_name_cmp_raw( &crt->subject_raw_no_hdr, - &crt->subject_raw_no_hdr, + ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw, + &frame->subject_raw, x509_crt_check_name, (void*) cn ); } - if( ret != 1 ) - *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + x509_crt_frame_release( crt, frame ); + + /* x509_crt_check_name() and x509_crt_subject_alt_check_name() + * return 1 when finding a name component matching `cn`. */ + if( ret == 1 ) + return( 0 ); + + if( ret != 0 ) + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + return( ret ); } /* From 872333683119fdbaaedf451b34d6cb7175c5dcb5 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 18:15:33 +0000 Subject: [PATCH 053/140] Make use of CRT acquire/release in x509_crt_verify_restartable --- library/x509_crt.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 6dba6a1c9..bf62f65d9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -3156,7 +3156,6 @@ int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, mbedtls_x509_crt_restart_ctx *rs_ctx ) { int ret; - mbedtls_pk_type_t pk_type; mbedtls_x509_crt_verify_chain ver_chain; uint32_t ee_flags; @@ -3172,16 +3171,31 @@ int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, /* check name if requested */ if( cn != NULL ) - x509_crt_verify_name( crt, cn, &ee_flags ); + { + ret = x509_crt_verify_name( crt, cn, &ee_flags ); + if( ret != 0 ) + return( ret ); + } - /* Check the type and size of the key */ - pk_type = mbedtls_pk_get_type( &crt->pk ); + { + mbedtls_pk_context *pk; + mbedtls_pk_type_t pk_type; - if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) - ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; + ret = x509_crt_pk_acquire( crt, &pk ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); - if( x509_profile_check_key( profile, &crt->pk ) != 0 ) - ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + /* Check the type and size of the key */ + pk_type = mbedtls_pk_get_type( pk ); + + if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) + ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, pk ) != 0 ) + ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + x509_crt_pk_release( crt, pk ); + } /* Check the chain */ ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile, From 5c03058bbce38b59bdaa5e4a55d7f205e77dc9de Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:45:32 +0000 Subject: [PATCH 054/140] Make use of CRT acquire/release in test_suite_x509parse suite --- tests/suites/test_suite_x509parse.function | 57 +++++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index c9fe63f09..24b9e40f7 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -24,6 +24,17 @@ const mbedtls_x509_crt_profile profile_all = 1024, }; +static void x509_free_name( mbedtls_x509_name *name ) +{ + while( name != NULL ) + { + mbedtls_x509_name *next = name->next; + mbedtls_platform_zeroize( name, sizeof( *name ) ); + mbedtls_free( name ); + name = next; + } +} + /* Profile for backward compatibility. Allows SHA-1, unlike the default profile. */ const mbedtls_x509_crt_profile compat_profile = @@ -142,25 +153,55 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint verify_print_context *ctx = (verify_print_context *) data; char *p = ctx->p; size_t n = ctx->buf + sizeof( ctx->buf ) - ctx->p; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_name subject; ((void) flags); - ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth ); - MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); - ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); - MBEDTLS_X509_SAFE_SNPRINTF; + /* Get linked list presentation of issuer which + * `mbedtls_x509_dn_gets()` understands. */ + { + unsigned char *subject_start = frame->subject_raw.p; + unsigned char *subject_end = frame->subject_raw.p + frame->subject_raw.len; + + ret = mbedtls_x509_get_name( &subject_start, subject_end, &subject ); + if( ret != 0 ) + goto cleanup; + } + + ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + + { + mbedtls_x509_buf serial; + serial.p = frame->serial.p; + serial.len = frame->serial.len; + ret = mbedtls_x509_serial_gets( p, n, &serial ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + } ret = mbedtls_snprintf( p, n, " - subject " ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); - MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &subject ); + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, " - flags 0x%08x\n", *flags ); - MBEDTLS_X509_SAFE_SNPRINTF; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ctx->p = p; +cleanup: + + x509_free_name( subject.next ); + mbedtls_x509_crt_frame_release( crt, frame ); + + if( ret < 0 ) + return( ret ); + return( 0 ); } #endif /* MBEDTLS_X509_CRT_PARSE_C */ From 6cb5f86dac2ff8ed401f371907a5efa712da5dc5 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:46:04 +0000 Subject: [PATCH 055/140] Make use of CRT acquire/release in mbedtls_debug_print_crt() --- library/debug.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/debug.c b/library/debug.c index c6788b62b..41769eca6 100644 --- a/library/debug.c +++ b/library/debug.c @@ -382,6 +382,8 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, while( crt != NULL ) { + int ret; + mbedtls_pk_context *pk; char buf[1024]; mbedtls_snprintf( str, sizeof( str ), "%s #%d:\n", text, ++i ); @@ -390,7 +392,17 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt ); debug_print_line_by_line( ssl, level, file, line, buf ); - debug_print_pk( ssl, level, file, line, "crt->", &crt->pk ); + ret = mbedtls_x509_crt_pk_acquire( crt, &pk ); + if( ret != 0 ) + { + mbedtls_snprintf( str, sizeof( str ), + "mbedtls_x509_crt_pk_acquire() failed with -%#04x\n", + -ret ); + debug_send_line( ssl, level, file, line, str ); + return; + } + debug_print_pk( ssl, level, file, line, "crt->", pk ); + mbedtls_x509_crt_pk_release( crt, pk ); crt = crt->next; } From 8c13ee615f60e40ddfc177ab4fe4cb36df932afe Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:48:17 +0000 Subject: [PATCH 056/140] Make use of CRT acquire/release in ssl_parse_certificate_verify() Access the peer's PK through the PK acquire/release API only. Care has to be taken not to accidentally overwrite the return value `ret` from the CRT chain verification. --- library/ssl_tls.c | 55 +++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 3257732e8..4a3c9fe8b 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6455,6 +6455,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, void *rs_ctx ) { int ret = 0; + int verify_ret; const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->handshake->ciphersuite_info; mbedtls_x509_crt *ca_chain; @@ -6479,7 +6480,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, /* * Main check: verify certificate */ - ret = mbedtls_x509_crt_verify_restartable( + verify_ret = mbedtls_x509_crt_verify_restartable( chain, ca_chain, ca_crl, ssl->conf->cert_profile, @@ -6487,13 +6488,13 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, &ssl->session_negotiate->verify_result, ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx ); - if( ret != 0 ) + if( verify_ret != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", verify_ret ); } #if defined(MBEDTLS_SSL__ECP_RESTARTABLE) - if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + if( verify_ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); #endif @@ -6503,29 +6504,37 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ECP_C) { - const mbedtls_pk_context *pk = &chain->pk; + mbedtls_pk_context *pk; + ret = mbedtls_x509_crt_pk_acquire( chain, &pk ); + if( ret != 0 ) + return( ret ); /* If certificate uses an EC key, make sure the curve is OK */ - if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && - mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) ) + ret = mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ); + + mbedtls_x509_crt_pk_release( chain, pk ); + + if( ret != 0 ) { ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); - if( ret == 0 ) - ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + if( verify_ret == 0 ) + verify_ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; } } #endif /* MBEDTLS_ECP_C */ - if( mbedtls_ssl_check_cert_usage( chain, - ciphersuite_info, - ! ssl->conf->endpoint, - &ssl->session_negotiate->verify_result ) != 0 ) + ret = mbedtls_ssl_check_cert_usage( chain, + ciphersuite_info, + ! ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ); + if( ret != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); - if( ret == 0 ) - ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + if( verify_ret == 0 ) + verify_ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; } /* mbedtls_x509_crt_verify_with_profile is supposed to report a @@ -6535,19 +6544,19 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, * functions, are treated as fatal and lead to a failure of * ssl_parse_certificate even if verification was optional. */ if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && - ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || - ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + ( verify_ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + verify_ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) { - ret = 0; + verify_ret = 0; } if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); - ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + verify_ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; } - if( ret != 0 ) + if( verify_ret != 0 ) { uint8_t alert; @@ -6592,7 +6601,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_DEBUG_C */ - return( ret ); + return( verify_ret ); } #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) @@ -6759,8 +6768,8 @@ crt_verify: crt_len = chain->raw.len; #endif /* MBEDTLS_SSL_RENEGOTIATION */ - pk_start = chain->pk_raw.p; - pk_len = chain->pk_raw.len; + pk_start = chain->cache->pk_raw.p; + pk_len = chain->cache->pk_raw.len; /* Free the CRT structures before computing * digest and copying the peer's public key. */ From 30649f7a1785f267cd7753b9d390bc04c402a074 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:49:40 +0000 Subject: [PATCH 057/140] Make use of CRT acquire/release in server-side ssl_pick_cert() --- library/ssl_srv.c | 70 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 9aef69a0f..7aa8f9d82 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -797,24 +797,55 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, for( cur = list; cur != NULL; cur = cur->next ) { + int match = 1; + mbedtls_pk_context *pk; + + /* WARNING: With the current X.509 caching architecture, this MUST + * happen outside of the PK acquire/release block, because it moves + * the cached PK context. In a threading-enabled build, this would + * rightfully fail, but lead to a use-after-free otherwise. */ + MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", + cur->cert ); + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /* ASYNC_PRIVATE may use a NULL entry for the opaque private key, so * we have to use the public key context to infer the capabilities * of the key. */ - mbedtls_pk_context *pk = &cur->cert->pk; + { + int ret; + ret = mbedtls_x509_crt_pk_acquire( cur->cert, &pk ); + if( ret != 0 ) + return( ret ); + } #else /* Outside of ASYNC_PRIVATE, use private key context directly * instead of querying for the public key context from the * certificate, so save a few bytes of code. */ - mbedtls_pk_context *pk = cur->key; + pk = cur->key; #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( ! mbedtls_pk_can_do( pk, pk_alg ) ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); - continue; + match = 0; } +#if defined(MBEDTLS_ECDSA_C) + if( pk_alg == MBEDTLS_PK_ECDSA && + ssl_check_key_curve( pk, ssl->handshake->curves ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); + match = 0; + } +#endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + mbedtls_x509_crt_pk_release( cur->cert, pk ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + if( match == 0 ) + continue; + /* * This avoids sending the client a cert it'll reject based on * keyUsage or other extensions. @@ -831,29 +862,32 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, continue; } -#if defined(MBEDTLS_ECDSA_C) - if( pk_alg == MBEDTLS_PK_ECDSA && - ssl_check_key_curve( pk, ssl->handshake->curves ) != 0 ) - { - MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); - continue; - } -#endif - /* * Try to select a SHA-1 certificate for pre-1.2 clients, but still * present them a SHA-higher cert rather than failing if it's the only * one we got that satisfies the other conditions. */ - if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 && - cur->cert->sig_md != MBEDTLS_MD_SHA1 ) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) { - if( fallback == NULL ) - fallback = cur; + mbedtls_md_type_t sig_md; { + int ret; + mbedtls_x509_crt_frame *frame; + ret = mbedtls_x509_crt_frame_acquire( cur->cert, &frame ); + if( ret != 0 ) + return( ret ); + sig_md = frame->sig_md; + mbedtls_x509_crt_frame_release( cur->cert, frame ); + } + + if( sig_md != MBEDTLS_MD_SHA1 ) + { + if( fallback == NULL ) + fallback = cur; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate not preferred: " - "sha-2 with pre-TLS 1.2 client" ) ); - continue; + "sha-2 with pre-TLS 1.2 client" ) ); + continue; } } From 232f8faf00e0887564edf1a68a30f0cd10c2254f Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:49:57 +0000 Subject: [PATCH 058/140] Make use of CRT acquire/release in ssl_write_certificate_request() --- library/ssl_srv.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 7aa8f9d82..fbe895646 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2991,24 +2991,33 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) while( crt != NULL && crt->raw.p != NULL ) { - dn_size = crt->subject_raw.len; + mbedtls_x509_crt_frame *frame; + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + + dn_size = frame->subject_raw_with_hdr.len; if( end < p || (size_t)( end - p ) < dn_size || (size_t)( end - p ) < 2 + dn_size ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); + mbedtls_x509_crt_frame_release( crt, frame ); break; } *p++ = (unsigned char)( dn_size >> 8 ); *p++ = (unsigned char)( dn_size ); - memcpy( p, crt->subject_raw.p, dn_size ); + memcpy( p, frame->subject_raw_with_hdr.p, dn_size ); p += dn_size; MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size ); total_dn_size += 2 + dn_size; + + mbedtls_x509_crt_frame_release( crt, frame ); + crt = crt->next; } } From 0c1681685caf4c3165ad59f91c0665812ca11bfd Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:02:30 +0000 Subject: [PATCH 059/140] Make use of acquire/release in client-side ssl_write_encrypted_pms() --- library/ssl_cli.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 174e8b150..0ea581de1 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2323,7 +2323,16 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, peer_pk = &ssl->handshake->peer_pubkey; #else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ if( ssl->session_negotiate->peer_cert != NULL ) - peer_pk = &ssl->session_negotiate->peer_cert->pk; + { + ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert, + &peer_pk ); + if( ret != 0 ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ if( peer_pk == NULL ) @@ -2339,7 +2348,8 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) ); - return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + ret = MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH; + goto cleanup; } if( ( ret = mbedtls_pk_encrypt( peer_pk, @@ -2349,7 +2359,7 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret ); - return( ret ); + goto cleanup; } #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ @@ -2362,11 +2372,16 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, } #endif +cleanup: + #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) /* We don't need the peer's public key anymore. Free it. */ mbedtls_pk_free( peer_pk ); -#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ - return( 0 ); +#else + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + return( ret ); } #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ From 39ae65cf73e31077e20390f6ac5ed54e74e362e7 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:03:20 +0000 Subject: [PATCH 060/140] Make use of acquire/release in ssl_get_ecdh_params_from_cert() --- library/ssl_cli.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 0ea581de1..36b4c3415 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2467,13 +2467,22 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - peer_pk = &ssl->session_negotiate->peer_cert->pk; + + ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert, + &peer_pk ); + if( ret != 0 ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); - return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + ret = MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH; + goto cleanup; } peer_key = mbedtls_pk_ec( *peer_pk ); @@ -2482,21 +2491,26 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) MBEDTLS_ECDH_THEIRS ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); - return( ret ); + goto cleanup; } if( ssl_check_server_ecdh_params( ssl ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + goto cleanup; } +cleanup: + #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) /* We don't need the peer's public key anymore. Free it, * so that more RAM is available for upcoming expensive * operations like ECDHE. */ mbedtls_pk_free( peer_pk ); -#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#else + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); } From 2fefa4845d0586ca1d797ebcb9d8faed5d3a604d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:03:46 +0000 Subject: [PATCH 061/140] Make use of acquire/release in ssl_parse_server_key_exchange() --- library/ssl_cli.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 36b4c3415..07e15c4cd 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2817,7 +2817,15 @@ start_processing: MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); } - peer_pk = &ssl->session_negotiate->peer_cert->pk; + + ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert, + &peer_pk ); + if( ret != 0 ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ /* @@ -2828,6 +2836,10 @@ start_processing: MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, + peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); } @@ -2849,6 +2861,10 @@ start_processing: if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; #endif +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, + peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); } @@ -2857,7 +2873,10 @@ start_processing: * so that more RAM is available for upcoming expensive * operations like ECDHE. */ mbedtls_pk_free( peer_pk ); -#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#else + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, + peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ From 73cd8d8adc3a436a457aed51c826e62326283da0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:04:16 +0000 Subject: [PATCH 062/140] Make use of acquire/release in ssl_parse_certificate_verify() --- library/ssl_srv.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index fbe895646..f661d11e6 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -4237,7 +4237,16 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) peer_pk = &ssl->handshake->peer_pubkey; #else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ if( ssl->session_negotiate->peer_cert != NULL ) - peer_pk = &ssl->session_negotiate->peer_cert->pk; + { + ret = mbedtls_x509_crt_pk_acquire( ssl->session_negotiate->peer_cert, + &peer_pk ); + if( ret != 0 ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ if( peer_pk == NULL ) @@ -4297,7 +4306,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) if( i + 2 > ssl->in_hslen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } /* @@ -4309,7 +4319,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" " for verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } #if !defined(MBEDTLS_MD_SHA1) @@ -4330,7 +4341,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" " for verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } /* @@ -4339,7 +4351,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) if( !mbedtls_pk_can_do( peer_pk, pk_alg ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } i++; @@ -4354,7 +4367,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) if( i + 2 > ssl->in_hslen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1]; @@ -4363,7 +4377,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) if( i + sig_len != ssl->in_hslen ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } /* Calculate hash and verify signature */ @@ -4377,13 +4392,20 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) ssl->in_msg + i, sig_len ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); - return( ret ); + goto exit; } mbedtls_ssl_update_handshake_status( ssl ); MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); +exit: + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, + peer_pk ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + return( ret ); } #endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ From b6c39fca5ca8f40d9d32aee5503b04cd04889900 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 25 Feb 2019 13:50:14 +0000 Subject: [PATCH 063/140] Add parsing cache to `mbedtls_x509_crt` This commit replaces the dummy implementation of the CRT acquire/release framework by a cache-based implementation which remembers frame and PK associated to a CRT across multiple `acquire/release` pairs. --- include/mbedtls/x509_crt.h | 140 +++++++++++++++++++ library/x509_crt.c | 272 ++++++++++++++++++++++--------------- 2 files changed, 302 insertions(+), 110 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 25e807743..3f8350a4a 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -32,6 +32,7 @@ #include "x509.h" #include "x509_crl.h" +#include "threading.h" /** * \addtogroup x509_module @@ -99,6 +100,22 @@ typedef struct mbedtls_x509_crt_frame } mbedtls_x509_crt_frame; +/* This is an internal structure used for caching parsed data from an X.509 CRT. + * + * This structure may change at any time, and it is discouraged + * to access it directly. + */ +typedef struct mbedtls_x509_crt_cache +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t frame_mutex; + mbedtls_threading_mutex_t pk_mutex; +#endif + mbedtls_x509_buf_raw pk_raw; + mbedtls_x509_crt_frame *frame; + mbedtls_pk_context *pk; +} mbedtls_x509_crt_cache; + /** * Container for an X.509 certificate. The certificate may be chained. */ @@ -150,6 +167,8 @@ typedef struct mbedtls_x509_crt mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */ + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ } mbedtls_x509_crt; @@ -643,6 +662,127 @@ void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ); */ void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + +/** + * \brief Flush internal X.509 CRT parsing cache, if present. + * + * \param crt The CRT structure whose cache to flush. + * + * \note Calling this function frequently reduces RAM usage + * at the cost of performance. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); + +/* Internal X.509 CRT cache handling functions. + * They are not part of the public API and may change + * at any time. */ + +int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ); +int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ); + +static inline int mbedtls_x509_crt_cache_frame_set( + mbedtls_x509_crt_cache *cache ) +{ + return( cache->frame != NULL ); +} + +static inline mbedtls_x509_crt_frame* mbedtls_x509_crt_cache_get_frame( + mbedtls_x509_crt_cache *cache ) +{ + return( cache->frame ); +} + +static inline int mbedtls_x509_crt_cache_pk_set( + mbedtls_x509_crt_cache *cache ) +{ + return( cache->pk != NULL ); +} + +static inline mbedtls_pk_context* mbedtls_x509_crt_cache_get_pk( + mbedtls_x509_crt_cache *cache ) +{ + return( cache->pk ); +} + +static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame **frame_ptr ) +{ +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + if( !mbedtls_x509_crt_cache_frame_set( crt->cache ) ) + { + int ret; + ret = mbedtls_x509_crt_cache_provide_frame( crt ); + if( ret != 0 ) + { +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + return( ret ); + } + } + + *frame_ptr = mbedtls_x509_crt_cache_get_frame( crt->cache ); + return( 0 ); +} + +static inline void mbedtls_x509_crt_frame_release( + mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame *frame ) +{ + ((void) frame); + ((void) crt); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock( &crt->cache->frame_mutex ); +#endif +} + +static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt *crt, + mbedtls_pk_context **pk_ptr ) +{ +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + if( !mbedtls_x509_crt_cache_pk_set( crt->cache ) ) + { + int ret; + ret = mbedtls_x509_crt_cache_provide_pk( crt ); + if( ret != 0 ) + { +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + return( ret ); + } + } + + *pk_ptr = mbedtls_x509_crt_cache_get_pk( crt->cache ); + return( 0 ); +} + +static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt *crt, + mbedtls_pk_context *pk ) +{ + ((void) pk); + ((void) crt); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_unlock( &crt->cache->pk_mutex ); +#endif +} + #endif /* MBEDTLS_X509_CRT_PARSE_C */ /* \} name */ diff --git a/library/x509_crt.c b/library/x509_crt.c index bf62f65d9..6c87959b6 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -93,55 +93,91 @@ static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, static void x509_free_sequence( mbedtls_x509_sequence *seq ); static void x509_free_name( mbedtls_x509_name *name ); -static int x509_crt_pk_acquire( mbedtls_x509_crt *crt, - mbedtls_pk_context **pk ); -static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame **frame ); -static void x509_crt_pk_release( mbedtls_x509_crt *crt, - mbedtls_pk_context *pk ); -static void x509_crt_frame_release( mbedtls_x509_crt *crt, - mbedtls_pk_context *pk ); - -static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame **frame_ptr ) +int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) { - int ret; + mbedtls_x509_crt_cache *cache = crt->cache; mbedtls_x509_crt_frame *frame; frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) ); if( frame == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + cache->frame = frame; - ret = x509_crt_parse_frame( crt->raw.p, crt->raw.p + crt->raw.len, - frame ); - if( ret != 0 ) - return( ret ); + return( x509_crt_parse_frame( crt->raw.p, + crt->raw.p + crt->raw.len, + frame ) ); +} - *frame_ptr = frame; +int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) +{ + mbedtls_x509_crt_cache *cache = crt->cache; + mbedtls_pk_context *pk; + + pk = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) ); + if( pk == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + *pk = crt->pk; + + cache->pk = pk; return( 0 ); } -static void x509_crt_frame_release( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame *frame ) +static void x509_crt_cache_init( mbedtls_x509_crt_cache *cache ) { - ((void) crt); - if( frame == NULL ) + memset( cache, 0, sizeof( *cache ) ); +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &cache->frame_mutex ); + mbedtls_mutex_init( &cache->pk_mutex ); +#endif +} + +static void x509_crt_cache_clear_pk( mbedtls_x509_crt_cache *cache ) +{ + /* The cache holds a shallow copy of the PK context + * in the legacy struct, so don't free PK context. */ + mbedtls_free( cache->pk ); + cache->pk = NULL; +} + +static void x509_crt_cache_clear_frame( mbedtls_x509_crt_cache *cache ) +{ + mbedtls_free( cache->frame ); + cache->frame = NULL; +} + +static void x509_crt_cache_free( mbedtls_x509_crt_cache *cache ) +{ + if( cache == NULL ) return; - mbedtls_free( frame ); -} -static int x509_crt_pk_acquire( mbedtls_x509_crt *crt, - mbedtls_pk_context **pk ) -{ - *pk = &crt->pk; - return( 0 ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &cache->frame_mutex ); + mbedtls_mutex_free( &cache->pk_mutex ); +#endif + + x509_crt_cache_clear_frame( cache ); + x509_crt_cache_clear_pk( cache ); + + memset( cache, 0, sizeof( *cache ) ); } -static void x509_crt_pk_release( mbedtls_x509_crt *crt, - mbedtls_pk_context *pk ) +int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) { - ((void) crt); - ((void) pk); - return; +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + x509_crt_cache_clear_frame( crt->cache ); + x509_crt_cache_clear_pk( crt->cache ); +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + return( 0 ); } /* @@ -1163,7 +1199,8 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, int make_copy ) { int ret; - mbedtls_x509_crt_frame frame; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_cache *cache; if( crt == NULL || buf == NULL ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); @@ -1185,19 +1222,21 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, crt->own_buffer = 1; } - /* Parse CRT frame. - * This omits: - * - Issuer, Subject - * - ExtKeyUsage, SubjectAltNames, - * - Time - * - PK - */ - ret = x509_crt_parse_frame( crt->raw.p, - crt->raw.p + crt->raw.len, - &frame ); + cache = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_cache ) ); + if( cache == NULL ) + { + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + goto exit; + } + crt->cache = cache; + x509_crt_cache_init( cache ); + + ret = mbedtls_x509_crt_cache_provide_frame( crt ); if( ret != 0 ) goto exit; + frame = mbedtls_x509_crt_cache_get_frame( crt->cache ); + /* Currently, we accept DER encoded CRTs with trailing garbage * and promise to not account for the garbage in the `raw` field. * @@ -1207,38 +1246,40 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, * need the size, and the garbage data doesn't need zeroization. */ crt->raw.len = frame->raw.len; + cache->pk_raw = frame->pubkey_raw; + /* Copy frame to legacy CRT structure -- that's inefficient, but if * memory matters, the new CRT structure should be used anyway. */ - crt->tbs.p = frame.tbs.p; - crt->tbs.len = frame.tbs.len; - crt->serial.p = frame.serial.p; - crt->serial.len = frame.serial.len; - crt->issuer_raw.p = frame.issuer_raw_with_hdr.p; - crt->issuer_raw.len = frame.issuer_raw_with_hdr.len; - crt->subject_raw.p = frame.subject_raw_with_hdr.p; - crt->subject_raw.len = frame.subject_raw_with_hdr.len; - crt->issuer_raw_no_hdr = frame.issuer_raw; - crt->subject_raw_no_hdr = frame.subject_raw; - crt->issuer_id.p = frame.issuer_id.p; - crt->issuer_id.len = frame.issuer_id.len; - crt->subject_id.p = frame.subject_id.p; - crt->subject_id.len = frame.subject_id.len; - crt->pk_raw.p = frame.pubkey_raw.p; - crt->pk_raw.len = frame.pubkey_raw.len; - crt->ext_key_usage_raw = frame.ext_key_usage_raw; - crt->subject_alt_raw = frame.subject_alt_raw; - crt->sig.p = frame.sig.p; - crt->sig.len = frame.sig.len; - crt->valid_from = frame.valid_from; - crt->valid_to = frame.valid_to; - crt->v3_ext.p = frame.v3_ext.p; - crt->v3_ext.len = frame.v3_ext.len; - crt->version = frame.version; - crt->ca_istrue = frame.ca_istrue; - crt->max_pathlen = frame.max_pathlen; - crt->ext_types = frame.ext_types; - crt->key_usage = frame.key_usage; - crt->ns_cert_type = frame.ns_cert_type; + crt->tbs.p = frame->tbs.p; + crt->tbs.len = frame->tbs.len; + crt->serial.p = frame->serial.p; + crt->serial.len = frame->serial.len; + crt->issuer_raw.p = frame->issuer_raw_with_hdr.p; + crt->issuer_raw.len = frame->issuer_raw_with_hdr.len; + crt->subject_raw.p = frame->subject_raw_with_hdr.p; + crt->subject_raw.len = frame->subject_raw_with_hdr.len; + crt->issuer_raw_no_hdr = frame->issuer_raw; + crt->subject_raw_no_hdr = frame->subject_raw; + crt->issuer_id.p = frame->issuer_id.p; + crt->issuer_id.len = frame->issuer_id.len; + crt->subject_id.p = frame->subject_id.p; + crt->subject_id.len = frame->subject_id.len; + crt->pk_raw.p = frame->pubkey_raw.p; + crt->pk_raw.len = frame->pubkey_raw.len; + crt->ext_key_usage_raw = frame->ext_key_usage_raw; + crt->subject_alt_raw = frame->subject_alt_raw; + crt->sig.p = frame->sig.p; + crt->sig.len = frame->sig.len; + crt->valid_from = frame->valid_from; + crt->valid_to = frame->valid_to; + crt->v3_ext.p = frame->v3_ext.p; + crt->v3_ext.len = frame->v3_ext.len; + crt->version = frame->version; + crt->ca_istrue = frame->ca_istrue; + crt->max_pathlen = frame->max_pathlen; + crt->ext_types = frame->ext_types; + crt->key_usage = frame->key_usage; + crt->ns_cert_type = frame->ns_cert_type; /* * Obtain the remaining fields from the frame. @@ -1247,8 +1288,8 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, { /* sig_oid: Previously, needed for convenience in * mbedtls_x509_crt_info(), now pure legacy burden. */ - unsigned char *tmp = frame.sig_alg.p; - unsigned char *end = tmp + frame.sig_alg.len; + unsigned char *tmp = frame->sig_alg.p; + unsigned char *end = tmp + frame->sig_alg.len; mbedtls_x509_buf sig_oid, sig_params; ret = mbedtls_x509_get_alg( &tmp, end, @@ -1264,7 +1305,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, crt->sig_oid = sig_oid; /* Signature parameters */ - tmp = frame.sig_alg.p; + tmp = frame->sig_alg.p; ret = mbedtls_x509_get_sig_alg_raw( &tmp, end, &crt->sig_md, &crt->sig_pk, &crt->sig_opts ); @@ -1276,23 +1317,31 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, } } - ret = x509_crt_pk_from_frame( &frame, &crt->pk ); + ret = x509_crt_pk_from_frame( frame, &crt->pk ); if( ret != 0 ) goto exit; - ret = x509_crt_subject_from_frame( &frame, &crt->subject ); + ret = x509_crt_subject_from_frame( frame, &crt->subject ); if( ret != 0 ) goto exit; - ret = x509_crt_issuer_from_frame( &frame, &crt->issuer ); + ret = x509_crt_issuer_from_frame( frame, &crt->issuer ); if( ret != 0 ) goto exit; - ret = x509_crt_subject_alt_from_frame( &frame, &crt->subject_alt_names ); + ret = x509_crt_subject_alt_from_frame( frame, &crt->subject_alt_names ); if( ret != 0 ) goto exit; - ret = x509_crt_ext_key_usage_from_frame( &frame, &crt->ext_key_usage ); + ret = x509_crt_ext_key_usage_from_frame( frame, &crt->ext_key_usage ); + if( ret != 0 ) + goto exit; + + + /* The cache just references the PK structure from the legacy + * implementation, so set up the latter first before setting up + * the cache. */ + ret = mbedtls_x509_crt_cache_provide_pk( crt ); if( ret != 0 ) goto exit; @@ -1858,11 +1907,11 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } - ret = x509_crt_frame_acquire( crt_raw, &crt ); + ret = mbedtls_x509_crt_frame_acquire( crt_raw, &crt ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); - ret = x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk ); + ret = mbedtls_x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; @@ -2023,8 +2072,8 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, cleanup: - x509_crt_frame_release( crt_raw, crt ); - x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk ); + mbedtls_x509_crt_frame_release( crt_raw, crt ); + mbedtls_x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk ); x509_crt_free_sig_info( &sig_info ); x509_free_name( issuer.next ); @@ -2122,12 +2171,13 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, { int ret; mbedtls_x509_crt_frame *frame; - ret = x509_crt_frame_acquire( crt, (mbedtls_x509_crt_frame**) &frame ); + ret = mbedtls_x509_crt_frame_acquire( crt, + (mbedtls_x509_crt_frame**) &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); ret = x509_crt_check_key_usage_frame( frame, usage ); - x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame ); + mbedtls_x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame ); return( ret ); } @@ -2174,7 +2224,7 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, unsigned char *p, *end; x509_crt_check_ext_key_usage_cb_ctx_t cb_ctx = { usage_oid, usage_len }; - ret = x509_crt_frame_acquire( crt, &frame ); + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2195,7 +2245,7 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; } - x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt, frame ); return( ret ); } #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ @@ -2231,14 +2281,14 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, int ret; mbedtls_x509_crt_frame *frame; - ret = x509_crt_frame_acquire( crt, &frame ); + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); ret = x509_serial_is_revoked( frame->serial.p, frame->serial.len, crl ); - x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt, frame ); return( ret ); } @@ -2265,7 +2315,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, { mbedtls_x509_crt_frame *ca; - ret = x509_crt_frame_acquire( ca_crt, &ca ); + ret = mbedtls_x509_crt_frame_acquire( ca_crt, &ca ); if( ret != 0 ) return( MBEDTLS_X509_BADCRL_NOT_TRUSTED ); @@ -2278,10 +2328,10 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, can_sign = 1; } - x509_crt_frame_release( ca_crt, ca ); + mbedtls_x509_crt_frame_release( ca_crt, ca ); } - ret = x509_crt_pk_acquire( ca_crt, &pk ); + ret = mbedtls_x509_crt_pk_acquire( ca_crt, &pk ); if( ret != 0 ) return( MBEDTLS_X509_BADCRL_NOT_TRUSTED ); @@ -2356,7 +2406,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, crl_list = crl_list->next; } - x509_crt_pk_release( ca_crt, pk ); + mbedtls_x509_crt_pk_release( ca_crt, pk ); return( flags ); } #endif /* MBEDTLS_X509_CRL_PARSE_C */ @@ -2371,7 +2421,7 @@ static int x509_crt_check_signature( const mbedtls_x509_crt_sig_info *sig_info, int ret; mbedtls_pk_context *pk; - ret = x509_crt_pk_acquire( parent, &pk ); + ret = mbedtls_x509_crt_pk_acquire( parent, &pk ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2405,7 +2455,7 @@ static int x509_crt_check_signature( const mbedtls_x509_crt_sig_info *sig_info, } exit: - x509_crt_pk_release( parent, pk ); + mbedtls_x509_crt_pk_release( parent, pk ); return( ret ); } @@ -2543,7 +2593,7 @@ check_signature: { mbedtls_x509_crt_frame *parent; - ret = x509_crt_frame_acquire( parent_crt, &parent ); + ret = mbedtls_x509_crt_frame_acquire( parent_crt, &parent ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2565,7 +2615,7 @@ check_signature: path_len_ok = 1; } - x509_crt_frame_release( parent_crt, parent ); + mbedtls_x509_crt_frame_release( parent_crt, parent ); } if( parent_match == 0 || path_len_ok == 0 ) @@ -2836,7 +2886,7 @@ find_parent: { mbedtls_x509_crt_frame *child; - ret = x509_crt_frame_acquire( child_crt, &child ); + ret = mbedtls_x509_crt_frame_acquire( child_crt, &child ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2849,7 +2899,7 @@ find_parent: /* Stop here for trusted roots (but not for trusted EE certs) */ if( child_is_trusted ) { - x509_crt_frame_release( child_crt, child ); + mbedtls_x509_crt_frame_release( child_crt, child ); return( 0 ); } @@ -2872,7 +2922,7 @@ find_parent: if( ver_chain->len == 1 && self_issued && x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) { - x509_crt_frame_release( child_crt, child ); + mbedtls_x509_crt_frame_release( child_crt, child ); return( 0 ); } @@ -2881,8 +2931,8 @@ find_parent: #endif /* MBEDTLS_X509_CRL_PARSE_C */ ret = x509_crt_get_sig_info( child, &child_sig ); + mbedtls_x509_crt_frame_release( child_crt, child ); - x509_crt_frame_release( child_crt, child ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); } @@ -2937,7 +2987,7 @@ find_parent: { mbedtls_pk_context *parent_pk; - ret = x509_crt_pk_acquire( parent_crt, &parent_pk ); + ret = mbedtls_x509_crt_pk_acquire( parent_crt, &parent_pk ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2945,7 +2995,7 @@ find_parent: if( x509_profile_check_key( profile, parent_pk ) != 0 ) *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - x509_crt_pk_release( parent_crt, parent_pk ); + mbedtls_x509_crt_pk_release( parent_crt, parent_pk ); } #if defined(MBEDTLS_X509_CRL_PARSE_C) @@ -3037,7 +3087,7 @@ static int x509_crt_verify_name( const mbedtls_x509_crt *crt, int ret; mbedtls_x509_crt_frame *frame; - ret = x509_crt_frame_acquire( crt, &frame ); + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -3063,7 +3113,7 @@ static int x509_crt_verify_name( const mbedtls_x509_crt *crt, x509_crt_check_name, (void*) cn ); } - x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt, frame ); /* x509_crt_check_name() and x509_crt_subject_alt_check_name() * return 1 when finding a name component matching `cn`. */ @@ -3181,7 +3231,7 @@ int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, mbedtls_pk_context *pk; mbedtls_pk_type_t pk_type; - ret = x509_crt_pk_acquire( crt, &pk ); + ret = mbedtls_x509_crt_pk_acquire( crt, &pk ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -3194,7 +3244,7 @@ int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, if( x509_profile_check_key( profile, pk ) != 0 ) ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - x509_crt_pk_release( crt, pk ); + mbedtls_x509_crt_pk_release( crt, pk ); } /* Check the chain */ @@ -3278,6 +3328,8 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) do { + x509_crt_cache_free( cert_cur->cache ); + mbedtls_free( cert_cur->cache ); mbedtls_pk_free( &cert_cur->pk ); #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) From 180f7bf60bcaae7c84cba6a28b4015cf780495e4 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 13:23:38 +0000 Subject: [PATCH 064/140] Add compile-time option to remove legacy CRT fields --- include/mbedtls/config.h | 32 ++++++++++++++++++++++++++++++++ include/mbedtls/x509_crt.h | 19 +++++++++++-------- library/version_features.c | 3 +++ library/x509_crt.c | 27 ++++++++++++++++++++++++--- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index e5d593312..4b8913ba7 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1757,6 +1757,38 @@ */ #define MBEDTLS_VERSION_FEATURES +/** + * \def MBEDTLS_X509_ON_DEMAND_PARSING + * + * Save RAM by reducing mbedtls_x509_crt to a pointer + * to the raw CRT data and parsing CRTs on demand only. + * + * \warning This option changes the API by removing most of + * the structure fields of mbedtls_x509_crt. + * + * \warning This option and its corresponding X.509 API are currently + * under development and may change at any time. + * + * Regardless of whether this option is enabled or not, direct access of + * structure fields of `mbedtls_x509_crt` should be replaced by calls to + * one of the following functions: + * - mbedtls_x509_crt_get_frame(), to obtain a CRT frame giving + * access to several basic CRT fields (such as the CRT version), + * as well as pointers to the raw ASN.1 data of more complex fields + * (such as the issuer). + * - mbedtls_x509_crt_get_pk(), to obtain a public key context + * for the public key contained in the certificate. + * - mbedtls_x509_crt_get_issuer(), to obtain the issuer name. + * - mbedtls_x509_crt_get_subject(), to obtain the subject name. + * - mbedtls_x509_crt_get_subject_alt_names(), to obtain the + * alternative names from the subject alternative names extension. + * - mbedtls_x509_crt_get_ext_key_usage(), to obtain the state of + * the extended key usage extension. + * + * Uncomment this to enable on-demand CRT parsing to save RAM. + */ +//#define MBEDTLS_X509_ON_DEMAND_PARSING + /** * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 * diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 3f8350a4a..db99aabba 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -122,8 +122,14 @@ typedef struct mbedtls_x509_crt_cache typedef struct mbedtls_x509_crt { int own_buffer; /**< Indicates if \c raw is owned - * by the structure or not. */ - mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + * by the structure or not. */ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */ + + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ + + /* Legacy fields */ +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ @@ -166,10 +172,7 @@ typedef struct mbedtls_x509_crt mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ - - mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */ - - struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ +#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ } mbedtls_x509_crt; @@ -746,7 +749,7 @@ static inline void mbedtls_x509_crt_frame_release( #endif } -static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt *crt, +static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, mbedtls_pk_context **pk_ptr ) { #if defined(MBEDTLS_THREADING_C) @@ -772,7 +775,7 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt *crt, return( 0 ); } -static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt *crt, +static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt, mbedtls_pk_context *pk ) { ((void) pk); diff --git a/library/version_features.c b/library/version_features.c index 5e9d9239b..e19e31455 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -534,6 +534,9 @@ static const char *features[] = { #if defined(MBEDTLS_VERSION_FEATURES) "MBEDTLS_VERSION_FEATURES", #endif /* MBEDTLS_VERSION_FEATURES */ +#if defined(MBEDTLS_X509_ON_DEMAND_PARSING) + "MBEDTLS_X509_ON_DEMAND_PARSING", +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ #if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", #endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */ diff --git a/library/x509_crt.c b/library/x509_crt.c index 6c87959b6..20f0bb020 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -116,10 +116,19 @@ int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) pk = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) ); if( pk == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); - *pk = crt->pk; - cache->pk = pk; + +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) + *pk = crt->pk; return( 0 ); +#else + { + mbedtls_x509_buf_raw pk_raw = cache->pk_raw; + return( mbedtls_pk_parse_subpubkey( &pk_raw.p, + pk_raw.p + pk_raw.len, + pk ) ); + } +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ } static void x509_crt_cache_init( mbedtls_x509_crt_cache *cache ) @@ -133,9 +142,15 @@ static void x509_crt_cache_init( mbedtls_x509_crt_cache *cache ) static void x509_crt_cache_clear_pk( mbedtls_x509_crt_cache *cache ) { +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) /* The cache holds a shallow copy of the PK context * in the legacy struct, so don't free PK context. */ mbedtls_free( cache->pk ); +#else + mbedtls_pk_free( cache->pk ); + mbedtls_free( cache->pk ); +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ + cache->pk = NULL; } @@ -1182,6 +1197,7 @@ static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, return( 0 ); } +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) static int x509_crt_pk_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_pk_context *pk ) { @@ -1189,6 +1205,7 @@ static int x509_crt_pk_from_frame( mbedtls_x509_crt_frame *frame, unsigned char *end = p + frame->pubkey_raw.len; return( mbedtls_pk_parse_subpubkey( &p, end, pk ) ); } +#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ /* * Parse and fill a single X.509 certificate in DER format @@ -1248,6 +1265,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, cache->pk_raw = frame->pubkey_raw; +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) /* Copy frame to legacy CRT structure -- that's inefficient, but if * memory matters, the new CRT structure should be used anyway. */ crt->tbs.p = frame->tbs.p; @@ -1336,7 +1354,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, ret = x509_crt_ext_key_usage_from_frame( frame, &crt->ext_key_usage ); if( ret != 0 ) goto exit; - +#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ /* The cache just references the PK structure from the legacy * implementation, so set up the latter first before setting up @@ -3330,6 +3348,8 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { x509_crt_cache_free( cert_cur->cache ); mbedtls_free( cert_cur->cache ); + +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) mbedtls_pk_free( &cert_cur->pk ); #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) @@ -3340,6 +3360,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) x509_free_name( cert_cur->subject.next ); x509_free_sequence( cert_cur->ext_key_usage.next ); x509_free_sequence( cert_cur->subject_alt_names.next ); +#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) { From 823efad6e85ccb2edd40a4f331783e3785815095 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 13:23:58 +0000 Subject: [PATCH 065/140] Add public API to query for CRT frame and PK This commit unconditionally adds two convenience API functions: - mbedtls_x509_crt_get_frame() - mbedtls_x509_crt_get_pk() which allow users to extract a CRT frame or PK context from a certificate. The difference with the existing acquire/release API for frame and PK contexts is that in contrast to the latter, the structures returned by the new API are owned by the user (and, in case of the PK context, need to be freed by him). This makes the API easier to use, but comes at the cost of additional memory overhead. --- include/mbedtls/x509_crt.h | 35 ++++++++++++++++++++++++++++++++++ library/x509_crt.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index db99aabba..ce1ee0539 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -666,6 +666,41 @@ void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ); void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ +/** + * \brief Request CRT frame giving access to basic CRT fields + * and raw ASN.1 data of complex fields. + * + * \param crt The CRT to use. This must be initialized and setup. + * \param dst The address of the destination frame structure. + * This need not be initialized. + * + * \note ::mbedtls_x509_crt_frame does not contain pointers to + * dynamically allocated memory, and hence need not be freed. + * Users may e.g. allocate an instance of + * ::mbedtls_x509_crt_frame on the stack and call this function + * on it, in which case no allocation/freeing has to be done. + * + * \return \c 0 on success. In this case, \p dst is updated + * to hold the frame for the given CRT. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame *dst ); + +/** + * \brief Setup a PK context with the public key in a certificate. + * + * \param crt The certificate to use. This must be initialized and setup. + * \param pk The address of the destination PK context to fill. + * This must be initialized via mbedtls_pk_init(). + * + * \return \c 0 on success. In this case, the user takes ownership + * of the destination PK context, and is responsible for + * calling mbedtls_pk_free() on it once it's no longer needed. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, + mbedtls_pk_context *pk ); /** * \brief Flush internal X.509 CRT parsing cache, if present. diff --git a/library/x509_crt.c b/library/x509_crt.c index 20f0bb020..960296de8 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -195,6 +195,45 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) return( 0 ); } +int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, + mbedtls_x509_crt_frame *dst ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + *dst = *frame; + mbedtls_x509_crt_frame_release( crt, frame ); + return( 0 ); +} + +int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, + mbedtls_pk_context *dst ) +{ +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) + mbedtls_x509_buf_raw pk_raw = crt->cache->pk_raw; + return( mbedtls_pk_parse_subpubkey( &pk_raw.p, + pk_raw.p + pk_raw.len, + dst ) ); +#else /* !MBEDTLS_X509_ON_DEMAND_PARSING */ + int ret; + mbedtls_pk_context *pk; + ret = mbedtls_x509_crt_pk_acquire( crt, &pk ); + if( ret != 0 ) + return( ret ); + + /* Move PK from CRT cache to destination pointer + * to avoid a copy. */ + *dst = *pk; + mbedtls_free( crt->cache->pk ); + crt->cache->pk = NULL; + + mbedtls_x509_crt_pk_release( crt, pk ); + return( 0 ); +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ +} + /* * Item in a verification chain: cert and flags for it */ From 63e6998dd7559a52d56d04583eeae62efdfb9a6e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 18:50:49 +0000 Subject: [PATCH 066/140] Add public API to query subject and issuer from CRT The legacy `mbedtls_x509_crt` contains fields `issuer/subject` which are dynamically allocated linked list presentations of the CRTs issuer and subject names, respectively. The new CRT frame structure `mbedtls_x509_crt_frame`, however, only provides pointers to the raw ASN.1 buffers for the issuer and subject, for reasons of memory usage. For convenience to users that previously used the `issuer`/`subject` fields of `mbedtls_x509_crt`, this commit adds two public API functions `mbedtls_x509_crt_get_subject()` and `mbedtls_x509_crt_get_issuer()` which allow to request the legacy linked list presentation of the CRTs subject / issuer names. Similar to `mbedtls_x509_crt_get_pk()`, the returned names are owned by the user, and must be freed through a call to `mbedtls_x509_name_free()`. --- include/mbedtls/x509_crt.h | 48 ++++++++++++++++++++++++++++++++++++++ library/x509_crt.c | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index ce1ee0539..790016efa 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -702,6 +702,54 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, mbedtls_pk_context *pk ); +/** + * \brief Request the subject name of a CRT, presented + * as a dynamically allocated linked list. + * + * \param crt The CRT to use. This must be initialized and setup. + * \param subject The address at which to store the address of the + * first entry of the generated linked list holding + * the subject name. + * + * \note Depending in your use case, consider using the raw ASN.1 + * describing the subject name instead of the heap-allocated + * linked list generated by this call. The pointers to the + * raw ASN.1 data are part of the CRT frame that can be queried + * via mbedtls_x509_crt_get_frame(), and they can be traversed + * via mbedtls_asn1_traverse_sequence_of(). + * + * \return \c 0 on success. In this case, the user takes ownership + * of the name context, and is responsible for freeing it + * once it's no longer needed. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, + mbedtls_x509_name **subject ); + +/** + * \brief Request the subject name of a CRT, presented + * as a dynamically allocated linked list. + * + * \param crt The CRT to use. This must be initialized and setup. + * \param issuer The address at which to store the address of the + * first entry of the generated linked list holding + * the subject name. + * + * \note Depending in your use case, consider using the raw ASN.1 + * describing the subject name instead of the heap-allocated + * linked list generated by this call. The pointers to the + * raw ASN.1 data are part of the CRT frame that can be queried + * via mbedtls_x509_crt_get_frame(), and they can be traversed + * via mbedtls_asn1_traverse_sequence_of(). + * + * \return \c 0 on success. In this case, the user takes ownership + * of the name context, and is responsible for freeing it + * once it's no longer needed. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, + mbedtls_x509_name **issuer ); + /** * \brief Flush internal X.509 CRT parsing cache, if present. * diff --git a/library/x509_crt.c b/library/x509_crt.c index 960296de8..fe782bbeb 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -195,6 +195,52 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) return( 0 ); } +int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, + mbedtls_x509_name **subject ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_name *name; + + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + + name = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + if( name == NULL ) + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + else + ret = x509_crt_subject_from_frame( frame, name ); + + mbedtls_x509_crt_frame_release( crt, frame ); + + *subject = name; + return( ret ); +} + +int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, + mbedtls_x509_name **issuer ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_name *name; + + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + + name = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + if( name == NULL ) + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + else + ret = x509_crt_issuer_from_frame( frame, name ); + + mbedtls_x509_crt_frame_release( crt, frame ); + + *issuer = name; + return( ret ); +} + int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame *dst ) { From ab6c8ea8bc895cdcec0988e4b3e1efef50727c47 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Feb 2019 17:33:14 +0000 Subject: [PATCH 067/140] Add public API to query SubjectAltNames and ExtKeyUsage extensions --- include/mbedtls/x509_crt.h | 50 ++++++++++++++++++++++++++++++++++++++ library/x509_crt.c | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 790016efa..ca93e1a92 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -750,6 +750,56 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, mbedtls_x509_name **issuer ); +/** + * \brief Request the subject alternative name of a CRT, presented + * as a dynamically allocated linked list. + * + * \param crt The CRT to use. This must be initialized and setup. + * \param subj_alt The address at which to store the address of the + * first component of the subject alternative names list. + * + * \note Depending in your use case, consider using the raw ASN.1 + * describing the subject alternative names extension + * instead of the heap-allocated linked list generated by this + * call. The pointers to the raw ASN.1 data are part of the CRT + * frame that can be queried via mbedtls_x509_crt_get_frame(), + * and mbedtls_asn1_traverse_sequence_of() can be used to + * traverse the list of subject alternative names. + * + * \return \c 0 on success. In this case, the user takes ownership + * of the name context, and is responsible for freeing it + * through a call to mbedtls_x509_sequence_free() once it's + * no longer needed. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, + mbedtls_x509_sequence **subj_alt ); + +/** + * \brief Request the ExtendedKeyUsage extension of a CRT, + * presented as a dynamically allocated linked list. + * + * \param crt The CRT to use. This must be initialized and setup. + * \param ext_key_usage The address at which to store the address of the + * first entry of the ExtendedKeyUsage extension. + * + * \note Depending in your use case, consider using the raw ASN.1 + * describing the extended key usage extension instead of + * the heap-allocated linked list generated by this call. + * The pointers to the raw ASN.1 data are part of the CRT + * frame that can be queried via mbedtls_x509_crt_get_frame(), + * and mbedtls_asn1_traverse_sequence_of() can be used to + * traverse the entries in the extended key usage extension. + * + * \return \c 0 on success. In this case, the user takes ownership + * of the name context, and is responsible for freeing it + * through a call to mbedtls_x509_sequence_free() once it's + * no longer needed. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, + mbedtls_x509_sequence **ext_key_usage ); + /** * \brief Flush internal X.509 CRT parsing cache, if present. * diff --git a/library/x509_crt.c b/library/x509_crt.c index fe782bbeb..643b5616d 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -195,6 +195,52 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) return( 0 ); } +int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, + mbedtls_x509_sequence **subj_alt ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_sequence *seq; + + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + + seq = mbedtls_calloc( 1, sizeof( mbedtls_x509_sequence ) ); + if( seq == NULL ) + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + else + ret = x509_crt_subject_alt_from_frame( frame, seq ); + + mbedtls_x509_crt_frame_release( crt, frame ); + + *subj_alt = seq; + return( ret ); +} + +int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, + mbedtls_x509_sequence **ext_key_usage ) +{ + int ret; + mbedtls_x509_crt_frame *frame; + mbedtls_x509_sequence *seq; + + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); + if( ret != 0 ) + return( ret ); + + seq = mbedtls_calloc( 1, sizeof( mbedtls_x509_sequence ) ); + if( seq == NULL ) + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + else + ret = x509_crt_ext_key_usage_from_frame( frame, seq ); + + mbedtls_x509_crt_frame_release( crt, frame ); + + *ext_key_usage = seq; + return( ret ); +} + int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, mbedtls_x509_name **subject ) { From 2bcc7640f8610e0b4a0ea3212b3816ac78dc02ef Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 19:01:00 +0000 Subject: [PATCH 068/140] Give x509_{sequence|name}_free() external linkage With the introduction of `mbedtls_x509_crt_get_{issuer|name}()`, users need an easy way of freeing the dynamic name structures these functions return. To that end, this commit renames `x509_{sequence|name}_free()` to `mbedtls_x509_{sequence|name}_free()` and gives them external linkage. --- include/mbedtls/x509.h | 20 +++++++++++++++++++ include/mbedtls/x509_crt.h | 6 ++++-- library/x509.c | 22 ++++++++++++++++++++ library/x509_crt.c | 41 ++++++++------------------------------ 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 583bc1228..2a9ce99a4 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -278,6 +278,26 @@ int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ); */ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ); +/** + * \brief Free a dynamic linked list presentation of an X.509 name + * as returned e.g. by mbedtls_x509_crt_get_subject(). + * + * \param name The address of the first name component. This may + * be \c NULL, in which case this functions returns + * immediately. + */ +void mbedtls_x509_name_free( mbedtls_x509_name *name ); + +/** + * \brief Free a dynamic linked list presentation of an X.509 sequence + * as returned e.g. by mbedtls_x509_crt_get_subject_alt_name(). + * + * \param seq The address of the first sequence component. This may + * be \c NULL, in which case this functions returns + * immediately. + */ +void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq ); + #if defined(MBEDTLS_SELF_TEST) /** diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index ca93e1a92..ad6140c42 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -720,7 +720,8 @@ int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, * * \return \c 0 on success. In this case, the user takes ownership * of the name context, and is responsible for freeing it - * once it's no longer needed. + * through a call to mbedtls_x509_name_free() once it's no + * longer needed. * \return A negative error code on failure. */ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, @@ -744,7 +745,8 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, * * \return \c 0 on success. In this case, the user takes ownership * of the name context, and is responsible for freeing it - * once it's no longer needed. + * through a call to mbedtls_x509_name_free() once it's no + * longer needed. * \return A negative error code on failure. */ int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, diff --git a/library/x509.c b/library/x509.c index 72cadd088..55726da98 100644 --- a/library/x509.c +++ b/library/x509.c @@ -1194,6 +1194,28 @@ int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) } #endif /* MBEDTLS_HAVE_TIME_DATE */ +void mbedtls_x509_name_free( mbedtls_x509_name *name ) +{ + while( name != NULL ) + { + mbedtls_x509_name *next = name->next; + mbedtls_platform_zeroize( name, sizeof( *name ) ); + mbedtls_free( name ); + name = next; + } +} + +void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq ) +{ + while( seq != NULL ) + { + mbedtls_x509_sequence *next = seq->next; + mbedtls_platform_zeroize( seq, sizeof( *seq ) ); + mbedtls_free( seq ); + seq = next; + } +} + #if defined(MBEDTLS_SELF_TEST) #include "mbedtls/x509_crt.h" diff --git a/library/x509_crt.c b/library/x509_crt.c index 643b5616d..46f139f09 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -90,9 +90,6 @@ static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_sequence *ext_key_usage ); -static void x509_free_sequence( mbedtls_x509_sequence *seq ); -static void x509_free_name( mbedtls_x509_name *name ); - int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) { mbedtls_x509_crt_cache *cache = crt->cache; @@ -2225,10 +2222,10 @@ cleanup: mbedtls_x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk ); x509_crt_free_sig_info( &sig_info ); - x509_free_name( issuer.next ); - x509_free_name( subject.next ); - x509_free_sequence( ext_key_usage.next ); - x509_free_sequence( subject_alt_names.next ); + mbedtls_x509_name_free( issuer.next ); + mbedtls_x509_name_free( subject.next ); + mbedtls_x509_sequence_free( ext_key_usage.next ); + mbedtls_x509_sequence_free( subject_alt_names.next ); return( ret ); } @@ -3445,28 +3442,6 @@ void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) * Unallocate all certificate data */ -static void x509_free_sequence( mbedtls_x509_sequence *seq ) -{ - while( seq != NULL ) - { - mbedtls_x509_sequence *next = seq->next; - mbedtls_platform_zeroize( seq, sizeof( *seq ) ); - mbedtls_free( seq ); - seq = next; - } -} - -static void x509_free_name( mbedtls_x509_name *name ) -{ - while( name != NULL ) - { - mbedtls_x509_name *next = name->next; - mbedtls_platform_zeroize( name, sizeof( *name ) ); - mbedtls_free( name ); - name = next; - } -} - void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) { mbedtls_x509_crt *cert_cur = crt; @@ -3487,10 +3462,10 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) mbedtls_free( cert_cur->sig_opts ); #endif - x509_free_name( cert_cur->issuer.next ); - x509_free_name( cert_cur->subject.next ); - x509_free_sequence( cert_cur->ext_key_usage.next ); - x509_free_sequence( cert_cur->subject_alt_names.next ); + mbedtls_x509_name_free( cert_cur->issuer.next ); + mbedtls_x509_name_free( cert_cur->subject.next ); + mbedtls_x509_sequence_free( cert_cur->ext_key_usage.next ); + mbedtls_x509_sequence_free( cert_cur->subject_alt_names.next ); #endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) From d8eab343d233c0f44a68fe0e01b15c60d9035276 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 18:47:11 +0000 Subject: [PATCH 069/140] Adapt cert_write example program to work with new CRT structure --- programs/x509/cert_write.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c index 497c3376b..521f25a93 100644 --- a/programs/x509/cert_write.c +++ b/programs/x509/cert_write.c @@ -524,6 +524,8 @@ int main( int argc, char *argv[] ) // if( !opt.selfsign && strlen( opt.issuer_crt ) ) { + mbedtls_x509_name *subject; + /* * 1.0.a. Load the certificates */ @@ -538,8 +540,17 @@ int main( int argc, char *argv[] ) goto exit; } + ret = mbedtls_x509_crt_get_subject( &issuer_crt, &subject ); + if( ret != 0 ) + { + mbedtls_strerror( ret, buf, 1024 ); + mbedtls_printf( " failed\n ! mbedtls_x509_crt_get_subject " + "returned -0x%04x - %s\n\n", -ret, buf ); + goto exit; + } + ret = mbedtls_x509_dn_gets( issuer_name, sizeof(issuer_name), - &issuer_crt.subject ); + subject ); if( ret < 0 ) { mbedtls_strerror( ret, buf, 1024 ); @@ -550,6 +561,8 @@ int main( int argc, char *argv[] ) opt.issuer_name = issuer_name; + mbedtls_x509_name_free( subject ); + mbedtls_printf( " ok\n" ); } @@ -627,12 +640,24 @@ int main( int argc, char *argv[] ) // if( strlen( opt.issuer_crt ) ) { - if( mbedtls_pk_check_pair( &issuer_crt.pk, issuer_key ) != 0 ) + mbedtls_pk_context pk; + ret = mbedtls_x509_crt_get_pk( &issuer_crt, &pk ); + if( ret != 0 ) + { + mbedtls_strerror( ret, buf, 1024 ); + mbedtls_printf( " failed\n ! mbedtls_x509_crt_get_pk " + "returned -0x%04x - %s\n\n", -ret, buf ); + goto exit; + } + + if( mbedtls_pk_check_pair( &pk, issuer_key ) != 0 ) { mbedtls_printf( " failed\n ! issuer_key does not match " "issuer certificate\n\n" ); goto exit; } + + mbedtls_pk_free( &pk ); } mbedtls_printf( " ok\n" ); From c69c4465b638963e1aac5e9601d492394d51adaa Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Feb 2019 09:05:41 +0000 Subject: [PATCH 070/140] Adapt test_suite_x509parse to new CRT structure --- tests/suites/test_suite_x509parse.function | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 24b9e40f7..91aa696b8 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -469,15 +469,19 @@ void mbedtls_x509_dn_gets( char * crt_file, char * entity, char * result_str ) mbedtls_x509_crt crt; char buf[2000]; int res = 0; + mbedtls_x509_name *subject = NULL, *issuer = NULL; mbedtls_x509_crt_init( &crt ); memset( buf, 0, 2000 ); TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_get_subject( &crt, &subject ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_get_issuer( &crt, &issuer ) == 0 ); + if( strcmp( entity, "subject" ) == 0 ) - res = mbedtls_x509_dn_gets( buf, 2000, &crt.subject ); + res = mbedtls_x509_dn_gets( buf, 2000, subject ); else if( strcmp( entity, "issuer" ) == 0 ) - res = mbedtls_x509_dn_gets( buf, 2000, &crt.issuer ); + res = mbedtls_x509_dn_gets( buf, 2000, issuer ); else TEST_ASSERT( "Unknown entity" == 0 ); @@ -487,6 +491,8 @@ void mbedtls_x509_dn_gets( char * crt_file, char * entity, char * result_str ) TEST_ASSERT( strcmp( buf, result_str ) == 0 ); exit: + mbedtls_x509_name_free( issuer ); + mbedtls_x509_name_free( subject ); mbedtls_x509_crt_free( &crt ); } /* END_CASE */ @@ -494,16 +500,18 @@ exit: /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ void mbedtls_x509_time_is_past( char * crt_file, char * entity, int result ) { - mbedtls_x509_crt crt; + mbedtls_x509_crt crt; + mbedtls_x509_crt_frame frame; mbedtls_x509_crt_init( &crt ); TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_get_frame( &crt, &frame ) == 0 ); if( strcmp( entity, "valid_from" ) == 0 ) - TEST_ASSERT( mbedtls_x509_time_is_past( &crt.valid_from ) == result ); + TEST_ASSERT( mbedtls_x509_time_is_past( &frame.valid_from ) == result ); else if( strcmp( entity, "valid_to" ) == 0 ) - TEST_ASSERT( mbedtls_x509_time_is_past( &crt.valid_to ) == result ); + TEST_ASSERT( mbedtls_x509_time_is_past( &frame.valid_to ) == result ); else TEST_ASSERT( "Unknown entity" == 0 ); @@ -515,16 +523,18 @@ exit: /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ void mbedtls_x509_time_is_future( char * crt_file, char * entity, int result ) { - mbedtls_x509_crt crt; + mbedtls_x509_crt crt; + mbedtls_x509_crt_frame frame; mbedtls_x509_crt_init( &crt ); TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_get_frame( &crt, &frame ) == 0 ); if( strcmp( entity, "valid_from" ) == 0 ) - TEST_ASSERT( mbedtls_x509_time_is_future( &crt.valid_from ) == result ); + TEST_ASSERT( mbedtls_x509_time_is_future( &frame.valid_from ) == result ); else if( strcmp( entity, "valid_to" ) == 0 ) - TEST_ASSERT( mbedtls_x509_time_is_future( &crt.valid_to ) == result ); + TEST_ASSERT( mbedtls_x509_time_is_future( &frame.valid_to ) == result ); else TEST_ASSERT( "Unknown entity" == 0 ); From 828a8c08b60a25a6e7b997dfcd215de0693a0f73 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 26 Feb 2019 16:48:55 +0000 Subject: [PATCH 071/140] Add compile-guard for < TLS1.2 path in server-side ssl_pick_cert() Minor code-size optimization along the way. --- library/ssl_srv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index f661d11e6..f00e44ba6 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -862,6 +862,8 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, continue; } +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) /* * Try to select a SHA-1 certificate for pre-1.2 clients, but still * present them a SHA-higher cert rather than failing if it's the only @@ -890,6 +892,9 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, continue; } } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_SSL3 */ /* If we get there, we got a winner */ break; From 7a4de9cdabac75708d09753d9c3a3240e3583cae Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Feb 2019 13:12:24 +0000 Subject: [PATCH 072/140] Flush CRT cache after parsing This commit modifies the CRT parsing routine to flush the CRT cache after parsing. More specifically, the frame cache is flushed before the PK is parsed, to avoid storing the PK and frame in RAM at the same time. --- library/x509_crt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 46f139f09..fd7979ff1 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1484,12 +1484,24 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, goto exit; #endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ + /* Free the frame before parsing the public key to + * keep peak RAM usage low. This is slightly inefficient + * because the frame will need to be parsed again on the + * first usage of the CRT, but that seems acceptable. + * As soon as the frame gets used multiple times, it + * will be cached by default. */ + x509_crt_cache_clear_frame( crt->cache ); + /* The cache just references the PK structure from the legacy * implementation, so set up the latter first before setting up - * the cache. */ + * the cache. + * + * We're not actually using the parsed PK context here; + * we just parse it to check that it's well-formed. */ ret = mbedtls_x509_crt_cache_provide_pk( crt ); if( ret != 0 ) goto exit; + x509_crt_cache_clear_pk( crt->cache ); exit: if( ret != 0 ) From 5226c53e134504f25d33b209183fa2f33f690686 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Feb 2019 17:38:40 +0000 Subject: [PATCH 073/140] Modify mbedtls_x509_crt_info() to use getter API --- library/x509_crt.c | 99 ++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index fd7979ff1..03222d50c 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2040,24 +2040,26 @@ static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, #define BEFORE_COLON 18 #define BC "18" int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, - const mbedtls_x509_crt *crt_raw ) + const mbedtls_x509_crt *crt ) { int ret; size_t n; char *p; char key_size_str[BEFORE_COLON]; - mbedtls_x509_crt_frame *crt; - mbedtls_pk_context *pk; + mbedtls_x509_crt_frame frame; + mbedtls_pk_context pk; - mbedtls_x509_name issuer, subject; - mbedtls_x509_sequence ext_key_usage, subject_alt_names; + mbedtls_x509_name *issuer = NULL, *subject = NULL; + mbedtls_x509_sequence *ext_key_usage = NULL, *subject_alt_names = NULL; mbedtls_x509_crt_sig_info sig_info; p = buf; n = size; memset( &sig_info, 0, sizeof( mbedtls_x509_crt_sig_info ) ); - if( NULL == crt_raw ) + mbedtls_pk_init( &pk ); + + if( NULL == crt ) { ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; @@ -2065,46 +2067,49 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } - ret = mbedtls_x509_crt_frame_acquire( crt_raw, &crt ); - if( ret != 0 ) - return( MBEDTLS_ERR_X509_FATAL_ERROR ); - - ret = mbedtls_x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk ); + ret = mbedtls_x509_crt_get_frame( crt, &frame ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; goto cleanup; } - ret = x509_crt_get_sig_info( crt, &sig_info ); + ret = mbedtls_x509_crt_get_subject( crt, &subject ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; goto cleanup; } - ret = x509_crt_subject_from_frame( crt, &subject ); + ret = mbedtls_x509_crt_get_issuer( crt, &issuer ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; goto cleanup; } - ret = x509_crt_issuer_from_frame( crt, &issuer ); + ret = mbedtls_x509_crt_get_subject_alt_names( crt, &subject_alt_names ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; goto cleanup; } - ret = x509_crt_subject_alt_from_frame( crt, &subject_alt_names ); + ret = mbedtls_x509_crt_get_ext_key_usage( crt, &ext_key_usage ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; goto cleanup; } - ret = x509_crt_ext_key_usage_from_frame( crt, &ext_key_usage ); + ret = mbedtls_x509_crt_get_pk( crt, &pk ); + if( ret != 0 ) + { + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + goto cleanup; + } + + ret = x509_crt_get_sig_info( &frame, &sig_info ); if( ret != 0 ) { ret = MBEDTLS_ERR_X509_FATAL_ERROR; @@ -2112,13 +2117,13 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, } ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", - prefix, crt->version ); + prefix, frame.version ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; { mbedtls_x509_buf serial; - serial.p = crt->serial.p; - serial.len = crt->serial.len; + serial.p = frame.serial.p; + serial.len = frame.serial.len; ret = mbedtls_snprintf( p, n, "%sserial number : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; @@ -2128,26 +2133,26 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - ret = mbedtls_x509_dn_gets( p, n, &issuer ); + ret = mbedtls_x509_dn_gets( p, n, issuer ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - ret = mbedtls_x509_dn_gets( p, n, &subject ); + ret = mbedtls_x509_dn_gets( p, n, subject ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crt->valid_from.year, crt->valid_from.mon, - crt->valid_from.day, crt->valid_from.hour, - crt->valid_from.min, crt->valid_from.sec ); + frame.valid_from.year, frame.valid_from.mon, + frame.valid_from.day, frame.valid_from.hour, + frame.valid_from.min, frame.valid_from.sec ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crt->valid_to.year, crt->valid_to.mon, - crt->valid_to.day, crt->valid_to.hour, - crt->valid_to.min, crt->valid_to.sec ); + frame.valid_to.year, frame.valid_to.mon, + frame.valid_to.day, frame.valid_to.hour, + frame.valid_to.min, frame.valid_to.sec ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); @@ -2159,67 +2164,67 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, /* Key size */ if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, - mbedtls_pk_get_name( pk ) ) ) != 0 ) + mbedtls_pk_get_name( &pk ) ) ) != 0 ) { return( ret ); } ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, - (int) mbedtls_pk_get_bitlen( pk ) ); + (int) mbedtls_pk_get_bitlen( &pk ) ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; /* * Optional extensions */ - if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) + if( frame.ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) { ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, - crt->ca_istrue ? "true" : "false" ); + frame.ca_istrue ? "true" : "false" ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - if( crt->max_pathlen > 0 ) + if( frame.max_pathlen > 0 ) { - ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); + ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", frame.max_pathlen - 1 ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; } } - if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + if( frame.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_subject_alt_name( &p, &n, - &subject_alt_names ) ) != 0 ) + subject_alt_names ) ) != 0 ) return( ret ); } - if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) + if( frame.ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) { ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) + if( ( ret = x509_info_cert_type( &p, &n, frame.ns_cert_type ) ) != 0 ) return( ret ); } - if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) + if( frame.ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) { ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) + if( ( ret = x509_info_key_usage( &p, &n, frame.key_usage ) ) != 0 ) return( ret ); } - if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) + if( frame.ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) { ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; if( ( ret = x509_info_ext_key_usage( &p, &n, - &ext_key_usage ) ) != 0 ) + ext_key_usage ) ) != 0 ) return( ret ); } @@ -2230,14 +2235,12 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, cleanup: - mbedtls_x509_crt_frame_release( crt_raw, crt ); - mbedtls_x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk ); - x509_crt_free_sig_info( &sig_info ); - mbedtls_x509_name_free( issuer.next ); - mbedtls_x509_name_free( subject.next ); - mbedtls_x509_sequence_free( ext_key_usage.next ); - mbedtls_x509_sequence_free( subject_alt_names.next ); + mbedtls_pk_free( &pk ); + mbedtls_x509_name_free( issuer ); + mbedtls_x509_name_free( subject ); + mbedtls_x509_sequence_free( ext_key_usage ); + mbedtls_x509_sequence_free( subject_alt_names ); return( ret ); } From 3f8f0dc3fd458393d9ed4f106102fd4ea0689a43 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 27 Feb 2019 18:06:47 +0000 Subject: [PATCH 074/140] Use mbedtls_x509_crt_get_subject() in test_suite_x509parse test --- tests/suites/test_suite_x509parse.function | 32 +++++----------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 91aa696b8..de0bc6d55 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -24,17 +24,6 @@ const mbedtls_x509_crt_profile profile_all = 1024, }; -static void x509_free_name( mbedtls_x509_name *name ) -{ - while( name != NULL ) - { - mbedtls_x509_name *next = name->next; - mbedtls_platform_zeroize( name, sizeof( *name ) ); - mbedtls_free( name ); - name = next; - } -} - /* Profile for backward compatibility. Allows SHA-1, unlike the default profile. */ const mbedtls_x509_crt_profile compat_profile = @@ -154,24 +143,17 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint char *p = ctx->p; size_t n = ctx->buf + sizeof( ctx->buf ) - ctx->p; mbedtls_x509_crt_frame *frame; - mbedtls_x509_name subject; + mbedtls_x509_name *subject; ((void) flags); + ret = mbedtls_x509_crt_get_subject( crt, &subject ); + if( ret != 0 ) + return( ret ); + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( ret ); - /* Get linked list presentation of issuer which - * `mbedtls_x509_dn_gets()` understands. */ - { - unsigned char *subject_start = frame->subject_raw.p; - unsigned char *subject_end = frame->subject_raw.p + frame->subject_raw.len; - - ret = mbedtls_x509_get_name( &subject_start, subject_end, &subject ); - if( ret != 0 ) - goto cleanup; - } - ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; @@ -186,7 +168,7 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint ret = mbedtls_snprintf( p, n, " - subject " ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; - ret = mbedtls_x509_dn_gets( p, n, &subject ); + ret = mbedtls_x509_dn_gets( p, n, subject ); MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; ret = mbedtls_snprintf( p, n, " - flags 0x%08x\n", *flags ); @@ -196,7 +178,7 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint cleanup: - x509_free_name( subject.next ); + mbedtls_x509_name_free( subject ); mbedtls_x509_crt_frame_release( crt, frame ); if( ret < 0 ) From 4588dc475461e9c00023e54c260cf407ae2b6f1d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:20:44 +0000 Subject: [PATCH 075/140] Update query_config.c --- programs/ssl/query_config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c index ab3c772ab..a00847208 100644 --- a/programs/ssl/query_config.c +++ b/programs/ssl/query_config.c @@ -1466,6 +1466,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_VERSION_FEATURES */ +#if defined(MBEDTLS_X509_ON_DEMAND_PARSING) + if( strcmp( "MBEDTLS_X509_ON_DEMAND_PARSING", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ON_DEMAND_PARSING ); + return( 0 ); + } +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ + #if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) if( strcmp( "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", config ) == 0 ) { From 5d9021e7f24b4b1c3e8cff73bbec905630dbaa87 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 14:32:37 +0000 Subject: [PATCH 076/140] Make use of new API in ssl_server2 example application --- programs/ssl/ssl_server2.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 8a12de23d..df39b5149 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1065,6 +1065,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, const unsigned char *input, size_t input_len ) { + int ret; ssl_async_key_context_t *config_data = mbedtls_ssl_conf_get_async_config_data( ssl->conf ); unsigned slot; @@ -1073,9 +1074,17 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, { char dn[100]; - if( mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject ) > 0 ) + mbedtls_x509_name *subject; + + ret = mbedtls_x509_crt_get_subject( cert, &subject ); + if( ret != 0 ) + return( ret ); + + if( mbedtls_x509_dn_gets( dn, sizeof( dn ), subject ) > 0 ) mbedtls_printf( "Async %s callback: looking for DN=%s\n", op_name, dn ); + + mbedtls_x509_name_free( subject ); } /* Look for a private key that matches the public key in cert. @@ -1084,8 +1093,14 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, * public key. */ for( slot = 0; slot < config_data->slots_used; slot++ ) { - if( mbedtls_pk_check_pair( &cert->pk, - config_data->slots[slot].pk ) == 0 ) + mbedtls_pk_context *pk; + int match; + ret = mbedtls_x509_crt_pk_acquire( cert, &pk ); + if( ret != 0 ) + return( ret ); + match = mbedtls_pk_check_pair( pk, config_data->slots[slot].pk ); + mbedtls_x509_crt_pk_release( cert, pk ); + if( match == 0 ) break; } if( slot == config_data->slots_used ) From 008d304d1ba1737d0b8288c67fd613a5304e9ee8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 16:51:01 +0000 Subject: [PATCH 077/140] Adapt ChangeLog --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 49c3acf5f..e3c335e23 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,13 @@ API Changes always return NULL, and removes the peer_cert field from the mbedtls_ssl_session structure which otherwise stores the peer's certificate. + * Add a new compile-time option `MBEDTLS_X509_ON_DEMAND_PARSING`, + disabled by default, which allows to parse and cache X.509 CRTs + on demand only, at the benefit of lower RAM usage. Enabling + this option breaks the structure API of X.509 in that most + fields of `mbedtls_x509_crt` are removed, but it keeps the + X.509 function API. See the API changes section as well as + the documentation in `config.h` for more information. Bugfix * Server's RSA certificate in certs.c was SHA-1 signed. In the default From bfabd1dfae7b93572820dc294db907d197c342e5 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 28 Feb 2019 17:31:54 +0000 Subject: [PATCH 078/140] Add test to all.sh This commit adds a `make test` and `ssl-opt.sh` run to `all.sh` exercising the default configuration, plus the following changes: - MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled - MBEDTLS_X509_ON_DEMAND_PARSING enabled. --- tests/scripts/all.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 2f1a1b54e..0f493ac62 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -918,6 +918,20 @@ component_test_asan_remove_peer_certificate_no_renego () { if_build_succeeded tests/compat.sh } +component_test_asan_on_demand_parsing_remove_peer_cert () { + msg "build: default config, no peer CRT, on-demand CRT parsing (ASan build)" + scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + scripts/config.pl set MBEDTLS_X509_ON_DEMAND_PARSING + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE, MBEDTLS_X509_ON_DEMAND_PARSING" + make test + + msg "test: ssl-opt.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE, MBEDTLS_X509_ON_DEMAND_PARSING" + if_build_succeeded tests/ssl-opt.sh +} + component_test_no_max_fragment_length_small_ssl_out_content_len () { msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)" scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH From ea32d8ba2adbffc1a16a5fc0b920f97ec62e263c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 4 Mar 2019 11:52:23 +0000 Subject: [PATCH 079/140] Provide direct way of setting up a CRT frame from legacy CRT struct Previously, `mbedtls_x509_crt_cache_provide_frame()` provided the requested CRT frame by always parsing the raw data underlying the CRT. That's inefficient in legacy mode, where the CRTs fields are permanently accessible through the legacy `mbedtls_x509_crt` structure. This commit modifies `mbedtls_x509_crt_cache_provide_frame()` in legacy mode (that is, !MBEDTLS_X509_ON_DEMAND_PARSING) to setup the CRT frame by copying fields from the legacy CRT structure. --- library/x509_crt.c | 86 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 03222d50c..bb064d677 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -90,6 +90,7 @@ static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_sequence *ext_key_usage ); +static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame ); int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) { mbedtls_x509_crt_cache *cache = crt->cache; @@ -100,9 +101,57 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); cache->frame = frame; +#if defined(MBEDTLS_X509_ON_DEMAND_PARSING) + /* This would work with !MBEDTLS_X509_ON_DEMAND_PARSING, too, + * but is inefficient compared to copying the respective fields + * from the legacy mbedtls_x509_crt. */ return( x509_crt_parse_frame( crt->raw.p, crt->raw.p + crt->raw.len, frame ) ); +#else /* MBEDTLS_X509_ON_DEMAND_PARSING */ + /* Make sure all extension related fields are properly initialized. */ + frame->ca_istrue = 0; + frame->max_pathlen = 0; + frame->ext_types = 0; + frame->version = crt->version; + frame->sig_md = crt->sig_md; + frame->sig_pk = crt->sig_pk; + frame->valid_from = crt->valid_from; + frame->valid_to = crt->valid_to; + frame->raw.p = crt->raw.p; + frame->raw.len = crt->raw.len; + frame->tbs.p = crt->tbs.p; + frame->tbs.len = crt->tbs.len; + frame->serial.p = crt->serial.p; + frame->serial.len = crt->serial.len; + frame->pubkey_raw.p = crt->pk_raw.p; + frame->pubkey_raw.len = crt->pk_raw.len; + frame->issuer_raw = crt->issuer_raw_no_hdr; + frame->subject_raw = crt->subject_raw_no_hdr; + frame->issuer_id.p = crt->issuer_id.p; + frame->issuer_id.len = crt->issuer_id.len; + frame->subject_id.p = crt->subject_id.p; + frame->subject_id.len = crt->subject_id.len; + frame->sig.p = crt->sig.p; + frame->sig.len = crt->sig.len; + frame->v3_ext.p = crt->v3_ext.p; + frame->v3_ext.len = crt->v3_ext.len; + frame->subject_alt_raw = crt->subject_alt_raw; + frame->ext_key_usage_raw = crt->ext_key_usage_raw; + frame->issuer_raw_with_hdr.p = crt->issuer_raw.p; + frame->issuer_raw_with_hdr.len = crt->issuer_raw.len; + frame->subject_raw_with_hdr.p = crt->subject_raw.p; + frame->subject_raw_with_hdr.len = crt->subject_raw.len; + + /* The legacy CRT structure doesn't explicitly contain + * the `AlgorithmIdentifier` bounds; however, those can + * be inferred from the surrounding (mandatory) `SerialNumber` + * and `Issuer` fields. */ + frame->sig_alg.p = crt->serial.p + crt->serial.len; + frame->sig_alg.len = crt->issuer_raw.p - frame->sig_alg.p; + + return( x509_crt_frame_parse_ext( frame ) ); +#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ } int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) @@ -1376,24 +1425,30 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, crt->cache = cache; x509_crt_cache_init( cache ); +#if defined(MBEDTLS_X509_ON_DEMAND_PARSING) + ret = mbedtls_x509_crt_cache_provide_frame( crt ); if( ret != 0 ) goto exit; frame = mbedtls_x509_crt_cache_get_frame( crt->cache ); - /* Currently, we accept DER encoded CRTs with trailing garbage - * and promise to not account for the garbage in the `raw` field. - * - * Note that this means that `crt->raw.len` is not necessarily the - * full size of the heap buffer allocated at `crt->raw.p` in case - * of copy-mode, but this is not a problem: freeing the buffer doesn't - * need the size, and the garbage data doesn't need zeroization. */ - crt->raw.len = frame->raw.len; +#else /* MBEDTLS_X509_ON_DEMAND_PARSING */ - cache->pk_raw = frame->pubkey_raw; + frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) ); + if( frame == NULL ) + { + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + goto exit; + } + cache->frame = frame; + + ret = x509_crt_parse_frame( crt->raw.p, + crt->raw.p + crt->raw.len, + frame ); + if( ret != 0 ) + goto exit; -#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) /* Copy frame to legacy CRT structure -- that's inefficient, but if * memory matters, the new CRT structure should be used anyway. */ crt->tbs.p = frame->tbs.p; @@ -1484,6 +1539,17 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, goto exit; #endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */ + /* Currently, we accept DER encoded CRTs with trailing garbage + * and promise to not account for the garbage in the `raw` field. + * + * Note that this means that `crt->raw.len` is not necessarily the + * full size of the heap buffer allocated at `crt->raw.p` in case + * of copy-mode, but this is not a problem: freeing the buffer doesn't + * need the size, and the garbage data doesn't need zeroization. */ + crt->raw.len = frame->raw.len; + + cache->pk_raw = frame->pubkey_raw; + /* Free the frame before parsing the public key to * keep peak RAM usage low. This is slightly inefficient * because the frame will need to be parsed again on the From 4e021c8f50f12fcb8c8924d25aaecff905f907b0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 4 Mar 2019 13:53:10 +0000 Subject: [PATCH 080/140] Remove raw SubjectAltNames and ExtKeyUsage from legacy CRT struct --- include/mbedtls/x509_crt.h | 2 -- library/x509_crt.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index ad6140c42..4335ab3c6 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -155,7 +155,6 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ 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_buf_raw subject_alt_raw; /**< Raw data for SubjectAlternativeNames extension. */ 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. */ @@ -164,7 +163,6 @@ typedef struct mbedtls_x509_crt unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ - mbedtls_x509_buf_raw ext_key_usage_raw; /**< Raw data of ExtendedKeyUsage extensions. */ unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ diff --git a/library/x509_crt.c b/library/x509_crt.c index bb064d677..fb5265a7f 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -136,8 +136,6 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) frame->sig.len = crt->sig.len; frame->v3_ext.p = crt->v3_ext.p; frame->v3_ext.len = crt->v3_ext.len; - frame->subject_alt_raw = crt->subject_alt_raw; - frame->ext_key_usage_raw = crt->ext_key_usage_raw; frame->issuer_raw_with_hdr.p = crt->issuer_raw.p; frame->issuer_raw_with_hdr.len = crt->issuer_raw.len; frame->subject_raw_with_hdr.p = crt->subject_raw.p; @@ -1467,8 +1465,6 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, crt->subject_id.len = frame->subject_id.len; crt->pk_raw.p = frame->pubkey_raw.p; crt->pk_raw.len = frame->pubkey_raw.len; - crt->ext_key_usage_raw = frame->ext_key_usage_raw; - crt->subject_alt_raw = frame->subject_alt_raw; crt->sig.p = frame->sig.p; crt->sig.len = frame->sig.len; crt->valid_from = frame->valid_from; From 1e11f217d4ea1c698617dfadfff5c63d7dff7b55 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 4 Mar 2019 14:43:43 +0000 Subject: [PATCH 081/140] Solely use raw X.509 name data references including SEQUENCE header So far, the CRT frame structure `mbedtls_x509_crt_frame` used as `issuer_raw` and `subject_raw` the _content_ of the ASN.1 name structure for issuer resp. subject. This was in contrast to the fields `issuer_raw` and `subject_raw` from the legacy `mbedtls_x509_crt` structure, and caused some information duplication by having both variants `xxx_no_hdr` and `xxx_with_hdr` in `mbedtls_x509_crt` and `mbedtls_x509_crt_frame`. This commit removes this mismatch by solely using the legacy form of `issuer_raw` and `subject_raw`, i.e. those _including_ the ASN.1 name header. --- include/mbedtls/x509.h | 4 +- include/mbedtls/x509_crl.h | 1 - include/mbedtls/x509_crt.h | 6 -- library/ssl_srv.c | 4 +- library/x509.c | 67 ++++++++++++---------- library/x509_crl.c | 10 ++-- library/x509_crt.c | 50 ++++++---------- library/x509_csr.c | 8 ++- tests/suites/test_suite_x509write.function | 7 +-- 9 files changed, 74 insertions(+), 83 deletions(-) diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 2a9ce99a4..e37573f8f 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -313,8 +313,8 @@ int mbedtls_x509_self_test( int verbose ); * Internal module functions. You probably do not want to use these unless you * know you do. */ -int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, - mbedtls_x509_name *cur ); +int mbedtls_x509_get_name( unsigned char *p, size_t len, + mbedtls_x509_name *cur ); int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *alg ); int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, diff --git a/include/mbedtls/x509_crl.h b/include/mbedtls/x509_crl.h index b035c6c4f..2950f302f 100644 --- a/include/mbedtls/x509_crl.h +++ b/include/mbedtls/x509_crl.h @@ -76,7 +76,6 @@ typedef struct mbedtls_x509_crl mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). */ - mbedtls_x509_buf_raw issuer_raw_no_hdr; mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 4335ab3c6..e4b888259 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -95,9 +95,6 @@ typedef struct mbedtls_x509_crt_frame mbedtls_x509_buf_raw subject_alt_raw; /**< The raw data for the SubjectAlternativeNames extension. */ mbedtls_x509_buf_raw ext_key_usage_raw; /**< The raw data for the ExtendedKeyUsage extension. */ - mbedtls_x509_buf_raw issuer_raw_with_hdr; - mbedtls_x509_buf_raw subject_raw_with_hdr; - } mbedtls_x509_crt_frame; /* This is an internal structure used for caching parsed data from an X.509 CRT. @@ -139,9 +136,6 @@ typedef struct mbedtls_x509_crt mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ - mbedtls_x509_buf_raw subject_raw_no_hdr; - mbedtls_x509_buf_raw issuer_raw_no_hdr; - mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index f00e44ba6..6757e2ab2 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3001,7 +3001,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) if( ret != 0 ) return( ret ); - dn_size = frame->subject_raw_with_hdr.len; + dn_size = frame->subject_raw.len; if( end < p || (size_t)( end - p ) < dn_size || @@ -3014,7 +3014,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) *p++ = (unsigned char)( dn_size >> 8 ); *p++ = (unsigned char)( dn_size ); - memcpy( p, frame->subject_raw_with_hdr.p, dn_size ); + memcpy( p, frame->subject_raw.p, dn_size ); p += dn_size; MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size ); diff --git a/library/x509.c b/library/x509.c index 55726da98..9d00bebb5 100644 --- a/library/x509.c +++ b/library/x509.c @@ -544,53 +544,67 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, void *abort_check_ctx ) { int ret; + size_t idx; + unsigned char *p[2], *end[2], *set[2]; - unsigned char *p_a, *end_a, *set_a; - unsigned char *p_b, *end_b, *set_b; + p[0] = a->p; + p[1] = b->p; + end[0] = p[0] + a->len; + end[1] = p[1] + b->len; - p_a = set_a = (unsigned char*) a->p; - p_b = set_b = (unsigned char*) b->p; + for( idx = 0; idx < 2; idx++ ) + { + size_t len; + ret = mbedtls_asn1_get_tag( &p[idx], end[idx], &len, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ); - end_a = p_a + a->len; - end_b = p_b + b->len; + if( end[idx] != p[idx] + len ) + { + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + set[idx] = p[idx]; + } while( 1 ) { int next_merged; - mbedtls_x509_buf oid_a, val_a, oid_b, val_b; + mbedtls_x509_buf oid[2], val[2]; - ret = x509_set_sequence_iterate( &p_a, (const unsigned char **) &set_a, - end_a, &oid_a, &val_a ); + ret = x509_set_sequence_iterate( &p[0], (const unsigned char **) &set[0], + end[0], &oid[0], &val[0] ); if( ret != 0 ) goto exit; - ret = x509_set_sequence_iterate( &p_b, (const unsigned char **) &set_b, - end_b, &oid_b, &val_b ); + ret = x509_set_sequence_iterate( &p[1], (const unsigned char **) &set[1], + end[1], &oid[1], &val[1] ); if( ret != 0 ) goto exit; - if( oid_a.len != oid_b.len || - memcmp( oid_a.p, oid_b.p, oid_b.len ) != 0 ) + if( oid[0].len != oid[1].len || + memcmp( oid[0].p, oid[1].p, oid[1].len ) != 0 ) { return( 1 ); } - if( x509_string_cmp( &val_a, &val_b ) != 0 ) + if( x509_string_cmp( &val[0], &val[1] ) != 0 ) return( 1 ); - next_merged = ( set_a != p_a ); - if( next_merged != ( set_b != p_b ) ) + next_merged = ( set[0] != p[0] ); + if( next_merged != ( set[1] != p[1] ) ) return( 1 ); if( abort_check != NULL ) { - ret = abort_check( abort_check_ctx, &oid_a, &val_a, + ret = abort_check( abort_check_ctx, &oid[0], &val[0], next_merged ); if( ret != 0 ) return( ret ); } - if( p_a == end_a && p_b == end_b ) + if( p[0] == end[0] && p[1] == end[1] ) break; } @@ -626,20 +640,15 @@ static int x509_get_name_cb( void *ctx, return( 0 ); } -int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, +int mbedtls_x509_get_name( unsigned char *p, + size_t len, mbedtls_x509_name *cur ) { - int ret; - mbedtls_x509_buf_raw name_buf = { *p, end - *p }; + mbedtls_x509_buf_raw name_buf = { p, len }; memset( cur, 0, sizeof( mbedtls_x509_name ) ); - ret = mbedtls_x509_name_cmp_raw( &name_buf, &name_buf, - x509_get_name_cb, - &cur ); - if( ret != 0 ) - return( ret ); - - *p = (unsigned char*) end; - return( 0 ); + return( mbedtls_x509_name_cmp_raw( &name_buf, &name_buf, + x509_get_name_cb, + &cur ) ); } static int x509_parse_int( unsigned char **p, size_t n, int *res ) diff --git a/library/x509_crl.c b/library/x509_crl.c index f07784128..5829425c4 100644 --- a/library/x509_crl.c +++ b/library/x509_crl.c @@ -428,17 +428,17 @@ int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, mbedtls_x509_crl_free( crl ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } - crl->issuer_raw_no_hdr.p = p; + p += len; + crl->issuer_raw.len = p - crl->issuer_raw.p; - if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + if( ( ret = mbedtls_x509_get_name( crl->issuer_raw.p, + crl->issuer_raw.len, + &crl->issuer ) ) != 0 ) { mbedtls_x509_crl_free( crl ); return( ret ); } - crl->issuer_raw_no_hdr.len = p - crl->issuer_raw_no_hdr.p; - crl->issuer_raw.len = p - crl->issuer_raw.p; - /* * thisUpdate Time * nextUpdate Time OPTIONAL diff --git a/library/x509_crt.c b/library/x509_crt.c index fb5265a7f..bd452b693 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -126,8 +126,10 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) frame->serial.len = crt->serial.len; frame->pubkey_raw.p = crt->pk_raw.p; frame->pubkey_raw.len = crt->pk_raw.len; - frame->issuer_raw = crt->issuer_raw_no_hdr; - frame->subject_raw = crt->subject_raw_no_hdr; + frame->issuer_raw.p = crt->issuer_raw.p; + frame->issuer_raw.len = crt->issuer_raw.len; + frame->subject_raw.p = crt->subject_raw.p; + frame->subject_raw.len = crt->subject_raw.len; frame->issuer_id.p = crt->issuer_id.p; frame->issuer_id.len = crt->issuer_id.len; frame->subject_id.p = crt->subject_id.p; @@ -136,10 +138,6 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) frame->sig.len = crt->sig.len; frame->v3_ext.p = crt->v3_ext.p; frame->v3_ext.len = crt->v3_ext.len; - frame->issuer_raw_with_hdr.p = crt->issuer_raw.p; - frame->issuer_raw_with_hdr.len = crt->issuer_raw.len; - frame->subject_raw_with_hdr.p = crt->subject_raw.p; - frame->subject_raw_with_hdr.len = crt->subject_raw.len; /* The legacy CRT structure doesn't explicitly contain * the `AlgorithmIdentifier` bounds; however, those can @@ -1185,15 +1183,14 @@ static int x509_crt_parse_frame( unsigned char *start, * * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName */ - frame->issuer_raw_with_hdr.p = p; + frame->issuer_raw.p = p; ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); if( ret != 0 ) return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT ); - frame->issuer_raw.p = p; - frame->issuer_raw.len = len; p += len; + frame->issuer_raw.len = p - frame->issuer_raw.p; ret = mbedtls_x509_name_cmp_raw( &frame->issuer_raw, &frame->issuer_raw, @@ -1201,8 +1198,6 @@ static int x509_crt_parse_frame( unsigned char *start, if( ret != 0 ) return( ret ); - frame->issuer_raw_with_hdr.len = p - frame->issuer_raw_with_hdr.p; - /* * Validity ::= SEQUENCE { ... */ @@ -1218,15 +1213,14 @@ static int x509_crt_parse_frame( unsigned char *start, * * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName */ - frame->subject_raw_with_hdr.p = p; + frame->subject_raw.p = p; ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); if( ret != 0 ) return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT ); - frame->subject_raw.p = p; - frame->subject_raw.len = len; p += len; + frame->subject_raw.len = p - frame->subject_raw.p; ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw, &frame->subject_raw, @@ -1234,8 +1228,6 @@ static int x509_crt_parse_frame( unsigned char *start, if( ret != 0 ) return( ret ); - frame->subject_raw_with_hdr.len = p - frame->subject_raw_with_hdr.p; - /* * SubjectPublicKeyInfo */ @@ -1317,19 +1309,17 @@ static int x509_crt_parse_frame( unsigned char *start, static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_name *subject ) { - unsigned char *p = frame->subject_raw.p; - unsigned char *end = p + frame->subject_raw.len; - - return( mbedtls_x509_get_name( &p, end, subject ) ); + return( mbedtls_x509_get_name( frame->subject_raw.p, + frame->subject_raw.len, + subject ) ); } static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_name *issuer ) { - unsigned char *p = frame->issuer_raw.p; - unsigned char *end = p + frame->issuer_raw.len; - - return( mbedtls_x509_get_name( &p, end, issuer ) ); + return( mbedtls_x509_get_name( frame->issuer_raw.p, + frame->issuer_raw.len, + issuer ) ); } static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, @@ -1453,12 +1443,10 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, crt->tbs.len = frame->tbs.len; crt->serial.p = frame->serial.p; crt->serial.len = frame->serial.len; - crt->issuer_raw.p = frame->issuer_raw_with_hdr.p; - crt->issuer_raw.len = frame->issuer_raw_with_hdr.len; - crt->subject_raw.p = frame->subject_raw_with_hdr.p; - crt->subject_raw.len = frame->subject_raw_with_hdr.len; - crt->issuer_raw_no_hdr = frame->issuer_raw; - crt->subject_raw_no_hdr = frame->subject_raw; + crt->issuer_raw.p = frame->issuer_raw.p; + crt->issuer_raw.len = frame->issuer_raw.len; + crt->subject_raw.p = frame->subject_raw.p; + crt->subject_raw.len = frame->subject_raw.len; crt->issuer_id.p = frame->issuer_id.p; crt->issuer_id.len = frame->issuer_id.len; crt->subject_id.p = frame->subject_id.p; @@ -2561,7 +2549,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, while( crl_list != NULL ) { if( crl_list->version == 0 || - mbedtls_x509_name_cmp_raw( &crl_list->issuer_raw_no_hdr, + mbedtls_x509_name_cmp_raw( &crl_list->issuer_raw, &ca_subject, NULL, NULL ) != 0 ) { crl_list = crl_list->next; diff --git a/library/x509_csr.c b/library/x509_csr.c index d1a276041..23af9aebc 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -183,15 +183,17 @@ int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, mbedtls_x509_csr_free( csr ); return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); } + p += len; + csr->subject_raw.len = p - csr->subject_raw.p; - if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) + if( ( ret = mbedtls_x509_get_name( csr->subject_raw.p, + csr->subject_raw.len, + &csr->subject ) ) != 0 ) { mbedtls_x509_csr_free( csr ); return( ret ); } - csr->subject_raw.len = p - csr->subject_raw.p; - /* * subjectPKInfo SubjectPublicKeyInfo */ diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 535807e3a..f404f898b 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -216,7 +216,7 @@ void mbedtls_x509_string_to_names( char * name, char * parsed_name, int result ) { int ret; - size_t len = 0; + size_t len; mbedtls_asn1_named_data *names = NULL; mbedtls_x509_name parsed, *parsed_cur, *parsed_prv; unsigned char buf[1024], out[1024], *c; @@ -234,10 +234,9 @@ void mbedtls_x509_string_to_names( char * name, char * parsed_name, int result ret = mbedtls_x509_write_names( &c, buf, names ); TEST_ASSERT( ret > 0 ); + len = (size_t) ret; - TEST_ASSERT( mbedtls_asn1_get_tag( &c, buf + sizeof( buf ), &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) == 0 ); - TEST_ASSERT( mbedtls_x509_get_name( &c, buf + sizeof( buf ), &parsed ) == 0 ); + TEST_ASSERT( mbedtls_x509_get_name( c, len, &parsed ) == 0 ); ret = mbedtls_x509_dn_gets( (char *) out, sizeof( out ), &parsed ); TEST_ASSERT( ret > 0 ); From 38f0cb487cd129597b07ad0ba25330afd17d575b Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 4 Mar 2019 15:13:45 +0000 Subject: [PATCH 082/140] Introduce helpers for conversion between X.509 buffer structs This commit introduces two static helpers - `x509_buf_to_buf_raw()` - `x509_buf_raw_to_buf()` which convert to/from the old `mbedtls_x509_buf` and the new `mbedtls_x509_buf_raw` (the latter omitting the ASN.1 tag field). --- library/x509_crt.c | 73 ++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index bd452b693..04b227abe 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -78,6 +78,22 @@ #endif /* !_WIN32 || EFIX64 || EFI32 */ #endif +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) +static void x509_buf_to_buf_raw( mbedtls_x509_buf_raw *dst, + mbedtls_x509_buf const *src ) +{ + dst->p = src->p; + dst->len = src->len; +} + +static void x509_buf_raw_to_buf( mbedtls_x509_buf *dst, + mbedtls_x509_buf_raw const *src ) +{ + dst->p = src->p; + dst->len = src->len; +} +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ + static int x509_crt_parse_frame( unsigned char *start, unsigned char *end, mbedtls_x509_crt_frame *frame ); @@ -118,26 +134,16 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) frame->sig_pk = crt->sig_pk; frame->valid_from = crt->valid_from; frame->valid_to = crt->valid_to; - frame->raw.p = crt->raw.p; - frame->raw.len = crt->raw.len; - frame->tbs.p = crt->tbs.p; - frame->tbs.len = crt->tbs.len; - frame->serial.p = crt->serial.p; - frame->serial.len = crt->serial.len; - frame->pubkey_raw.p = crt->pk_raw.p; - frame->pubkey_raw.len = crt->pk_raw.len; - frame->issuer_raw.p = crt->issuer_raw.p; - frame->issuer_raw.len = crt->issuer_raw.len; - frame->subject_raw.p = crt->subject_raw.p; - frame->subject_raw.len = crt->subject_raw.len; - frame->issuer_id.p = crt->issuer_id.p; - frame->issuer_id.len = crt->issuer_id.len; - frame->subject_id.p = crt->subject_id.p; - frame->subject_id.len = crt->subject_id.len; - frame->sig.p = crt->sig.p; - frame->sig.len = crt->sig.len; - frame->v3_ext.p = crt->v3_ext.p; - frame->v3_ext.len = crt->v3_ext.len; + x509_buf_to_buf_raw( &frame->raw, &crt->raw ); + x509_buf_to_buf_raw( &frame->tbs, &crt->tbs ); + x509_buf_to_buf_raw( &frame->serial, &crt->serial ); + x509_buf_to_buf_raw( &frame->pubkey_raw, &crt->pk_raw ); + x509_buf_to_buf_raw( &frame->issuer_raw, &crt->issuer_raw ); + x509_buf_to_buf_raw( &frame->subject_raw, &crt->subject_raw ); + x509_buf_to_buf_raw( &frame->subject_id, &crt->subject_id ); + x509_buf_to_buf_raw( &frame->issuer_id, &crt->issuer_id ); + x509_buf_to_buf_raw( &frame->sig, &crt->sig ); + x509_buf_to_buf_raw( &frame->v3_ext, &crt->v3_ext ); /* The legacy CRT structure doesn't explicitly contain * the `AlgorithmIdentifier` bounds; however, those can @@ -1439,26 +1445,17 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, /* Copy frame to legacy CRT structure -- that's inefficient, but if * memory matters, the new CRT structure should be used anyway. */ - crt->tbs.p = frame->tbs.p; - crt->tbs.len = frame->tbs.len; - crt->serial.p = frame->serial.p; - crt->serial.len = frame->serial.len; - crt->issuer_raw.p = frame->issuer_raw.p; - crt->issuer_raw.len = frame->issuer_raw.len; - crt->subject_raw.p = frame->subject_raw.p; - crt->subject_raw.len = frame->subject_raw.len; - crt->issuer_id.p = frame->issuer_id.p; - crt->issuer_id.len = frame->issuer_id.len; - crt->subject_id.p = frame->subject_id.p; - crt->subject_id.len = frame->subject_id.len; - crt->pk_raw.p = frame->pubkey_raw.p; - crt->pk_raw.len = frame->pubkey_raw.len; - crt->sig.p = frame->sig.p; - crt->sig.len = frame->sig.len; + x509_buf_raw_to_buf( &crt->tbs, &frame->tbs ); + x509_buf_raw_to_buf( &crt->serial, &frame->serial ); + x509_buf_raw_to_buf( &crt->issuer_raw, &frame->issuer_raw ); + x509_buf_raw_to_buf( &crt->subject_raw, &frame->subject_raw ); + x509_buf_raw_to_buf( &crt->issuer_id, &frame->issuer_id ); + x509_buf_raw_to_buf( &crt->subject_id, &frame->subject_id ); + x509_buf_raw_to_buf( &crt->pk_raw, &frame->pubkey_raw ); + x509_buf_raw_to_buf( &crt->sig, &frame->sig ); + x509_buf_raw_to_buf( &crt->v3_ext, &frame->v3_ext ); crt->valid_from = frame->valid_from; crt->valid_to = frame->valid_to; - crt->v3_ext.p = frame->v3_ext.p; - crt->v3_ext.len = frame->v3_ext.len; crt->version = frame->version; crt->ca_istrue = frame->ca_istrue; crt->max_pathlen = frame->max_pathlen; From 7dbf49a51846c2125302bea7a11621efdb9e1694 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 4 Mar 2019 16:30:14 +0000 Subject: [PATCH 083/140] Enable threading in all.sh test for X.509 on demand parsing --- tests/scripts/all.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 0f493ac62..45236922c 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -922,6 +922,8 @@ component_test_asan_on_demand_parsing_remove_peer_cert () { msg "build: default config, no peer CRT, on-demand CRT parsing (ASan build)" scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE scripts/config.pl set MBEDTLS_X509_ON_DEMAND_PARSING + scripts/config.pl set MBEDTLS_THREADING_C + scripts/config.pl set MBEDTLS_THREADING_PTHREAD CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . make From c6d1c3ed1c39a4ce002bcc99fcaa0fbc941a38f0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 13:50:56 +0000 Subject: [PATCH 084/140] Remove frame/pk parameter from mbedtls_x509_crt_xxx_release() --- include/mbedtls/x509_crt.h | 9 ++--- library/debug.c | 2 +- library/ssl_cli.c | 13 +++---- library/ssl_srv.c | 11 +++--- library/ssl_tls.c | 2 +- library/x509_crt.c | 41 +++++++++++----------- programs/ssl/ssl_server2.c | 2 +- tests/suites/test_suite_x509parse.function | 2 +- 8 files changed, 36 insertions(+), 46 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index e4b888259..c3ef4380a 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -864,11 +864,8 @@ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, return( 0 ); } -static inline void mbedtls_x509_crt_frame_release( - mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame *frame ) +static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) { - ((void) frame); ((void) crt); #if defined(MBEDTLS_THREADING_C) @@ -902,10 +899,8 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, return( 0 ); } -static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt, - mbedtls_pk_context *pk ) +static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) { - ((void) pk); ((void) crt); #if defined(MBEDTLS_THREADING_C) diff --git a/library/debug.c b/library/debug.c index 41769eca6..b02a4f8b5 100644 --- a/library/debug.c +++ b/library/debug.c @@ -402,7 +402,7 @@ void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, return; } debug_print_pk( ssl, level, file, line, "crt->", pk ); - mbedtls_x509_crt_pk_release( crt, pk ); + mbedtls_x509_crt_pk_release( crt ); crt = crt->next; } diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 07e15c4cd..c3c28c703 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2378,7 +2378,7 @@ cleanup: /* We don't need the peer's public key anymore. Free it. */ mbedtls_pk_free( peer_pk ); #else - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); @@ -2509,7 +2509,7 @@ cleanup: * operations like ECDHE. */ mbedtls_pk_free( peer_pk ); #else - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); @@ -2837,8 +2837,7 @@ start_processing: mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, - peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); } @@ -2862,8 +2861,7 @@ start_processing: ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; #endif #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, - peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); } @@ -2874,8 +2872,7 @@ start_processing: * operations like ECDHE. */ mbedtls_pk_free( peer_pk ); #else - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, - peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 6757e2ab2..1fd1d310a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -840,7 +840,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, #endif #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - mbedtls_x509_crt_pk_release( cur->cert, pk ); + mbedtls_x509_crt_pk_release( cur->cert ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( match == 0 ) @@ -879,7 +879,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, if( ret != 0 ) return( ret ); sig_md = frame->sig_md; - mbedtls_x509_crt_frame_release( cur->cert, frame ); + mbedtls_x509_crt_frame_release( cur->cert ); } if( sig_md != MBEDTLS_MD_SHA1 ) @@ -3008,7 +3008,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) (size_t)( end - p ) < 2 + dn_size ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); break; } @@ -3021,7 +3021,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) total_dn_size += 2 + dn_size; - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); crt = crt->next; } @@ -4407,8 +4407,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) exit: #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) - mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert, - peer_pk ); + mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert ); #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ return( ret ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 4a3c9fe8b..560ef4c07 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6513,7 +6513,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) ) ret = mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ); - mbedtls_x509_crt_pk_release( chain, pk ); + mbedtls_x509_crt_pk_release( chain ); if( ret != 0 ) { diff --git a/library/x509_crt.c b/library/x509_crt.c index 04b227abe..b5710ed74 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -260,7 +260,7 @@ int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, else ret = x509_crt_subject_alt_from_frame( frame, seq ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); *subj_alt = seq; return( ret ); @@ -283,7 +283,7 @@ int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, else ret = x509_crt_ext_key_usage_from_frame( frame, seq ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); *ext_key_usage = seq; return( ret ); @@ -306,7 +306,7 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, else ret = x509_crt_subject_from_frame( frame, name ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); *subject = name; return( ret ); @@ -329,7 +329,7 @@ int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, else ret = x509_crt_issuer_from_frame( frame, name ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); *issuer = name; return( ret ); @@ -344,7 +344,7 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, if( ret != 0 ) return( ret ); *dst = *frame; - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); return( 0 ); } @@ -369,7 +369,7 @@ int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, mbedtls_free( crt->cache->pk ); crt->cache->pk = NULL; - mbedtls_x509_crt_pk_release( crt, pk ); + mbedtls_x509_crt_pk_release( crt ); return( 0 ); #endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ } @@ -2379,13 +2379,12 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, { int ret; mbedtls_x509_crt_frame *frame; - ret = mbedtls_x509_crt_frame_acquire( crt, - (mbedtls_x509_crt_frame**) &frame ); + ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); ret = x509_crt_check_key_usage_frame( frame, usage ); - mbedtls_x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame ); + mbedtls_x509_crt_frame_release( crt ); return( ret ); } @@ -2453,7 +2452,7 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; } - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); return( ret ); } #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ @@ -2496,7 +2495,7 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, ret = x509_serial_is_revoked( frame->serial.p, frame->serial.len, crl ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); return( ret ); } @@ -2536,7 +2535,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, can_sign = 1; } - mbedtls_x509_crt_frame_release( ca_crt, ca ); + mbedtls_x509_crt_frame_release( ca_crt ); } ret = mbedtls_x509_crt_pk_acquire( ca_crt, &pk ); @@ -2614,7 +2613,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, crl_list = crl_list->next; } - mbedtls_x509_crt_pk_release( ca_crt, pk ); + mbedtls_x509_crt_pk_release( ca_crt ); return( flags ); } #endif /* MBEDTLS_X509_CRL_PARSE_C */ @@ -2663,7 +2662,7 @@ static int x509_crt_check_signature( const mbedtls_x509_crt_sig_info *sig_info, } exit: - mbedtls_x509_crt_pk_release( parent, pk ); + mbedtls_x509_crt_pk_release( parent ); return( ret ); } @@ -2823,7 +2822,7 @@ check_signature: path_len_ok = 1; } - mbedtls_x509_crt_frame_release( parent_crt, parent ); + mbedtls_x509_crt_frame_release( parent_crt ); } if( parent_match == 0 || path_len_ok == 0 ) @@ -3107,7 +3106,7 @@ find_parent: /* Stop here for trusted roots (but not for trusted EE certs) */ if( child_is_trusted ) { - mbedtls_x509_crt_frame_release( child_crt, child ); + mbedtls_x509_crt_frame_release( child_crt ); return( 0 ); } @@ -3130,7 +3129,7 @@ find_parent: if( ver_chain->len == 1 && self_issued && x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) { - mbedtls_x509_crt_frame_release( child_crt, child ); + mbedtls_x509_crt_frame_release( child_crt ); return( 0 ); } @@ -3139,7 +3138,7 @@ find_parent: #endif /* MBEDTLS_X509_CRL_PARSE_C */ ret = x509_crt_get_sig_info( child, &child_sig ); - mbedtls_x509_crt_frame_release( child_crt, child ); + mbedtls_x509_crt_frame_release( child_crt ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -3203,7 +3202,7 @@ find_parent: if( x509_profile_check_key( profile, parent_pk ) != 0 ) *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - mbedtls_x509_crt_pk_release( parent_crt, parent_pk ); + mbedtls_x509_crt_pk_release( parent_crt ); } #if defined(MBEDTLS_X509_CRL_PARSE_C) @@ -3321,7 +3320,7 @@ static int x509_crt_verify_name( const mbedtls_x509_crt *crt, x509_crt_check_name, (void*) cn ); } - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); /* x509_crt_check_name() and x509_crt_subject_alt_check_name() * return 1 when finding a name component matching `cn`. */ @@ -3452,7 +3451,7 @@ int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, if( x509_profile_check_key( profile, pk ) != 0 ) ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; - mbedtls_x509_crt_pk_release( crt, pk ); + mbedtls_x509_crt_pk_release( crt ); } /* Check the chain */ diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index df39b5149..8488bada8 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1099,7 +1099,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, if( ret != 0 ) return( ret ); match = mbedtls_pk_check_pair( pk, config_data->slots[slot].pk ); - mbedtls_x509_crt_pk_release( cert, pk ); + mbedtls_x509_crt_pk_release( cert ); if( match == 0 ) break; } diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index de0bc6d55..3b926084e 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -179,7 +179,7 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint cleanup: mbedtls_x509_name_free( subject ); - mbedtls_x509_crt_frame_release( crt, frame ); + mbedtls_x509_crt_frame_release( crt ); if( ret < 0 ) return( ret ); From ffcd8c39a493daedd5c240c1d1b5d0434311bebf Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 13:44:33 +0000 Subject: [PATCH 085/140] Introduce compile-time option to always flush X.509 CRT caches This commit introduces a compile-time option MBEDTLS_X509_ALWAYS_FLUSH which controls whether releasing of CRT frames or public key contexts associated to X.509 CRTs (or, in the future, other cached parsed X.509 structures) should lead to freeing those structures immediately. Enabling this alongside of the MBEDTLS_X509_ON_DEMAND_PARSING leads to significant reduction of the average RAM consumption of Mbed TLS. The option is enabled by default to reduce the permanent RAM overhead of MBEDTLS_X509_ON_DEMAND_PARSING in case the latter is *disabled* (default). (Note that there is very little performance penalty enabling MBEDTLS_X509_ALWAYS_FLUSH in case MBEDTLS_X509_ON_DEMAND_PARSING is disabled, because hardly any parsing needs to be done to setup a CRT frame / PK context from the legacy `mbedtls_x509_crt` structure.) --- include/mbedtls/config.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 4b8913ba7..0d4d30a2c 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1789,6 +1789,22 @@ */ //#define MBEDTLS_X509_ON_DEMAND_PARSING +/** + * \def MBEDTLS_X509_ALWAYS_FLUSH + * + * Save RAM by having Mbed TLS always flush caches for parsed X.509 + * structures after use: This means, firstly, that caches of X.509 + * structures used by an API call are flushed when the call returns, + * but it also encompasses immediate flushing of caches when Mbed TLS uses + * multiple structures in succession, thereby reducing the peak RAM usage. + * Setting this option leads to minimal RAM usage of the X.509 module at + * the cost of performance penalties when using X.509 structures multiple + * times (such as trusted CRTs on systems serving many connections). + * + * Uncomment this to always flush caches for unused X.509 structures. + */ +#define MBEDTLS_X509_ALWAYS_FLUSH + /** * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 * From bc685199d96c5a28f3d561ae9311f9d34f4aebbd Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 15:35:31 +0000 Subject: [PATCH 086/140] Implement MBEDTLS_X509_ALWAYS_FLUSH --- include/mbedtls/x509_crt.h | 13 ++++++- library/x509_crt.c | 72 ++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index c3ef4380a..c7f816bc5 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -811,6 +811,9 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); * They are not part of the public API and may change * at any time. */ +int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ); +int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ); + int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ); int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ); @@ -839,7 +842,7 @@ static inline mbedtls_pk_context* mbedtls_x509_crt_cache_get_pk( } static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame **frame_ptr ) + mbedtls_x509_crt_frame **frame_ptr ) { #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) @@ -871,6 +874,10 @@ static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->frame_mutex ); #endif + +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) + (void) mbedtls_x509_crt_flush_cache_frame( crt ); +#endif /* MBEDTLS_X509_ALWAYS_FLUSH */ } static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, @@ -906,6 +913,10 @@ static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->pk_mutex ); #endif + +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) + (void) mbedtls_x509_crt_flush_cache_pk( crt ); +#endif /* MBEDTLS_X509_ALWAYS_FLUSH */ } #endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/library/x509_crt.c b/library/x509_crt.c index b5710ed74..91b29b614 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -106,6 +106,59 @@ static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, mbedtls_x509_sequence *ext_key_usage ); +int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ) +{ +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + +#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) + /* The cache holds a shallow copy of the PK context + * in the legacy struct, so don't free PK context. */ + mbedtls_free( crt->cache->pk ); +#else + mbedtls_pk_free( crt->cache->pk ); + mbedtls_free( crt->cache->pk ); +#endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ + crt->cache->pk = NULL; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + return( 0 ); +} + +int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ) +{ +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_free( crt->cache->frame ); + crt->cache->frame = NULL; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + return( 0 ); +} + +int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) +{ + int ret; + ret = mbedtls_x509_crt_flush_cache_frame( crt ); + if( ret != 0 ) + return( ret ); + ret = mbedtls_x509_crt_flush_cache_pk( crt ); + if( ret != 0 ) + return( ret ); + return( 0 ); +} + static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame ); int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) { @@ -224,25 +277,6 @@ static void x509_crt_cache_free( mbedtls_x509_crt_cache *cache ) memset( cache, 0, sizeof( *cache ) ); } -int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) -{ -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); - if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - x509_crt_cache_clear_frame( crt->cache ); - x509_crt_cache_clear_pk( crt->cache ); -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); - if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - return( 0 ); -} - int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, mbedtls_x509_sequence **subj_alt ) { From 76428359b374fc3b9b5bdc87142407ff8b1a32bd Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 15:29:23 +0000 Subject: [PATCH 087/140] Move existence check for pk/frame to mbedtls_x509_crt_provide_xxx() --- include/mbedtls/x509_crt.h | 58 +++++++++----------------------------- library/x509_crt.c | 8 +++++- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index c7f816bc5..b3570be58 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -817,53 +817,26 @@ int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ); int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ); int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ); -static inline int mbedtls_x509_crt_cache_frame_set( - mbedtls_x509_crt_cache *cache ) -{ - return( cache->frame != NULL ); -} - -static inline mbedtls_x509_crt_frame* mbedtls_x509_crt_cache_get_frame( - mbedtls_x509_crt_cache *cache ) -{ - return( cache->frame ); -} - -static inline int mbedtls_x509_crt_cache_pk_set( - mbedtls_x509_crt_cache *cache ) -{ - return( cache->pk != NULL ); -} - -static inline mbedtls_pk_context* mbedtls_x509_crt_cache_get_pk( - mbedtls_x509_crt_cache *cache ) -{ - return( cache->pk ); -} - static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame **frame_ptr ) { + int ret; #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - if( !mbedtls_x509_crt_cache_frame_set( crt->cache ) ) + ret = mbedtls_x509_crt_cache_provide_frame( crt ); + if( ret != 0 ) { - int ret; - ret = mbedtls_x509_crt_cache_provide_frame( crt ); - if( ret != 0 ) - { #if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - return( ret ); - } + return( ret ); } - *frame_ptr = mbedtls_x509_crt_cache_get_frame( crt->cache ); + *frame_ptr = crt->cache->frame; return( 0 ); } @@ -883,26 +856,23 @@ static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, mbedtls_pk_context **pk_ptr ) { + int ret; #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - if( !mbedtls_x509_crt_cache_pk_set( crt->cache ) ) + ret = mbedtls_x509_crt_cache_provide_pk( crt ); + if( ret != 0 ) { - int ret; - ret = mbedtls_x509_crt_cache_provide_pk( crt ); - if( ret != 0 ) - { #if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - return( ret ); - } + return( ret ); } - *pk_ptr = mbedtls_x509_crt_cache_get_pk( crt->cache ); + *pk_ptr = crt->cache->pk; return( 0 ); } diff --git a/library/x509_crt.c b/library/x509_crt.c index 91b29b614..9004be4f0 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -165,6 +165,9 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) mbedtls_x509_crt_cache *cache = crt->cache; mbedtls_x509_crt_frame *frame; + if( cache->frame != NULL ) + return( 0 ); + frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) ); if( frame == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); @@ -214,6 +217,9 @@ int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) mbedtls_x509_crt_cache *cache = crt->cache; mbedtls_pk_context *pk; + if( cache->pk != NULL ) + return( 0 ); + pk = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) ); if( pk == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); @@ -1459,7 +1465,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, if( ret != 0 ) goto exit; - frame = mbedtls_x509_crt_cache_get_frame( crt->cache ); + frame = crt->cache->frame; #else /* MBEDTLS_X509_ON_DEMAND_PARSING */ From a7ac412dcdc8786945c253b946ec6ccadfb62025 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 17:40:40 +0000 Subject: [PATCH 088/140] Update query_config.c --- programs/ssl/query_config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c index a00847208..39053838d 100644 --- a/programs/ssl/query_config.c +++ b/programs/ssl/query_config.c @@ -1474,6 +1474,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) + if( strcmp( "MBEDTLS_X509_ALWAYS_FLUSH", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ALWAYS_FLUSH ); + return( 0 ); + } +#endif /* MBEDTLS_X509_ALWAYS_FLUSH */ + #if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) if( strcmp( "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", config ) == 0 ) { From 1421246d4485509b3762546bf7513382672d5a18 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 5 Mar 2019 17:53:48 +0000 Subject: [PATCH 089/140] Update version_features.c --- library/version_features.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/version_features.c b/library/version_features.c index e19e31455..8d3f2adb0 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -537,6 +537,9 @@ static const char *features[] = { #if defined(MBEDTLS_X509_ON_DEMAND_PARSING) "MBEDTLS_X509_ON_DEMAND_PARSING", #endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) + "MBEDTLS_X509_ALWAYS_FLUSH", +#endif /* MBEDTLS_X509_ALWAYS_FLUSH */ #if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", #endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */ From f6bc8886c72d6b0cbc5964ab611d1f3a15278af3 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 13:05:58 +0100 Subject: [PATCH 090/140] Move declarations of internal X.509 functions to separate header This makes it easier to distinguish public from internal functions; for us, for users, and for automated API compatibility checkers. --- include/mbedtls/x509.h | 57 --------------- include/mbedtls/x509_internal.h | 83 ++++++++++++++++++++++ library/x509.c | 1 + library/x509_create.c | 1 + library/x509_crl.c | 1 + library/x509_crt.c | 1 + library/x509_csr.c | 1 + library/x509write_crt.c | 1 + library/x509write_csr.c | 1 + tests/suites/test_suite_x509parse.function | 1 + tests/suites/test_suite_x509write.function | 1 + 11 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 include/mbedtls/x509_internal.h diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index e37573f8f..753019aac 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -309,63 +309,6 @@ int mbedtls_x509_self_test( int verbose ); #endif /* MBEDTLS_SELF_TEST */ -/* - * Internal module functions. You probably do not want to use these unless you - * know you do. - */ -int mbedtls_x509_get_name( unsigned char *p, size_t len, - mbedtls_x509_name *cur ); -int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *alg ); -int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) -int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, - mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, - int *salt_len ); -#endif -int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); -int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end, - mbedtls_md_type_t *md_alg, - mbedtls_pk_type_t *pk_alg, - void **sig_opts ); -int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, - mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, - void **sig_opts ); -int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, - mbedtls_x509_time *t ); -int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *serial ); -int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, - mbedtls_x509_buf_raw const *b, - int (*check)( void *ctx, - mbedtls_x509_buf *oid, - mbedtls_x509_buf *val, - int next_merged ), - void *check_ctx ); -int mbedtls_x509_memcasecmp( const void *s1, const void *s2, - size_t len1, size_t lend2 ); -int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *ext, int tag ); - -#if !defined(MBEDTLS_X509_REMOVE_INFO) -int mbedtls_x509_sig_alg_gets( char *buf, size_t size, - mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, - const void *sig_opts ); -#endif -int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); -int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); -int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, - int critical, const unsigned char *val, - size_t val_len ); -int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, - mbedtls_asn1_named_data *first ); -int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, - mbedtls_asn1_named_data *first ); -int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, - const char *oid, size_t oid_len, - unsigned char *sig, size_t size ); - #define MBEDTLS_X509_SAFE_SNPRINTF \ do { \ if( ret < 0 || (size_t) ret >= n ) \ diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h new file mode 100644 index 000000000..6fc6fe6f1 --- /dev/null +++ b/include/mbedtls/x509_internal.h @@ -0,0 +1,83 @@ +/** + * \file x509_internal.h + * + * \brief Internal X.509 functions + */ +/* + * Copyright (C) 2006-2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_X509_INTERNAL_H +#define MBEDTLS_X509_INTERNAL_H + +#include "x509.h" + +int mbedtls_x509_get_name( unsigned char *p, size_t len, + mbedtls_x509_name *cur ); +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ); +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ); +#endif +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg_raw( unsigned char **p, unsigned char const *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *t ); +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ); +int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, + mbedtls_x509_buf_raw const *b, + int (*check)( void *ctx, + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val, + int next_merged ), + void *check_ctx ); +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, + size_t len1, size_t lend2 ); +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ); + +#if !defined(MBEDTLS_X509_REMOVE_INFO) +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ); +#endif +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, + size_t val_len ); +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); + +#endif /* MBEDTLS_X509_INTERNAL_H */ diff --git a/library/x509.c b/library/x509.c index 9d00bebb5..0a9138fa7 100644 --- a/library/x509.c +++ b/library/x509.c @@ -38,6 +38,7 @@ #if defined(MBEDTLS_X509_USE_C) #include "mbedtls/x509.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/asn1.h" #include "mbedtls/oid.h" diff --git a/library/x509_create.c b/library/x509_create.c index 546e8fa1a..1639630a2 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -28,6 +28,7 @@ #if defined(MBEDTLS_X509_CREATE_C) #include "mbedtls/x509.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/asn1write.h" #include "mbedtls/oid.h" diff --git a/library/x509_crl.c b/library/x509_crl.c index 5829425c4..3113de42c 100644 --- a/library/x509_crl.c +++ b/library/x509_crl.c @@ -38,6 +38,7 @@ #if defined(MBEDTLS_X509_CRL_PARSE_C) #include "mbedtls/x509_crl.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" diff --git a/library/x509_crt.c b/library/x509_crt.c index 9004be4f0..0f72e2f08 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -40,6 +40,7 @@ #if defined(MBEDTLS_X509_CRT_PARSE_C) #include "mbedtls/x509_crt.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" diff --git a/library/x509_csr.c b/library/x509_csr.c index 23af9aebc..9b58a86fe 100644 --- a/library/x509_csr.c +++ b/library/x509_csr.c @@ -38,6 +38,7 @@ #if defined(MBEDTLS_X509_CSR_PARSE_C) #include "mbedtls/x509_csr.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" diff --git a/library/x509write_crt.c b/library/x509write_crt.c index 10497e752..93cd82f7a 100644 --- a/library/x509write_crt.c +++ b/library/x509write_crt.c @@ -34,6 +34,7 @@ #if defined(MBEDTLS_X509_CRT_WRITE_C) #include "mbedtls/x509_crt.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/oid.h" #include "mbedtls/asn1write.h" #include "mbedtls/sha1.h" diff --git a/library/x509write_csr.c b/library/x509write_csr.c index d70ba0ed9..85331b163 100644 --- a/library/x509write_csr.c +++ b/library/x509write_csr.c @@ -33,6 +33,7 @@ #if defined(MBEDTLS_X509_CSR_WRITE_C) #include "mbedtls/x509_csr.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/oid.h" #include "mbedtls/asn1write.h" #include "mbedtls/platform_util.h" diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 3b926084e..04e9501b1 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -4,6 +4,7 @@ #include "mbedtls/x509_crt.h" #include "mbedtls/x509_crl.h" #include "mbedtls/x509_csr.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/pem.h" #include "mbedtls/oid.h" #include "mbedtls/base64.h" diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index f404f898b..923716594 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -2,6 +2,7 @@ #include "mbedtls/bignum.h" #include "mbedtls/x509_crt.h" #include "mbedtls/x509_csr.h" +#include "mbedtls/x509_internal.h" #include "mbedtls/pem.h" #include "mbedtls/oid.h" #include "mbedtls/rsa.h" From be0cf9b1f65c5f92d065f79d361683d695cea06d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 13:17:29 +0100 Subject: [PATCH 091/140] Improve formatting in x509.c --- library/x509.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/x509.c b/library/x509.c index 0a9138fa7..4ed8a4d76 100644 --- a/library/x509.c +++ b/library/x509.c @@ -539,9 +539,9 @@ static int x509_string_cmp( const mbedtls_x509_buf *a, int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, mbedtls_x509_buf_raw const *b, int (*abort_check)( void *ctx, - mbedtls_x509_buf *oid, - mbedtls_x509_buf *val, - int next_merged ), + mbedtls_x509_buf *oid, + mbedtls_x509_buf *val, + int next_merged ), void *abort_check_ctx ) { int ret; From e452add01ec460853067d5548d78148851f873ae Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 13:19:34 +0100 Subject: [PATCH 092/140] Comment on return value type in two internal X.509 functions --- library/x509.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/x509.c b/library/x509.c index 4ed8a4d76..627a5a39b 100644 --- a/library/x509.c +++ b/library/x509.c @@ -348,6 +348,8 @@ int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, * AttributeType ::= OBJECT IDENTIFIER * * AttributeValue ::= ANY DEFINED BY AttributeType + * + * NOTE: This function returns an ASN.1 low-level error code. */ static int x509_get_attr_type_value( unsigned char **p, const unsigned char *end, @@ -423,6 +425,8 @@ exit: * For the general case we still use a flat list, but we mark elements of the * same set so that they are "merged" together in the functions that consume * this list, eg mbedtls_x509_dn_gets(). + * + * NOTE: This function returns an ASN.1 low-level error code. */ static int x509_set_sequence_iterate( unsigned char **p, unsigned char const **end_set, @@ -446,6 +450,7 @@ static int x509_set_sequence_iterate( unsigned char **p, *end_set = *p + set_len; } + /* x509_get_attr_type_value() returns ASN.1 low-level error codes. */ ret = x509_get_attr_type_value( p, *end_set, oid, val ); exit: From 15b73b4066ddc56b461ca876b91d1b3831a448a8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 13:21:27 +0100 Subject: [PATCH 093/140] Correct placement of comment on X.509 SAN parsing --- library/x509_crt.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 0f72e2f08..e2de120ce 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -816,6 +816,31 @@ static int x509_get_ext_key_usage( unsigned char **p, MBEDTLS_ASN1_OID ) ); } +static int x509_get_subject_alt_name_cb( void *ctx, + int tag, + unsigned char *data, + size_t data_len ) +{ + mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx; + mbedtls_asn1_sequence *cur = *cur_ptr; + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + cur = cur->next; + } + + cur->buf.tag = tag; + cur->buf.p = data; + cur->buf.len = data_len; + + *cur_ptr = cur; + return( 0 ); +} + /* * SubjectAltName ::= GeneralNames * @@ -842,31 +867,6 @@ static int x509_get_ext_key_usage( unsigned char **p, * * NOTE: we only parse and use dNSName at this point. */ -static int x509_get_subject_alt_name_cb( void *ctx, - int tag, - unsigned char *data, - size_t data_len ) -{ - mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx; - mbedtls_asn1_sequence *cur = *cur_ptr; - - /* Allocate and assign next pointer */ - if( cur->buf.p != NULL ) - { - cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); - if( cur->next == NULL ) - return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); - cur = cur->next; - } - - cur->buf.tag = tag; - cur->buf.p = data; - cur->buf.len = data_len; - - *cur_ptr = cur; - return( 0 ); -} - static int x509_get_subject_alt_name( unsigned char *p, const unsigned char *end, mbedtls_x509_sequence *subject_alt_name ) From 529f25d1199c9f12531247c2e78706b4bbae3ba0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 14:48:25 +0100 Subject: [PATCH 094/140] Don't use mbedtls_asn1_get_sequence_of() in x509_crt.c This commit modifies the implementation of x509_get_ext_key_usage() to not rely on mbedtls_asn1_get_sequence_of() but to instead use mbedtls_asn1_traverse_sequence_of() with the same sequence-building callback that also x509_get_subject_alt_name() uses, and which agrees with the callback used by mbedtls_asn1_get_sequence_of(). The reason for this is that with this change, Mbed TLS itself isn't using mbedtls_asn1_get_sequence_of() anymore, but only the more powerful mbedtls_asn1_traverse_sequence_of(), so that unless application code makes use of mbedtls_asn1_get_sequence_of(), its implementation -- including the underlying sequence building callback -- will be removed by link time garbage collection. --- library/x509_crt.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index e2de120ce..75ea5e604 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -803,23 +803,10 @@ static int x509_get_key_usage( unsigned char **p, return( 0 ); } -/* - * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId - * - * KeyPurposeId ::= OBJECT IDENTIFIER - */ -static int x509_get_ext_key_usage( unsigned char **p, - const unsigned char *end, - mbedtls_x509_sequence *ext_key_usage) -{ - return( mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, - MBEDTLS_ASN1_OID ) ); -} - -static int x509_get_subject_alt_name_cb( void *ctx, - int tag, - unsigned char *data, - size_t data_len ) +static int asn1_build_sequence_cb( void *ctx, + int tag, + unsigned char *data, + size_t data_len ) { mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx; mbedtls_asn1_sequence *cur = *cur_ptr; @@ -841,6 +828,22 @@ static int x509_get_subject_alt_name_cb( void *ctx, return( 0 ); } +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *ext_key_usage) +{ + return( mbedtls_asn1_traverse_sequence_of( p, end, + 0xFF, MBEDTLS_ASN1_OID, + 0, 0, + asn1_build_sequence_cb, + (void*) &ext_key_usage ) ); +} + /* * SubjectAltName ::= GeneralNames * @@ -876,7 +879,7 @@ static int x509_get_subject_alt_name( unsigned char *p, MBEDTLS_ASN1_CONTEXT_SPECIFIC, MBEDTLS_ASN1_TAG_VALUE_MASK, 2 /* SubjectAlt DNS */, - x509_get_subject_alt_name_cb, + asn1_build_sequence_cb, (void*) &subject_alt_name ) ); } From 0ed348a14ed36d459b7ceeda01efebaadd0f9db0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Thu, 2 May 2019 16:16:46 +0100 Subject: [PATCH 095/140] Update VS2010 project file --- visualc/VS2010/mbedTLS.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 73c92bda5..2ec9178af 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -223,6 +223,7 @@ + From 7b8e11e724edd83687fdd97954f929fbcb9c309f Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 3 May 2019 12:37:12 +0100 Subject: [PATCH 096/140] Avoid allocating empty buffers when handling length-0 CRTs --- library/x509_crt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 75ea5e604..5834a4ce9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1445,7 +1445,11 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, } else { - crt->raw.p = mbedtls_calloc( 1, buflen ); + /* Call mbedtls_calloc with buflen + 1 in order to avoid potential + * return of NULL in case of length 0 certificates, which we want + * to cleanly fail with MBEDTLS_ERR_X509_INVALID_FORMAT in the + * core parsing routine, but not here. */ + crt->raw.p = mbedtls_calloc( 1, buflen + 1 ); if( crt->raw.p == NULL ) return( MBEDTLS_ERR_X509_ALLOC_FAILED ); crt->raw.len = buflen; From f332a97e1bf370b9ea15c0e18e76d3fe8cf92c26 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 11:56:21 +0100 Subject: [PATCH 097/140] Add ASN.1 API to free linked list representation of ASN.1 sequences --- include/mbedtls/asn1.h | 37 +++++++++++++++++++++++++++++++------ include/mbedtls/x509.h | 5 ++++- library/asn1parse.c | 10 ++++++++++ library/x509.c | 11 ----------- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h index 5b7b2b82d..b471a94b6 100644 --- a/include/mbedtls/asn1.h +++ b/include/mbedtls/asn1.h @@ -276,13 +276,38 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end size_t *len ); /** - * \brief Parses and splits an ASN.1 "SEQUENCE OF " - * Updated the pointer to immediately behind the full sequence tag. + * \brief Free a heap-allocated linked list presentation of + * an ASN.1 sequence, including the first element. * - * \param p The position in the ASN.1 data - * \param end End of data - * \param cur First variable in the chain to fill - * \param tag Type of sequence + * \param seq The address of the first sequence component. This may + * be \c NULL, in which case this functions returns + * immediately. + */ +void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq ); + +/** + * \brief This function parses and splits an ASN.1 "SEQUENCE OF " + * and updates the source buffer pointer to immediately behind + * the full sequence. + * + * \param p The address of the pointer to the beginning of the + * ASN.1 SEQUENCE OF structure, including ASN.1 tag+length header. + * On success, `*p` is advanced to point to the first byte + * following the parsed ASN.1 sequence. + * \param end The end of the ASN.1 input buffer starting at \p p. This is + * used for bounds checking. + * \param cur The address at which to store the first entry in the parsed + * sequence. Further entries are heap-allocated and referenced + * from \p cur. + * \param tag The common tag of the entries in the ASN.1 sequence. + * + * \note Ownership for the heap-allocated elements \c cur->next, + * \c cur->next->next, ..., is passed to the caller. It + * is hence the caller's responsibility to free them when + * no longer needed, and mbedtls_asn1_sequence_free() can + * be used for that, passing \c cur->next as the \c seq + * argument (or \p cur if \p cur itself was heap-allocated + * by the caller). * * \return 0 if successful or a specific ASN.1 error code. */ diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 753019aac..5d091bc2d 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -296,7 +296,10 @@ void mbedtls_x509_name_free( mbedtls_x509_name *name ); * be \c NULL, in which case this functions returns * immediately. */ -void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq ); +static inline void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq ) +{ + mbedtls_asn1_sequence_free( (mbedtls_asn1_sequence*) seq ); +} #if defined(MBEDTLS_SELF_TEST) diff --git a/library/asn1parse.c b/library/asn1parse.c index f24fee69f..68a70e61f 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -229,6 +229,16 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end return( 0 ); } +void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq ) +{ + while( seq != NULL ) + { + mbedtls_asn1_sequence *next = seq->next; + mbedtls_platform_zeroize( seq, sizeof( *seq ) ); + mbedtls_free( seq ); + seq = next; + } +} /* * Traverse an ASN.1 "SEQUENCE OF " diff --git a/library/x509.c b/library/x509.c index 627a5a39b..f1c96a827 100644 --- a/library/x509.c +++ b/library/x509.c @@ -1220,17 +1220,6 @@ void mbedtls_x509_name_free( mbedtls_x509_name *name ) } } -void mbedtls_x509_sequence_free( mbedtls_x509_sequence *seq ) -{ - while( seq != NULL ) - { - mbedtls_x509_sequence *next = seq->next; - mbedtls_platform_zeroize( seq, sizeof( *seq ) ); - mbedtls_free( seq ); - seq = next; - } -} - #if defined(MBEDTLS_SELF_TEST) #include "mbedtls/x509_crt.h" From 54f1c2cb2036b9d880462b89296029efa7de9c91 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 11:58:47 +0100 Subject: [PATCH 098/140] Rename MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR to _WITH_CLEANUP --- library/x509_crt.c | 40 +++++++++++----------- tests/suites/test_suite_x509parse.function | 10 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 5834a4ce9..ffd3d9bc4 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2157,7 +2157,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( NULL == crt ) { ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; return( (int) ( size - n ) ); } @@ -2213,7 +2213,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", prefix, frame.version ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; { mbedtls_x509_buf serial; @@ -2221,41 +2221,41 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, serial.len = frame.serial.len; ret = mbedtls_snprintf( p, n, "%sserial number : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_x509_serial_gets( p, n, &serial ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; } ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_x509_dn_gets( p, n, issuer ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_x509_dn_gets( p, n, subject ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, frame.valid_from.year, frame.valid_from.mon, frame.valid_from.day, frame.valid_from.hour, frame.valid_from.min, frame.valid_from.sec ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, frame.valid_to.year, frame.valid_to.mon, frame.valid_to.day, frame.valid_to.hour, frame.valid_to.min, frame.valid_to.sec ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_x509_sig_alg_gets( p, n, sig_info.sig_pk, sig_info.sig_md, sig_info.sig_opts ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; /* Key size */ if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, @@ -2266,7 +2266,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, (int) mbedtls_pk_get_bitlen( &pk ) ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; /* * Optional extensions @@ -2276,19 +2276,19 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, { ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, frame.ca_istrue ? "true" : "false" ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; if( frame.max_pathlen > 0 ) { ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", frame.max_pathlen - 1 ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; } } if( frame.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) { ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; if( ( ret = x509_info_subject_alt_name( &p, &n, subject_alt_names ) ) != 0 ) @@ -2298,7 +2298,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( frame.ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) { ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; if( ( ret = x509_info_cert_type( &p, &n, frame.ns_cert_type ) ) != 0 ) return( ret ); @@ -2307,7 +2307,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( frame.ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) { ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; if( ( ret = x509_info_key_usage( &p, &n, frame.key_usage ) ) != 0 ) return( ret ); @@ -2316,7 +2316,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, if( frame.ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) { ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; if( ( ret = x509_info_ext_key_usage( &p, &n, ext_key_usage ) ) != 0 ) @@ -2324,7 +2324,7 @@ int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, } ret = mbedtls_snprintf( p, n, "\n" ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = (int) ( size - n ); diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 04e9501b1..87b8b7804 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -156,24 +156,24 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint return( ret ); ret = mbedtls_snprintf( p, n, "depth %d - serial ", certificate_depth ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; { mbedtls_x509_buf serial; serial.p = frame->serial.p; serial.len = frame->serial.len; ret = mbedtls_x509_serial_gets( p, n, &serial ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; } ret = mbedtls_snprintf( p, n, " - subject " ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_x509_dn_gets( p, n, subject ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ret = mbedtls_snprintf( p, n, " - flags 0x%08x\n", *flags ); - MBEDTLS_X509_SAFE_SNPRINTF_WITH_ERROR; + MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP; ctx->p = p; From 00d390338d54cfb4509cab3c64af5d21e94a097d Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 12:39:44 +0100 Subject: [PATCH 099/140] Move internal mbedtls_x509_crt_cache to x509_internal.h We cannot move it to x509_crt.c because there are some static inline function definitions in x509_crt.h which access members of mbedtls_x509_crt_cache. --- include/mbedtls/x509_crt.h | 20 ++------------------ include/mbedtls/x509_internal.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index b3570be58..26f3a622c 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -32,7 +32,7 @@ #include "x509.h" #include "x509_crl.h" -#include "threading.h" +#include "x509_internal.h" /** * \addtogroup x509_module @@ -97,22 +97,6 @@ typedef struct mbedtls_x509_crt_frame } mbedtls_x509_crt_frame; -/* This is an internal structure used for caching parsed data from an X.509 CRT. - * - * This structure may change at any time, and it is discouraged - * to access it directly. - */ -typedef struct mbedtls_x509_crt_cache -{ -#if defined(MBEDTLS_THREADING_C) - mbedtls_threading_mutex_t frame_mutex; - mbedtls_threading_mutex_t pk_mutex; -#endif - mbedtls_x509_buf_raw pk_raw; - mbedtls_x509_crt_frame *frame; - mbedtls_pk_context *pk; -} mbedtls_x509_crt_cache; - /** * Container for an X.509 certificate. The certificate may be chained. */ @@ -121,7 +105,7 @@ typedef struct mbedtls_x509_crt int own_buffer; /**< Indicates if \c raw is owned * by the structure or not. */ mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ - mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */ + mbedtls_x509_crt_cache *cache; /**< Internal parsing cache. */ struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index 6fc6fe6f1..30f428854 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -26,6 +26,23 @@ #define MBEDTLS_X509_INTERNAL_H #include "x509.h" +#include "threading.h" + +/* Internal structure used for caching parsed data from an X.509 CRT. */ + +struct mbedtls_x509_crt; +struct mbedtls_pk_context; +struct mbedtls_x509_crt_frame; +typedef struct mbedtls_x509_crt_cache +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t frame_mutex; + mbedtls_threading_mutex_t pk_mutex; +#endif + mbedtls_x509_buf_raw pk_raw; + struct mbedtls_x509_crt_frame *frame; + struct mbedtls_pk_context *pk; +} mbedtls_x509_crt_cache; int mbedtls_x509_get_name( unsigned char *p, size_t len, mbedtls_x509_name *cur ); From fd5c185ed656cbf4e1668973c95c67bfda02e1fe Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 12:52:57 +0100 Subject: [PATCH 100/140] Use uint16_t to store key usage field in X.509 CRT Also, reorder the fields to avoid padding, thereby reducing the size of mbedtls_x509_crt_frame by 2 Bytes. --- include/mbedtls/x509_crt.h | 8 ++++---- library/x509_crt.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 26f3a622c..47b29def1 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -63,13 +63,13 @@ typedef struct mbedtls_x509_crt_frame uint8_t ns_cert_type; /**< Optional Netscape certificate type extension value: * See the values in x509.h */ - unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ - uint32_t ext_types; /**< Bitfield indicating which extensions are present. - * See the values in x509.h. */ - mbedtls_md_type_t sig_md; /**< The hash algorithm used to hash CRT before signing. */ mbedtls_pk_type_t sig_pk; /**< The signature algorithm used to sign the CRT hash. */ + uint16_t key_usage; /**< Optional key usage extension value: See the values in x509.h */ + uint32_t ext_types; /**< Bitfield indicating which extensions are present. + * See the values in x509.h. */ + mbedtls_x509_time valid_from; /**< The start time of certificate validity. */ mbedtls_x509_time valid_to; /**< The end time of certificate validity. */ diff --git a/library/x509_crt.c b/library/x509_crt.c index ffd3d9bc4..4e5f6f50f 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -781,7 +781,7 @@ static int x509_get_ns_cert_type( unsigned char **p, static int x509_get_key_usage( unsigned char **p, const unsigned char *end, - unsigned int *key_usage) + uint16_t *key_usage) { int ret; size_t i; @@ -795,9 +795,9 @@ static int x509_get_key_usage( unsigned char **p, /* Get actual bitstring */ *key_usage = 0; - for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) + for( i = 0; i < bs.len && i < sizeof( *key_usage ); i++ ) { - *key_usage |= (unsigned int) bs.p[i] << (8*i); + *key_usage |= (uint16_t) bs.p[i] << ( 8*i ); } return( 0 ); From c0dab627ce85c9ae28420a414a72095cc8fa5e13 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 13:04:53 +0100 Subject: [PATCH 101/140] Fix typo 'setup' -> 'set up' throughout x509_crt.h --- include/mbedtls/x509_crt.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 47b29def1..e47e70c42 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -646,7 +646,7 @@ void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); * \brief Request CRT frame giving access to basic CRT fields * and raw ASN.1 data of complex fields. * - * \param crt The CRT to use. This must be initialized and setup. + * \param crt The CRT to use. This must be initialized and set up. * \param dst The address of the destination frame structure. * This need not be initialized. * @@ -666,7 +666,7 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, /** * \brief Setup a PK context with the public key in a certificate. * - * \param crt The certificate to use. This must be initialized and setup. + * \param crt The certificate to use. This must be initialized and set up. * \param pk The address of the destination PK context to fill. * This must be initialized via mbedtls_pk_init(). * @@ -682,7 +682,7 @@ int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, * \brief Request the subject name of a CRT, presented * as a dynamically allocated linked list. * - * \param crt The CRT to use. This must be initialized and setup. + * \param crt The CRT to use. This must be initialized and set up. * \param subject The address at which to store the address of the * first entry of the generated linked list holding * the subject name. @@ -707,7 +707,7 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, * \brief Request the subject name of a CRT, presented * as a dynamically allocated linked list. * - * \param crt The CRT to use. This must be initialized and setup. + * \param crt The CRT to use. This must be initialized and set up. * \param issuer The address at which to store the address of the * first entry of the generated linked list holding * the subject name. @@ -732,7 +732,7 @@ int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, * \brief Request the subject alternative name of a CRT, presented * as a dynamically allocated linked list. * - * \param crt The CRT to use. This must be initialized and setup. + * \param crt The CRT to use. This must be initialized and set up. * \param subj_alt The address at which to store the address of the * first component of the subject alternative names list. * @@ -757,7 +757,7 @@ int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, * \brief Request the ExtendedKeyUsage extension of a CRT, * presented as a dynamically allocated linked list. * - * \param crt The CRT to use. This must be initialized and setup. + * \param crt The CRT to use. This must be initialized and set up. * \param ext_key_usage The address at which to store the address of the * first entry of the ExtendedKeyUsage extension. * From 3c3d5c58369d41cf9de4b651159c6b93e7ab818c Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 13:38:40 +0100 Subject: [PATCH 102/140] Fix spacing in declaration of mbedtls_asn1_get_sequence_of() --- include/mbedtls/asn1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h index b471a94b6..94990fe5e 100644 --- a/include/mbedtls/asn1.h +++ b/include/mbedtls/asn1.h @@ -314,7 +314,7 @@ void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq ); int mbedtls_asn1_get_sequence_of( unsigned char **p, const unsigned char *end, mbedtls_asn1_sequence *cur, - int tag); + int tag ); /** * \brief Traverse an ASN.1 SEQUENCE container and From a4dfc0d73d1f94d55dfd77d69505b22a7de93ba6 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 13:45:11 +0100 Subject: [PATCH 103/140] Move X.509 CRT cache handling functions to x509_internal.h --- include/mbedtls/x509_crt.h | 10 ---------- include/mbedtls/x509_internal.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index e47e70c42..77609efe9 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -791,16 +791,6 @@ int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, */ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); -/* Internal X.509 CRT cache handling functions. - * They are not part of the public API and may change - * at any time. */ - -int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ); -int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ); - -int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ); -int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ); - static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame **frame_ptr ) { diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index 30f428854..19d63ec00 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -44,6 +44,16 @@ typedef struct mbedtls_x509_crt_cache struct mbedtls_pk_context *pk; } mbedtls_x509_crt_cache; +/* Internal X.509 CRT cache handling functions. */ + +int mbedtls_x509_crt_flush_cache_frame( struct mbedtls_x509_crt const *crt ); +int mbedtls_x509_crt_flush_cache_pk( struct mbedtls_x509_crt const *crt ); + +int mbedtls_x509_crt_cache_provide_frame( struct mbedtls_x509_crt const *crt ); +int mbedtls_x509_crt_cache_provide_pk( struct mbedtls_x509_crt const *crt ); + +/* Uncategorized internal X.509 functions */ + int mbedtls_x509_get_name( unsigned char *p, size_t len, mbedtls_x509_name *cur ); int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, From 1250623ad1095497ecf74f12686a348dbb043424 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 13 May 2019 13:53:21 +0100 Subject: [PATCH 104/140] Mark CRT frame argument to mbedtls_x509_xxx_from_frame() constant --- library/x509_crt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 4e5f6f50f..29b304a6e 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -98,13 +98,13 @@ static void x509_buf_raw_to_buf( mbedtls_x509_buf *dst, static int x509_crt_parse_frame( unsigned char *start, unsigned char *end, mbedtls_x509_crt_frame *frame ); -static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_name *subject ); -static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_name *issuer ); -static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_sequence *subject_alt ); -static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_sequence *ext_key_usage ); int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ) @@ -1356,7 +1356,7 @@ static int x509_crt_parse_frame( unsigned char *start, return( 0 ); } -static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_name *subject ) { return( mbedtls_x509_get_name( frame->subject_raw.p, @@ -1364,7 +1364,7 @@ static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame, subject ) ); } -static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_name *issuer ) { return( mbedtls_x509_get_name( frame->issuer_raw.p, @@ -1372,7 +1372,7 @@ static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame, issuer ) ); } -static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_sequence *subject_alt ) { int ret; @@ -1390,7 +1390,7 @@ static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame, return( ret ); } -static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame, +static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame const *frame, mbedtls_x509_sequence *ext_key_usage ) { int ret; From 9219f9e7b8035ee020e645626dd7baaa52946d52 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 14 May 2019 12:40:58 +0100 Subject: [PATCH 105/140] Fix yet another occasions of 'setup' vs. 'set up' typo in x509_crt.h --- include/mbedtls/x509_crt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 77609efe9..2fb26fda6 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -664,7 +664,7 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame *dst ); /** - * \brief Setup a PK context with the public key in a certificate. + * \brief Set up a PK context with the public key in a certificate. * * \param crt The certificate to use. This must be initialized and set up. * \param pk The address of the destination PK context to fill. From 5f268b3cf672648d423d40e6588bb3dfe1a3d3f4 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 20 May 2019 16:26:34 +0100 Subject: [PATCH 106/140] Don't allow change of CRT frame returned by x509_crt_frame_acquire() --- include/mbedtls/x509_crt.h | 2 +- library/ssl_srv.c | 4 ++-- library/x509_crt.c | 24 +++++++++++----------- tests/suites/test_suite_x509parse.function | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 2fb26fda6..62429836f 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -792,7 +792,7 @@ int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame **frame_ptr ) + mbedtls_x509_crt_frame const **frame_ptr ) { int ret; #if defined(MBEDTLS_THREADING_C) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 1fd1d310a..1e3c6fa5c 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -874,7 +874,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, mbedtls_md_type_t sig_md; { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( cur->cert, &frame ); if( ret != 0 ) return( ret ); @@ -2996,7 +2996,7 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) while( crt != NULL && crt->raw.p != NULL ) { - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( ret ); diff --git a/library/x509_crt.c b/library/x509_crt.c index 29b304a6e..04e812556 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -288,7 +288,7 @@ int mbedtls_x509_crt_get_subject_alt_names( mbedtls_x509_crt const *crt, mbedtls_x509_sequence **subj_alt ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; mbedtls_x509_sequence *seq; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); @@ -311,7 +311,7 @@ int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, mbedtls_x509_sequence **ext_key_usage ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; mbedtls_x509_sequence *seq; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); @@ -334,7 +334,7 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, mbedtls_x509_name **subject ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; mbedtls_x509_name *name; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); @@ -357,7 +357,7 @@ int mbedtls_x509_crt_get_issuer( mbedtls_x509_crt const *crt, mbedtls_x509_name **issuer ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; mbedtls_x509_name *name; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); @@ -380,7 +380,7 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, mbedtls_x509_crt_frame *dst ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( ret ); @@ -2426,7 +2426,7 @@ int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, unsigned int usage ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); @@ -2474,7 +2474,7 @@ int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, size_t usage_len ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; unsigned ext_types; unsigned char *p, *end; x509_crt_check_ext_key_usage_cb_ctx_t cb_ctx = { usage_oid, usage_len }; @@ -2534,7 +2534,7 @@ int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) @@ -2569,7 +2569,7 @@ static int x509_crt_verifycrl( unsigned char *crt_serial, return( flags ); { - mbedtls_x509_crt_frame *ca; + mbedtls_x509_crt_frame const *ca; ret = mbedtls_x509_crt_frame_acquire( ca_crt, &ca ); if( ret != 0 ) return( MBEDTLS_X509_BADCRL_NOT_TRUSTED ); @@ -2846,7 +2846,7 @@ check_signature: parent_valid = parent_match = path_len_ok = 0; { - mbedtls_x509_crt_frame *parent; + mbedtls_x509_crt_frame const *parent; ret = mbedtls_x509_crt_frame_acquire( parent_crt, &parent ); if( ret != 0 ) @@ -3139,7 +3139,7 @@ find_parent: { mbedtls_x509_crt_sig_info child_sig; { - mbedtls_x509_crt_frame *child; + mbedtls_x509_crt_frame const *child; ret = mbedtls_x509_crt_frame_acquire( child_crt, &child ); if( ret != 0 ) @@ -3340,7 +3340,7 @@ static int x509_crt_verify_name( const mbedtls_x509_crt *crt, uint32_t *flags ) { int ret; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 87b8b7804..2df187de0 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -143,7 +143,7 @@ int verify_print( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint verify_print_context *ctx = (verify_print_context *) data; char *p = ctx->p; size_t n = ctx->buf + sizeof( ctx->buf ) - ctx->p; - mbedtls_x509_crt_frame *frame; + mbedtls_x509_crt_frame const *frame; mbedtls_x509_name *subject; ((void) flags); From b8670fcab35320299764ccbe593205f40ad25076 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 20 May 2019 16:50:45 +0100 Subject: [PATCH 107/140] Document mbedtls_x509_crt_frame_{acquire/release}() --- include/mbedtls/x509_crt.h | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 62429836f..33318a686 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -791,8 +791,33 @@ int mbedtls_x509_crt_get_ext_key_usage( mbedtls_x509_crt const *crt, */ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); +/** + * \brief Request temporary read-access to a certificate frame + * for a given certificate. + * + * Once no longer needed, the frame must be released + * through a call to mbedtls_x509_crt_frame_release(). + * + * This is a copy-less version of mbedtls_x509_crt_get_frame(). + * See there for more information. + * + * \param crt The certificate to use. This must be initialized and set up. + * \param dst The address at which to store the address of a readable + * certificate frame for the input certificate \p crt which the + * caller can use until calling mbedtls_x509_crt_frame_release(). + * + * \note The certificate frame `**frame_ptr` returned by this function + * is owned by the X.509 module and must not be freed or modified + * by the caller. The X.509 module guarantees its validity as long + * as \p crt is valid and mbedtls_x509_crt_frame_release() hasn't + * been issued. + * + * \return \c 0 on success. In this case, `*frame_ptr` is updated + * to hold the address of a frame for the given CRT. + * \return A negative error code on failure. + */ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame const **frame_ptr ) + mbedtls_x509_crt_frame const **frame_ptr ) { int ret; #if defined(MBEDTLS_THREADING_C) @@ -814,6 +839,13 @@ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, return( 0 ); } +/** + * \brief Release access to a certificate frame acquired + * through a prior call to mbedtls_x509_crt_frame_acquire(). + * + * \param crt The certificate for which a certificate frame has + * previously been acquired. + */ static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) { ((void) crt); From 4b70e12dde988387b652472a7e1b6a2d97004ed0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 20 May 2019 16:51:01 +0100 Subject: [PATCH 108/140] Document mbedtls_x509_crt_pk_{acquire/release}() In contrast to mbedtls_x509_crt_frame_acquire(), the public key context returned by mbedtls_x509_crt_pk_acquire() cannot be marked `const` because the caller must be able to use it e.g. for mbedtls_pk_sign() and mbedtls_pk_verify(), which don't have `const` input parameters. Instead, return a non-`const` context, but explicitly state that callers must use that context in a thread-safe way. --- include/mbedtls/x509_crt.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 33318a686..fb5269e7e 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -859,6 +859,33 @@ static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) #endif /* MBEDTLS_X509_ALWAYS_FLUSH */ } +/** + * \brief Request temporary access to a public key context + * for a given certificate. + * + * Once no longer needed, the frame must be released + * through a call to mbedtls_x509_crt_pk_release(). + * + * This is a copy-less version of mbedtls_x509_crt_get_pk(). + * See there for more information. + * + * \param crt The certificate to use. This must be initialized and set up. + * \param dst The address at which to store the address of a public key + * context for the public key in the input certificate \p crt. + * + * \warning The public key context `**pk_ptr` returned by this function + * is owned by the X.509 module and must be used by the caller + * in a thread-safe way. In particular, the caller must only + * use the context with functions which are `const` on the input + * context, or those which are known to be thread-safe. The latter + * for example includes mbedtls_pk_sign() and mbedtls_pk_verify() + * for ECC or RSA public key contexts. + * + * \return \c 0 on success. In this case, `*pk_ptr` is updated + * to hold the address of a public key context for the given + * certificate. + * \return A negative error code on failure. + */ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, mbedtls_pk_context **pk_ptr ) { @@ -882,6 +909,13 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, return( 0 ); } +/** + * \brief Release access to a public key context acquired + * through a prior call to mbedtls_x509_crt_frame_acquire(). + * + * \param crt The certificate for which a certificate frame has + * previously been acquired. + */ static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) { ((void) crt); From fd8b7bd63fabd41ba65c9029e4b544ef972cf2e0 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 28 May 2019 16:16:17 +0100 Subject: [PATCH 109/140] Add concurrent X.509 CRT verification test This commit enhances the X.509 parsing test suite by a test which exercises multiple threads concurrently verifying the same certificate with the same set of trusted roots. --- tests/suites/test_suite_x509parse.data | 20 +++++ tests/suites/test_suite_x509parse.function | 94 ++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index f8d787533..c2152d9ce 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2554,3 +2554,23 @@ x509_verify_restart:"data_files/server10_int3-bs.pem":"data_files/test-int-ca2.c X509 CRT verify restart: one int, int badsign, max_ops=500 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_RSA_C x509_verify_restart:"data_files/server10_int3-bs.pem":"data_files/test-int-ca2.crt":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_NOT_TRUSTED:500:25:100 + +X509 CRT concurrent verification #1 (RSA cert, RSA CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:100:10 + +X509 CRT concurrent verification #2 (EC cert, RSA CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:100:10 + +X509 CRT concurrent verification #3 (RSA cert, EC CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECP_DP_SECP384R1_ENABLED +x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:100:10 + +X509 CRT concurrent verification #4 (EC cert, EC CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED +x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:100:10 + +X509 CRT concurrent verification #5 (RSA cert, RSA CA, RSASSA-PSS) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_X509_RSASSA_PSS_SUPPORT:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:100:10 diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 2df187de0..ffd9376f9 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -58,6 +58,44 @@ const mbedtls_x509_crt_profile profile_sha512 = 1024, }; + +typedef struct +{ + mbedtls_x509_crt *crt; + mbedtls_x509_crt *ca; + uint32_t expected_flags; + unsigned id; + int expected_result; + int iter_total; + int result; +} x509_verify_thread_ctx; + +void* x509_verify_thread_worker( void *p ) +{ + unsigned iter_cnt; + x509_verify_thread_ctx *ctx = (x509_verify_thread_ctx *) p; + + for( iter_cnt=0; iter_cnt < (unsigned) ctx->iter_total; iter_cnt++ ) + { + uint32_t flags; + int res; + + res = mbedtls_x509_crt_verify_with_profile( ctx->crt, ctx->ca, + NULL, &compat_profile, + NULL, &flags, NULL, NULL ); + if( res != ctx->expected_result || + flags != ctx->expected_flags ) + { + ctx->result = 1; + pthread_exit( NULL ); + } + } + + ctx->result = 0; + pthread_exit( NULL ); + return( NULL ); +} + int verify_none( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags ) { ((void) data); @@ -352,6 +390,62 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ +void x509_verify_thread( char *crt_file, char *ca_file, + int result, int flags_result, + int thread_total, + int iterations_per_thread ) +{ + x509_verify_thread_ctx *thread_ctx; + pthread_t *threads; + int cur_thread; + + mbedtls_x509_crt crt; + mbedtls_x509_crt ca; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + TEST_ASSERT( psa_crypto_init() == 0 ); +#endif + + mbedtls_x509_crt_init( &crt ); + mbedtls_x509_crt_init( &ca ); + threads = mbedtls_calloc( thread_total, sizeof( pthread_t ) ); + thread_ctx = mbedtls_calloc( thread_total, sizeof( x509_verify_thread_ctx ) ); + + TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 ); + TEST_ASSERT( threads != NULL ); + + /* Start all verify threads */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + { + thread_ctx[ cur_thread ].id = (unsigned) cur_thread; + thread_ctx[ cur_thread ].ca = &ca; + thread_ctx[ cur_thread ].crt = &crt; + thread_ctx[ cur_thread ].expected_result = result; + thread_ctx[ cur_thread ].expected_flags = flags_result; + thread_ctx[ cur_thread ].iter_total = iterations_per_thread; + TEST_ASSERT( pthread_create( &threads[ cur_thread ], NULL, + &x509_verify_thread_worker, + &thread_ctx[ cur_thread ] ) == 0 ); + } + + /* Wait for all threads to complete */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + TEST_ASSERT( pthread_join( threads[ cur_thread ], NULL ) == 0 ); + + /* Check their results */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + TEST_ASSERT( thread_ctx[ cur_thread ].result == 0 ); + +exit: + mbedtls_free( threads ); + mbedtls_free( thread_ctx ); + mbedtls_x509_crt_free( &crt ); + mbedtls_x509_crt_free( &ca ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_X509_CRL_PARSE_C */ void x509_verify( char *crt_file, char *ca_file, char *crl_file, char *cn_name_str, int result, int flags_result, From 1ba602c2f6a5a23110aa05c125a51c79ce9aaafc Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 28 May 2019 16:17:09 +0100 Subject: [PATCH 110/140] CMake: Link test suites with pthread if LINK_WITH_PTHREAD set The pre-existing LINK_WITH_PTHREAD CMake option controls whether `pthread` should be linked into the library, but didn't apply to the test suites so far. This commit also links test suites to `pthread` in CMake-based builds which have LINK_WITH_PTHREAD set. --- tests/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a8e7523e5..5938a5fc8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,5 @@ +option(LINK_WITH_PTHREAD "Explicitly link mbed TLS library to pthread." OFF) + set(libs mbedtls ) @@ -10,6 +12,10 @@ if(ENABLE_ZLIB_SUPPORT) set(libs ${libs} ${ZLIB_LIBRARIES}) endif(ENABLE_ZLIB_SUPPORT) +if(LINK_WITH_PTHREAD) + set(libs ${libs} pthread) +endif(LINK_WITH_PTHREAD) + find_package(Perl) if(NOT PERL_FOUND) message(FATAL_ERROR "Cannot build test suites without Perl") From fa37d07a0d17582962721e2b765c959d5a74b36e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 28 May 2019 16:38:18 +0100 Subject: [PATCH 111/140] Make: Link test suites with pthread if PTHREAD is set --- tests/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Makefile b/tests/Makefile index 4ef74177b..4c784e015 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -53,6 +53,11 @@ ifdef ZLIB LOCAL_LDFLAGS += -lz endif +# Pthread shared library extension +ifdef PTHREAD +LOCAL_LDFLAGS += -lpthread +endif + # A test application is built for each suites/test_suite_*.data file. # Application name is same as .data file's base name and can be # constructed by stripping path 'suites/' and extension .data. From 22cf255e091d4d735517b92abafe1ce8128b4f0e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 28 May 2019 16:45:21 +0100 Subject: [PATCH 112/140] Force linking of pthread in 'full config' tests in all.sh --- tests/scripts/all.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 45236922c..b884e20cf 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -728,7 +728,7 @@ component_test_full_cmake_clang () { msg "build: cmake, full config, clang" # ~ 50s scripts/config.pl full scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests - CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On . + CC=clang cmake -D LINK_WITH_PTHREAD=1 -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On . make msg "test: main suites (full config)" # ~ 5s @@ -750,7 +750,7 @@ component_build_deprecated () { scripts/config.pl set MBEDTLS_DEPRECATED_WARNING # Build with -O -Wextra to catch a maximum of issues. make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs - make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests + make PTHREAD=1 CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s # No cleanup, just tweak the configuration and rebuild @@ -759,7 +759,7 @@ component_build_deprecated () { scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED # Build with -O -Wextra to catch a maximum of issues. make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs - make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests + make PTHREAD=1 CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests } @@ -807,7 +807,7 @@ component_test_check_params_without_platform () { scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED scripts/config.pl unset MBEDTLS_PLATFORM_C - make CC=gcc CFLAGS='-Werror -O1' all test + make CC=gcc PTHREAD=1 CFLAGS='-Werror -O1' all test } component_test_check_params_silent () { @@ -815,7 +815,7 @@ component_test_check_params_silent () { scripts/config.pl full # includes CHECK_PARAMS scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests sed -i 's/.*\(#define MBEDTLS_PARAM_FAILED( cond )\).*/\1/' "$CONFIG_H" - make CC=gcc CFLAGS='-Werror -O1' all test + make CC=gcc PTHREAD=1 CFLAGS='-Werror -O1' all test } component_test_no_platform () { @@ -837,8 +837,8 @@ component_test_no_platform () { scripts/config.pl unset MBEDTLS_FS_IO # Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19, # to re-enable platform integration features otherwise disabled in C99 builds - make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs - make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0' test } component_build_no_std_function () { @@ -847,21 +847,21 @@ component_build_no_std_function () { scripts/config.pl full scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED - make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0' } component_build_no_ssl_srv () { msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s scripts/config.pl full scripts/config.pl unset MBEDTLS_SSL_SRV_C - make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0' } component_build_no_ssl_cli () { msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s scripts/config.pl full scripts/config.pl unset MBEDTLS_SSL_CLI_C - make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0' } component_build_no_sockets () { @@ -871,7 +871,7 @@ component_build_no_sockets () { scripts/config.pl full scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc. scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux - make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib } component_test_no_max_fragment_length () { @@ -924,7 +924,7 @@ component_test_asan_on_demand_parsing_remove_peer_cert () { scripts/config.pl set MBEDTLS_X509_ON_DEMAND_PARSING scripts/config.pl set MBEDTLS_THREADING_C scripts/config.pl set MBEDTLS_THREADING_PTHREAD - CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan -D LINK_WITH_PTHREAD=1 . make msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE, MBEDTLS_X509_ON_DEMAND_PARSING" @@ -1024,7 +1024,7 @@ component_test_m32_o0 () { # Build once with -O0, to compile out the i386 specific inline assembly msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s scripts/config.pl full - make CC=gcc CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address' + make CC=gcc PTHREAD=1 CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address' msg "test: i386, make, gcc -O0 (ASan build)" make test @@ -1043,7 +1043,7 @@ component_test_m32_o1 () { scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C scripts/config.pl unset MBEDTLS_MEMORY_DEBUG - make CC=gcc CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address' + make CC=gcc PTHREAD=1 CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address' msg "test: i386, make, gcc -O1 (ASan build)" make test @@ -1058,7 +1058,7 @@ support_test_m32_o1 () { component_test_mx32 () { msg "build: 64-bit ILP32, make, gcc" # ~ 30s scripts/config.pl full - make CC=gcc CFLAGS='-Werror -Wall -Wextra -mx32' + make CC=gcc PTHREAD=1 CFLAGS='-Werror -Wall -Wextra -mx32' msg "test: 64-bit ILP32, make, gcc" make test From d687ef0a91f405f2fa366d7a356c4af198f10409 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 29 May 2019 13:05:55 +0100 Subject: [PATCH 113/140] Move X.509 threading test to separate test suite This allows to build the library + tests via `make` without specifying `PTHREAD=1`, in which case the X.509 threading test suite will be silently dropped. This is analogous to the pre-existing handling of the example application `ssl_pthread_server`, which is only build if `PTHREAD=1` and silently dropped otherwise. --- tests/Makefile | 5 +- tests/suites/test_suite_x509parse.data | 20 --- tests/suites/test_suite_x509parse.function | 94 ------------- .../suites/test_suite_x509parse_pthread.data | 19 +++ .../test_suite_x509parse_pthread.function | 125 ++++++++++++++++++ 5 files changed, 148 insertions(+), 115 deletions(-) create mode 100644 tests/suites/test_suite_x509parse_pthread.data create mode 100644 tests/suites/test_suite_x509parse_pthread.function diff --git a/tests/Makefile b/tests/Makefile index 4c784e015..30fbafdff 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -63,6 +63,10 @@ endif # constructed by stripping path 'suites/' and extension .data. APPS = $(basename $(subst suites/,,$(wildcard suites/test_suite_*.data))) +ifndef PTHREAD +APPS := $(filter-out test_suite_x509parse_pthread, $(APPS)) +endif + # Construct executable name by adding OS specific suffix $(EXEXT). BINARIES := $(addsuffix $(EXEXT),$(APPS)) @@ -141,4 +145,3 @@ $(EMBEDDED_TESTS): embedded_%: suites/$$(firstword $$(subst ., ,$$*)).function s -o ./TESTS/mbedtls/$* generate-target-tests: $(EMBEDDED_TESTS) - diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index c2152d9ce..f8d787533 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2554,23 +2554,3 @@ x509_verify_restart:"data_files/server10_int3-bs.pem":"data_files/test-int-ca2.c X509 CRT verify restart: one int, int badsign, max_ops=500 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_RSA_C x509_verify_restart:"data_files/server10_int3-bs.pem":"data_files/test-int-ca2.crt":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_NOT_TRUSTED:500:25:100 - -X509 CRT concurrent verification #1 (RSA cert, RSA CA) -depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:100:10 - -X509 CRT concurrent verification #2 (EC cert, RSA CA) -depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:100:10 - -X509 CRT concurrent verification #3 (RSA cert, EC CA) -depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECP_DP_SECP384R1_ENABLED -x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:100:10 - -X509 CRT concurrent verification #4 (EC cert, EC CA) -depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED -x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:100:10 - -X509 CRT concurrent verification #5 (RSA cert, RSA CA, RSASSA-PSS) -depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_X509_RSASSA_PSS_SUPPORT:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:100:10 diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index ffd9376f9..2df187de0 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -58,44 +58,6 @@ const mbedtls_x509_crt_profile profile_sha512 = 1024, }; - -typedef struct -{ - mbedtls_x509_crt *crt; - mbedtls_x509_crt *ca; - uint32_t expected_flags; - unsigned id; - int expected_result; - int iter_total; - int result; -} x509_verify_thread_ctx; - -void* x509_verify_thread_worker( void *p ) -{ - unsigned iter_cnt; - x509_verify_thread_ctx *ctx = (x509_verify_thread_ctx *) p; - - for( iter_cnt=0; iter_cnt < (unsigned) ctx->iter_total; iter_cnt++ ) - { - uint32_t flags; - int res; - - res = mbedtls_x509_crt_verify_with_profile( ctx->crt, ctx->ca, - NULL, &compat_profile, - NULL, &flags, NULL, NULL ); - if( res != ctx->expected_result || - flags != ctx->expected_flags ) - { - ctx->result = 1; - pthread_exit( NULL ); - } - } - - ctx->result = 0; - pthread_exit( NULL ); - return( NULL ); -} - int verify_none( void *data, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags ) { ((void) data); @@ -390,62 +352,6 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */ -void x509_verify_thread( char *crt_file, char *ca_file, - int result, int flags_result, - int thread_total, - int iterations_per_thread ) -{ - x509_verify_thread_ctx *thread_ctx; - pthread_t *threads; - int cur_thread; - - mbedtls_x509_crt crt; - mbedtls_x509_crt ca; - -#if defined(MBEDTLS_USE_PSA_CRYPTO) - TEST_ASSERT( psa_crypto_init() == 0 ); -#endif - - mbedtls_x509_crt_init( &crt ); - mbedtls_x509_crt_init( &ca ); - threads = mbedtls_calloc( thread_total, sizeof( pthread_t ) ); - thread_ctx = mbedtls_calloc( thread_total, sizeof( x509_verify_thread_ctx ) ); - - TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); - TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 ); - TEST_ASSERT( threads != NULL ); - - /* Start all verify threads */ - for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) - { - thread_ctx[ cur_thread ].id = (unsigned) cur_thread; - thread_ctx[ cur_thread ].ca = &ca; - thread_ctx[ cur_thread ].crt = &crt; - thread_ctx[ cur_thread ].expected_result = result; - thread_ctx[ cur_thread ].expected_flags = flags_result; - thread_ctx[ cur_thread ].iter_total = iterations_per_thread; - TEST_ASSERT( pthread_create( &threads[ cur_thread ], NULL, - &x509_verify_thread_worker, - &thread_ctx[ cur_thread ] ) == 0 ); - } - - /* Wait for all threads to complete */ - for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) - TEST_ASSERT( pthread_join( threads[ cur_thread ], NULL ) == 0 ); - - /* Check their results */ - for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) - TEST_ASSERT( thread_ctx[ cur_thread ].result == 0 ); - -exit: - mbedtls_free( threads ); - mbedtls_free( thread_ctx ); - mbedtls_x509_crt_free( &crt ); - mbedtls_x509_crt_free( &ca ); -} -/* END_CASE */ - /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_X509_CRL_PARSE_C */ void x509_verify( char *crt_file, char *ca_file, char *crl_file, char *cn_name_str, int result, int flags_result, diff --git a/tests/suites/test_suite_x509parse_pthread.data b/tests/suites/test_suite_x509parse_pthread.data new file mode 100644 index 000000000..b4b9f0450 --- /dev/null +++ b/tests/suites/test_suite_x509parse_pthread.data @@ -0,0 +1,19 @@ +X509 CRT concurrent verification #1 (RSA cert, RSA CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:100:10 + +X509 CRT concurrent verification #2 (EC cert, RSA CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:100:10 + +X509 CRT concurrent verification #3 (RSA cert, EC CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECP_DP_SECP384R1_ENABLED +x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:100:10 + +X509 CRT concurrent verification #4 (EC cert, EC CA) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED +x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:100:10 + +X509 CRT concurrent verification #5 (RSA cert, RSA CA, RSASSA-PSS) +depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_X509_RSASSA_PSS_SUPPORT:MBEDTLS_SHA1_C +x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:100:10 diff --git a/tests/suites/test_suite_x509parse_pthread.function b/tests/suites/test_suite_x509parse_pthread.function new file mode 100644 index 000000000..2728e9617 --- /dev/null +++ b/tests/suites/test_suite_x509parse_pthread.function @@ -0,0 +1,125 @@ +/* BEGIN_HEADER */ +#include "mbedtls/bignum.h" +#include "mbedtls/x509.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/x509_crl.h" +#include "mbedtls/x509_csr.h" +#include "mbedtls/x509_internal.h" +#include "mbedtls/pem.h" +#include "mbedtls/oid.h" +#include "mbedtls/base64.h" +#include "string.h" + +/* Profile for backward compatibility. Allows SHA-1, unlike the default + profile. */ +const mbedtls_x509_crt_profile compat_profile = +{ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, +}; + +typedef struct +{ + mbedtls_x509_crt *crt; + mbedtls_x509_crt *ca; + uint32_t expected_flags; + unsigned id; + int expected_result; + int iter_total; + int result; +} x509_verify_thread_ctx; + +void* x509_verify_thread_worker( void *p ) +{ + unsigned iter_cnt; + x509_verify_thread_ctx *ctx = (x509_verify_thread_ctx *) p; + + for( iter_cnt=0; iter_cnt < (unsigned) ctx->iter_total; iter_cnt++ ) + { + uint32_t flags; + int res; + + res = mbedtls_x509_crt_verify_with_profile( ctx->crt, ctx->ca, + NULL, &compat_profile, + NULL, &flags, NULL, NULL ); + if( res != ctx->expected_result || + flags != ctx->expected_flags ) + { + ctx->result = 1; + pthread_exit( NULL ); + } + } + + ctx->result = 0; + pthread_exit( NULL ); + return( NULL ); +} +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_THREADING_PTHREAD:MBEDTLS_X509_CRT_PARSE_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */ +void x509_verify_thread( char *crt_file, char *ca_file, + int result, int flags_result, + int thread_total, + int iterations_per_thread ) +{ + x509_verify_thread_ctx *thread_ctx; + pthread_t *threads; + int cur_thread; + + mbedtls_x509_crt crt; + mbedtls_x509_crt ca; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + TEST_ASSERT( psa_crypto_init() == 0 ); +#endif + + mbedtls_x509_crt_init( &crt ); + mbedtls_x509_crt_init( &ca ); + threads = mbedtls_calloc( thread_total, sizeof( pthread_t ) ); + thread_ctx = mbedtls_calloc( thread_total, sizeof( x509_verify_thread_ctx ) ); + + TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 ); + TEST_ASSERT( threads != NULL ); + + /* Start all verify threads */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + { + thread_ctx[ cur_thread ].id = (unsigned) cur_thread; + thread_ctx[ cur_thread ].ca = &ca; + thread_ctx[ cur_thread ].crt = &crt; + thread_ctx[ cur_thread ].expected_result = result; + thread_ctx[ cur_thread ].expected_flags = flags_result; + thread_ctx[ cur_thread ].iter_total = iterations_per_thread; + TEST_ASSERT( pthread_create( &threads[ cur_thread ], NULL, + &x509_verify_thread_worker, + &thread_ctx[ cur_thread ] ) == 0 ); + } + + /* Wait for all threads to complete */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + TEST_ASSERT( pthread_join( threads[ cur_thread ], NULL ) == 0 ); + + /* Check their results */ + for( cur_thread = 0; cur_thread < thread_total; cur_thread++ ) + TEST_ASSERT( thread_ctx[ cur_thread ].result == 0 ); + +exit: + mbedtls_free( threads ); + mbedtls_free( thread_ctx ); + mbedtls_x509_crt_free( &crt ); + mbedtls_x509_crt_free( &ca ); +} +/* END_CASE */ From 2ba9fbdfe97604632bf844ac77a97287582222c8 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 28 May 2019 16:11:43 +0100 Subject: [PATCH 114/140] Allow multiple concurrent readers for X.509 CRT frame and PK context Previously, only one thread could access the parsing cache of an X.509 CRT at a time. Firstly, this leads to significant performance penalties on systems running many concurrent threads which share CRT structures -- for example, server threads sharing an SSL configuration containing the server CRT. Secondly, the locking should be logically unnecessary, because the threads are supposed to access the CRT frame and PK in a read-only, or at least thread-safe manner. This commit modifies the X.509 CRT cache implementation by allowing an arbitrary number of concurrent readers, locking only the path of setting up and clearing the cache. --- include/mbedtls/x509_crt.h | 93 +++++++++++++++++++++------------ include/mbedtls/x509_internal.h | 4 ++ library/x509_crt.c | 28 ++++++---- 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index fb5269e7e..3ef2b48dc 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -817,26 +817,31 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); * \return A negative error code on failure. */ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, - mbedtls_x509_crt_frame const **frame_ptr ) + mbedtls_x509_crt_frame const **dst ) { - int ret; + int ret = 0; #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - ret = mbedtls_x509_crt_cache_provide_frame( crt ); - if( ret != 0 ) + if( crt->cache->frame_readers == 0 ) +#endif /* MBEDTLS_THREADING_C */ { -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - return( ret ); + ret = mbedtls_x509_crt_cache_provide_frame( crt ); } - *frame_ptr = crt->cache->frame; - return( 0 ); +#if defined(MBEDTLS_THREADING_C) + if( crt->cache->frame_readers == MBEDTLS_X509_CACHE_FRAME_READERS_MAX ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + crt->cache->frame_readers++; + + if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ + + *dst = crt->cache->frame; + return( ret ); } /** @@ -846,17 +851,24 @@ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, * \param crt The certificate for which a certificate frame has * previously been acquired. */ -static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) +static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) { - ((void) crt); - #if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + if( crt->cache->frame_readers == 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + crt->cache->frame_readers--; + mbedtls_mutex_unlock( &crt->cache->frame_mutex ); -#endif +#endif /* MBEDTLS_THREADING_C */ #if defined(MBEDTLS_X509_ALWAYS_FLUSH) - (void) mbedtls_x509_crt_flush_cache_frame( crt ); + (void) mbedtls_x509_crt_flush_cache_frame( crt ); #endif /* MBEDTLS_X509_ALWAYS_FLUSH */ + return( 0 ); } /** @@ -887,26 +899,31 @@ static inline void mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) * \return A negative error code on failure. */ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, - mbedtls_pk_context **pk_ptr ) + mbedtls_pk_context **dst ) { - int ret; + int ret = 0; #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - ret = mbedtls_x509_crt_cache_provide_pk( crt ); - if( ret != 0 ) + if( crt->cache->pk_readers == 0 ) +#endif /* MBEDTLS_THREADING_C */ { -#if defined(MBEDTLS_THREADING_C) - if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - return( ret ); + ret = mbedtls_x509_crt_cache_provide_pk( crt ); } - *pk_ptr = crt->cache->pk; - return( 0 ); +#if defined(MBEDTLS_THREADING_C) + if( crt->cache->pk_readers == MBEDTLS_X509_CACHE_PK_READERS_MAX ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + crt->cache->pk_readers++; + + if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ + + *dst = crt->cache->pk; + return( ret ); } /** @@ -916,17 +933,25 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, * \param crt The certificate for which a certificate frame has * previously been acquired. */ -static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) +static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) { - ((void) crt); - #if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + if( crt->cache->pk_readers == 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + crt->cache->pk_readers--; + mbedtls_mutex_unlock( &crt->cache->pk_mutex ); -#endif +#endif /* MBEDTLS_THREADING_C */ #if defined(MBEDTLS_X509_ALWAYS_FLUSH) - (void) mbedtls_x509_crt_flush_cache_pk( crt ); + (void) mbedtls_x509_crt_flush_cache_pk( crt ); #endif /* MBEDTLS_X509_ALWAYS_FLUSH */ + + return( 0 ); } #endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index 19d63ec00..3816c3611 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -33,9 +33,13 @@ struct mbedtls_x509_crt; struct mbedtls_pk_context; struct mbedtls_x509_crt_frame; +#define MBEDTLS_X509_CACHE_PK_READERS_MAX ((uint32_t) -1) +#define MBEDTLS_X509_CACHE_FRAME_READERS_MAX ((uint32_t) -1) typedef struct mbedtls_x509_crt_cache { #if defined(MBEDTLS_THREADING_C) + uint32_t frame_readers; + uint32_t pk_readers; mbedtls_threading_mutex_t frame_mutex; mbedtls_threading_mutex_t pk_mutex; #endif diff --git a/library/x509_crt.c b/library/x509_crt.c index 04e812556..03cda69c5 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -112,17 +112,21 @@ int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif + /* Can only free the PK context if nobody is using it. */ + if( crt->cache->pk_readers == 0 ) +#endif + { #if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) - /* The cache holds a shallow copy of the PK context - * in the legacy struct, so don't free PK context. */ - mbedtls_free( crt->cache->pk ); + /* The cache holds a shallow copy of the PK context + * in the legacy struct, so don't free PK context. */ + mbedtls_free( crt->cache->pk ); #else - mbedtls_pk_free( crt->cache->pk ); - mbedtls_free( crt->cache->pk ); + mbedtls_pk_free( crt->cache->pk ); + mbedtls_free( crt->cache->pk ); #endif /* MBEDTLS_X509_ON_DEMAND_PARSING */ - crt->cache->pk = NULL; + crt->cache->pk = NULL; + } #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) @@ -136,10 +140,14 @@ int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); -#endif - mbedtls_free( crt->cache->frame ); - crt->cache->frame = NULL; + /* Can only free the frame if nobody is using it. */ + if( crt->cache->frame_readers == 0 ) +#endif + { + mbedtls_free( crt->cache->frame ); + crt->cache->frame = NULL; + } #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) From 484caf0abc27dd03dcd6a463cb3bb01d8ee1d745 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 29 May 2019 14:41:44 +0100 Subject: [PATCH 115/140] Consistently use (type *) instead of (type*) for pointer conversion --- library/bignum.c | 4 ++-- library/cipher.c | 10 +++++----- library/cipher_wrap.c | 2 +- library/debug.c | 2 +- library/net_sockets.c | 4 ++-- library/x509_crt.c | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 41946183c..d94754a56 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -127,7 +127,7 @@ int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) if( X->n < nblimbs ) { - if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL ) + if( ( p = (mbedtls_mpi_uint *)mbedtls_calloc( nblimbs, ciL ) ) == NULL ) return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); if( X->p != NULL ) @@ -169,7 +169,7 @@ int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) if( i < nblimbs ) i = nblimbs; - if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL ) + if( ( p = (mbedtls_mpi_uint *)mbedtls_calloc( i, ciL ) ) == NULL ) return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); if( X->p != NULL ) diff --git a/library/cipher.c b/library/cipher.c index 273997577..58217163c 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -331,13 +331,13 @@ int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, ? MBEDTLS_CHACHAPOLY_ENCRYPT : MBEDTLS_CHACHAPOLY_DECRYPT; - result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context *) ctx->cipher_ctx, ctx->iv, mode ); if ( result != 0 ) return( result ); - return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context *) ctx->cipher_ctx, ad, ad_len ) ); } #endif @@ -391,7 +391,7 @@ int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *i if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) { *olen = ilen; - return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context *) ctx->cipher_ctx, ilen, input, output ) ); } #endif @@ -924,7 +924,7 @@ int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, if ( tag_len != 16U ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + return( mbedtls_chachapoly_finish( (mbedtls_chachapoly_context *) ctx->cipher_ctx, tag ) ); } #endif @@ -975,7 +975,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, if ( tag_len != sizeof( check_tag ) ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context *) ctx->cipher_ctx, check_tag ); if ( ret != 0 ) { diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c index 6dd8c5d3a..54572efb9 100644 --- a/library/cipher_wrap.c +++ b/library/cipher_wrap.c @@ -1987,7 +1987,7 @@ static int chachapoly_setkey_wrap( void *ctx, if( key_bitlen != 256U ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); - if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context*)ctx, key ) ) + if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context *)ctx, key ) ) return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); return( 0 ); diff --git a/library/debug.c b/library/debug.c index b02a4f8b5..da4ceac2c 100644 --- a/library/debug.c +++ b/library/debug.c @@ -71,7 +71,7 @@ static inline void debug_send_line( const mbedtls_ssl_context *ssl, int level, */ #if defined(MBEDTLS_THREADING_C) char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */ - mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void*)ssl, str ); + mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void *)ssl, str ); ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, idstr ); #else ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, str ); diff --git a/library/net_sockets.c b/library/net_sockets.c index 816b1303d..bbcf630bc 100644 --- a/library/net_sockets.c +++ b/library/net_sockets.c @@ -72,8 +72,8 @@ #endif #endif /* _MSC_VER */ -#define read(fd,buf,len) recv( fd, (char*)( buf ), (int)( len ), 0 ) -#define write(fd,buf,len) send( fd, (char*)( buf ), (int)( len ), 0 ) +#define read(fd,buf,len) recv( fd, (char *)( buf ), (int)( len ), 0 ) +#define write(fd,buf,len) send( fd, (char *)( buf ), (int)( len ), 0 ) #define close(fd) closesocket(fd) static int wsa_init_done = 0; diff --git a/library/x509_crt.c b/library/x509_crt.c index 03cda69c5..57e772df5 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -849,7 +849,7 @@ static int x509_get_ext_key_usage( unsigned char **p, 0xFF, MBEDTLS_ASN1_OID, 0, 0, asn1_build_sequence_cb, - (void*) &ext_key_usage ) ); + (void *) &ext_key_usage ) ); } /* @@ -888,7 +888,7 @@ static int x509_get_subject_alt_name( unsigned char *p, MBEDTLS_ASN1_TAG_VALUE_MASK, 2 /* SubjectAlt DNS */, asn1_build_sequence_cb, - (void*) &subject_alt_name ) ); + (void *) &subject_alt_name ) ); } /* @@ -3367,13 +3367,13 @@ static int x509_crt_verify_name( const mbedtls_x509_crt *crt, MBEDTLS_ASN1_TAG_VALUE_MASK, 2 /* SubjectAlt DNS */, x509_crt_subject_alt_check_name, - (void*) cn ); + (void *) cn ); } else { ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw, &frame->subject_raw, - x509_crt_check_name, (void*) cn ); + x509_crt_check_name, (void *) cn ); } mbedtls_x509_crt_frame_release( crt ); From b36a245654c0276aec4e423327c15995ea9bbcfa Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 29 May 2019 14:43:17 +0100 Subject: [PATCH 116/140] Add comment to #endif indicating which condition was guarded --- library/x509_crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 57e772df5..ee9e95dc9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -958,7 +958,7 @@ static int x509_crt_get_ext_cb( void *ctx, ret = MBEDTLS_ERR_ASN1_UNEXPECTED_TAG; goto err; } -#endif +#endif /* MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */ return( 0 ); } From 938a80507a3ad9597b6599f97d586691bfbf8328 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Wed, 5 Jun 2019 18:07:00 +0100 Subject: [PATCH 117/140] Add MBEDTLS_X509_ON_DEMAND_PARSING to baremetal config --- configs/baremetal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/baremetal.h b/configs/baremetal.h index f82e5f2b9..175f48a63 100644 --- a/configs/baremetal.h +++ b/configs/baremetal.h @@ -85,6 +85,8 @@ #define MBEDTLS_X509_CHECK_KEY_USAGE #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE #define MBEDTLS_X509_REMOVE_INFO +#define MBEDTLS_X509_ON_DEMAND_PARSING +#define MBEDTLS_X509_ALWAYS_FLUSH #define MBEDTLS_ASN1_PARSE_C /* X.509 CSR writing */ From fd64f14ef9a1a8b9ba328a1494f5b094c67b700e Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 7 Jun 2019 11:47:12 +0100 Subject: [PATCH 118/140] Remove redundant CRT version check during CRT parsing --- library/x509_crt.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index ee9e95dc9..c79193e61 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1297,26 +1297,25 @@ static int x509_crt_parse_frame( unsigned char *start, p += len; frame->pubkey_raw.len = p - frame->pubkey_raw.p; - /* - * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - */ if( frame->version == 2 || frame->version == 3 ) { + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + */ + ret = x509_get_uid( &p, end, &tmp, 1 /* implicit tag */ ); if( ret != 0 ) return( ret ); frame->issuer_id.p = tmp.p; frame->issuer_id.len = tmp.len; - } - /* - * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - */ - if( frame->version == 2 || frame->version == 3 ) - { + /* + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + */ + ret = x509_get_uid( &p, end, &tmp, 2 /* implicit tag */ ); if( ret != 0 ) return( ret ); From e908412a35f6bc8329b73411aa9ad519b7a3f664 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 7 Jun 2019 12:04:39 +0100 Subject: [PATCH 119/140] Simplify logic for issuer/subject ID parsing --- library/x509_crt.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index c79193e61..e9672e4dd 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -696,15 +696,13 @@ static int x509_get_dates( unsigned char **p, */ static int x509_get_uid( unsigned char **p, const unsigned char *end, - mbedtls_x509_buf *uid, int n ) + mbedtls_x509_buf_raw *uid, int n ) { int ret; if( *p == end ) return( 0 ); - uid->tag = **p; - if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) { @@ -1303,25 +1301,17 @@ static int x509_crt_parse_frame( unsigned char *start, * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 */ - - ret = x509_get_uid( &p, end, &tmp, 1 /* implicit tag */ ); + ret = x509_get_uid( &p, end, &frame->issuer_id, 1 /* implicit tag */ ); if( ret != 0 ) return( ret ); - frame->issuer_id.p = tmp.p; - frame->issuer_id.len = tmp.len; - /* * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 */ - - ret = x509_get_uid( &p, end, &tmp, 2 /* implicit tag */ ); + ret = x509_get_uid( &p, end, &frame->subject_id, 2 /* implicit tag */ ); if( ret != 0 ) return( ret ); - - frame->subject_id.p = tmp.p; - frame->subject_id.len = tmp.len; } /* From 7c5fbbeec0b5e10a8898fb3670f9ea844d62ea72 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 7 Jun 2019 16:45:45 +0100 Subject: [PATCH 120/140] Reduce number of parallel workers in X.509 CRT threading test The previous tests used 100 parallel workers which for EC certificates leads to a memory usage of more than 1Mb, hence leading to an out of memory condition in tests using the memory buffer allocator which has a pool of 1Mb. Use 25 workers but an increased number of iterations per worker instead. --- tests/suites/test_suite_x509parse_pthread.data | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/suites/test_suite_x509parse_pthread.data b/tests/suites/test_suite_x509parse_pthread.data index b4b9f0450..7940b7f57 100644 --- a/tests/suites/test_suite_x509parse_pthread.data +++ b/tests/suites/test_suite_x509parse_pthread.data @@ -1,19 +1,19 @@ X509 CRT concurrent verification #1 (RSA cert, RSA CA) depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:100:10 +x509_verify_thread:"data_files/server1.crt":"data_files/test-ca.crt":0:0:25:50 X509 CRT concurrent verification #2 (EC cert, RSA CA) depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:100:10 +x509_verify_thread:"data_files/server3.crt":"data_files/test-ca.crt":0:0:25:50 X509 CRT concurrent verification #3 (RSA cert, EC CA) depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECP_DP_SECP384R1_ENABLED -x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:100:10 +x509_verify_thread:"data_files/server4.crt":"data_files/test-ca2.crt":0:0:25:50 X509 CRT concurrent verification #4 (EC cert, EC CA) depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED -x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:100:10 +x509_verify_thread:"data_files/server5.crt":"data_files/test-ca2.crt":0:0:25:50 X509 CRT concurrent verification #5 (RSA cert, RSA CA, RSASSA-PSS) depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_X509_RSASSA_PSS_SUPPORT:MBEDTLS_SHA1_C -x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:100:10 +x509_verify_thread:"data_files/server9-with-ca.crt":"data_files/test-ca.crt":0:0:25:50 From 60785d113b769ee32752792798ea790ac8a0a0c1 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 7 Jun 2019 17:49:11 +0100 Subject: [PATCH 121/140] Remove unused variable warning in on-demand X.509 parsing --- include/mbedtls/x509_crt.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 3ef2b48dc..ff1422b0a 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -866,8 +866,14 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) #endif /* MBEDTLS_THREADING_C */ #if defined(MBEDTLS_X509_ALWAYS_FLUSH) - (void) mbedtls_x509_crt_flush_cache_frame( crt ); + (void) mbedtls_x509_crt_flush_cache_frame( crt ); #endif /* MBEDTLS_X509_ALWAYS_FLUSH */ + +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + ((void) crt); +#endif + return( 0 ); } @@ -948,9 +954,14 @@ static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) #endif /* MBEDTLS_THREADING_C */ #if defined(MBEDTLS_X509_ALWAYS_FLUSH) - (void) mbedtls_x509_crt_flush_cache_pk( crt ); + (void) mbedtls_x509_crt_flush_cache_pk( crt ); #endif /* MBEDTLS_X509_ALWAYS_FLUSH */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + ((void) crt); +#endif + return( 0 ); } From 97aa4363e1a119b09fc0c57771375f86f9a5d3ac Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Sat, 8 Jun 2019 07:38:20 +0100 Subject: [PATCH 122/140] Simplify X.509 CRT version check in UID parsing WHen parsing the CRT version, we already check that version is either 1, 2, or 3, so checking whether version == 2 or version == 3 is equivalent to version != 1. --- library/x509_crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index e9672e4dd..b5ad86715 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1295,7 +1295,7 @@ static int x509_crt_parse_frame( unsigned char *start, p += len; frame->pubkey_raw.len = p - frame->pubkey_raw.p; - if( frame->version == 2 || frame->version == 3 ) + if( frame->version != 1 ) { /* * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, From 040c56488815a46e52afd1a4882c0f9b6e68a338 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Mon, 10 Jun 2019 11:14:24 +0100 Subject: [PATCH 123/140] Fix certificate validity checking logic to work with !TIME_DATE If MBEDTLS_HAVE_TIME_DATE is undefined, the functions `mbedtls_x509_time_is_past()` and `mbedtls_x509_time_is_future()` are still defined but return `0` (that is, no time is seen to in the past or future). To maintain functional correctness, this means that these functions have to be called in a way where the condition being checked for is the erroneous one: Concretely, one shouldn't check that a CRT's `validFrom` is in the past, or that its `validTo` is in the future, because that would fail if !MBEDTLS_HAVE_TIME_DATE. Instead, one should check that `validFrom` is NOT in the future, and `validTo` is NOT in the past. That was the logic previously, but an uncautious change during transition to X.509 on-demand parsing has changed it. This commit fixes this. --- library/x509_crt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index b5ad86715..45768ca87 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -2849,8 +2849,8 @@ check_signature: if( ret != 0 ) return( MBEDTLS_ERR_X509_FATAL_ERROR ); - if( mbedtls_x509_time_is_past( &parent->valid_from ) && - mbedtls_x509_time_is_future( &parent->valid_to ) ) + if( !mbedtls_x509_time_is_past( &parent->valid_to ) && + !mbedtls_x509_time_is_future( &parent->valid_from ) ) { parent_valid = 1; } From 08d341211dfd460d835d73154fe1cda2998ac5a1 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 25 Jun 2019 09:42:57 +0100 Subject: [PATCH 124/140] Move signature-info extraction out of MBEDTLS_X509_REMOVE_INFO During rebase, the definition of ::mbedtls_x509_crt_sig_info as well as x509_crt_free_sig_info() and x509_crt_get_sig_info() were accidentally guarded by !MBEDTLS_X509_REMOVE_INFO. This commit moves their definition outside of that guard. --- library/x509_crt.c | 130 ++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 45768ca87..3a8c5bbdf 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1931,6 +1931,71 @@ cleanup: } #endif /* MBEDTLS_FS_IO */ +typedef struct mbedtls_x509_crt_sig_info +{ + mbedtls_md_type_t sig_md; + mbedtls_pk_type_t sig_pk; + void *sig_opts; + uint8_t crt_hash[MBEDTLS_MD_MAX_SIZE]; + size_t crt_hash_len; + mbedtls_x509_buf_raw sig; + mbedtls_x509_buf_raw issuer_raw; +} mbedtls_x509_crt_sig_info; + +static void x509_crt_free_sig_info( mbedtls_x509_crt_sig_info *info ) +{ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( info->sig_opts ); +#else + ((void) info); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +} + +static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, + mbedtls_x509_crt_sig_info *info ) +{ + const mbedtls_md_info_t *md_info; + + md_info = mbedtls_md_info_from_type( frame->sig_md ); + if( mbedtls_md( md_info, frame->tbs.p, frame->tbs.len, + info->crt_hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + + info->crt_hash_len = mbedtls_md_get_size( md_info ); + + /* Make sure that this function leaves the target structure + * ready to be freed, regardless of success of failure. */ + info->sig_opts = NULL; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + { + int ret; + unsigned char *alg_start = frame->sig_alg.p; + unsigned char *alg_end = alg_start + frame->sig_alg.len; + + /* Get signature options -- currently only + * necessary for RSASSA-PSS. */ + ret = mbedtls_x509_get_sig_alg_raw( &alg_start, alg_end, &info->sig_md, + &info->sig_pk, &info->sig_opts ); + if( ret != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + } +#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + info->sig_md = frame->sig_md; + info->sig_pk = frame->sig_pk; +#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + info->issuer_raw = frame->issuer_raw; + info->sig = frame->sig; + return( 0 ); +} + #if !defined(MBEDTLS_X509_REMOVE_INFO) static int x509_info_subject_alt_name( char **buf, size_t *size, const mbedtls_x509_sequence *subject_alt_name ) @@ -2061,71 +2126,6 @@ static int x509_info_ext_key_usage( char **buf, size_t *size, return( 0 ); } -typedef struct mbedtls_x509_crt_sig_info -{ - mbedtls_md_type_t sig_md; - mbedtls_pk_type_t sig_pk; - void *sig_opts; - uint8_t crt_hash[MBEDTLS_MD_MAX_SIZE]; - size_t crt_hash_len; - mbedtls_x509_buf_raw sig; - mbedtls_x509_buf_raw issuer_raw; -} mbedtls_x509_crt_sig_info; - -static void x509_crt_free_sig_info( mbedtls_x509_crt_sig_info *info ) -{ -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) - mbedtls_free( info->sig_opts ); -#else - ((void) info); -#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ -} - -static int x509_crt_get_sig_info( mbedtls_x509_crt_frame const *frame, - mbedtls_x509_crt_sig_info *info ) -{ - const mbedtls_md_info_t *md_info; - - md_info = mbedtls_md_info_from_type( frame->sig_md ); - if( mbedtls_md( md_info, frame->tbs.p, frame->tbs.len, - info->crt_hash ) != 0 ) - { - /* Note: this can't happen except after an internal error */ - return( -1 ); - } - - info->crt_hash_len = mbedtls_md_get_size( md_info ); - - /* Make sure that this function leaves the target structure - * ready to be freed, regardless of success of failure. */ - info->sig_opts = NULL; - -#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) - { - int ret; - unsigned char *alg_start = frame->sig_alg.p; - unsigned char *alg_end = alg_start + frame->sig_alg.len; - - /* Get signature options -- currently only - * necessary for RSASSA-PSS. */ - ret = mbedtls_x509_get_sig_alg_raw( &alg_start, alg_end, &info->sig_md, - &info->sig_pk, &info->sig_opts ); - if( ret != 0 ) - { - /* Note: this can't happen except after an internal error */ - return( -1 ); - } - } -#else /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - info->sig_md = frame->sig_md; - info->sig_pk = frame->sig_pk; -#endif /* !MBEDTLS_X509_RSASSA_PSS_SUPPORT */ - - info->issuer_raw = frame->issuer_raw; - info->sig = frame->sig; - return( 0 ); -} - /* * Return an informational string about the certificate. */ From 2656bfe9b0dd37102dce3e5fa56467c263af47d9 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 25 Jun 2019 09:44:56 +0100 Subject: [PATCH 125/140] [FIXUP] Fix typo in declaration of mbedtls_x509_memcasecmp() --- include/mbedtls/x509_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index 3816c3611..bed9772e3 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -89,7 +89,7 @@ int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a, int next_merged ), void *check_ctx ); int mbedtls_x509_memcasecmp( const void *s1, const void *s2, - size_t len1, size_t lend2 ); + size_t len1, size_t len2 ); int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *ext, int tag ); From 35b86a872f5595f91bdc637ac191290ee3f23bd2 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 25 Jun 2019 09:50:07 +0100 Subject: [PATCH 126/140] [FIXUP] Fix bug in ASN.1 traversal of silently ignored tag --- library/asn1parse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/asn1parse.c b/library/asn1parse.c index 68a70e61f..aac253b01 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -273,11 +273,11 @@ int mbedtls_asn1_traverse_sequence_of( if( ( tag & tag_must_mask ) != tag_must_val ) return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 ) + return( ret ); + if( ( tag & tag_may_mask ) == tag_may_val ) { - if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 ) - return( ret ); - if( cb != NULL ) { ret = cb( ctx, tag, *p, len ); From ed058881956569152467471d498543029076ba16 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:46:43 +0100 Subject: [PATCH 127/140] x509_crt.c: Add blank line to increase readability --- library/x509_crt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index 3a8c5bbdf..c601686f9 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -169,6 +169,7 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ) } static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame ); + int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) { mbedtls_x509_crt_cache *cache = crt->cache; From 608de6a50daae99f0daa989feda3abf9bd7cc65b Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:48:01 +0100 Subject: [PATCH 128/140] Reference copy-less versions of X.509 CRT frame/PK getters --- include/mbedtls/x509_crt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index ff1422b0a..c17285776 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -656,6 +656,10 @@ void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); * ::mbedtls_x509_crt_frame on the stack and call this function * on it, in which case no allocation/freeing has to be done. * + * \note You may also use mbedtls_x509_crt_frame_acquire() and + * mbedtls_x509_crt_frame_release() for copy-less variants + * of this function. + * * \return \c 0 on success. In this case, \p dst is updated * to hold the frame for the given CRT. * \return A negative error code on failure. @@ -670,6 +674,10 @@ int mbedtls_x509_crt_get_frame( mbedtls_x509_crt const *crt, * \param pk The address of the destination PK context to fill. * This must be initialized via mbedtls_pk_init(). * + * \note You may also use mbedtls_x509_crt_pk_acquire() and + * mbedtls_x509_crt_pk_release() for copy-less variants + * of this function. + * * \return \c 0 on success. In this case, the user takes ownership * of the destination PK context, and is responsible for * calling mbedtls_pk_free() on it once it's no longer needed. From d92078fc550883993e0d14ba229f34dabedd68e5 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:48:57 +0100 Subject: [PATCH 129/140] Fix copy pasta in x509_crt.h --- include/mbedtls/x509_crt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index c17285776..293a710ed 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -695,7 +695,7 @@ int mbedtls_x509_crt_get_pk( mbedtls_x509_crt const *crt, * first entry of the generated linked list holding * the subject name. * - * \note Depending in your use case, consider using the raw ASN.1 + * \note Depending on your use case, consider using the raw ASN.1 * describing the subject name instead of the heap-allocated * linked list generated by this call. The pointers to the * raw ASN.1 data are part of the CRT frame that can be queried @@ -720,8 +720,8 @@ int mbedtls_x509_crt_get_subject( mbedtls_x509_crt const *crt, * first entry of the generated linked list holding * the subject name. * - * \note Depending in your use case, consider using the raw ASN.1 - * describing the subject name instead of the heap-allocated + * \note Depending on your use case, consider using the raw ASN.1 + * describing the issuer name instead of the heap-allocated * linked list generated by this call. The pointers to the * raw ASN.1 data are part of the CRT frame that can be queried * via mbedtls_x509_crt_get_frame(), and they can be traversed From 2224ccf390c39e34d16bb2631226cf09a7d4632a Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:52:45 +0100 Subject: [PATCH 130/140] Don't use assertion for failures of mbedtls_x509_crt_x_acquire() These functions may afil in a regular run, e.g. due to an out of memory error. --- library/ssl_cli.c | 15 ++++++--------- library/ssl_srv.c | 14 +++++++++++--- library/ssl_tls.c | 3 +++ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/library/ssl_cli.c b/library/ssl_cli.c index c3c28c703..0a1fce8ff 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2328,9 +2328,8 @@ static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, &peer_pk ); if( ret != 0 ) { - /* Should never happen */ - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); + return( ret ); } } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ @@ -2472,9 +2471,8 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) &peer_pk ); if( ret != 0 ) { - /* Should never happen */ - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); + return( ret ); } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ @@ -2822,9 +2820,8 @@ start_processing: &peer_pk ); if( ret != 0 ) { - /* Should never happen */ - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); + return( ret ); } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 1e3c6fa5c..9e15f756a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -815,7 +815,10 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, int ret; ret = mbedtls_x509_crt_pk_acquire( cur->cert, &pk ); if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); return( ret ); + } } #else /* Outside of ASYNC_PRIVATE, use private key context directly @@ -877,7 +880,10 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( cur->cert, &frame ); if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_frame_acquire", ret ); return( ret ); + } sig_md = frame->sig_md; mbedtls_x509_crt_frame_release( cur->cert ); } @@ -2999,7 +3005,10 @@ static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) mbedtls_x509_crt_frame const *frame; ret = mbedtls_x509_crt_frame_acquire( crt, &frame ); if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_frame_acquire", ret ); return( ret ); + } dn_size = frame->subject_raw.len; @@ -4247,9 +4256,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) &peer_pk ); if( ret != 0 ) { - /* Should never happen */ - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); + return( ret ); } } #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 560ef4c07..f1075cbf1 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6507,7 +6507,10 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, mbedtls_pk_context *pk; ret = mbedtls_x509_crt_pk_acquire( chain, &pk ); if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_x509_crt_pk_acquire", ret ); return( ret ); + } /* If certificate uses an EC key, make sure the curve is OK */ if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) ) From b653aa3d16d53ea3f00b36a8433d92af8b543385 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:53:55 +0100 Subject: [PATCH 131/140] Don't mention pk_sign() in the context of public-key contexts --- include/mbedtls/x509_crt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 293a710ed..6db9bc9fa 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -904,8 +904,8 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) * in a thread-safe way. In particular, the caller must only * use the context with functions which are `const` on the input * context, or those which are known to be thread-safe. The latter - * for example includes mbedtls_pk_sign() and mbedtls_pk_verify() - * for ECC or RSA public key contexts. + * for example includes mbedtls_pk_verify() for ECC or RSA public + * key contexts. * * \return \c 0 on success. In this case, `*pk_ptr` is updated * to hold the address of a public key context for the given From 94a94f6c33a9c884cb5acac6e617ecf576499662 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 13:43:33 +0100 Subject: [PATCH 132/140] Remove memory buffer alloc from i386 test in all.sh Otherwise, the CI fails this test due to timeout. The buffer allocator is tested e.g. in test_full_cmake_clang(). --- tests/scripts/all.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index b884e20cf..7ae1bc5c0 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -1024,6 +1024,9 @@ component_test_m32_o0 () { # Build once with -O0, to compile out the i386 specific inline assembly msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s scripts/config.pl full + scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE + scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C + scripts/config.pl unset MBEDTLS_MEMORY_DEBUG make CC=gcc PTHREAD=1 CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address' msg "test: i386, make, gcc -O0 (ASan build)" From a4bfaa8204826fb6f50a5fa2dd3e63f629659622 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 10:34:23 +0100 Subject: [PATCH 133/140] Make X.509 CRT cache reference counting unconditional Previously, reference counting for the CRT frames and PK contexts handed out by mbedtls_x509_crt_{frame|pk}_acquire() was implemented only in case threading support was enabled, which leaves the door open for a potential use-after-free should a single-threaded application use nested calls to mbedtls_x509_crt_acquire(). Since Mbed TLS itself does not use such nested calls, it might be preferred long-term to forbid nesting of acquire calls on the API level, and hence get rid of reference counting in the interest of code-size benefits. However, this can be considered as an optimization of X.509 on demand parsing, and for now this commit introduces reference counting unconditionally to have a safe version of on demand parsing to build further optimizations upon. --- include/mbedtls/x509_crt.h | 16 ++++++++-------- include/mbedtls/x509_internal.h | 2 +- library/x509_crt.c | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 6db9bc9fa..85943c7b3 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -831,19 +831,17 @@ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ if( crt->cache->frame_readers == 0 ) -#endif /* MBEDTLS_THREADING_C */ - { ret = mbedtls_x509_crt_cache_provide_frame( crt ); - } -#if defined(MBEDTLS_THREADING_C) if( crt->cache->frame_readers == MBEDTLS_X509_CACHE_FRAME_READERS_MAX ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->frame_readers++; +#if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ @@ -864,12 +862,14 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ if( crt->cache->frame_readers == 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->frame_readers--; +#if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->frame_mutex ); #endif /* MBEDTLS_THREADING_C */ @@ -919,19 +919,17 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ if( crt->cache->pk_readers == 0 ) -#endif /* MBEDTLS_THREADING_C */ - { ret = mbedtls_x509_crt_cache_provide_pk( crt ); - } -#if defined(MBEDTLS_THREADING_C) if( crt->cache->pk_readers == MBEDTLS_X509_CACHE_PK_READERS_MAX ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->pk_readers++; +#if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ @@ -952,12 +950,14 @@ static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* MBEDTLS_THREADING_C */ if( crt->cache->pk_readers == 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->pk_readers--; +#if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->pk_mutex ); #endif /* MBEDTLS_THREADING_C */ diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index bed9772e3..77291089f 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -37,9 +37,9 @@ struct mbedtls_x509_crt_frame; #define MBEDTLS_X509_CACHE_FRAME_READERS_MAX ((uint32_t) -1) typedef struct mbedtls_x509_crt_cache { -#if defined(MBEDTLS_THREADING_C) uint32_t frame_readers; uint32_t pk_readers; +#if defined(MBEDTLS_THREADING_C) mbedtls_threading_mutex_t frame_mutex; mbedtls_threading_mutex_t pk_mutex; #endif diff --git a/library/x509_crt.c b/library/x509_crt.c index c601686f9..fa5124147 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -112,10 +112,9 @@ int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); - +#endif /* Can only free the PK context if nobody is using it. */ if( crt->cache->pk_readers == 0 ) -#endif { #if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) /* The cache holds a shallow copy of the PK context @@ -140,10 +139,10 @@ int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ) #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif /* Can only free the frame if nobody is using it. */ if( crt->cache->frame_readers == 0 ) -#endif { mbedtls_free( crt->cache->frame ); crt->cache->frame = NULL; From fc99a09cc4713ee3b6f9a2557330d4354f1b0d85 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 14:45:26 +0100 Subject: [PATCH 134/140] Don't allow nested CRT acquire()-calls if MBEDTLS_X509_ALWAYS_FLUSH Forbidding nested calls to acquire() allows to remove the reference counting logic and hence saving some bytes of code. This is valuable because MBEDTLS_X509_ALWAYS_FLUSH is likely to be used on constrained systems where code-size is limited. --- include/mbedtls/x509_crt.h | 28 +++++++++++++++++++++++++ include/mbedtls/x509_internal.h | 3 +++ library/x509_crt.c | 37 +++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 85943c7b3..692bfe4f2 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -820,6 +820,11 @@ int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt ); * as \p crt is valid and mbedtls_x509_crt_frame_release() hasn't * been issued. * + * \note In a single-threaded application using + * MBEDTLS_X509_ALWAYS_FLUSH, nested calls to this function + * are not allowed and will fail gracefully with + * MBEDTLS_ERR_X509_FATAL_ERROR. + * * \return \c 0 on success. In this case, `*frame_ptr` is updated * to hold the address of a frame for the given CRT. * \return A negative error code on failure. @@ -833,13 +838,19 @@ static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt, return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->frame_readers == 0 ) +#endif ret = mbedtls_x509_crt_cache_provide_frame( crt ); +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->frame_readers == MBEDTLS_X509_CACHE_FRAME_READERS_MAX ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->frame_readers++; +#endif #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 ) @@ -864,10 +875,13 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->frame_readers == 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->frame_readers--; +#endif #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->frame_mutex ); @@ -907,6 +921,11 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) * for example includes mbedtls_pk_verify() for ECC or RSA public * key contexts. * + * \note In a single-threaded application using + * MBEDTLS_X509_ALWAYS_FLUSH, nested calls to this function + * are not allowed and will fail gracefully with + * MBEDTLS_ERR_X509_FATAL_ERROR. + * * \return \c 0 on success. In this case, `*pk_ptr` is updated * to hold the address of a public key context for the given * certificate. @@ -921,13 +940,19 @@ static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt const *crt, return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->pk_readers == 0 ) +#endif ret = mbedtls_x509_crt_cache_provide_pk( crt ); +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->pk_readers == MBEDTLS_X509_CACHE_PK_READERS_MAX ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->pk_readers++; +#endif #if defined(MBEDTLS_THREADING_C) if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 ) @@ -952,10 +977,13 @@ static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif /* MBEDTLS_THREADING_C */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) if( crt->cache->pk_readers == 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); crt->cache->pk_readers--; +#endif #if defined(MBEDTLS_THREADING_C) mbedtls_mutex_unlock( &crt->cache->pk_mutex ); diff --git a/include/mbedtls/x509_internal.h b/include/mbedtls/x509_internal.h index 77291089f..6ca3db590 100644 --- a/include/mbedtls/x509_internal.h +++ b/include/mbedtls/x509_internal.h @@ -37,8 +37,11 @@ struct mbedtls_x509_crt_frame; #define MBEDTLS_X509_CACHE_FRAME_READERS_MAX ((uint32_t) -1) typedef struct mbedtls_x509_crt_cache { +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) uint32_t frame_readers; uint32_t pk_readers; +#endif /* !MBEDTLS_X509_ALWAYS_FLUSH || MBEDTLS_THREADING_C */ #if defined(MBEDTLS_THREADING_C) mbedtls_threading_mutex_t frame_mutex; mbedtls_threading_mutex_t pk_mutex; diff --git a/library/x509_crt.c b/library/x509_crt.c index fa5124147..4f33d211d 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -113,8 +113,17 @@ int mbedtls_x509_crt_flush_cache_pk( mbedtls_x509_crt const *crt ) if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - /* Can only free the PK context if nobody is using it. */ + +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) + /* Can only free the PK context if nobody is using it. + * If MBEDTLS_X509_ALWAYS_FLUSH is set, nested uses + * of xxx_acquire() are prohibited, and no reference + * counting is needed. Also, notice that the code-path + * below is safe if the cache isn't filled. */ if( crt->cache->pk_readers == 0 ) +#endif /* !MBEDTLS_X509_ALWAYS_FLUSH || + MBEDTLS_THREADING_C */ { #if !defined(MBEDTLS_X509_ON_DEMAND_PARSING) /* The cache holds a shallow copy of the PK context @@ -141,8 +150,16 @@ int mbedtls_x509_crt_flush_cache_frame( mbedtls_x509_crt const *crt ) return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); #endif - /* Can only free the frame if nobody is using it. */ +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) + /* Can only free the PK context if nobody is using it. + * If MBEDTLS_X509_ALWAYS_FLUSH is set, nested uses + * of xxx_acquire() are prohibited, and no reference + * counting is needed. Also, notice that the code-path + * below is safe if the cache isn't filled. */ if( crt->cache->frame_readers == 0 ) +#endif /* !MBEDTLS_X509_ALWAYS_FLUSH || + MBEDTLS_THREADING_C */ { mbedtls_free( crt->cache->frame ); crt->cache->frame = NULL; @@ -175,7 +192,15 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) mbedtls_x509_crt_frame *frame; if( cache->frame != NULL ) + { +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) return( 0 ); +#else + /* If MBEDTLS_X509_ALWAYS_FLUSH is set, we don't + * allow nested uses of acquire. */ + return( MBEDTLS_ERR_X509_FATAL_ERROR ); +#endif + } frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) ); if( frame == NULL ) @@ -227,7 +252,15 @@ int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) mbedtls_pk_context *pk; if( cache->pk != NULL ) + { +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) return( 0 ); +#else + /* If MBEDTLS_X509_ALWAYS_FLUSH is set, we don't + * allow nested uses of acquire. */ + return( MBEDTLS_ERR_X509_FATAL_ERROR ); +#endif + } pk = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) ); if( pk == NULL ) From 69c303360e11b5946d8665fb1aa0f1a0c4eba232 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 15:47:53 +0100 Subject: [PATCH 135/140] Don't return threading error on release()-without-acquire() calls Previously, a call to mbedtls_x509_crt_xxx_release() would return MBEDTLS_ERR_THREADING_MUTEX_ERROR if usage counter for the frame/PK was 0. Now that resource counting can also be used outside of threading support, this is no longer adequate, and this commit changes the return code to MBEDTLS_ERR_X509_FATAL_ERROR; while generic, this at least matches the top-level module. --- include/mbedtls/x509_crt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index 692bfe4f2..3eee460fb 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -878,7 +878,7 @@ static inline int mbedtls_x509_crt_frame_release( mbedtls_x509_crt const *crt ) #if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ defined(MBEDTLS_THREADING_C) if( crt->cache->frame_readers == 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + return( MBEDTLS_ERR_X509_FATAL_ERROR ); crt->cache->frame_readers--; #endif @@ -980,7 +980,7 @@ static inline int mbedtls_x509_crt_pk_release( mbedtls_x509_crt const *crt ) #if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ defined(MBEDTLS_THREADING_C) if( crt->cache->pk_readers == 0 ) - return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + return( MBEDTLS_ERR_X509_FATAL_ERROR ); crt->cache->pk_readers--; #endif From 7ab8a2e2a0986708edd7603fe937024b4cc2e271 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 28 Jun 2019 15:52:54 +0100 Subject: [PATCH 136/140] Add X.509 CRT test for nested calls for CRT frame / PK acquire --- tests/suites/test_suite_x509parse.data | 4 + tests/suites/test_suite_x509parse.function | 93 ++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index f8d787533..6536cc9c7 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -935,6 +935,10 @@ X509 Parse Selftest depends_on:MBEDTLS_SHA1_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_CERTS_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15 x509_selftest: +X509 nested acquire +depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C +x509_nested_acquire:"308196308180a0030201008204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffff300d06092a864886f70d01010b0500030200ff" + X509 CRT ASN1 (Empty Certificate) x509parse_crt:"":"":MBEDTLS_ERR_X509_INVALID_FORMAT diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index 2df187de0..25b0d7f8f 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -597,6 +597,99 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */ +void x509_nested_acquire( data_t * buf ) +{ + /* This tests exercises the behavior of the library when + * facing nested calls to mbedtls_x509_crt_xxx_acquire(). + * This is allowed if !MBEDTLS_X509_ALWAYS_FLUSH or + * MBEDTLS_THREADING_C, but forbidden otherwise. */ + + mbedtls_x509_crt crt; + mbedtls_x509_crt_init( &crt ); + TEST_ASSERT( mbedtls_x509_crt_parse_der( &crt, buf->x, buf->len ) == 0 ); + + /* Nested aquire for CRT frames */ + { + int ret; + mbedtls_x509_crt_frame const *frame1; + mbedtls_x509_crt_frame const *frame2; + + /* Perform a (hopefully) innocent acquire-release pair first. */ + + TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 ); + + /* Perform two nested acquire calls. */ + + TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 ); + + ret = mbedtls_x509_crt_frame_acquire( &crt, &frame2 ); +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR ); +#else + TEST_ASSERT( ret == 0 ); + TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 ); +#endif + + TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 ); + + ret = mbedtls_x509_crt_frame_release( &crt ); + + /* In contexts which use resource counting, we expect an + * error on an attempted release() without prior acquire(). */ +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + TEST_ASSERT( ret == 0 ); +#else + TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR ); +#endif + } + + /* Nested aquire for PK contexts */ + { + int ret; + mbedtls_pk_context *pk1; + mbedtls_pk_context *pk2; + + /* Perform a (hopefully) innocent acquire-release pair first. */ + + TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 ); + TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 ); + + /* Perform two nested acquire calls. */ + + TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 ); + + ret = mbedtls_x509_crt_pk_acquire( &crt, &pk2 ); +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR ); +#else + TEST_ASSERT( ret == 0 ); + TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 ); +#endif + + TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 ); + + ret = mbedtls_x509_crt_pk_release( &crt ); + + /* In contexts which use resource counting, we expect an + * error on an attempted release() without prior acquire(). */ +#if defined(MBEDTLS_X509_ALWAYS_FLUSH) && \ + !defined(MBEDTLS_THREADING_C) + TEST_ASSERT( ret == 0 ); +#else + TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR ); +#endif + } + +exit: + mbedtls_x509_crt_free( &crt ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_X509_CRL_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */ void x509parse_crl( data_t * buf, char * result_str, int result ) { From 410322f23e16c17a6bc42b93801ade286c0ad190 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 2 Jul 2019 13:37:12 +0100 Subject: [PATCH 137/140] Fix guard controlling whether nested acquire calls are allowed Resource counting as a safe-guard against nested acquire calls is implemented if and only if MBEDTLS_X509_ALWAYS_FLUSH is disabled _or_ MBEDTLS_THREADING_C is enabled. --- library/x509_crt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/x509_crt.c b/library/x509_crt.c index 4f33d211d..59898f724 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -193,7 +193,8 @@ int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt ) if( cache->frame != NULL ) { -#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) return( 0 ); #else /* If MBEDTLS_X509_ALWAYS_FLUSH is set, we don't @@ -253,7 +254,8 @@ int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt ) if( cache->pk != NULL ) { -#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) +#if !defined(MBEDTLS_X509_ALWAYS_FLUSH) || \ + defined(MBEDTLS_THREADING_C) return( 0 ); #else /* If MBEDTLS_X509_ALWAYS_FLUSH is set, we don't From bc6b59859fe12c77500a5a05dd8b227077df1ca2 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 2 Jul 2019 15:36:44 +0100 Subject: [PATCH 138/140] [Fixup] Add missing PK release call in Cert Verify parsing mbedtls_ssl_read() can fail non-fatally, in which case ssl_parse_certificate_verify() returned immediately without calling mbedtls_x509_crt_pk_release(), which in turn lead to a fatal error because of nested acquire calls in the next call to the function. --- library/ssl_srv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 9e15f756a..40f8e0663 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -4274,7 +4274,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) if( 0 != ret ) { MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record" ), ret ); - return( ret ); + goto exit; } ssl->state++; @@ -4284,7 +4284,8 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); - return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY; + goto exit; } i = mbedtls_ssl_hs_hdr_len( ssl ); From 3aa121660ea80297430bddd08dea687e61e82fa1 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 2 Jul 2019 16:47:40 +0100 Subject: [PATCH 139/140] Add comment about X.509 name comparison of buffer with itself --- library/x509_crt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/x509_crt.c b/library/x509_crt.c index 59898f724..61e4a9e22 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1283,6 +1283,7 @@ static int x509_crt_parse_frame( unsigned char *start, p += len; frame->issuer_raw.len = p - frame->issuer_raw.p; + /* Comparing the raw buffer to itself amounts to structural validation. */ ret = mbedtls_x509_name_cmp_raw( &frame->issuer_raw, &frame->issuer_raw, NULL, NULL ); @@ -1313,6 +1314,7 @@ static int x509_crt_parse_frame( unsigned char *start, p += len; frame->subject_raw.len = p - frame->subject_raw.p; + /* Comparing the raw buffer to itself amounts to structural validation. */ ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw, &frame->subject_raw, NULL, NULL ); From b1d720c016a7c01f0a81de41b47aa36be87bbf47 Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Tue, 2 Jul 2019 16:47:57 +0100 Subject: [PATCH 140/140] Remove superfluous new line in x509.c --- library/x509.c | 1 - 1 file changed, 1 deletion(-) diff --git a/library/x509.c b/library/x509.c index f1c96a827..89645a755 100644 --- a/library/x509.c +++ b/library/x509.c @@ -433,7 +433,6 @@ static int x509_set_sequence_iterate( unsigned char **p, unsigned char const *end, mbedtls_x509_buf *oid, mbedtls_x509_buf *val ) - { int ret; size_t set_len;