summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-13 17:21:22 +0200
committerBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-15 15:35:10 +0200
commite69c68a2c4b9b8f8d556f376c8f023f602a95eff (patch)
treed6ebd79ecabb3292139e288e5c0ab8a33c8f9ea3
parenteed3e5deaf3fd13c353361e45420735a93d0f3d0 (diff)
Include full certificate chain in auth context
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java2
-rw-r--r--jrt/tests/com/yahoo/jrt/EchoTest.java4
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java7
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java12
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java22
5 files changed, 29 insertions, 18 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
index 6ca39a25d9c..288d064f150 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/security/MultiTenantRpcAuthorizer.java
@@ -173,7 +173,7 @@ public class MultiTenantRpcAuthorizer implements RpcAuthorizer {
}
return Optional.empty(); // client choose to communicate over insecure channel
}
- List<X509Certificate> certChain = authCtx.get().peerCertificate();
+ List<X509Certificate> certChain = authCtx.get().peerCertificateChain();
if (certChain.isEmpty()) {
throw new IllegalStateException("Client authentication is not enforced!"); // clients should be required to authenticate when TLS is enabled
}
diff --git a/jrt/tests/com/yahoo/jrt/EchoTest.java b/jrt/tests/com/yahoo/jrt/EchoTest.java
index 7213068c0f9..e6243eaf4da 100644
--- a/jrt/tests/com/yahoo/jrt/EchoTest.java
+++ b/jrt/tests/com/yahoo/jrt/EchoTest.java
@@ -64,7 +64,7 @@ public class EchoTest {
assertEquals(1, metrics.clientTlsConnectionsEstablished());
},
(ConnectionAuthContextAssertion) context -> {
- List<X509Certificate> chain = context.peerCertificate();
+ List<X509Certificate> chain = context.peerCertificateChain();
assertEquals(1, chain.size());
assertEquals(CryptoUtils.certificate, chain.get(0));
}},
@@ -82,7 +82,7 @@ public class EchoTest {
assertEquals(1, metrics.clientTlsConnectionsEstablished());
},
(ConnectionAuthContextAssertion) context -> {
- List<X509Certificate> chain = context.peerCertificate();
+ List<X509Certificate> chain = context.peerCertificateChain();
assertEquals(1, chain.size());
assertEquals(CryptoUtils.certificate, chain.get(0));
}}};
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java
index a5fb51da763..18f61fc7aa4 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java
@@ -10,14 +10,19 @@ import java.util.TreeSet;
/**
* @author bjorncs
*/
-public record ConnectionAuthContext(List<X509Certificate> peerCertificate,
+public record ConnectionAuthContext(List<X509Certificate> peerCertificateChain,
CapabilitySet capabilities,
SortedSet<String> matchedPolicies) {
public ConnectionAuthContext {
+ if (peerCertificateChain.isEmpty()) throw new IllegalArgumentException("Peer certificate chain is empty");
+ peerCertificateChain = List.copyOf(peerCertificateChain);
+ if (matchedPolicies.isEmpty() && !CapabilitySet.none().equals(capabilities)) throw new AssertionError();
matchedPolicies = new TreeSet<>(matchedPolicies);
}
public boolean succeeded() { return matchedPolicies.size() > 0; }
+ public X509Certificate peerCertificate() { return peerCertificateChain.get(0); }
+
}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
index 353f704b136..30b6ac3f34b 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java
@@ -37,11 +37,15 @@ public class PeerAuthorizer {
this.authorizedPeers = authorizedPeers;
}
- public ConnectionAuthContext authorizePeer(X509Certificate peerCertificate) {
+
+ public ConnectionAuthContext authorizePeer(X509Certificate cert) { return authorizePeer(List.of(cert)); }
+
+ public ConnectionAuthContext authorizePeer(List<X509Certificate> certChain) {
+ X509Certificate cert = certChain.get(0);
SortedSet<String> matchedPolicies = new TreeSet<>();
Set<CapabilitySet> grantedCapabilities = new HashSet<>();
- String cn = getCommonName(peerCertificate).orElse(null);
- List<String> sans = getSubjectAlternativeNames(peerCertificate);
+ String cn = getCommonName(cert).orElse(null);
+ List<String> sans = getSubjectAlternativeNames(cert);
log.fine(() -> String.format("Subject info from x509 certificate: CN=[%s], 'SAN=%s", cn, sans));
for (PeerPolicy peerPolicy : authorizedPeers.peerPolicies()) {
if (matchesPolicy(peerPolicy, cn, sans)) {
@@ -49,7 +53,7 @@ public class PeerAuthorizer {
grantedCapabilities.add(peerPolicy.capabilities());
}
}
- return new ConnectionAuthContext(List.of(peerCertificate), CapabilitySet.unionOf(grantedCapabilities), matchedPolicies);
+ return new ConnectionAuthContext(certChain, CapabilitySet.unionOf(grantedCapabilities), matchedPolicies);
}
private static boolean matchesPolicy(PeerPolicy peerPolicy, String cn, List<String> sans) {
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java
index 925e21c63ff..ea920a90c7b 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java
@@ -15,6 +15,7 @@ import java.net.Socket;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
@@ -55,39 +56,39 @@ public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType);
- authorizePeer(chain[0], authType, true, null);
+ authorizePeer(chain, authType, true, null);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkServerTrusted(chain, authType);
- authorizePeer(chain[0], authType, false, null);
+ authorizePeer(chain, authType, false, null);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType, socket);
- authorizePeer(chain[0], authType, true, null);
+ authorizePeer(chain, authType, true, null);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
overrideHostnameVerificationForClient(socket);
defaultTrustManager.checkServerTrusted(chain, authType, socket);
- authorizePeer(chain[0], authType, false, null);
+ authorizePeer(chain, authType, false, null);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType, sslEngine);
- authorizePeer(chain[0], authType, true, sslEngine);
+ authorizePeer(chain, authType, true, sslEngine);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException {
overrideHostnameVerificationForClient(sslEngine);
defaultTrustManager.checkServerTrusted(chain, authType, sslEngine);
- authorizePeer(chain[0], authType, false, sslEngine);
+ authorizePeer(chain, authType, false, sslEngine);
}
@Override
@@ -103,18 +104,19 @@ public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager {
.flatMap(session -> Optional.ofNullable((ConnectionAuthContext) session.getValue(HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY)));
}
- private void authorizePeer(X509Certificate certificate, String authType, boolean isVerifyingClient, SSLEngine sslEngine) throws CertificateException {
+ private void authorizePeer(X509Certificate[] certChain, String authType, boolean isVerifyingClient, SSLEngine sslEngine) throws CertificateException {
if (mode == AuthorizationMode.DISABLE) return;
- log.fine(() -> "Verifying certificate: " + createInfoString(certificate, authType, isVerifyingClient));
- ConnectionAuthContext result = authorizer.authorizePeer(certificate);
+
+ log.fine(() -> "Verifying certificate: " + createInfoString(certChain[0], authType, isVerifyingClient));
+ ConnectionAuthContext result = authorizer.authorizePeer(List.of(certChain));
if (sslEngine != null) { // getHandshakeSession() will never return null in this context
sslEngine.getHandshakeSession().putValue(HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY, result);
}
if (result.succeeded()) {
log.fine(() -> String.format("Verification result: %s", result));
} else {
- String errorMessage = "Authorization failed: " + createInfoString(certificate, authType, isVerifyingClient);
+ String errorMessage = "Authorization failed: " + createInfoString(certChain[0], authType, isVerifyingClient);
log.warning(errorMessage);
if (mode == AuthorizationMode.ENFORCE) {
throw new CertificateException(errorMessage);