CVE-2017-14032: Improper Authentication (CWE-287)
value: ARM mbed TLS before 1.3.21 and 2.x before 2.1.9, if optional authentication is configured, allows remote attackers to bypass peer authentication via an X.509 certificate chain with many intermediates. NOTE: although mbed TLS was formerly known as PolarSSL, the releases shipped with the PolarSSL name are not affected.
CWE description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
CVSS v3 base score: 8.1
Published: 2017-08-30T20:29Z
Repository: https://github.com/ARMmbed/mbedtls
Language: Other
Files changed: ChangeLog, library/x509_crt.c, tests/suites/test_suite_x509parse.data
Commit date: 2017-07-06 11:58:41 +0200
Commit message: Improve behaviour on fatal errors

If we didn't walk the whole chain, then there may be any kind of errors in the
part of the chain we didn't check, so setting all flags looks like the safe
thing to do.

Diff: diff --git a/ChangeLog b/ChangeLog
index 2f0116bc..9bf6a171 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,14 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
+= mbed TLS 2.y.z released YYYY-MM-DD
+
+Changes
+   * Certificate verification functions now set flags to -1 in case the full
+     chain was not verified due to an internal error (including in the verify
+     callback) or chain length limitations.
+
 = mbed TLS 2.5.1 released 2017-06-21
 
 Security
    * Fixed unlimited overread of heap-based buffer in mbedtls_ssl_read().
      The issue could only happen client-side with renegotiation enabled.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index d86857de..ee5f27e4 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -2200,15 +2200,18 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
     mbedtls_x509_crt *parent;
     mbedtls_x509_name *name;
     mbedtls_x509_sequence *cur = NULL;
     mbedtls_pk_type_t pk_type;
 
-    if( profile == NULL )
-        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
-
     *flags = 0;
 
+    if( profile == NULL )
+    {
+        ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
+        goto exit;
+    }
+
     if( cn != NULL )
     {
         name = &crt->subject;
         cn_len = strlen( cn );
 
@@ -2278,11 +2281,11 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
     if( parent != NULL )
     {
         ret = x509_crt_verify_top( crt, parent, ca_crl, profile,
                                    pathlen, selfsigned, flags, f_vrfy, p_vrfy );
         if( ret != 0 )
-            return( ret );
+            goto exit;
     }
     else
     {
         /* Look for a parent upwards the chain */
         for( parent = crt->next; parent != NULL; parent = parent->next )
@@ -2293,21 +2296,28 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
         if( parent != NULL )
         {
             ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile,
                                          pathlen, selfsigned, flags, f_vrfy, p_vrfy );
             if( ret != 0 )
-                return( ret );
+                goto exit;
         }
         else
         {
             ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile,
                                        pathlen, selfsigned, flags, f_vrfy, p_vrfy );
             if( ret != 0 )
-                return( ret );
+                goto exit;
         }
     }
 
+exit:
+    if( ret != 0 )
+    {
+        *flags = (uint32_t) -1;
+        return( ret );
+    }
+
     if( *flags != 0 )
         return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED );
 
     return( 0 );
 }
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 9d3108ab..6df52987 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1202,11 +1202,11 @@ X509 CRT verify long chain (max intermediate CA, untrusted)
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED
 mbedtls_x509_crt_verify_max:"data_files/test-ca2.crt":"data_files/dir-maxpath":MBEDTLS_X509_MAX_INTERMEDIATE_CA-1:MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_NOT_TRUSTED
 
 X509 CRT verify long chain (max intermediate CA + 1)
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
-mbedtls_x509_crt_verify_max:"data_files/dir-maxpath/00.crt":"data_files/dir-maxpath":MBEDTLS_X509_MAX_INTERMEDIATE_CA+1:MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:0
+mbedtls_x509_crt_verify_max:"data_files/dir-maxpath/00.crt":"data_files/dir-maxpath":MBEDTLS_X509_MAX_INTERMEDIATE_CA+1:MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:-1
 
 X509 CRT verify chain #1 (zero pathlen intermediate)
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
 mbedtls_x509_crt_verify_chain:"data_files/dir4/cert14.crt data_files/dir4/cert13.crt data_files/dir4/cert12.crt":"data_files/dir4/cert11.crt":MBEDTLS_X509_BADCERT_NOT_TRUSTED
 

Vulnerable code:     if( profile == NULL )
        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );

            return( ret );
                return( ret );
                return( ret );
mbedtls_x509_crt_verify_max:"data_files/dir-maxpath/00.crt":"data_files/dir-maxpath":MBEDTLS_X509_MAX_INTERMEDIATE_CA+1:MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:0
Fixed code: = mbed TLS 2.y.z released YYYY-MM-DD

Changes
   * Certificate verification functions now set flags to -1 in case the full
     chain was not verified due to an internal error (including in the verify
     callback) or chain length limitations.

    if( profile == NULL )
    {
        ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
        goto exit;
    }

            goto exit;
                goto exit;
                goto exit;
exit:
    if( ret != 0 )
    {
        *flags = (uint32_t) -1;
        return( ret );
    }

mbedtls_x509_crt_verify_max:"data_files/dir-maxpath/00.crt":"data_files/dir-maxpath":MBEDTLS_X509_MAX_INTERMEDIATE_CA+1:MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:-1