diff options
author | Øyvind Grønnesby <oyving@verizonmedia.com> | 2022-01-30 12:42:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-30 12:42:11 +0100 |
commit | 9d4a1d80b09d58a6a91257e45afdf6bb3315a7d3 (patch) | |
tree | 87f2edf4b66ee026b1d75e5c27b32d36d556b49a | |
parent | 03edb19207234e238db22d81ae3d613aaf14f965 (diff) | |
parent | 2f1e67ec08a409f074b7f59975cb33ab6b9cf612 (diff) |
Merge pull request #20960 from vespa-engine/bjorncs/connection-log
Add issuer and fingerprint of peer certificate to connection log
3 files changed, 42 insertions, 6 deletions
diff --git a/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java b/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java index 26cdd1597c5..e2eeb5d3517 100644 --- a/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java +++ b/container-core/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java @@ -31,6 +31,8 @@ public class ConnectionLogEntry { private final String sslPeerSubject; private final Instant sslPeerNotBefore; private final Instant sslPeerNotAfter; + private final String sslPeerIssuerSubject; + private final String sslPeerFingerprint; private final String sslSniServerName; private final SslHandshakeFailure sslHandshakeFailure; private final List<String> sslSubjectAlternativeNames; @@ -58,6 +60,8 @@ public class ConnectionLogEntry { this.sslPeerSubject = builder.sslPeerSubject; this.sslPeerNotBefore = builder.sslPeerNotBefore; this.sslPeerNotAfter = builder.sslPeerNotAfter; + this.sslPeerIssuerSubject = builder.sslPeerIssuerSubject; + this.sslPeerFingerprint = builder.sslPeerFingerprint; this.sslSniServerName = builder.sslSniServerName; this.sslHandshakeFailure = builder.sslHandshakeFailure; this.sslSubjectAlternativeNames = builder.sslSubjectAlternativeNames; @@ -88,6 +92,8 @@ public class ConnectionLogEntry { public Optional<String> sslPeerSubject() { return Optional.ofNullable(sslPeerSubject); } public Optional<Instant> sslPeerNotBefore() { return Optional.ofNullable(sslPeerNotBefore); } public Optional<Instant> sslPeerNotAfter() { return Optional.ofNullable(sslPeerNotAfter); } + public Optional<String> sslPeerIssuerSubject() { return Optional.ofNullable(sslPeerIssuerSubject); } + public Optional<String> sslPeerFingerprint() { return Optional.ofNullable(sslPeerFingerprint); } public Optional<String> sslSniServerName() { return Optional.ofNullable(sslSniServerName); } public Optional<SslHandshakeFailure> sslHandshakeFailure() { return Optional.ofNullable(sslHandshakeFailure); } public List<String> sslSubjectAlternativeNames() { return sslSubjectAlternativeNames == null ? List.of() : sslSubjectAlternativeNames; } @@ -140,6 +146,8 @@ public class ConnectionLogEntry { private String sslPeerSubject; private Instant sslPeerNotBefore; private Instant sslPeerNotAfter; + private String sslPeerIssuerSubject; + private String sslPeerFingerprint; private String sslSniServerName; private SslHandshakeFailure sslHandshakeFailure; private List<String> sslSubjectAlternativeNames; @@ -221,6 +229,14 @@ public class ConnectionLogEntry { this.sslPeerNotAfter = sslPeerNotAfter; return this; } + public Builder withSslPeerIssuerSubject(String value) { + this.sslPeerIssuerSubject = value; + return this; + } + public Builder withSslPeerFingerprint(String value) { + this.sslPeerFingerprint = value; + return this; + } public Builder withSslSniServerName(String sslSniServerName) { this.sslSniServerName = sslSniServerName; return this; diff --git a/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java b/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java index d686c97249f..6d98c247ca0 100644 --- a/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java +++ b/container-core/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java @@ -68,20 +68,24 @@ class JsonConnectionLogWriter implements LogWriter<ConnectionLogEntry> { Instant sslPeerNotBefore = unwrap(record.sslPeerNotBefore()); Instant sslPeerNotAfter = unwrap(record.sslPeerNotAfter()); String sslSniServerName = unwrap(record.sslSniServerName()); + String sslPeerIssuerSubject = unwrap(record.sslPeerIssuerSubject()); + String sslPeerFingerprint = unwrap(record.sslPeerFingerprint()); ConnectionLogEntry.SslHandshakeFailure sslHandshakeFailure = unwrap(record.sslHandshakeFailure()); List<String> sslSubjectAlternativeNames = record.sslSubjectAlternativeNames(); if (isAnyValuePresent( sslProtocol, sslSessionId, sslCipherSuite, sslPeerSubject, sslPeerNotBefore, sslPeerNotAfter, - sslSniServerName, sslHandshakeFailure)) { + sslSniServerName, sslHandshakeFailure, sslPeerIssuerSubject, sslPeerFingerprint)) { generator.writeObjectFieldStart("ssl"); writeOptionalString(generator, "protocol", sslProtocol); writeOptionalString(generator, "sessionId", sslSessionId); writeOptionalString(generator, "cipherSuite", sslCipherSuite); writeOptionalString(generator, "peerSubject", sslPeerSubject); + writeOptionalString(generator, "peerIssuerSubject", sslPeerIssuerSubject); writeOptionalTimestamp(generator, "peerNotBefore", sslPeerNotBefore); writeOptionalTimestamp(generator, "peerNotAfter", sslPeerNotAfter); + writeOptionalString(generator, "peerFingerprint", sslPeerFingerprint); writeOptionalString(generator, "sniServerName", sslSniServerName); if (sslHandshakeFailure != null) { diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java index 451a7dbf10d..4e3fd3f29b3 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java @@ -30,6 +30,9 @@ import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.StandardConstants; import java.net.InetSocketAddress; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.time.Instant; import java.util.ArrayList; @@ -227,7 +230,6 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List throw new IllegalArgumentException("Unknown connection endpoint type: " + endpoint.getClass().getName()); } } - @FunctionalInterface private interface ListenerHandler { void run() throws Exception; } private static class ConnectionInfo { @@ -249,6 +251,8 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List private Date sslPeerNotBefore; private Date sslPeerNotAfter; private List<SNIServerName> sslSniServerNames; + private String sslPeerIssuerSubject; + private byte[] sslPeerEncodedCertificate; private SSLHandshakeException sslHandshakeException; private List<String> sslSubjectAlternativeNames; private String proxyProtocolVersion; @@ -307,8 +311,9 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List this.sslSubjectAlternativeNames = X509CertificateUtils.getSubjectAlternativeNames(peerCertificate).stream() .map(SubjectAlternativeName::getValue) .collect(Collectors.toList()); - - } catch (SSLPeerUnverifiedException e) { + this.sslPeerIssuerSubject = peerCertificate.getIssuerDN().getName(); + this.sslPeerEncodedCertificate = peerCertificate.getEncoded(); + } catch (SSLPeerUnverifiedException | CertificateEncodingException e) { // Throw if peer is not authenticated (e.g when client auth is disabled) // JSSE provides no means of checking for client authentication without catching this exception } @@ -365,10 +370,13 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List .findAny() .ifPresent(builder::withSslSniServerName); } - if (sslPeerSubject != null && sslPeerNotAfter != null && sslPeerNotBefore != null) { + if (sslPeerSubject != null && sslPeerNotAfter != null && sslPeerNotBefore != null + && sslPeerIssuerSubject != null && sslPeerEncodedCertificate != null) { builder.withSslPeerSubject(sslPeerSubject) + .withSslPeerIssuerSubject(sslPeerIssuerSubject) .withSslPeerNotAfter(sslPeerNotAfter.toInstant()) - .withSslPeerNotBefore(sslPeerNotBefore.toInstant()); + .withSslPeerNotBefore(sslPeerNotBefore.toInstant()) + .withSslPeerFingerprint(certificateFingerprint(sslPeerEncodedCertificate)); } if (sslSubjectAlternativeNames != null && !sslSubjectAlternativeNames.isEmpty()) { builder.withSslSubjectAlternativeNames(sslSubjectAlternativeNames); @@ -394,6 +402,14 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List return builder.build(); } + private static String certificateFingerprint(byte[] derEncoded) { + try { + return HexDump.toHexString(MessageDigest.getInstance("SHA-1").digest(derEncoded)); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + } } |