1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
Description: Fix CVE-2017-14032: authentication bypass
If a malicious peer supplies an X.509 certificate chain that has more
than MBEDTLS_X509_MAX_INTERMEDIATE_CA intermediates (which by default is
8), it could bypass authentication of the certificates, when the
authentication mode was set to 'optional' eg.
MBEDTLS_SSL_VERIFY_OPTIONAL. The issue could be triggered remotely by
both the client and server sides.
.
Fix by backporting two patches from the upstream 2.6 branch:
d15795acd507 = Improve behaviour on fatal errors
31458a18788b = Only return VERIFY_FAILED from a single point
Author: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
Origin: backport, https://github.com/ARMmbed/mbedtls/commit/d15795acd5074e0b44e71f7ede8bdfe1b48591fc
Origin: backport, https://github.com/ARMmbed/mbedtls/commit/31458a18788b0cf0b722acda9bb2f2fe13a3fb32
Bug-Debian: https://bugs.debian.org/873557
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -2055,8 +2055,8 @@ static int x509_crt_verify_child(
/* path_cnt is 0 for the first intermediate CA */
if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
{
- *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
- return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED );
+ /* return immediately as the goal is to avoid unbounded recursion */
+ return( MBEDTLS_ERR_X509_FATAL_ERROR );
}
if( mbedtls_x509_time_is_past( &child->valid_to ) )
@@ -2200,11 +2200,14 @@ int mbedtls_x509_crt_verify_with_profile
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;
@@ -2278,7 +2281,7 @@ int mbedtls_x509_crt_verify_with_profile
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
{
@@ -2293,17 +2296,28 @@ int mbedtls_x509_crt_verify_with_profile
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:
+ /* prevent misuse of the vrfy callback */
+ if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED )
+ ret = MBEDTLS_ERR_X509_FATAL_ERROR;
+
+ if( ret != 0 )
+ {
+ *flags = (uint32_t) -1;
+ return( ret );
+ }
+
if( *flags != 0 )
return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED );
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -71,7 +71,7 @@
* Name ID Nr of Errors
* PEM 1 9
* PKCS#12 1 4 (Started from top)
- * X509 2 19
+ * X509 2 20
* PKCS5 2 4 (Started from top)
* DHM 3 9
* PK 3 14 (Started from top)
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1042,7 +1042,7 @@ void mbedtls_ssl_conf_authmode( mbedtls_
*
* If set, the verify callback is called for each
* certificate in the chain. For implementation
- * information, please see \c x509parse_verify()
+ * information, please see \c mbedtls_x509_crt_verify()
*
* \param conf SSL configuration
* \param f_vrfy verification function
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -76,6 +76,7 @@
#define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */
#define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */
#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */
+#define MBEDTLS_ERR_X509_FATAL_ERROR -0x3000 /**< A fatal error occured, eg the chain is too long or the vrfy callback failed. */
/* \} name */
/**
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -267,7 +267,13 @@ int mbedtls_x509_crt_verify_info( char *
*
* All flags left after returning from the callback
* are also returned to the application. The function should
- * return 0 for anything but a fatal error.
+ * return 0 for anything (including invalid certificates)
+ * other than fatal error, as a non-zero return code
+ * immediately aborts the verification process. For fatal
+ * errors, a specific error code should be used (different
+ * from MBEDTLS_ERR_X509_CERT_VERIFY_FAILED which should not
+ * be returned at this point), or MBEDTLS_ERR_X509_FATAL_ERROR
+ * can be used if no better code is available.
*
* \note In case verification failed, the results can be displayed
* using \c mbedtls_x509_crt_verify_info()
--- a/library/error.c
+++ b/library/error.c
@@ -480,6 +480,8 @@ void mbedtls_strerror( int ret, char *bu
mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" );
if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) )
mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" );
+ if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) )
+ mbedtls_snprintf( buf, buflen, "X509 - A fatal error occured, eg the chain is too long or the vrfy callback failed" );
#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
// END generated code
|