Skip to content
Open
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
8 changes: 7 additions & 1 deletion include/seastar/net/tls.hh
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,13 @@ namespace tls {
public:
/// \brief whether to wait for EOF from server on session termination
deprecated_wait_for_eof_on_shutdown wait_for_eof_on_shutdown;
/// \brief server name to be used for the SNI TLS extension
/// \brief expected name of the server. Sent in the SNI TLS extension
/// and, unless certificate verification has been disabled on the
/// credentials, matched against the peer certificate (an IP literal
/// against its iPAddress SANs, a DNS name against its dNSName SANs,
/// with the subject CN as fallback). A mismatch fails the handshake
/// with a verification_error. When empty, no SNI is sent and no name
/// check is performed.
sstring server_name = {};

/// \brief whether server certificate should be verified. May be set to false
Expand Down
23 changes: 23 additions & 0 deletions src/net/tls_openssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,29 @@ class openssl_session : public enable_shared_from_this<openssl_session>, public
if (!_options.server_name.empty()) {
Comment thread
pgellert marked this conversation as resolved.
SSL_set_tlsext_host_name(
_ssl.get(), _options.server_name.c_str());
if (_creds->_enable_certificate_verification) {
Comment thread
travisdowns marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on backporting this?

// OpenSSL matches the peer certificate against the name
// we intended to connect to only when that name is
// installed as a reference identifier on the
// verification parameters; chain validation alone
// accepts a certificate issued to anyone, as long as
// the issuer is trusted. A mismatch is reported through
// SSL_get_verify_result(), which verify() converts into
// a verification_error. Matching GnuTLS semantics: an
// IP literal is matched against iPAddress SANs, a DNS
// name against dNSName SANs (subject CN as fallback),
// and partial-wildcard matching is disabled.
auto* param = SSL_get0_param(_ssl.get());
X509_VERIFY_PARAM_set_hostflags(
param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
const auto& name = _options.server_name;
if (1 != X509_VERIFY_PARAM_set1_ip_asc(param, name.c_str())
&& 1 != X509_VERIFY_PARAM_set1_host(
param, name.c_str(), name.size())) {
throw make_openssl_error(
"Failed to set expected server name");
Comment on lines +917 to +918
}
}
}
SSL_set_connect_state(_ssl.get());
}
Expand Down
29 changes: 27 additions & 2 deletions tests/unit/tls_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,33 @@ SEASTAR_TEST_CASE(test_x509_client_server_cert_validation_fail) {
}

SEASTAR_TEST_CASE(test_x509_client_server_cert_validation_fail_name) {
// Use trust store with our signer, but wrong host name
return run_echo_test(message, 1, certfile("tls-ca-bundle.pem"), "nils.holgersson.gov").then([] {
// Use trust store with our signer, but wrong host name. The certificate
// chain is fully trusted, so the only thing standing between the client
// and an impostor is the peer name check.
return run_echo_test(message, 1, certfile("catest.pem"), "nils.holgersson.gov").then([] {
BOOST_FAIL("Should have gotten validation error");
}).handle_exception([](auto ep) {
try {
std::rethrow_exception(ep);
} catch (tls::verification_error&) {
// ok.
} catch (...) {
BOOST_FAIL("Unexpected exception");
}
});
}

SEASTAR_TEST_CASE(test_x509_client_server_cert_validation_ip_match) {
// test.crt carries an iPAddress SAN for 127.0.0.1. An IP-literal
// server_name must be matched against that SAN as an address, not as a
// DNS name.
return run_echo_test(message, 1, certfile("catest.pem"), "127.0.0.1");
}

SEASTAR_TEST_CASE(test_x509_client_server_cert_validation_fail_ip) {
// Trusted signer, but an IP that does not match the certificate's
// iPAddress SAN (127.0.0.1).
return run_echo_test(message, 1, certfile("catest.pem"), "127.0.0.2").then([] {
BOOST_FAIL("Should have gotten validation error");
}).handle_exception([](auto ep) {
try {
Expand Down
Loading