Skip to content

Commit

Permalink
tls: add ssl.curves and ssl.sigalgs to tracked TLS stats. (#5339)
Browse files Browse the repository at this point in the history
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
  • Loading branch information
PiotrSikora authored and ggreenway committed Dec 18, 2018
1 parent 20b1930 commit 5ff5f95
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 36 deletions.
8 changes: 5 additions & 3 deletions docs/root/configuration/listeners/stats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ Every listener has a statistics tree rooted at *listener.<address>.* with the fo
ssl.connection_error, Counter, Total TLS connection errors not including failed certificate verifications
ssl.handshake, Counter, Total successful TLS connection handshakes
ssl.session_reused, Counter, Total successful TLS session resumptions
ssl.no_certificate, Counter, Total successul TLS connections with no client certificate
ssl.no_certificate, Counter, Total successful TLS connections with no client certificate
ssl.fail_verify_no_cert, Counter, Total TLS connections that failed because of missing client certificate
ssl.fail_verify_error, Counter, Total TLS connections that failed CA verification
ssl.fail_verify_san, Counter, Total TLS connections that failed SAN verification
ssl.fail_verify_cert_hash, Counter, Total TLS connections that failed certificate pinning verification
ssl.ciphers.<cipher>, Counter, Total TLS connections that used <cipher>
ssl.versions.<version>, Counter, Total successful handshakes that used protocol <version>
ssl.ciphers.<cipher>, Counter, Total successful TLS connections that used cipher <cipher>
ssl.curves.<curve>, Counter, Total successful TLS connections that used ECDHE curve <curve>
ssl.sigalgs.<sigalg>, Counter, Total successful TLS connections that used signature algorithm <sigalg>
ssl.versions.<version>, Counter, Total successful TLS connections that used protocol version <version>

Listener manager
----------------
Expand Down
3 changes: 2 additions & 1 deletion docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ Version history
* stream: renamed `perRequestState` to `filterState` in `StreamInfo`.
* stream: added `downstreamDirectRemoteAddress` to `StreamInfo`.
* thrift_proxy: introduced thrift rate limiter filter
* tls: added ssl.versions.<version> to :ref:`listener metrics <config_listener_stats>` to track TLS versions in use.
* tls: added ssl.curves.<curve>, ssl.sigalgs.<sigalg> and ssl.versions.<version> to
:ref:`listener metrics <config_listener_stats>` to track TLS algorithms and versions in use.
* tls: added support for :ref:`client-side session resumption <envoy_api_field_auth.UpstreamTlsContext.max_session_keys>`.
* tls: added support for CRLs in :ref:`trusted_ca <envoy_api_field_auth.CertificateValidationContext.trusted_ca>`.
* tls: added support for :ref:`multiple server TLS certificates <arch_overview_ssl_cert_select>`.
Expand Down
16 changes: 14 additions & 2 deletions source/common/ssl/context_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,20 @@ void ContextImpl::logHandshake(SSL* ssl) const {
const char* cipher = SSL_get_cipher_name(ssl);
scope_.counter(fmt::format("ssl.ciphers.{}", std::string{cipher})).inc();

std::string protocol_version = std::string{SSL_get_version(ssl)};
scope_.counter(fmt::format("ssl.versions.{}", protocol_version)).inc();
const char* version = SSL_get_version(ssl);
scope_.counter(fmt::format("ssl.versions.{}", std::string{version})).inc();

uint16_t curve_id = SSL_get_curve_id(ssl);
if (curve_id) {
const char* curve = SSL_get_curve_name(curve_id);
scope_.counter(fmt::format("ssl.curves.{}", std::string{curve})).inc();
}

uint16_t sigalg_id = SSL_get_peer_signature_algorithm(ssl);
if (sigalg_id) {
const char* sigalg = SSL_get_signature_algorithm_name(sigalg_id, 1 /* include curve */);
scope_.counter(fmt::format("ssl.sigalgs.{}", std::string{sigalg})).inc();
}

bssl::UniquePtr<X509> cert(SSL_get_peer_certificate(ssl));
if (!cert.get()) {
Expand Down
87 changes: 57 additions & 30 deletions test/common/ssl/ssl_socket_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2720,20 +2720,20 @@ TEST_P(SslSocketTest, ProtocolVersions) {
// Connection using TLSv1.0 (client) and defaults (server) succeeds.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
client_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
testUtilV2(listener, client, "", true, "TLSv1", "", "", "", "", "ssl.handshake", "ssl.handshake",
GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1", "", "", "", "", "ssl.versions.TLSv1",
"ssl.versions.TLSv1", GetParam(), nullptr);

// Connection using TLSv1.1 (client) and defaults (server) succeeds.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_1);
client_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_1);
testUtilV2(listener, client, "", true, "TLSv1.1", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1.1", "", "", "", "", "ssl.versions.TLSv1.1",
"ssl.versions.TLSv1.1", GetParam(), nullptr);

// Connection using TLSv1.2 (client) and defaults (server) succeeds.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_2);
client_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_2);
testUtilV2(listener, client, "", true, "TLSv1.2", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1.2", "", "", "", "", "ssl.versions.TLSv1.2",
"ssl.versions.TLSv1.2", GetParam(), nullptr);

// Connection using TLSv1.3 (client) and defaults (server) fails.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_3);
Expand All @@ -2744,28 +2744,28 @@ TEST_P(SslSocketTest, ProtocolVersions) {
// Connection using TLSv1.3 (client) and TLSv1.0-1.3 (server) succeeds.
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
server_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_3);
testUtilV2(listener, client, "", true, "TLSv1.3", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1.3", "", "", "", "", "ssl.versions.TLSv1.3",
"ssl.versions.TLSv1.3", GetParam(), nullptr);

// Connection using defaults (client) and TLSv1.0 (server) succeeds.
client_params->clear_tls_minimum_protocol_version();
client_params->clear_tls_maximum_protocol_version();
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
server_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
testUtilV2(listener, client, "", true, "TLSv1", "", "", "", "", "ssl.handshake", "ssl.handshake",
GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1", "", "", "", "", "ssl.versions.TLSv1",
"ssl.versions.TLSv1", GetParam(), nullptr);

// Connection using defaults (client) and TLSv1.1 (server) succeeds.
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_1);
server_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_1);
testUtilV2(listener, client, "", true, "TLSv1.1", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1.1", "", "", "", "", "ssl.versions.TLSv1.1",
"ssl.versions.TLSv1.1", GetParam(), nullptr);

// Connection using defaults (client) and TLSv1.2 (server) succeeds.
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_2);
server_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_2);
testUtilV2(listener, client, "", true, "TLSv1.2", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);
testUtilV2(listener, client, "", true, "TLSv1.2", "", "", "", "", "ssl.versions.TLSv1.2",
"ssl.versions.TLSv1.2", GetParam(), nullptr);

// Connection using defaults (client) and TLSv1.3 (server) fails.
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_3);
Expand All @@ -2776,21 +2776,8 @@ TEST_P(SslSocketTest, ProtocolVersions) {
// Connection using TLSv1.0-TLSv1.3 (client) and TLSv1.3 (server) succeeds.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
client_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_3);
testUtilV2(listener, client, "", true, "TLSv1.3", "", "", "", "", "ssl.handshake",
"ssl.handshake", GetParam(), nullptr);

// Protocol version logged correctly when connecting using TLSv1.0-TLSv1.3
// for the client and TLSv1.3 for the server.
testUtilV2(listener, client, "", true, "TLSv1.3", "", "", "", "", "ssl.versions.TLSv1.3",
"ssl.versions.TLSv1.3", GetParam(), nullptr);

// Protocol version logged correctly when connecting using TLSv1.0 for both.
client_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
client_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
server_params->set_tls_minimum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
server_params->set_tls_maximum_protocol_version(envoy::api::v2::auth::TlsParameters::TLSv1_0);
testUtilV2(listener, client, "", true, "TLSv1", "", "", "", "", "ssl.versions.TLSv1",
"ssl.versions.TLSv1", GetParam(), nullptr);
}

TEST_P(SslSocketTest, ALPN) {
Expand Down Expand Up @@ -2889,7 +2876,8 @@ TEST_P(SslSocketTest, CipherSuites) {
client_params->add_cipher_suites("ECDHE-RSA-CHACHA20-POLY1305");
server_params->add_cipher_suites("ECDHE-RSA-CHACHA20-POLY1305");
server_params->add_cipher_suites("ECDHE-RSA-AES128-GCM-SHA256");
testUtilV2(listener, client, "", true, "", "", "", "", "", "ssl.handshake", "ssl.handshake",
testUtilV2(listener, client, "", true, "", "", "", "", "",
"ssl.ciphers.ECDHE-RSA-CHACHA20-POLY1305", "ssl.ciphers.ECDHE-RSA-CHACHA20-POLY1305",
GetParam(), nullptr);
client_params->clear_cipher_suites();
server_params->clear_cipher_suites();
Expand Down Expand Up @@ -2934,8 +2922,8 @@ TEST_P(SslSocketTest, EcdhCurves) {
server_params->add_ecdh_curves("X25519");
server_params->add_ecdh_curves("P-256");
server_params->add_cipher_suites("ECDHE-RSA-AES128-GCM-SHA256");
testUtilV2(listener, client, "", true, "", "", "", "", "", "ssl.handshake", "ssl.handshake",
GetParam(), nullptr);
testUtilV2(listener, client, "", true, "", "", "", "", "", "ssl.curves.X25519",
"ssl.curves.X25519", GetParam(), nullptr);
client_params->clear_ecdh_curves();
server_params->clear_ecdh_curves();
server_params->clear_cipher_suites();
Expand All @@ -2951,6 +2939,45 @@ TEST_P(SslSocketTest, EcdhCurves) {
server_params->clear_cipher_suites();
}

TEST_P(SslSocketTest, SignatureAlgorithms) {
envoy::api::v2::Listener listener;
envoy::api::v2::listener::FilterChain* filter_chain = listener.add_filter_chains();
envoy::api::v2::auth::CertificateValidationContext* server_validation_ctx =
filter_chain->mutable_tls_context()
->mutable_common_tls_context()
->mutable_validation_context();
server_validation_ctx->mutable_trusted_ca()->set_filename(
TestEnvironment::substitute("{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem"));
// Server ECDSA certificate.
envoy::api::v2::auth::TlsCertificate* server_cert =
filter_chain->mutable_tls_context()->mutable_common_tls_context()->add_tls_certificates();
server_cert->mutable_certificate_chain()->set_filename(TestEnvironment::substitute(
"{{ test_rundir }}/test/common/ssl/test_data/selfsigned_ecdsa_p256_cert.pem"));
server_cert->mutable_private_key()->set_filename(TestEnvironment::substitute(
"{{ test_rundir }}/test/common/ssl/test_data/selfsigned_ecdsa_p256_key.pem"));

envoy::api::v2::auth::UpstreamTlsContext client;
// Client RSA certificate.
envoy::api::v2::auth::TlsCertificate* client_cert =
client.mutable_common_tls_context()->add_tls_certificates();
client_cert->mutable_certificate_chain()->set_filename(
TestEnvironment::substitute("{{ test_rundir }}/test/common/ssl/test_data/san_uri_cert.pem"));
client_cert->mutable_private_key()->set_filename(
TestEnvironment::substitute("{{ test_rundir }}/test/common/ssl/test_data/san_uri_key.pem"));

// Connection using defaults (client & server) succeeds.
testUtilV2(listener, client, "", true, "", "", "spiffe://lyft.com/test-team", "", "",
"ssl.sigalgs.rsa_pss_rsae_sha256", "ssl.sigalgs.ecdsa_secp256r1_sha256", GetParam(),
nullptr);

// Connection using defaults (client & server) succeeds, even with client renegotiation.
client.set_allow_renegotiation(true);
testUtilV2(listener, client, "", true, "", "", "spiffe://lyft.com/test-team", "", "",
"ssl.sigalgs.rsa_pss_rsae_sha256", "ssl.sigalgs.ecdsa_secp256r1_sha256", GetParam(),
nullptr);
client.set_allow_renegotiation(false);
}

TEST_P(SslSocketTest, RevokedCertificate) {

const std::string server_ctx_yaml = R"EOF(
Expand Down

0 comments on commit 5ff5f95

Please sign in to comment.