diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 80cd588f1c..f4cbe88080 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1572,8 +1572,6 @@ static CURLcode glts_apple_verify(struct Curl_cfilter *cf, result = Curl_vtls_apple_verify(cf, data, peer, chain->num_certs, gtls_chain_get_der, chain, NULL, 0); *pverified = !result; - if(*pverified) - infof(data, " SSL certificate verified by Apple SecTrust."); return result; } #endif /* USE_APPLE_SECTRUST */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index f0e89b617c..ae1fe6cbb1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3371,32 +3371,42 @@ ossl_init_session_and_alpns(struct ossl_ctx *octx, sizeof(error_buffer))); } else { - infof(data, "SSL reusing session with ALPN '%s'", - scs->alpn ? scs->alpn : "-"); - octx->reused_session = TRUE; + if(conn_cfg->verifypeer && + (SSL_get_verify_result(octx->ssl) != X509_V_OK)) { + /* Session was from unverified connection, cannot reuse here */ + SSL_set_session(octx->ssl, NULL); + infof(data, "SSL session not peer verified, not reusing"); + } + else { + infof(data, "SSL reusing session with ALPN '%s'", + scs->alpn ? scs->alpn : "-"); + octx->reused_session = TRUE; + infof(data, "SSL verify result: %lx", + SSL_get_verify_result(octx->ssl)); #ifdef HAVE_OPENSSL_EARLYDATA - if(ssl_config->earlydata && scs->alpn && - SSL_SESSION_get_max_early_data(ssl_session) && - !cf->conn->connect_only && - (SSL_version(octx->ssl) == TLS1_3_VERSION)) { - bool do_early_data = FALSE; - if(sess_reuse_cb) { - result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data); - if(result) { - SSL_SESSION_free(ssl_session); - return result; + if(ssl_config->earlydata && scs->alpn && + SSL_SESSION_get_max_early_data(ssl_session) && + !cf->conn->connect_only && + (SSL_version(octx->ssl) == TLS1_3_VERSION)) { + bool do_early_data = FALSE; + if(sess_reuse_cb) { + result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data); + if(result) { + SSL_SESSION_free(ssl_session); + return result; + } + } + if(do_early_data) { + /* We only try the ALPN protocol the session used before, + * otherwise we might send early data for the wrong protocol */ + Curl_alpn_restrict_to(&alpns, scs->alpn); } } - if(do_early_data) { - /* We only try the ALPN protocol the session used before, - * otherwise we might send early data for the wrong protocol */ - Curl_alpn_restrict_to(&alpns, scs->alpn); - } - } #else - (void)ssl_config; - (void)sess_reuse_cb; + (void)ssl_config; + (void)sess_reuse_cb; #endif + } } SSL_SESSION_free(ssl_session); } @@ -4681,8 +4691,15 @@ static CURLcode ossl_apple_verify(struct Curl_cfilter *cf, if(!chain.num_certs && (conn_config->verifypeer || conn_config->verifyhost)) { - failf(data, "SSL: could not get peer certificate"); - result = CURLE_PEER_FAILED_VERIFICATION; + if(!octx->reused_session) { + failf(data, "SSL: could not get peer certificate chain"); + result = CURLE_PEER_FAILED_VERIFICATION; + } + else { + /* when session was reused, there is no peer cert chain */ + *pverified = FALSE; + return CURLE_OK; + } } else { #ifdef HAVE_BORINGSSL_LIKE @@ -4758,6 +4775,7 @@ CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, ossl_verify = SSL_get_verify_result(octx->ssl); ssl_config->certverifyresult = ossl_verify; + infof(data, "OpenSSL verify result: %lx", ossl_verify); verified = (ossl_verify == X509_V_OK); if(verified) diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index ba11880b0b..b4ea2a42d1 100644 --- a/tests/http/test_02_download.py +++ b/tests/http/test_02_download.py @@ -286,7 +286,8 @@ class TestDownload: if not client.exists(): pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ - '-n', f'{count}', '-P', f'{pause_offset}', '-V', proto, url + '-n', f'{count}', '-P', f'{pause_offset}', + '-C', env.ca.cert_file, '-V', proto, url ]) r.check_exit_code(0) srcfile = os.path.join(httpd.docs_dir, docname) @@ -305,7 +306,8 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', - '-P', f'{pause_offset}', '-V', proto, url + '-P', f'{pause_offset}', '-C', env.ca.cert_file, + '-V', proto, url ]) r.check_exit_code(0) srcfile = os.path.join(httpd.docs_dir, docname) @@ -329,6 +331,7 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', '-a', + '-C', env.ca.cert_file, '-P', f'{pause_offset}', '-V', proto, url ]) r.check_exit_code(0) @@ -354,6 +357,7 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', '-a', + '-C', env.ca.cert_file, '-A', f'{abort_offset}', '-V', proto, url ]) r.check_exit_code(42) # CURLE_ABORTED_BY_CALLBACK @@ -379,6 +383,7 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', '-a', + '-C', env.ca.cert_file, '-F', f'{fail_offset}', '-V', proto, url ]) r.check_exit_code(23) # CURLE_WRITE_ERROR @@ -487,7 +492,8 @@ class TestDownload: if not client.exists(): pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ - '-n', f'{count}', '-P', f'{pause_offset}', '-V', proto, url + '-n', f'{count}', '-P', f'{pause_offset}', + '-C', env.ca.cert_file, '-V', proto, url ]) r.check_exit_code(0) srcfile = os.path.join(httpd.docs_dir, docname) @@ -549,6 +555,7 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', + '-C', env.ca.cert_file, '-e', # use TLS earlydata '-f', # forbid reuse of connections '-r', f'{env.domain1}:{port}:127.0.0.1', @@ -596,6 +603,7 @@ class TestDownload: r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', + '-C', env.ca.cert_file, '-x', # always use a fresh connection '-M', str(max_host_conns), # limit conns per host '-r', f'{env.domain1}:{port}:127.0.0.1', @@ -634,6 +642,7 @@ class TestDownload: r = client.run(args=[ '-n', f'{count}', '-m', f'{max_parallel}', + '-C', env.ca.cert_file, '-x', # always use a fresh connection '-T', str(max_total_conns), # limit total connections '-r', f'{env.domain1}:{port}:127.0.0.1', @@ -673,7 +682,8 @@ class TestDownload: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', '-m', f'{count}', - '-P', f'{pause_offset}', '-V', proto, url + '-P', f'{pause_offset}', '-C', env.ca.cert_file, + '-V', proto, url ]) r.check_exit_code(0) diff --git a/tests/http/test_08_caddy.py b/tests/http/test_08_caddy.py index 9229ce1f22..b854dceb45 100644 --- a/tests/http/test_08_caddy.py +++ b/tests/http/test_08_caddy.py @@ -184,6 +184,7 @@ class TestCaddy: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', + '-C', env.ca.cert_file, '-e', # use TLS earlydata '-f', # forbid reuse of connections '-r', f'{env.domain1}:{caddy.port}:127.0.0.1', diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index 4ef8ad1f94..34a8a2d394 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -382,7 +382,7 @@ class TestSSLUse: if not env.have_h3(): pytest.skip("h3 not supported") if not env.curl_uses_lib('quictls') and \ - not (env.curl_uses_lib('openssl') and env.curl_uses_lib('ngtcp2')) and \ + not env.curl_uses_lib('openssl') and \ not env.curl_uses_lib('gnutls') and \ not env.curl_uses_lib('wolfssl'): pytest.skip("QUIC session reuse not implemented") @@ -395,6 +395,7 @@ class TestSSLUse: r = client.run(args=[ '-n', f'{count}', '-f', # forbid reuse of connections + '-C', env.ca.cert_file, '-r', f'{env.domain1}:{env.port_for("h3")}:127.0.0.1', '-V', 'h3', url ]) diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py index efa7657fe9..7cb8ce6415 100644 --- a/tests/http/test_19_shutdown.py +++ b/tests/http/test_19_shutdown.py @@ -123,7 +123,8 @@ class TestShutdown: if not client.exists(): pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ - '-n', f'{count}', '-f', '-V', proto, url + '-n', f'{count}', '-f', '-C', env.ca.cert_file, + '-V', proto, url ]) r.check_exit_code(0) shutdowns = [line for line in r.trace_lines @@ -199,6 +200,7 @@ class TestShutdown: pytest.skip(f'example client not built: {client.name}') r = client.run(args=[ '-n', f'{count}', # that many transfers + '-C', env.ca.cert_file, '-f', # forbid conn reuse '-m', '10', # max parallel '-T', '5', # max total conns at a time diff --git a/tests/libtest/cli_hx_download.c b/tests/libtest/cli_hx_download.c index 9bd9542409..51e0d46715 100644 --- a/tests/libtest/cli_hx_download.c +++ b/tests/libtest/cli_hx_download.c @@ -211,13 +211,13 @@ static int my_progress_d_cb(void *userdata, static int setup_hx_download(CURL *curl, const char *url, struct transfer_d *t, long http_version, struct curl_slist *host, CURLSH *share, int use_earlydata, - int fresh_connect) + int fresh_connect, char *cafile) { curl_easy_setopt(curl, CURLOPT_SHARE, share); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, http_version); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + if(cafile) + curl_easy_setopt(curl, CURLOPT_CAINFO, cafile); curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, (long)(128 * 1024)); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_d_cb); @@ -292,11 +292,12 @@ static CURLcode test_cli_hx_download(const char *URL) size_t max_host_conns = 0; size_t max_total_conns = 0; int fresh_connect = 0; + char *cafile = NULL; CURLcode result = CURLE_OK; (void)URL; - while((ch = cgetopt(test_argc, test_argv, "aefhm:n:xA:F:M:P:r:T:V:")) + while((ch = cgetopt(test_argc, test_argv, "aefhm:n:xA:C:F:M:P:r:T:V:")) != -1) { const char *opt = coptarg; curl_off_t num; @@ -329,6 +330,10 @@ static CURLcode test_cli_hx_download(const char *URL) if(!curlx_str_number(&opt, &num, LONG_MAX)) abort_offset = (size_t)num; break; + case 'C': + curlx_free(cafile); + cafile = curlx_strdup(coptarg); + break; case 'F': if(!curlx_str_number(&opt, &num, LONG_MAX)) fail_offset = (size_t)num; @@ -432,7 +437,7 @@ static CURLcode test_cli_hx_download(const char *URL) t->curl = curl_easy_init(); if(!t->curl || setup_hx_download(t->curl, url, t, http_version, host, share, - use_earlydata, fresh_connect)) { + use_earlydata, fresh_connect, cafile)) { curl_mfprintf(stderr, "[t-%zu] FAILED setup\n", i); result = (CURLcode)1; goto cleanup; @@ -515,7 +520,7 @@ static CURLcode test_cli_hx_download(const char *URL) t->curl = curl_easy_init(); if(!t->curl || setup_hx_download(t->curl, url, t, http_version, host, share, - use_earlydata, fresh_connect)) { + use_earlydata, fresh_connect, cafile)) { curl_mfprintf(stderr, "[t-%zu] FAILED setup\n", i); result = (CURLcode)1; goto cleanup; @@ -566,6 +571,7 @@ cleanup: optcleanup: curlx_free(resolve); + curlx_free(cafile); return result; }