+From e8bd647d8271174d3737dcf68086126b73a73df6 Mon Sep 17 00:00:00 2001
+From: Oleksii Beketov <ol.beketov@samsung.com>
+Date: Mon, 18 Dec 2017 15:23:28 +0200
+Subject: [PATCH] CVE-2017-14032
+
+Signed-off-by: Oleksii Beketov <ol.beketov@samsung.com>
+---
+ include/mbedtls/error.h | 2 +-
+ include/mbedtls/ssl.h | 2 +-
+ include/mbedtls/x509.h | 1 +
+ include/mbedtls/x509_crt.h | 8 +++++++-
+ library/error.c | 2 ++
+ library/x509_crt.c | 30 ++++++++++++++++++++++--------
+ 6 files changed, 34 insertions(+), 11 deletions(-)
+
+diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
+index 5e549f6..31591e2 100644
+--- 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)
+diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
+index 495e02c..4f171e0 100644
+--- a/include/mbedtls/ssl.h
++++ b/include/mbedtls/ssl.h
+@@ -1042,7 +1042,7 @@ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode );
+ *
+ * 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
+diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
+index f219bf1..128eade 100644
+--- 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 */
+
+ /**
+diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
+index 383e484..fd20336 100644
+--- a/include/mbedtls/x509_crt.h
++++ b/include/mbedtls/x509_crt.h
+@@ -267,7 +267,13 @@ int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix,
+ *
+ * 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()
+diff --git a/library/error.c b/library/error.c
+index dd2db0c..db42381 100644
+--- a/library/error.c
++++ b/library/error.c
+@@ -480,6 +480,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
+ 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
+
+diff --git a/library/x509_crt.c b/library/x509_crt.c
+index 234f145..1f31a6b 100644
+--- 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_crt *crt,
+ 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( mbedtls_x509_crt *crt,
+ 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( mbedtls_x509_crt *crt,
+ 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 );
+
+--
+1.9.1
+