Merge remote-tracking branch 'origin/pr/2539' into development

Resolve conflicts by performing the following:
  - Ensure calls to mbedtls_x509_crt_verify_* are made with callbacks

* origin/pr/2539:
  Make CRT callback tests more robust
  Rename constant in client2.c
  Fix typo
  Add test for configuration specific CRT callback
  Fix doxygen documentation of mbedtls_ssl_set_verify()
  Add test exercising context-specific CRT callback to ssl-opt.sh
  Add cmd to use context-specific CRT callback in ssl_client2
  Implement context-specific verification callbacks
  Add context-specific CRT verification callbacks
  Improve documentation of mbedtls_ssl_conf_verify()
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 35e5764..135be05 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1094,6 +1094,12 @@
     unsigned badmac_seen;       /*!< records with a bad MAC received    */
 #endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+    /** Callback to customize X.509 certificate chain verification          */
+    int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *);
+    void *p_vrfy;                   /*!< context for X.509 verify callback */
+#endif
+
     mbedtls_ssl_send_t *f_send; /*!< Callback for network send */
     mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */
     mbedtls_ssl_recv_timeout_t *f_recv_timeout;
@@ -1370,13 +1376,17 @@
 /**
  * \brief          Set the verification callback (Optional).
  *
- *                 If set, the verify callback is called for each
- *                 certificate in the chain. For implementation
- *                 information, please see \c mbedtls_x509_crt_verify()
+ *                 If set, the provided verify callback is called for each
+ *                 certificate in the peer's CRT chain, including the trusted
+ *                 root. For more information, please see the documentation of
+ *                 \c mbedtls_x509_crt_verify().
  *
- * \param conf     SSL configuration
- * \param f_vrfy   verification function
- * \param p_vrfy   verification parameter
+ * \note           For per context callbacks and contexts, please use
+ *                 mbedtls_ssl_set_verify() instead.
+ *
+ * \param conf     The SSL configuration to use.
+ * \param f_vrfy   The verification callback to use during CRT verification.
+ * \param p_vrfy   The opaque context to be passed to the callback.
  */
 void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf,
                      int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
@@ -1494,6 +1504,30 @@
 void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+/**
+ * \brief          Set a connection-specific verification callback (optional).
+ *
+ *                 If set, the provided verify callback is called for each
+ *                 certificate in the peer's CRT chain, including the trusted
+ *                 root. For more information, please see the documentation of
+ *                 \c mbedtls_x509_crt_verify().
+ *
+ * \note           This call is analogous to mbedtls_ssl_conf_verify() but
+ *                 binds the verification callback and context to an SSL context
+ *                 as opposed to an SSL configuration.
+ *                 If mbedtls_ssl_conf_verify() and mbedtls_ssl_set_verify()
+ *                 are both used, mbedtls_ssl_set_verify() takes precedence.
+ *
+ * \param ssl      The SSL context to use.
+ * \param f_vrfy   The verification callback to use during CRT verification.
+ * \param p_vrfy   The opaque context to be passed to the callback.
+ */
+void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl,
+                     int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
+                     void *p_vrfy );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
 /**
  * \brief          Set the timeout period for mbedtls_ssl_read()
  *                 (Default: no timeout.)
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 09645cd..dac160d 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -6037,9 +6037,25 @@
         ssl->transform_negotiate->ciphersuite_info;
     int have_ca_chain = 0;
 
+    int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *);
+    void *p_vrfy;
+
     if( authmode == MBEDTLS_SSL_VERIFY_NONE )
         return( 0 );
 
+    if( ssl->f_vrfy != NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use context-specific verification callback" ) );
+        f_vrfy = ssl->f_vrfy;
+        p_vrfy = ssl->p_vrfy;
+    }
+    else
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use configuration-specific verification callback" ) );
+        f_vrfy = ssl->conf->f_vrfy;
+        p_vrfy = ssl->conf->p_vrfy;
+    }
+
     /*
      * Main check: verify certificate
      */
@@ -6057,7 +6073,7 @@
             ssl->conf->cert_profile,
             ssl->hostname,
             &ssl->session_negotiate->verify_result,
-            ssl->conf->f_vrfy, ssl->conf->p_vrfy );
+            f_vrfy, p_vrfy );
     }
     else
 #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
@@ -6087,7 +6103,7 @@
             ssl->conf->cert_profile,
             ssl->hostname,
             &ssl->session_negotiate->verify_result,
-            ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
+            f_vrfy, p_vrfy, rs_ctx );
     }
 
     if( ret != 0 )
@@ -7949,6 +7965,16 @@
 }
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl,
+                     int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
+                     void *p_vrfy )
+{
+    ssl->f_vrfy = f_vrfy;
+    ssl->p_vrfy = p_vrfy;
+}
+#endif
+
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
 /*
  * Set EC J-PAKE password for current handshake
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index f0c7164..2cddfb4 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -82,6 +82,7 @@
 #define DFL_REQUEST_PAGE        "/"
 #define DFL_REQUEST_SIZE        -1
 #define DFL_DEBUG_LEVEL         0
+#define DFL_CONTEXT_CRT_CB      0
 #define DFL_NBIO                0
 #define DFL_EVENT               0
 #define DFL_READ_TIMEOUT        0
@@ -131,6 +132,16 @@
 #define GET_REQUEST_END "\r\n\r\n"
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#define USAGE_CONTEXT_CRT_CB \
+    "    context_crt_cb=%%d   This determines whether the CRT verification callback is bound\n" \
+    "                        to the SSL configuration of the SSL context.\n" \
+    "                        Possible values:\n"\
+    "                        - 0 (default): Use CRT callback bound to configuration\n" \
+    "                        - 1: Use CRT callback bound to SSL context\n"
+#else
+#define USAGE_CONTEXT_CRT_CB ""
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
 #if defined(MBEDTLS_FS_IO)
 #define USAGE_IO \
     "    ca_file=%%s          The single file containing the top-level CA(s) you fully trust\n" \
@@ -339,6 +350,7 @@
     USAGE_TICKETS                                           \
     USAGE_MAX_FRAG_LEN                                      \
     USAGE_TRUNC_HMAC                                        \
+    USAGE_CONTEXT_CRT_CB                                    \
     USAGE_ALPN                                              \
     USAGE_FALLBACK                                          \
     USAGE_EMS                                               \
@@ -435,6 +447,7 @@
     int dgram_packing;          /* allow/forbid datagram packing            */
     int extended_ms;            /* negotiate extended master secret?        */
     int etm;                    /* negotiate encrypt then mac?              */
+    int context_crt_cb;         /* use context-specific CRT verify callback */
 } opt;
 
 int query_config( const char *config );
@@ -757,6 +770,7 @@
     opt.debug_level         = DFL_DEBUG_LEVEL;
     opt.nbio                = DFL_NBIO;
     opt.event               = DFL_EVENT;
+    opt.context_crt_cb      = DFL_CONTEXT_CRT_CB;
     opt.read_timeout        = DFL_READ_TIMEOUT;
     opt.max_resend          = DFL_MAX_RESEND;
     opt.request_page        = DFL_REQUEST_PAGE;
@@ -834,6 +848,12 @@
             if( opt.debug_level < 0 || opt.debug_level > 65535 )
                 goto usage;
         }
+        else if( strcmp( p, "context_crt_cb" ) == 0 )
+        {
+            opt.context_crt_cb = atoi( q );
+            if( opt.context_crt_cb != 0 && opt.context_crt_cb != 1 )
+                goto usage;
+        }
         else if( strcmp( p, "nbio" ) == 0 )
         {
             opt.nbio = atoi( q );
@@ -1590,7 +1610,9 @@
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
     }
 
-    mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+    if( opt.context_crt_cb == 0 )
+        mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+
     memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
@@ -1799,6 +1821,11 @@
     }
 #endif
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+    if( opt.context_crt_cb == 1 )
+        mbedtls_ssl_set_verify( &ssl, my_verify, NULL );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
     if( opt.nbio == 2 )
         mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv, NULL );
     else
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index ac717ab..a6d41b1 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1031,6 +1031,27 @@
             -u "IV used" \
             -U "IV used"
 
+# Tests for certificate verification callback
+run_test    "Configuration-specific CRT verification callback" \
+            "$P_SRV debug_level=3" \
+            "$P_CLI context_crt_cb=0 debug_level=3" \
+            0 \
+            -S "error" \
+            -c "Verify requested for " \
+            -c "Use configuration-specific verification callback" \
+            -C "Use context-specific verification callback" \
+            -C "error"
+
+run_test    "Context-specific CRT verification callback" \
+            "$P_SRV debug_level=3" \
+            "$P_CLI context_crt_cb=1 debug_level=3" \
+            0 \
+            -S "error" \
+            -c "Verify requested for " \
+            -c "Use context-specific verification callback" \
+            -C "Use configuration-specific verification callback" \
+            -C "error"
+
 # Tests for rc4 option
 
 requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES