diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index b927e8d108..88fcddceae 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -287,6 +287,9 @@ 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_serial_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ); +int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len ); +int mbedtls_x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ); int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, mbedtls_x509_name *cur ); int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, diff --git a/library/x509.c b/library/x509.c index 371d6da1dc..1b3b684098 100644 --- a/library/x509.c +++ b/library/x509.c @@ -898,6 +898,103 @@ int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) 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 ); +} + #if defined(MBEDTLS_HAVE_TIME_DATE) /* * Set the time structure to the current time. diff --git a/library/x509_crt.c b/library/x509_crt.c index 056e46308b..67cf44574e 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1943,35 +1943,6 @@ static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, } #endif /* MBEDTLS_X509_CRL_PARSE_C */ -/* - * 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 */ @@ -1996,7 +1967,7 @@ static int x509_check_wildcard( const char *cn, 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 ); } @@ -2004,74 +1975,6 @@ static int x509_check_wildcard( const char *cn, 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 ); -} - /* * Check if 'parent' is a suitable parent (signing CA) for 'child'. * Return 0 if yes, -1 if not. @@ -2086,7 +1989,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 */ @@ -2276,7 +2179,7 @@ static int x509_crt_verify_child( const mbedtls_md_info_t *md_info; /* Counting intermediate self signed certificates */ - if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + if( ( path_cnt != 0 ) && mbedtls_x509_name_cmp( &child->issuer, &child->subject ) == 0 ) self_cnt++; /* path_cnt is 0 for the first intermediate CA */ @@ -2447,7 +2350,7 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, while( cur != NULL ) { if( cur->buf.len == cn_len && - x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) + mbedtls_x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) break; if( cur->buf.len > 2 && @@ -2470,7 +2373,7 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) { if( name->val.len == cn_len && - x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) + mbedtls_x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) break; if( name->val.len > 2 && diff --git a/library/x509_ocsp.c b/library/x509_ocsp.c index a21769f152..fb61a06ff4 100644 --- a/library/x509_ocsp.c +++ b/library/x509_ocsp.c @@ -1192,11 +1192,68 @@ static int x509_ocsp_verify_response_status( mbedtls_x509_ocsp_response *resp, } } +static int x509_ocsp_mdcmp( mbedtls_md_type_t md_alg, unsigned char *input, + size_t len, unsigned char *output ) +{ + int ret; + const mbedtls_md_info_t *md_info; + unsigned char *buf; + size_t md_len; + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + + md_len = mbedtls_md_get_size( md_info ); + + if( ( buf = mbedtls_calloc( md_len, sizeof( unsigned char ) ) ) == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + if( ( ret = mbedtls_md( md_info, input, len, buf ) ) != 0 ) + goto exit; + + /* Check whether the hash matches the expected value */ + ret = ( memcmp( buf, output, md_len ) != 0 ) ? 1 : 0; + +exit: + mbedtls_free( buf ); + + return( ret ); +} + static int x509_ocsp_is_issuer( mbedtls_x509_ocsp_responder_id *responder_id, mbedtls_x509_crt *crt, mbedtls_x509_crt **issuer ) { - return( 0 ) + int ret; + + switch( responder_id->type ) + { + case MBEDTLS_X509_OCSP_RESPONDER_ID_TYPE_NAME: + /* Compare the responderID with the candidate issuer's subject */ + if( mbedtls_x509_name_cmp( &responder_id->id.name, + &crt->subject ) == 0 ) + { + *issuer = crt; + } + + return( 0 ); + + case MBEDTLS_X509_OCSP_RESPONDER_ID_TYPE_KEY_HASH: + /* Check hash of the certificate issuer's public key matches */ + ret = x509_ocsp_mdcmp( MBEDTLS_MD_SHA1, crt->pk_raw.p, + crt->pk_raw.len, responder_id->id.key.p ); + if( ret < 0 ) + return( ret ); + else if( ret == 0 ) + *issuer = crt; + else + *issuer = NULL; + + return( 0 ); + + default: + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } } /*