mirror of
https://github.com/curl/curl.git
synced 2026-07-24 20:27:18 +03:00
TLS: IP address verification, extend test
Change the test certificate to carry a altname 'dns:127.0.0.1' which should *not* match in test_17_05_bad_ip_addr. wolfSSL: since `wolfSSL_check_domain_name()` does not differentiate between DNS and IP names, use if only for DNS names. For IP addresses, get the peer certificate after the handshake and check that using wolfSSL_X509_check_ip_asc(). Unfortunately, this succeeds where it should not, as wolfSSL internally used the same check code for both cases. So, skip the test case until wolfSSL fixes that. Reported-by: Joshua Rogers Closes #19252
This commit is contained in:
parent
2bb33c18a7
commit
692c7f133e
7 changed files with 67 additions and 14 deletions
|
|
@ -178,12 +178,17 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
|
|||
#elif defined(USE_WOLFSSL)
|
||||
(void)data;
|
||||
if(conn_config->verifyhost) {
|
||||
char *snihost = peer->sni ? peer->sni : peer->hostname;
|
||||
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
|
||||
if(wolfSSL_X509_check_host(cert, snihost, strlen(snihost), 0, NULL)
|
||||
== WOLFSSL_FAILURE) {
|
||||
if(!cert)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
else if(peer->sni &&
|
||||
(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
|
||||
== WOLFSSL_FAILURE))
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
else if(!peer->sni &&
|
||||
(wolfSSL_X509_check_ip_asc(cert, peer->hostname, 0)
|
||||
== WOLFSSL_FAILURE))
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
wolfSSL_X509_free(cert);
|
||||
}
|
||||
if(!result)
|
||||
|
|
|
|||
|
|
@ -1491,11 +1491,10 @@ wssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Enable RFC2818 checks */
|
||||
if(conn_config->verifyhost) {
|
||||
char *snihost = connssl->peer.sni ?
|
||||
connssl->peer.sni : connssl->peer.hostname;
|
||||
if(wolfSSL_check_domain_name(wssl->ssl, snihost) !=
|
||||
/* Enable RFC2818 checks on domain names. This cannot check
|
||||
* IP addresses which we need to do extra after the handshake. */
|
||||
if(conn_config->verifyhost && connssl->peer.sni) {
|
||||
if(wolfSSL_check_domain_name(wssl->ssl, connssl->peer.sni) !=
|
||||
WOLFSSL_SUCCESS) {
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
|
@ -1719,6 +1718,25 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf,
|
|||
detail = wolfSSL_get_error(wssl->ssl, ret);
|
||||
CURL_TRC_CF(data, cf, "wolfSSL_connect() -> %d, detail=%d", ret, detail);
|
||||
|
||||
/* On a successful handshake with an IP address, do an extra check
|
||||
* on the peer certificate */
|
||||
if(ret == WOLFSSL_SUCCESS &&
|
||||
conn_config->verifyhost &&
|
||||
!connssl->peer.sni) {
|
||||
/* we have an IP address as host name. */
|
||||
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(wssl->ssl);
|
||||
if(!cert) {
|
||||
failf(data, "unable to get peer certificate");
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
ret = wolfSSL_X509_check_ip_asc(cert, connssl->peer.hostname, 0);
|
||||
CURL_TRC_CF(data, cf, "check peer certificate for IP match on %s -> %d",
|
||||
connssl->peer.hostname, ret);
|
||||
if(ret != WOLFSSL_SUCCESS)
|
||||
detail = DOMAIN_NAME_MISMATCH;
|
||||
wolfSSL_X509_free(cert);
|
||||
}
|
||||
|
||||
if(ret == WOLFSSL_SUCCESS) {
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -610,6 +610,8 @@ class TestDownload:
|
|||
pytest.skip("h3 not supported")
|
||||
if proto != 'h3' and sys.platform.startswith('darwin') and env.ci_run:
|
||||
pytest.skip('failing on macOS CI runners')
|
||||
if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('wolfssl'):
|
||||
pytest.skip('h3 wolfssl early data failing on macOS')
|
||||
if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('gnutls'):
|
||||
pytest.skip('h3 gnutls early data failing on macOS')
|
||||
count = 2
|
||||
|
|
|
|||
|
|
@ -712,6 +712,8 @@ class TestUpload:
|
|||
pytest.skip("h3 not supported")
|
||||
if proto != 'h3' and sys.platform.startswith('darwin') and env.ci_run:
|
||||
pytest.skip('failing on macOS CI runners')
|
||||
if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('wolfssl'):
|
||||
pytest.skip('h3 wolfssl early data failing on macOS')
|
||||
if proto == 'h3' and sys.platform.startswith('darwin') and env.curl_uses_lib('gnutls'):
|
||||
pytest.skip('h3 gnutls early data failing on macOS')
|
||||
count = 2
|
||||
|
|
|
|||
|
|
@ -186,6 +186,27 @@ class TestSSLUse:
|
|||
r = curl.http_get(url=url, alpn_proto=proto)
|
||||
assert r.exit_code == 60, f'{r}'
|
||||
|
||||
# use IP address that is in cert as DNS name (not really legal)
|
||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||
def test_17_05_very_bad_ip_addr(self, env: Env, proto,
|
||||
httpd, configures_httpd,
|
||||
nghttpx, configures_nghttpx):
|
||||
if proto == 'h3' and not env.have_h3():
|
||||
pytest.skip("h3 not supported")
|
||||
if env.curl_uses_lib('mbedtls'):
|
||||
pytest.skip("mbedtls falsely verifies a DNS: altname as IP address")
|
||||
if env.curl_uses_lib('wolfssl'):
|
||||
pytest.skip("wolfSSL falsely verifies a DNS: altname as IP address")
|
||||
httpd.set_domain1_cred_name('domain1-very-bad')
|
||||
httpd.reload_if_config_changed()
|
||||
if proto == 'h3':
|
||||
nghttpx.set_cred_name('domain1-very-bad')
|
||||
nghttpx.reload_if_config_changed()
|
||||
curl = CurlClient(env=env)
|
||||
url = f'https://127.0.0.1:{env.port_for(proto)}/curltest/sslinfo'
|
||||
r = curl.http_get(url=url, alpn_proto=proto)
|
||||
assert r.exit_code == 60, f'{r}'
|
||||
|
||||
# use localhost for connect
|
||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||
def test_17_06_localhost(self, env: Env, proto, httpd, nghttpx):
|
||||
|
|
|
|||
|
|
@ -459,11 +459,15 @@ class TestCA:
|
|||
def _add_leaf_usages(csr: Any, domains: List[str], issuer: Credentials) -> Any:
|
||||
names = []
|
||||
for name in domains:
|
||||
try:
|
||||
names.append(x509.IPAddress(ipaddress.ip_address(name)))
|
||||
# TODO: specify specific exceptions here
|
||||
except: # noqa: E722
|
||||
names.append(x509.DNSName(name))
|
||||
m = re.match(r'dns:(.+)', name)
|
||||
if m:
|
||||
names.append(x509.DNSName(m.group(1)))
|
||||
else:
|
||||
try:
|
||||
names.append(x509.IPAddress(ipaddress.ip_address(name)))
|
||||
# TODO: specify specific exceptions here
|
||||
except: # noqa: E722
|
||||
names.append(x509.DNSName(name))
|
||||
|
||||
return csr.add_extension(
|
||||
x509.BasicConstraints(ca=False, path_length=None),
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ class EnvConfig:
|
|||
self.cert_specs = [
|
||||
CertificateSpec(domains=[self.domain1, self.domain1brotli, 'localhost', '127.0.0.1'], key_type='rsa2048'),
|
||||
CertificateSpec(name='domain1-no-ip', domains=[self.domain1, self.domain1brotli], key_type='rsa2048'),
|
||||
CertificateSpec(name='domain1-very-bad', domains=[self.domain1, 'dns: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'),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue