]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
OpenSSL: improvde error message on expired certificate
authorStefan Eissing <stefan@eissing.org>
Tue, 19 Nov 2024 13:44:02 +0000 (14:44 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 2 Dec 2024 20:17:59 +0000 (21:17 +0100)
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

lib/vtls/openssl.c
tests/http/test_17_ssl_use.py
tests/http/testenv/env.py
tests/http/testenv/httpd.py

index 0643ba046efa368cb5a2d14e028ca85876796619..f2987ea94428fe25b13545dbbfdde256d144f00f 100644 (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;
index f129b110181641de7dbd4a3ff36360980d79f531..883d4a5f6f9e54a313a24b27563c5918eaa03556 100644 (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()}'
index 4eb0eb7653c8179dba8915b87a648695e1798f82..5360c4605547032caa0cd6f6f24c9e9f80dfca91 100644 (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']
index f3ca46f133c2ae1d866cd250e9016c36973c5af7..414f358ee2465ad9c31fb05b008cc390027c5b68 100644 (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}',