OpenSSL: check reuse of sessions for verify status
No binary (build failed)
—
(log yok)
| @@ -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 */ | |
| @@ -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) | |
| @@ -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) | |
| @@ -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', | |
| @@ -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 | |
| ]) | |
| @@ -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 | |
| @@ -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; | |
| } | |