diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-04-08 15:32:04 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-04-08 15:40:15 +0200 |
commit | 440de4cd80bf0640445ba854efc12942b2344b3a (patch) | |
tree | c435d38b3e4f75ed4b7c2b79940ca4cfafaae81c /jdisc_http_service/src | |
parent | 7ed8e0eda85d186d6a8250112a4a52a6a7cbc9ad (diff) |
Report expired client certificate as a separate metric
Diffstat (limited to 'jdisc_http_service/src')
3 files changed, 46 insertions, 0 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java index c5f42ff9cc5..04db58f6d07 100644 --- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java @@ -110,6 +110,7 @@ public class JettyHttpServer extends AbstractServerProvider { String CONTENT_SIZE = "jdisc.http.request.content_size"; String SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT = "jdisc.http.ssl.handshake.failure.missing_client_cert"; + String SSL_HANDSHAKE_FAILURE_EXPIRED_CLIENT_CERT = "jdisc.http.ssl.handshake.failure.expired_client_cert"; String SSL_HANDSHAKE_FAILURE_INVALID_CLIENT_CERT = "jdisc.http.ssl.handshake.failure.invalid_client_cert"; String SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_PROTOCOLS = "jdisc.http.ssl.handshake.failure.incompatible_protocols"; String SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_CIPHERS = "jdisc.http.ssl.handshake.failure.incompatible_ciphers"; diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java index 886071243ba..75df82036a2 100644 --- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java +++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/SslHandshakeFailedListener.java @@ -56,6 +56,10 @@ class SslHandshakeFailedListener implements SslHandshakeListener { MISSING_CLIENT_CERT( Metrics.SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT, "Empty server certificate chain"), + EXPIRED_CLIENT_CERTIFICATE( + Metrics.SSL_HANDSHAKE_FAILURE_EXPIRED_CLIENT_CERT, + // Note: this pattern will match certificates with too late notBefore as well + "PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed"), INVALID_CLIENT_CERT( Metrics.SSL_HANDSHAKE_FAILURE_INVALID_CLIENT_CERT, "PKIX path (building|validation) failed: .+"); diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java index f2f3fb0ef11..dfa4fe37ef3 100644 --- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java +++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java @@ -27,6 +27,8 @@ import com.yahoo.jdisc.http.server.jetty.JettyHttpServer.Metrics; import com.yahoo.jdisc.http.server.jetty.TestDrivers.TlsClientAuth; import com.yahoo.jdisc.service.BindingSetNotFoundException; import com.yahoo.security.KeyUtils; +import com.yahoo.security.Pkcs10Csr; +import com.yahoo.security.Pkcs10CsrBuilder; import com.yahoo.security.SslContextBuilder; import com.yahoo.security.X509CertificateBuilder; import com.yahoo.security.X509CertificateUtils; @@ -56,6 +58,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; +import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -667,6 +670,29 @@ public class HttpServerTest { } @Test + public void requireThatMetricIsIncrementedWhenClientUsesExpiredCertificateInHandshake() throws IOException { + Path rootPrivateKeyFile = tmpFolder.newFile().toPath(); + Path rootCertificateFile = tmpFolder.newFile().toPath(); + Path privateKeyFile = tmpFolder.newFile().toPath(); + Path certificateFile = tmpFolder.newFile().toPath(); + Instant notAfter = Instant.now().minus(100, ChronoUnit.DAYS); + generatePrivateKeyAndCertificate(rootPrivateKeyFile, rootCertificateFile, privateKeyFile, certificateFile, notAfter); + var metricConsumer = new MetricConsumerMock(); + TestDriver driver = createSslTestDriver(rootCertificateFile, rootPrivateKeyFile, metricConsumer); + + SSLContext clientCtx = new SslContextBuilder() + .withTrustStore(rootCertificateFile) + .withKeyStore(privateKeyFile, certificateFile) + .build(); + + assertHttpsRequestTriggersSslHandshakeException( + driver, clientCtx, null, null, "Received fatal alert: certificate_unknown"); + verify(metricConsumer.mockitoMock()) + .add(Metrics.SSL_HANDSHAKE_FAILURE_EXPIRED_CLIENT_CERT, 1L, MetricConsumerMock.STATIC_CONTEXT); + assertThat(driver.close(), is(true)); + } + + @Test public void requireThatProxyProtocolIsAcceptedAndActualRemoteAddressStoredInAccessLog() throws Exception { Path privateKeyFile = tmpFolder.newFile().toPath(); Path certificateFile = tmpFolder.newFile().toPath(); @@ -788,6 +814,21 @@ public class HttpServerTest { Files.writeString(certificateFile, X509CertificateUtils.toPem(certificate)); } + private static void generatePrivateKeyAndCertificate(Path rootPrivateKeyFile, Path rootCertificateFile, + Path privateKeyFile, Path certificateFile, Instant notAfter) throws IOException { + generatePrivateKeyAndCertificate(rootPrivateKeyFile, rootCertificateFile); + X509Certificate rootCertificate = X509CertificateUtils.fromPem(Files.readString(rootCertificateFile)); + PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(Files.readString(rootPrivateKeyFile)); + + KeyPair keyPair = KeyUtils.generateKeypair(RSA, 2048); + Files.writeString(privateKeyFile, KeyUtils.toPem(keyPair.getPrivate())); + Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(new X500Principal("CN=myclient"), keyPair, SHA256_WITH_RSA).build(); + X509Certificate certificate = X509CertificateBuilder + .fromCsr(csr, rootCertificate.getSubjectX500Principal(), Instant.EPOCH, notAfter, privateKey, SHA256_WITH_RSA, BigInteger.ONE) + .build(); + Files.writeString(certificateFile, X509CertificateUtils.toPem(certificate)); + } + private static RequestHandler mockRequestHandler() { final RequestHandler mockRequestHandler = mock(RequestHandler.class); when(mockRequestHandler.refer()).thenReturn(References.NOOP_REFERENCE); |