diff --git a/library/x509_crt.c b/library/x509_crt.c index 3fb2b686e..cb63b13d5 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1766,7 +1766,8 @@ static int x509_crt_check_parent( const x509_crt *child, static int x509_crt_verify_top( x509_crt *child, x509_crt *trust_ca, - x509_crl *ca_crl, int path_cnt, int *flags, + x509_crl *ca_crl, + int path_cnt, int self_cnt, int *flags, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ) { @@ -1815,8 +1816,9 @@ static int x509_crt_verify_top( check_path_cnt--; } + /* Self signed certificates do not count towards the limit */ if( trust_ca->max_pathlen > 0 && - trust_ca->max_pathlen < check_path_cnt ) + trust_ca->max_pathlen < check_path_cnt - self_cnt ) { continue; } @@ -1881,8 +1883,9 @@ static int x509_crt_verify_top( } static int x509_crt_verify_child( - x509_crt *child, x509_crt *parent, x509_crt *trust_ca, - x509_crl *ca_crl, int path_cnt, int *flags, + x509_crt *child, x509_crt *parent, + x509_crt *trust_ca, x509_crl *ca_crl, + int path_cnt, int self_cnt, int *flags, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ) { @@ -1892,6 +1895,10 @@ static int x509_crt_verify_child( x509_crt *grandparent; const md_info_t *md_info; + /* Counting intermediate self signed certificates */ + if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + self_cnt++; + /* path_cnt is 0 for the first intermediate CA */ if( 1 + path_cnt > POLARSSL_X509_MAX_INTERMEDIATE_CA ) { @@ -1943,7 +1950,7 @@ static int x509_crt_verify_child( if( grandparent != NULL ) { ret = x509_crt_verify_top( parent, grandparent, ca_crl, - path_cnt + 1, &parent_flags, f_vrfy, p_vrfy ); + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } @@ -1954,6 +1961,15 @@ static int x509_crt_verify_child( grandparent != NULL; grandparent = grandparent->next ) { + /* +2 because the current step is not yet accounted for + * and because max_pathlen is one higher than it should be. + * Also self signed certificates do not count to the limit. */ + if( grandparent->max_pathlen > 0 && + grandparent->max_pathlen < 2 + path_cnt - self_cnt ) + { + continue; + } + if( x509_crt_check_parent( parent, grandparent, 0, path_cnt == 0 ) == 0 ) break; @@ -1963,7 +1979,7 @@ static int x509_crt_verify_child( if( grandparent != NULL ) { ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, - path_cnt + 1, &parent_flags, + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); @@ -1971,7 +1987,7 @@ static int x509_crt_verify_child( else { ret = x509_crt_verify_top( parent, trust_ca, ca_crl, - path_cnt + 1, &parent_flags, + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); @@ -2001,6 +2017,7 @@ int x509_crt_verify( x509_crt *crt, size_t cn_len; int ret; int pathlen = 0; + int selfsigned = 0; x509_crt *parent; x509_name *name; x509_sequence *cur = NULL; @@ -2067,7 +2084,7 @@ int x509_crt_verify( x509_crt *crt, if( parent != NULL ) { ret = x509_crt_verify_top( crt, parent, ca_crl, - pathlen, flags, f_vrfy, p_vrfy ); + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } @@ -2076,6 +2093,14 @@ int x509_crt_verify( x509_crt *crt, /* Look for a parent upwards the chain */ for( parent = crt->next; parent != NULL; parent = parent->next ) { + /* +2 because the current step is not yet accounted for + * and because max_pathlen is one higher than it should be */ + if( parent->max_pathlen > 0 && + parent->max_pathlen < 2 + pathlen ) + { + continue; + } + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) break; } @@ -2084,14 +2109,14 @@ int x509_crt_verify( x509_crt *crt, if( parent != NULL ) { ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, - pathlen, flags, f_vrfy, p_vrfy ); + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } else { ret = x509_crt_verify_top( crt, trust_ca, ca_crl, - pathlen, flags, f_vrfy, p_vrfy ); + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); }