OpenSSL: improvde error message on expired certificate

Fix regression that no longer printed the error messages about expired
certificates in openssl. Add test case for openssl/gnutls/wolfssl.

Fixes #15612
Reported-by: hiimmat on github
Closes #15613
This commit is contained in:
Stefan Eissing 2024-11-19 14:44:02 +01:00 committed by Daniel Stenberg
parent 55968fd14b
commit fd4528a8d8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
4 changed files with 54 additions and 7 deletions

View File

@ -4220,14 +4220,11 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
lerr = SSL_get_verify_result(octx->ssl);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
"SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
failf(data, "SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
}
else {
else
failf(data, "%s", "SSL certificate verification failed");
return result;
}
}
#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
/* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
@ -4278,7 +4275,6 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
connssl->peer.hostname, connssl->peer.port);
return result;
}
return result;

View File

@ -366,3 +366,27 @@ class TestSSLUse:
])
assert r.exit_code == 0, f'{r}'
assert r.json, f'{r}'
# connect to an expired certificate
@pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
def test_17_14_expired_cert(self, env: Env, proto):
if proto == 'h3' and not env.have_h3():
pytest.skip("h3 not supported")
curl = CurlClient(env=env)
url = f'https://{env.expired_domain}:{env.port_for(proto)}/'
r = curl.http_get(url=url, alpn_proto=proto)
assert r.exit_code == 60, f'{r}' # peer failed verification
exp_trace = None
match_trace = None
if env.curl_uses_lib('openssl') or env.curl_uses_lib('quictls'):
exp_trace = r'.*SSL certificate problem: certificate has expired$'
elif env.curl_uses_lib('gnutls'):
exp_trace = r'.*server verification failed: certificate has expired\..*'
elif env.curl_uses_lib('wolfssl'):
exp_trace = r'.*server verification failed: certificate has expired\.$'
if exp_trace is not None:
for line in r.trace_lines:
if re.match(exp_trace, line):
match_trace = line
break
assert match_trace, f'Did not find "{exp_trace}" in trace\n{r.dump_logs()}'

View File

@ -32,6 +32,7 @@ import socket
import subprocess
import tempfile
from configparser import ConfigParser, ExtendedInterpolation
from datetime import timedelta
from typing import Optional
from .certs import CertificateSpec, Credentials, TestCA
@ -143,11 +144,14 @@ class EnvConfig:
self.domain2 = f"two.{self.tld}"
self.ftp_domain = f"ftp.{self.tld}"
self.proxy_domain = f"proxy.{self.tld}"
self.expired_domain = f"expired.{self.tld}"
self.cert_specs = [
CertificateSpec(domains=[self.domain1, self.domain1brotli, 'localhost', '127.0.0.1'], key_type='rsa2048'),
CertificateSpec(domains=[self.domain2], key_type='rsa2048'),
CertificateSpec(domains=[self.ftp_domain], key_type='rsa2048'),
CertificateSpec(domains=[self.proxy_domain, '127.0.0.1'], key_type='rsa2048'),
CertificateSpec(domains=[self.expired_domain], key_type='rsa2048',
valid_from=timedelta(days=-100), valid_to=timedelta(days=-10)),
CertificateSpec(name="clientsX", sub_specs=[
CertificateSpec(name="user1", client=True),
]),
@ -502,6 +506,10 @@ class Env:
def proxy_domain(self) -> str:
return self.CONFIG.proxy_domain
@property
def expired_domain(self) -> str:
return self.CONFIG.expired_domain
@property
def http_port(self) -> int:
return self.CONFIG.ports['http']

View File

@ -219,6 +219,9 @@ class Httpd:
domain2 = self.env.domain2
creds2 = self.env.get_credentials(domain2)
assert creds2 # convince pytype this isn't None
exp_domain = self.env.expired_domain
exp_creds = self.env.get_credentials(exp_domain)
assert exp_creds # convince pytype this isn't None
proxy_domain = self.env.proxy_domain
proxy_creds = self.env.get_credentials(proxy_domain)
assert proxy_creds # convince pytype this isn't None
@ -346,6 +349,22 @@ class Httpd:
'</VirtualHost>',
'',
])
conf.extend([ # https host for expired domain
f'<VirtualHost *:{self.env.https_port}>',
f' ServerName {exp_domain}',
' Protocols h2 http/1.1',
' SSLEngine on',
f' SSLCertificateFile {exp_creds.cert_file}',
f' SSLCertificateKeyFile {exp_creds.pkey_file}',
f' DocumentRoot "{self._docs_dir}/expired"',
])
conf.extend(self._curltest_conf(exp_domain))
if exp_domain in self._extra_configs:
conf.extend(self._extra_configs[exp_domain])
conf.extend([
'</VirtualHost>',
'',
])
conf.extend([ # http forward proxy
f'<VirtualHost *:{self.env.proxy_port}>',
f' ServerName {proxy_domain}',