Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion base/poco/NetSSL_OpenSSL/src/SSLManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,9 @@ void SSLManager::initDefaultContext(bool server)
{
_ptrDefaultClientContext->enableSessionCache(cacheSessions);
}
bool extendedVerification = config.getBool(prefix + CFG_EXTENDED_VERIFICATION, false);
/// Only an outbound connection has a requested host name to check: on an accepted socket this
/// would run against the client's address, which a client certificate does not name.
bool extendedVerification = config.getBool(prefix + CFG_EXTENDED_VERIFICATION, !server);
if (server)
_ptrDefaultServerContext->enableExtendedCertificateVerification(extendedVerification);
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ Keys for server/client settings:
| `certificateFile` | Path to the client/server certificate file in PEM format. You can omit it if `privateKeyFile` contains the certificate. | |
| `cipherList` | Supported OpenSSL encryptions. | `ALL:!ADH:!LOW:!EXP:!MD5:!3DES:@STRENGTH` |
| `disableProtocols` | Protocols that are not allowed to be used. | |
| `extendedVerification` | If enabled, verify that the certificate CN or SAN matches the peer hostname. | `false` |
| `extendedVerification` | If enabled, verify that the certificate CN or SAN matches the peer hostname. | `true` for `openSSL.client`, `false` for `openSSL.server` |
| `fips` | Activates OpenSSL FIPS mode. Supported if the library's OpenSSL version supports FIPS. | `false` |
| `invalidCertificateHandler` | Class (a subclass of CertificateHandler) for verifying invalid certificates. For example: `<invalidCertificateHandler> <name>RejectCertificateHandler</name> </invalidCertificateHandler>` . | `RejectCertificateHandler` |
| `loadDefaultCAFile` | Wether built-in CA certificates for OpenSSL will be used. ClickHouse assumes that builtin CA certificates are in the file `/etc/ssl/cert.pem` (resp. the directory `/etc/ssl/certs`) or in file (resp. directory) specified by the environment variable `SSL_CERT_FILE` (resp. `SSL_CERT_DIR`). | `true` |
Expand Down
2 changes: 1 addition & 1 deletion src/Core/ServerSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1594,7 +1594,7 @@ Configured as `named_collections_storage.type` (`<named_collections_storage><typ
DECLARE(Bool, openssl_client_load_default_ca_file, true, R"(Determines whether built-in CA certificates for OpenSSL will be used. ClickHouse assumes that builtin CA certificates are in the file `</etc/ssl/cert.pem>` (resp. the directory `</etc/ssl/certs>`) or in file (resp. directory) specified by the environment variable `<SSL_CERT_FILE>` (resp. `<SSL_CERT_DIR>`).)", 0, "openSSL.client.loadDefaultCAFile") \
DECLARE(String, openssl_client_chipher_list, "ALL:!ADH:!LOW:!EXP:!MD5:!3DES:@STRENGTH", R"(Supported OpenSSL encryptions.)", 0, "openSSL.client.cipherList") \
DECLARE(Bool, openssl_client_cache_sessions, false, R"(Enables or disables caching sessions. Must be used in combination with `<sessionIdContext>`. Acceptable values: `<true>`, `<false>`.)", 0, "openSSL.client.cacheSessions") \
DECLARE(Bool, openssl_client_extended_verification, false, R"(If enabled, verify that the certificate CN or SAN matches the peer hostname.)", 0, "openSSL.client.extendedVerification") \
DECLARE(Bool, openssl_client_extended_verification, true, R"(If enabled, verify that the certificate CN or SAN matches the peer hostname.)", 0, "openSSL.client.extendedVerification") \
DECLARE(Bool, openssl_client_required_tls_v1, false, R"(Require a TLSv1 connection. Acceptable values: `<true>`, `<false>`.)", 0, "openSSL.client.requireTLSv1") \
DECLARE(Bool, openssl_client_required_tls_v1_1, false, R"(Require a TLSv1.1 connection. Acceptable values: `<true>`, `<false>`.)", 0, "openSSL.client.requireTLSv1_1") \
DECLARE(Bool, openssl_client_required_tls_v1_2, false, R"(Require a TLSv1.2 connection. Acceptable values: `<true>`, `<false>`.)", 0, "openSSL.client.requireTLSv1_2") \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<clickhouse>
<!-- Native interface with TLS, presenting a certificate that the client's CA signs but whose
name (CN=client) is not the address the client connects to.
-->
<tcp_port_secure>9440</tcp_port_secure>

<openSSL replace="replace">
<server> <!-- Used for https server AND secure tcp port -->
<certificateFile>/etc/clickhouse-server/config.d/client-cert.pem</certificateFile>
<privateKeyFile>/etc/clickhouse-server/config.d/client-key.pem</privateKeyFile>
<caConfig>/etc/clickhouse-server/config.d/ca-cert.pem</caConfig>
<verificationMode>none</verificationMode>
</server>
</openSSL>
</clickhouse>
69 changes: 69 additions & 0 deletions tests/integration/test_accept_invalid_certificate/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
MAX_RETRY = 5
CA_CERT = f"{SCRIPT_DIR}/certs/ca-cert.pem"

cluster = ClickHouseCluster(__file__)
instance = cluster.add_instance(
Expand All @@ -34,6 +35,18 @@
)


node2 = cluster.add_instance(
"node2",
main_configs=[
"configs/ssl_config_ca_signed.xml",
"certs/client-key.pem",
"certs/client-cert.pem",
"certs/ca-cert.pem",
],
with_zookeeper=False,
)


@pytest.fixture(scope="module", autouse=True)
def started_cluster():
try:
Expand All @@ -60,6 +73,36 @@ def started_cluster():
</connections_credentials>
</clickhouse>"""

# node2 presents a certificate this CA signs, so the chain is valid and only the name can fail.
config_ca_signed = """<clickhouse>
<openSSL>
<client>
<caConfig>{caConfig}</caConfig>
<loadDefaultCAFile>false</loadDefaultCAFile>
</client>
</openSSL>
</clickhouse>"""

config_ca_signed_sni_override = """<clickhouse>
<tls-sni-override>client</tls-sni-override>
<openSSL>
<client>
<caConfig>{caConfig}</caConfig>
<loadDefaultCAFile>false</loadDefaultCAFile>
</client>
</openSSL>
</clickhouse>"""

config_ca_signed_no_extended_verification = """<clickhouse>
<openSSL>
<client>
<caConfig>{caConfig}</caConfig>
<loadDefaultCAFile>false</loadDefaultCAFile>
<extendedVerification>false</extendedVerification>
</client>
</openSSL>
</clickhouse>"""


def execute_query_native(node, query, config):
config_path = f"{SCRIPT_DIR}/configs/client.xml"
Expand Down Expand Up @@ -131,3 +174,29 @@ def test_strict_connection_reject():
config_connection_accept.format(ip_address=f"{instance.ip_address}"),
)
assert "certificate verify failed" in str(err.value)


def test_hostname_mismatch_rejected_by_default():
with pytest.raises(Exception) as err:
execute_query_native(node2, "SELECT 1", config_ca_signed.format(caConfig=CA_CERT))
assert "Unacceptable certificate" in str(err.value)


def test_hostname_match_accepted():
assert (
execute_query_native(
node2, "SELECT 1", config_ca_signed_sni_override.format(caConfig=CA_CERT)
)
== "1\n"
)


def test_extended_verification_disabled():
assert (
execute_query_native(
node2,
"SELECT 1",
config_ca_signed_no_extended_verification.format(caConfig=CA_CERT),
)
== "1\n"
)
3 changes: 3 additions & 0 deletions tests/integration/test_acme_tls/configs/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
</acme>
<openSSL>
<client>
<!-- Pebble is reached at a pinned address, and its serving certificate names
localhost, pebble and 127.0.0.1 only. -->
<extendedVerification>false</extendedVerification>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/test_acme_tls/configs/config_multi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
</acme>
<openSSL>
<client>
<!-- Pebble is reached at a pinned address, and its serving certificate names
localhost, pebble and 127.0.0.1 only. -->
<extendedVerification>false</extendedVerification>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<privateKeyFile>/etc/clickhouse-server/config.d/server.key</privateKeyFile>
</server>
<client>
<!-- This test asserts the source address a connection is made from, not the identity
of the peer, and server.crt names only localhost while the clusters use node1..4. -->
<extendedVerification>false</extendedVerification>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/test_ssl_cert_authentication/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def started_cluster():


config = """<clickhouse>
<tls-sni-override>{sslHost}</tls-sni-override>
<openSSL>
<client>
<verificationMode>strict</verificationMode>
Expand All @@ -61,6 +62,7 @@ def execute_query_native(node, query, user, cert_name, password=None):
certificateFile=f"{SCRIPT_DIR}/certs/{cert_name}-cert.pem",
privateKeyFile=f"{SCRIPT_DIR}/certs/{cert_name}-key.pem",
caConfig=f"{SCRIPT_DIR}/certs/ca-cert.pem",
sslHost=SSL_HOST,
)

file = open(config_path, "w")
Expand Down
Loading