From 2ed95279c026199e798418a1451bf1dabe425337 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 21 Jan 2022 18:02:17 -0500 Subject: [PATCH 1/6] Add server certificate selection callback https://github.com/ARMmbed/mbedtls/issues/5430 Signed-off-by: Glenn Strauss --- ChangeLog.d/mbedtls_ssl_cert_cb.txt | 3 +++ include/mbedtls/ssl.h | 26 ++++++++++++++++++++++++++ library/ssl_srv.c | 12 +++++++++++- library/ssl_tls.c | 8 ++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 ChangeLog.d/mbedtls_ssl_cert_cb.txt diff --git a/ChangeLog.d/mbedtls_ssl_cert_cb.txt b/ChangeLog.d/mbedtls_ssl_cert_cb.txt new file mode 100644 index 000000000000..89e9fdff7f96 --- /dev/null +++ b/ChangeLog.d/mbedtls_ssl_cert_cb.txt @@ -0,0 +1,3 @@ +Features + * Add server certificate selection callback near end of Client Hello. + Register callback with mbedtls_ssl_conf_cert_cb(). diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 7544f42637f0..0e93849db8c2 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1475,6 +1475,10 @@ struct mbedtls_ssl_config * access it afterwards. */ mbedtls_ssl_user_data_t MBEDTLS_PRIVATE(user_data); + +#if defined(MBEDTLS_SSL_SRV_C) + int (*MBEDTLS_PRIVATE(f_cert_cb))(mbedtls_ssl_context *); /*!< certificate selection callback */ +#endif /* MBEDTLS_SSL_SRV_C */ }; struct mbedtls_ssl_context @@ -2220,6 +2224,28 @@ void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, mbedtls_ssl_set_timer_t *f_set_timer, mbedtls_ssl_get_timer_t *f_get_timer ); +#if defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the certificate selection callback (server-side only). + * + * If set, the callback is always called for each handshake, + * after `ClientHello` processing has finished. + * + * The callback has the following parameters: + * - \c mbedtls_ssl_context*: The SSL context to which + * the operation applies. + * The return value of the callback is 0 if successful, + * or a specific MBEDTLS_ERR_XXX code, which will cause + * the handshake to be aborted. + * + * \param conf The SSL configuration to register the callback with. + * \param f_cert_cb The callback for selecting server certificate after + * `ClientHello` processing has finished. + */ +void mbedtls_ssl_conf_cert_cb( mbedtls_ssl_config *conf, + int (*f_cert_cb)(mbedtls_ssl_context *) ); +#endif /* MBEDTLS_SSL_SRV_C */ + /** * \brief Callback type: generate and write session ticket * diff --git a/library/ssl_srv.c b/library/ssl_srv.c index e9febfd84393..bd0982c3c919 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -1870,10 +1870,20 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE ); } + /* + * Server certification selection (after processing TLS extensions) + */ + if( ssl->conf->f_cert_cb && ( ret = ssl->conf->f_cert_cb( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cert_cb", ret ); + return( ret ); + } + /* * Search for a matching ciphersuite * (At the end because we need information from the EC-based extensions - * and certificate from the SNI callback triggered by the SNI extension.) + * and certificate from the SNI callback triggered by the SNI extension + * or certificate from server certificate selection callback.) */ got_common_suite = 0; ciphersuites = ssl->conf->ciphersuite_list; diff --git a/library/ssl_tls.c b/library/ssl_tls.c index adb18ab6c2f4..9d41cb42f023 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1232,6 +1232,14 @@ void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, mbedtls_ssl_set_timer( ssl, 0 ); } +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_cert_cb( mbedtls_ssl_config *conf, + int (*f_cert_cb)(mbedtls_ssl_context *) ) +{ + conf->f_cert_cb = f_cert_cb; +} +#endif /* MBEDTLS_SSL_SRV_C */ + #if defined(MBEDTLS_SSL_SRV_C) void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, void *p_cache, From 36872dbd0bf49de8371206b8de87fb5e917cc71c Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sat, 22 Jan 2022 05:06:31 -0500 Subject: [PATCH 2/6] Provide means to reset handshake cert list Extend mbedtls_ssl_set_hs_own_cert() to reset handshake cert list if cert provided is null. Previously, mbedtls_ssl_set_hs_own_cert() only provided a way to append to the handshake certificate list, without providing a way to replace the handshake certificate list. Signed-off-by: Glenn Strauss --- ChangeLog.d/mbedtls_ssl_cert_cb.txt | 2 ++ include/mbedtls/ssl.h | 3 ++ library/ssl_tls.c | 48 +++++++++++++--------------- tests/suites/test_suite_ssl.function | 9 ++++++ 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/ChangeLog.d/mbedtls_ssl_cert_cb.txt b/ChangeLog.d/mbedtls_ssl_cert_cb.txt index 89e9fdff7f96..9a00c547d21f 100644 --- a/ChangeLog.d/mbedtls_ssl_cert_cb.txt +++ b/ChangeLog.d/mbedtls_ssl_cert_cb.txt @@ -1,3 +1,5 @@ Features * Add server certificate selection callback near end of Client Hello. Register callback with mbedtls_ssl_conf_cert_cb(). + * Provide mechanism to reset handshake cert list by calling + mbedtls_ssl_set_hs_own_cert() with NULL value for own_cert param. diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 0e93849db8c2..d1fec95116c1 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3546,6 +3546,9 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); * \note Same as \c mbedtls_ssl_conf_own_cert() but for use within * the SNI callback. * + * \note Passing null \c own_cert clears the certificate list for + * the current handshake. + * * \param ssl SSL context * \param own_cert own public certificate chain * \param pk_key own private key diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 9d41cb42f023..089f239123f2 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1299,6 +1299,18 @@ void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, conf->cert_profile = profile; } +static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) +{ + mbedtls_ssl_key_cert *cur = key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } +} + /* Append a new keycert entry to a (possibly empty) list */ static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, mbedtls_x509_crt *cert, @@ -1306,6 +1318,14 @@ static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, { mbedtls_ssl_key_cert *new_cert; + if( cert == NULL ) + { + /* Free list if cert is null */ + ssl_key_cert_free( *head ); + *head = NULL; + return( 0 ); + } + new_cert = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); if( new_cert == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -1314,7 +1334,7 @@ static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, new_cert->key = key; new_cert->next = NULL; - /* Update head is the list was null, else add to the end */ + /* Update head if the list was null, else add to the end */ if( *head == NULL ) { *head = new_cert; @@ -2949,20 +2969,6 @@ int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_RENEGOTIATION */ -#if defined(MBEDTLS_X509_CRT_PARSE_C) -static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) -{ - mbedtls_ssl_key_cert *cur = key_cert, *next; - - while( cur != NULL ) - { - next = cur->next; - mbedtls_free( cur ); - cur = next; - } -} -#endif /* MBEDTLS_X509_CRT_PARSE_C */ - void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) { mbedtls_ssl_handshake_params *handshake = ssl->handshake; @@ -3050,17 +3056,7 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) * Free only the linked list wrapper, not the keys themselves * since the belong to the SNI callback */ - if( handshake->sni_key_cert != NULL ) - { - mbedtls_ssl_key_cert *cur = handshake->sni_key_cert, *next; - - while( cur != NULL ) - { - next = cur->next; - mbedtls_free( cur ); - cur = next; - } - } + ssl_key_cert_free( handshake->sni_key_cert ); #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 4f5ee9762d2d..0c8928f16a53 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -854,6 +854,15 @@ int mbedtls_endpoint_certificate_init( mbedtls_endpoint *ep, int pk_alg ) ret = mbedtls_ssl_conf_own_cert( &( ep->conf ), &( cert->cert ), &( cert->pkey ) ); TEST_ASSERT( ret == 0 ); + TEST_ASSERT( ep->conf.key_cert != NULL ); + + ret = mbedtls_ssl_conf_own_cert( &( ep->conf ), NULL, NULL ); + TEST_ASSERT( ret == 0 ); + TEST_ASSERT( ep->conf.key_cert == NULL ); + + ret = mbedtls_ssl_conf_own_cert( &( ep->conf ), &( cert->cert ), + &( cert->pkey ) ); + TEST_ASSERT( ret == 0 ); exit: if( ret != 0 ) From 698940726195eb543059a9701afc8cd18f075d50 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Mon, 24 Jan 2022 12:58:00 -0500 Subject: [PATCH 3/6] Add accessor to retrieve SNI during handshake Signed-off-by: Glenn Strauss --- ChangeLog.d/mbedtls_ssl_cert_cb.txt | 2 ++ include/mbedtls/ssl.h | 21 +++++++++++++++++++++ library/ssl_misc.h | 5 +++++ library/ssl_srv.c | 12 +++++++++--- library/ssl_tls.c | 7 +++++++ tests/ssl-opt.sh | 2 -- 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/ChangeLog.d/mbedtls_ssl_cert_cb.txt b/ChangeLog.d/mbedtls_ssl_cert_cb.txt index 9a00c547d21f..fcdc23cf0c19 100644 --- a/ChangeLog.d/mbedtls_ssl_cert_cb.txt +++ b/ChangeLog.d/mbedtls_ssl_cert_cb.txt @@ -3,3 +3,5 @@ Features Register callback with mbedtls_ssl_conf_cert_cb(). * Provide mechanism to reset handshake cert list by calling mbedtls_ssl_set_hs_own_cert() with NULL value for own_cert param. + * Add accessor mbedtls_ssl_get_hs_sni() to retrieve SNI from within + cert callback (mbedtls_ssl_conf_cert_cb()) during handshake. diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index d1fec95116c1..738f07bf54c6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3540,6 +3540,27 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +/** + * \brief Retrieve SNI extension value for the current handshake. + * Available in \p f_cert_cb of \c mbedtls_ssl_conf_cert_cb(), + * this is the same value passed to \p f_sni callback of + * \c mbedtls_ssl_conf_sni() and may be used instead of + * \c mbedtls_ssl_conf_sni(). + * + * \param ssl SSL context + * \param name_len pointer into which to store length of returned value. + * 0 if SNI extension is not present or not yet processed. + * + * \return const pointer to SNI extension value. + * - value is valid only when called in \p f_cert_cb + * registered with \c mbedtls_ssl_conf_cert_cb(). + * - value is NULL if SNI extension is not present. + * - value is not '\0'-terminated. Use \c name_len for len. + * - value must not be freed. + */ +const unsigned char *mbedtls_ssl_get_hs_sni( mbedtls_ssl_context *ssl, + size_t *name_len ); + /** * \brief Set own certificate and key for the current handshake * diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 0656439678d8..4ecf9155b215 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -849,6 +849,11 @@ struct mbedtls_ssl_handshake_params * The library does not use it internally. */ void *user_async_ctx; #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + const unsigned char *sni_name; /*!< raw SNI */ + size_t sni_name_len; /*!< raw SNI len */ +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ }; typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer; diff --git a/library/ssl_srv.c b/library/ssl_srv.c index bd0982c3c919..c757ac803d31 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -118,6 +118,11 @@ static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) { + ssl->handshake->sni_name = p + 3; + ssl->handshake->sni_name_len = hostname_len; + if( ssl->conf->f_sni == NULL ) + return( 0 ); + ret = ssl->conf->f_sni( ssl->conf->p_sni, ssl, p + 3, hostname_len ); if( ret != 0 ) @@ -1643,9 +1648,6 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) case MBEDTLS_TLS_EXT_SERVERNAME: MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); - if( ssl->conf->f_sni == NULL ) - break; - ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); if( ret != 0 ) return( ret ); @@ -1878,6 +1880,10 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_RET( 1, "f_cert_cb", ret ); return( ret ); } +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ssl->handshake->sni_name = NULL; + ssl->handshake->sni_name_len = 0; +#endif /* * Search for a matching ciphersuite diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 089f239123f2..2220721f1e2e 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1389,6 +1389,13 @@ void mbedtls_ssl_conf_ca_cb( mbedtls_ssl_config *conf, #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +const unsigned char *mbedtls_ssl_get_hs_sni( mbedtls_ssl_context *ssl, + size_t *name_len ) +{ + *name_len = ssl->handshake->sni_name_len; + return( ssl->handshake->sni_name ); +} + int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, mbedtls_x509_crt *own_cert, mbedtls_pk_context *pk_key ) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 2fe7a4016f8c..a0d007f3f549 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -5025,7 +5025,6 @@ run_test "SNI: no SNI callback" \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ "$P_CLI server_name=localhost" \ 0 \ - -S "parse ServerName extension" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" @@ -5175,7 +5174,6 @@ run_test "SNI: DTLS, no SNI callback" \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ "$P_CLI server_name=localhost dtls=1" \ 0 \ - -S "parse ServerName extension" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" From 48a37f01b389957c3f11b6aa7f7ddc2f9bc46eba Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Mon, 24 Jan 2022 16:40:20 -0500 Subject: [PATCH 4/6] Add cert_cb use to programs/ssl/ssl_server2.c (for use by some tests/) Signed-off-by: Glenn Strauss --- programs/ssl/ssl_server2.c | 47 ++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 595300e85593..802078c23b5b 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -823,18 +823,23 @@ int sni_callback( void *p_info, mbedtls_ssl_context *ssl, { const sni_entry *cur = (const sni_entry *) p_info; + /* preserve behavior which checks for SNI match in sni_callback() for + * the benefits of tests using sni_callback(), even though the actual + * certificate assignment has moved to certificate selection callback + * in this application. This exercises sni_callback and cert_callback + * even though real applications might choose to do this differently. + * Application might choose to save name and name_len in user_data for + * later use in certificate selection callback. + */ while( cur != NULL ) { if( name_len == strlen( cur->name ) && memcmp( name, cur->name, name_len ) == 0 ) { - if( cur->ca != NULL ) - mbedtls_ssl_set_hs_ca_chain( ssl, cur->ca, cur->crl ); - - if( cur->authmode != DFL_AUTH_MODE ) - mbedtls_ssl_set_hs_authmode( ssl, cur->authmode ); - - return( mbedtls_ssl_set_hs_own_cert( ssl, cur->cert, cur->key ) ); + void *p; + *(const void **)&p = cur; + mbedtls_ssl_set_user_data_p( ssl, p ); + return( 0 ); } cur = cur->next; @@ -843,6 +848,33 @@ int sni_callback( void *p_info, mbedtls_ssl_context *ssl, return( -1 ); } +/* + * server certificate selection callback. + */ +int cert_callback( mbedtls_ssl_context *ssl ) +{ + const sni_entry *cur = (sni_entry *) mbedtls_ssl_get_user_data_p( ssl ); + if( cur != NULL ) + { + /*(exercise mbedtls_ssl_get_hs_sni(); not otherwise used here)*/ + size_t name_len; + const unsigned char *name = mbedtls_ssl_get_hs_sni( ssl, &name_len ); + if( strlen( cur->name ) != name_len || + memcmp( cur->name, name, name_len ) != 0 ) + return( MBEDTLS_ERR_SSL_DECODE_ERROR ); + + if( cur->ca != NULL ) + mbedtls_ssl_set_hs_ca_chain( ssl, cur->ca, cur->crl ); + + if( cur->authmode != DFL_AUTH_MODE ) + mbedtls_ssl_set_hs_authmode( ssl, cur->authmode ); + + return( mbedtls_ssl_set_hs_own_cert( ssl, cur->cert, cur->key ) ); + } + + return( 0 ); +} + #endif /* SNI_OPTION */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -2923,6 +2955,7 @@ int main( int argc, char *argv[] ) if( opt.sni != NULL ) { mbedtls_ssl_conf_sni( &conf, sni_callback, sni_info ); + mbedtls_ssl_conf_cert_cb( &conf, cert_callback ); #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay2 >= 0 ) { From 0ebf24a66803fdc858cbb96ba8e50bf96026e628 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Mon, 24 Jan 2022 18:30:13 -0500 Subject: [PATCH 5/6] Adjust comment describing mbedtls_ssl_conf_sni() Signed-off-by: Glenn Strauss --- include/mbedtls/ssl.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 738f07bf54c6..aa6a21209ce6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3624,8 +3624,7 @@ void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, * mbedtls_ssl_set_hs_ca_chain() as well as the client * authentication mode with \c mbedtls_ssl_set_hs_authmode(), * then must return 0. If no matching name is found, the - * callback must either set a default cert, or - * return non-zero to abort the handshake at this point. + * callback may return non-zero to abort the handshake. * * \param conf SSL configuration * \param f_sni verification function From 9bff95f051343b78d42ac2442b327413ed9a9b97 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Wed, 9 Mar 2022 14:39:08 -0500 Subject: [PATCH 6/6] Adjust comment describing mbedtls_ssl_set_hs_own_cert() mbedtls_ssl_set_hs_own_cert() is callable from the certificate selection callback. Signed-off-by: Glenn Strauss --- include/mbedtls/ssl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index aa6a21209ce6..b819bbad8f7a 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3565,7 +3565,7 @@ const unsigned char *mbedtls_ssl_get_hs_sni( mbedtls_ssl_context *ssl, * \brief Set own certificate and key for the current handshake * * \note Same as \c mbedtls_ssl_conf_own_cert() but for use within - * the SNI callback. + * the SNI callback or the certificate selection callback. * * \note Passing null \c own_cert clears the certificate list for * the current handshake. @@ -3585,7 +3585,7 @@ int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, * current handshake * * \note Same as \c mbedtls_ssl_conf_ca_chain() but for use within - * the SNI callback. + * the SNI callback or the certificate selection callback. * * \param ssl SSL context * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) @@ -3599,7 +3599,7 @@ void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, * \brief Set authmode for the current handshake. * * \note Same as \c mbedtls_ssl_conf_authmode() but for use within - * the SNI callback. + * the SNI callback or the certificate selection callback. * * \param ssl SSL context * \param authmode MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL or