diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-07-20 16:01:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-20 16:01:16 +0200 |
commit | 37b82350dd673de1d7375c01838123bf0b1e1a91 (patch) | |
tree | d57a651f4c11589a5acefd26f70b612766857f3f /security-utils/src/main/java/com/yahoo/security/tls | |
parent | 02c4a8fff7668971d0b82581081c1ea9466d5fc8 (diff) | |
parent | 4dcb1c83c96b51ec9a1770c269e75a94debebb9d (diff) |
Merge pull request #23528 from vespa-engine/bjorncs/capabilities
Bjorncs/capabilities [run-systemtest]
Diffstat (limited to 'security-utils/src/main/java/com/yahoo/security/tls')
29 files changed, 136 insertions, 588 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/AuthorizedPeers.java b/security-utils/src/main/java/com/yahoo/security/tls/AuthorizedPeers.java index 5e49a5b341c..9631ab32334 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/AuthorizedPeers.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/AuthorizedPeers.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Set; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/AutoReloadingX509KeyManager.java b/security-utils/src/main/java/com/yahoo/security/tls/AutoReloadingX509KeyManager.java deleted file mode 100644 index 259d4b50d3f..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/AutoReloadingX509KeyManager.java +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import com.yahoo.security.KeyStoreBuilder; -import com.yahoo.security.KeyStoreType; -import com.yahoo.security.KeyUtils; -import com.yahoo.security.X509CertificateUtils; -import com.yahoo.security.X509CertificateWithKey; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedKeyManager; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.KeyStore; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.time.Duration; -import java.util.Arrays; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A {@link X509ExtendedKeyManager} that reloads the certificate and private key from file regularly. - * - * @author bjorncs - */ -public class AutoReloadingX509KeyManager extends X509ExtendedKeyManager implements AutoCloseable { - - public static final String CERTIFICATE_ALIAS = "default"; - - private static final Duration UPDATE_PERIOD = Duration.ofHours(1); - - private static final Logger log = Logger.getLogger(AutoReloadingX509KeyManager.class.getName()); - - private final MutableX509KeyManager mutableX509KeyManager; - private final ScheduledExecutorService scheduler; - private final Path privateKeyFile; - private final Path certificatesFile; - - private AutoReloadingX509KeyManager(Path privateKeyFile, Path certificatesFile) { - this(privateKeyFile, certificatesFile, createDefaultScheduler()); - } - - AutoReloadingX509KeyManager(Path privateKeyFile, Path certificatesFile, ScheduledExecutorService scheduler) { - this.privateKeyFile = privateKeyFile; - this.certificatesFile = certificatesFile; - this.scheduler = scheduler; - this.mutableX509KeyManager = new MutableX509KeyManager(createKeystore(privateKeyFile, certificatesFile), new char[0]); - scheduler.scheduleAtFixedRate( - new KeyManagerReloader(), UPDATE_PERIOD.getSeconds()/*initial delay*/, UPDATE_PERIOD.getSeconds(), TimeUnit.SECONDS); - } - - public static AutoReloadingX509KeyManager fromPemFiles(Path privateKeyFile, Path certificatesFile) { - return new AutoReloadingX509KeyManager(privateKeyFile, certificatesFile); - } - - public X509CertificateWithKey getCurrentCertificateWithKey() { - X509ExtendedKeyManager manager = mutableX509KeyManager.currentManager(); - X509Certificate[] certificateChain = manager.getCertificateChain(CERTIFICATE_ALIAS); - PrivateKey privateKey = manager.getPrivateKey(CERTIFICATE_ALIAS); - return new X509CertificateWithKey(Arrays.asList(certificateChain), privateKey); - } - - private static KeyStore createKeystore(Path privateKey, Path certificateChain) { - try { - return KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withKeyEntry( - CERTIFICATE_ALIAS, - KeyUtils.fromPemEncodedPrivateKey(new String(Files.readAllBytes(privateKey), StandardCharsets.UTF_8)), - X509CertificateUtils.certificateListFromPem(new String(Files.readAllBytes(certificateChain), StandardCharsets.UTF_8))) - .build(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static ScheduledExecutorService createDefaultScheduler() { - return Executors.newSingleThreadScheduledExecutor(runnable -> { - Thread thread = new Thread(runnable, "auto-reloading-x509-key-manager"); - thread.setDaemon(true); - return thread; - }); - } - - private class KeyManagerReloader implements Runnable { - @Override - public void run() { - try { - log.log(Level.FINE, () -> String.format("Reloading key and certificate chain (private-key='%s', certificates='%s')", privateKeyFile, certificatesFile)); - mutableX509KeyManager.updateKeystore(createKeystore(privateKeyFile, certificatesFile), new char[0]); - } catch (Throwable t) { - log.log(Level.SEVERE, - String.format("Failed to load X509 key manager (private-key='%s', certificates='%s'): %s", - privateKeyFile, certificatesFile, t.getMessage()), - t); - } - } - } - - @Override - public void close() { - try { - scheduler.shutdownNow(); - scheduler.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - // - // Methods from X509ExtendedKeyManager - // - - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return mutableX509KeyManager.getServerAliases(keyType, issuers); - } - - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return mutableX509KeyManager.getClientAliases(keyType, issuers); - } - - @Override - public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { - return mutableX509KeyManager.chooseServerAlias(keyType, issuers, socket); - } - - @Override - public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { - return mutableX509KeyManager.chooseClientAlias(keyType, issuers, socket); - } - - @Override - public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { - return mutableX509KeyManager.chooseEngineServerAlias(keyType, issuers, engine); - } - - @Override - public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { - return mutableX509KeyManager.chooseEngineClientAlias(keyType, issuers, engine); - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - return mutableX509KeyManager.getCertificateChain(alias); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - return mutableX509KeyManager.getPrivateKey(alias); - } - -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java b/security-utils/src/main/java/com/yahoo/security/tls/Capability.java index 09d4de37831..0ae253985a6 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/Capability.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Arrays; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/CapabilityMode.java b/security-utils/src/main/java/com/yahoo/security/tls/CapabilityMode.java new file mode 100644 index 00000000000..c2fa11ce7f7 --- /dev/null +++ b/security-utils/src/main/java/com/yahoo/security/tls/CapabilityMode.java @@ -0,0 +1,26 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.security.tls; + +import java.util.Arrays; + +/** + * @author bjorncs + */ +public enum CapabilityMode { + DISABLE("disable"), LOG_ONLY("log_only"), ENFORCE("enforce"); + + private final String configValue; + + CapabilityMode(String configValue) { this.configValue = configValue; } + + public String configValue() { return configValue; } + + /** @return Default value when mode is not explicitly specified */ + public static CapabilityMode defaultValue() { return DISABLE; } + + public static CapabilityMode fromConfigValue(String configValue) { + return Arrays.stream(values()) + .filter(c -> c.configValue.equals(configValue)) + .findFirst().orElseThrow(() -> new IllegalArgumentException("Unknown value: " + configValue)); + } +} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java b/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java index 50de98c621c..ec402719efa 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Arrays; import java.util.Collection; @@ -72,6 +72,9 @@ public class CapabilitySet { public boolean hasAll() { return this.caps.equals(ALL_CAPABILITIES.caps); } public boolean hasNone() { return this.caps.equals(NO_CAPABILITIES.caps); } + public boolean has(CapabilitySet caps) { return this.caps.containsAll(caps.caps); } + public boolean has(Collection<Capability> caps) { return this.caps.containsAll(caps); } + public boolean has(Capability... caps) { return this.caps.containsAll(List.of(caps)); } public SortedSet<String> toNames() { return caps.stream().map(Capability::asString).collect(Collectors.toCollection(TreeSet::new)); diff --git a/security-utils/src/main/java/com/yahoo/security/tls/ConfigFileBasedTlsContext.java b/security-utils/src/main/java/com/yahoo/security/tls/ConfigFileBasedTlsContext.java index cc664786734..69635b92e74 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/ConfigFileBasedTlsContext.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/ConfigFileBasedTlsContext.java @@ -4,9 +4,10 @@ package com.yahoo.security.tls; import com.yahoo.security.KeyStoreBuilder; import com.yahoo.security.KeyStoreType; import com.yahoo.security.KeyUtils; +import com.yahoo.security.MutableX509KeyManager; +import com.yahoo.security.MutableX509TrustManager; import com.yahoo.security.SslContextBuilder; import com.yahoo.security.X509CertificateUtils; -import com.yahoo.security.tls.authz.PeerAuthorizerTrustManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java b/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java new file mode 100644 index 00000000000..b4e8878fb01 --- /dev/null +++ b/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java @@ -0,0 +1,72 @@ +package com.yahoo.security.tls; + +import com.yahoo.security.SubjectAlternativeName; +import com.yahoo.security.X509CertificateUtils; + +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static com.yahoo.security.SubjectAlternativeName.Type.DNS; +import static com.yahoo.security.SubjectAlternativeName.Type.URI; + +/** + * @author bjorncs + */ +public record ConnectionAuthContext(List<X509Certificate> peerCertificateChain, + CapabilitySet capabilities, + Set<String> matchedPolicies) { + + private static final ConnectionAuthContext DEFAULT_ALL_CAPABILITIES = new ConnectionAuthContext(List.of()); + + public ConnectionAuthContext { + peerCertificateChain = List.copyOf(peerCertificateChain); + matchedPolicies = Set.copyOf(matchedPolicies); + } + + private ConnectionAuthContext(List<X509Certificate> certs) { this(certs, CapabilitySet.all(), Set.of()); } + + public boolean authorized() { return !capabilities.hasNone(); } + + public Optional<X509Certificate> peerCertificate() { + return peerCertificateChain.isEmpty() ? Optional.empty() : Optional.of(peerCertificateChain.get(0)); + } + + public Optional<String> peerCertificateString() { + X509Certificate cert = peerCertificate().orElse(null); + if (cert == null) return Optional.empty(); + StringBuilder b = new StringBuilder("["); + String cn = X509CertificateUtils.getSubjectCommonName(cert).orElse(null); + if (cn != null) { + b.append("CN='").append(cn).append("'"); + } + var sans = X509CertificateUtils.getSubjectAlternativeNames(cert); + List<String> dnsNames = sans.stream() + .filter(s -> s.getType() == DNS) + .map(SubjectAlternativeName::getValue) + .toList(); + if (!dnsNames.isEmpty()) { + if (cn != null) b.append(", "); + b.append("SAN_DNS=").append(dnsNames); + } + List<String> uris = sans.stream() + .filter(s -> s.getType() == URI) + .map(SubjectAlternativeName::getValue) + .toList(); + if (!uris.isEmpty()) { + if (cn != null || !dnsNames.isEmpty()) b.append(", "); + b.append("SAN_URI=").append(uris); + } + return Optional.of(b.append("]").toString()); + } + + /** Construct instance with all capabilities */ + public static ConnectionAuthContext defaultAllCapabilities() { return DEFAULT_ALL_CAPABILITIES; } + + /** Construct instance with all capabilities */ + public static ConnectionAuthContext defaultAllCapabilities(List<X509Certificate> certs) { + return new ConnectionAuthContext(certs); + } + +} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/DefaultTlsContext.java b/security-utils/src/main/java/com/yahoo/security/tls/DefaultTlsContext.java index c2ee573dfc6..88e4f409260 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/DefaultTlsContext.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/DefaultTlsContext.java @@ -2,8 +2,6 @@ package com.yahoo.security.tls; import com.yahoo.security.SslContextBuilder; -import com.yahoo.security.tls.authz.PeerAuthorizerTrustManager; -import com.yahoo.security.tls.policy.AuthorizedPeers; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/GlobPattern.java b/security-utils/src/main/java/com/yahoo/security/tls/GlobPattern.java index 46a38a77844..c945e48a361 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/GlobPattern.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/GlobPattern.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Arrays; import java.util.Objects; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java b/security-utils/src/main/java/com/yahoo/security/tls/HostGlobPattern.java index cb9ba13cae4..7e2c40182f0 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/HostGlobPattern.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/HostGlobPattern.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Objects; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/KeyManagerUtils.java b/security-utils/src/main/java/com/yahoo/security/tls/KeyManagerUtils.java deleted file mode 100644 index c9216d7273c..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/KeyManagerUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import com.yahoo.security.KeyStoreBuilder; -import com.yahoo.security.KeyStoreType; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.X509ExtendedKeyManager; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; - -/** - * Utility methods for constructing {@link X509ExtendedKeyManager}. - * - * @author bjorncs - */ -public class KeyManagerUtils { - - public static X509ExtendedKeyManager createDefaultX509KeyManager(KeyStore keystore, char[] password) { - try { - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keystore, password); - KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); - return Arrays.stream(keyManagers) - .filter(manager -> manager instanceof X509ExtendedKeyManager) - .map(X509ExtendedKeyManager.class::cast) - .findFirst() - .orElseThrow(() -> new RuntimeException("No X509ExtendedKeyManager in " + Arrays.asList(keyManagers))); - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } - } - - public static X509ExtendedKeyManager createDefaultX509KeyManager(PrivateKey privateKey, List<X509Certificate> certificateChain) { - KeyStore keystore = KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withKeyEntry("default", privateKey, certificateChain) - .build(); - return createDefaultX509KeyManager(keystore, new char[0]); - } - - public static X509ExtendedKeyManager createDefaultX509KeyManager() { - return createDefaultX509KeyManager(null, new char[0]); - } -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509KeyManager.java b/security-utils/src/main/java/com/yahoo/security/tls/MutableX509KeyManager.java deleted file mode 100644 index 6d784efc3e8..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509KeyManager.java +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedKeyManager; -import java.net.Socket; -import java.security.KeyStore; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.WeakHashMap; - -/** - * A {@link X509ExtendedKeyManager} which can be updated with new certificate chain and private key while in use. - * - * The implementations assumes that aliases are retrieved from the same thread as the certificate chain and private key. - * This is case for OpenJDK 11. - * - * @author bjorncs - */ -public class MutableX509KeyManager extends X509ExtendedKeyManager { - - private final Object monitor = new Object(); - // Not using ThreadLocal as we want the thread local x509 key manager instances to be garbage collected - // when either the thread dies or the MutableX509KeyManager instance is collected (latter not the case for ThreadLocal). - private final WeakHashMap<Thread, X509ExtendedKeyManager> threadLocalManager = new WeakHashMap<>(); - private X509ExtendedKeyManager currentManager; - - public MutableX509KeyManager(KeyStore keystore, char[] password) { - synchronized (monitor) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(keystore, password); - } - } - - public MutableX509KeyManager() { - synchronized (monitor) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(); - } - } - - public void updateKeystore(KeyStore keystore, char[] password) { - synchronized (monitor) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(keystore, password); - } - } - - public void useDefaultKeystore() { - synchronized (monitor) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(); - } - } - - public X509ExtendedKeyManager currentManager() { - synchronized (monitor) { - return currentManager; - } - } - - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return updateAndGetThreadLocalManager() - .getServerAliases(keyType, issuers); - } - - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return updateAndGetThreadLocalManager() - .getClientAliases(keyType, issuers); - } - - @Override - public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { - return updateAndGetThreadLocalManager() - .chooseServerAlias(keyType, issuers, socket); - } - - @Override - public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { - return updateAndGetThreadLocalManager() - .chooseClientAlias(keyType, issuers, socket); - } - - @Override - public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { - return updateAndGetThreadLocalManager() - .chooseEngineServerAlias(keyType, issuers, engine); - } - - @Override - public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { - return updateAndGetThreadLocalManager() - .chooseEngineClientAlias(keyType, issuers, engine); - } - - private X509ExtendedKeyManager updateAndGetThreadLocalManager() { - synchronized (monitor) { - X509ExtendedKeyManager currentManager = this.currentManager; - threadLocalManager.put(Thread.currentThread(), currentManager); - return currentManager; - } - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - if (alias == null) return null; // this method can be called with 'null' alias prior to any alias getter methods. - return getThreadLocalManager() - .getCertificateChain(alias); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - if (alias == null) return null; // this method can be called with 'null' alias prior to any alias getter methods. - return getThreadLocalManager() - .getPrivateKey(alias); - } - - private X509ExtendedKeyManager getThreadLocalManager() { - synchronized (monitor) { - X509ExtendedKeyManager manager = threadLocalManager.get(Thread.currentThread()); - if (manager == null) { - throw new IllegalStateException("Methods to retrieve valid aliases has not been called previously from this thread"); - } - return manager; - } - } -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509TrustManager.java b/security-utils/src/main/java/com/yahoo/security/tls/MutableX509TrustManager.java deleted file mode 100644 index 6db43ef94a9..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509TrustManager.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedTrustManager; -import java.net.Socket; -import java.security.KeyStore; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -/** - * A {@link X509ExtendedTrustManager} which can be updated with new CA certificates while in use. - * - * @author bjorncs - */ -public class MutableX509TrustManager extends X509ExtendedTrustManager { - - private volatile X509ExtendedTrustManager currentManager; - - public MutableX509TrustManager(KeyStore truststore) { - this.currentManager = TrustManagerUtils.createDefaultX509TrustManager(truststore); - } - - public MutableX509TrustManager() { - this.currentManager = TrustManagerUtils.createDefaultX509TrustManager(); - } - - public void updateTruststore(KeyStore truststore) { - this.currentManager = TrustManagerUtils.createDefaultX509TrustManager(truststore); - } - - public void useDefaultTruststore() { - this.currentManager = TrustManagerUtils.createDefaultX509TrustManager(); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - currentManager.checkClientTrusted(chain, authType); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - currentManager.checkServerTrusted(chain, authType); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { - currentManager.checkClientTrusted(chain, authType, socket); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { - currentManager.checkServerTrusted(chain, authType, socket); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException { - currentManager.checkClientTrusted(chain, authType, sslEngine); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) throws CertificateException { - currentManager.checkServerTrusted(chain, authType, sslEngine); - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return currentManager.getAcceptedIssuers(); - } -} 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/PeerAuthorizer.java index a87c578f8c6..5db86fd93bc 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizer.java @@ -1,12 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.authz; +package com.yahoo.security.tls; import com.yahoo.security.SubjectAlternativeName; import com.yahoo.security.X509CertificateUtils; -import com.yahoo.security.tls.policy.AuthorizedPeers; -import com.yahoo.security.tls.policy.CapabilitySet; -import com.yahoo.security.tls.policy.PeerPolicy; -import com.yahoo.security.tls.policy.RequiredPeerCredential; import java.security.cert.X509Certificate; import java.util.HashSet; @@ -15,9 +11,9 @@ import java.util.Optional; import java.util.Set; import java.util.logging.Logger; -import static com.yahoo.security.SubjectAlternativeName.Type.DNS_NAME; -import static com.yahoo.security.SubjectAlternativeName.Type.IP_ADDRESS; -import static com.yahoo.security.SubjectAlternativeName.Type.UNIFORM_RESOURCE_IDENTIFIER; +import static com.yahoo.security.SubjectAlternativeName.Type.DNS; +import static com.yahoo.security.SubjectAlternativeName.Type.IP; +import static com.yahoo.security.SubjectAlternativeName.Type.URI; import static java.util.stream.Collectors.toList; /** @@ -39,9 +35,7 @@ public class PeerAuthorizer { public ConnectionAuthContext authorizePeer(X509Certificate cert) { return authorizePeer(List.of(cert)); } public ConnectionAuthContext authorizePeer(List<X509Certificate> certChain) { - if (authorizedPeers.isEmpty()) { - return new ConnectionAuthContext(certChain, CapabilitySet.all(), Set.of()); - } + if (authorizedPeers.isEmpty()) return ConnectionAuthContext.defaultAllCapabilities(certChain); X509Certificate cert = certChain.get(0); Set<String> matchedPolicies = new HashSet<>(); Set<CapabilitySet> grantedCapabilities = new HashSet<>(); @@ -82,7 +76,7 @@ public class PeerAuthorizer { private static List<String> getSubjectAlternativeNames(X509Certificate peerCertificate) { return X509CertificateUtils.getSubjectAlternativeNames(peerCertificate).stream() - .filter(san -> san.getType() == DNS_NAME || san.getType() == IP_ADDRESS || san.getType() == UNIFORM_RESOURCE_IDENTIFIER) + .filter(san -> san.getType() == DNS || san.getType() == IP || san.getType() == URI) .map(SubjectAlternativeName::getValue) .collect(toList()); } 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/PeerAuthorizerTrustManager.java index 334216a2c19..b92cd6c9538 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizerTrustManager.java @@ -1,12 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.authz; +package com.yahoo.security.tls; +import com.yahoo.security.TrustManagerUtils; import com.yahoo.security.X509CertificateUtils; -import com.yahoo.security.tls.AuthorizationMode; -import com.yahoo.security.tls.HostnameVerification; -import com.yahoo.security.tls.TrustManagerUtils; -import com.yahoo.security.tls.policy.AuthorizedPeers; -import com.yahoo.security.tls.policy.CapabilitySet; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; @@ -18,7 +14,6 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.logging.Logger; /** @@ -110,7 +105,7 @@ public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager { log.fine(() -> "Verifying certificate: " + createInfoString(certChain[0], authType, isVerifyingClient)); ConnectionAuthContext result = mode != AuthorizationMode.DISABLE ? authorizer.authorizePeer(List.of(certChain)) - : new ConnectionAuthContext(List.of(certChain), CapabilitySet.all(), Set.of()); + : ConnectionAuthContext.defaultAllCapabilities(List.of(certChain)); if (sslEngine != null) { // getHandshakeSession() will never return null in this context sslEngine.getHandshakeSession().putValue(HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY, result); } diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java b/security-utils/src/main/java/com/yahoo/security/tls/PeerPolicy.java index cb39e5e9c3c..ea3d4cfe002 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/PeerPolicy.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.List; import java.util.Optional; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java b/security-utils/src/main/java/com/yahoo/security/tls/RequiredPeerCredential.java index 4c96a2935f8..9a18da9dffd 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/RequiredPeerCredential.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/RequiredPeerCredential.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Objects; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptions.java b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptions.java index a8802b7f0d3..4397f27ebb7 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptions.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptions.java @@ -1,9 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.security.tls; -import com.yahoo.security.tls.json.TransportSecurityOptionsJsonSerializer; -import com.yahoo.security.tls.policy.AuthorizedPeers; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptionsEntity.java index b80a7e4f2fb..f1799a64a57 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptionsEntity.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.json; +package com.yahoo.security.tls; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptionsJsonSerializer.java index fcd84056212..0349d4085db 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptionsJsonSerializer.java @@ -1,16 +1,11 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.json; +package com.yahoo.security.tls; import com.fasterxml.jackson.databind.ObjectMapper; -import com.yahoo.security.tls.TransportSecurityOptions; -import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.AuthorizedPeer; -import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.CredentialField; -import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.Files; -import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.RequiredCredential; -import com.yahoo.security.tls.policy.AuthorizedPeers; -import com.yahoo.security.tls.policy.CapabilitySet; -import com.yahoo.security.tls.policy.PeerPolicy; -import com.yahoo.security.tls.policy.RequiredPeerCredential; +import com.yahoo.security.tls.TransportSecurityOptionsEntity.AuthorizedPeer; +import com.yahoo.security.tls.TransportSecurityOptionsEntity.CredentialField; +import com.yahoo.security.tls.TransportSecurityOptionsEntity.Files; +import com.yahoo.security.tls.TransportSecurityOptionsEntity.RequiredCredential; import java.io.IOException; import java.io.InputStream; @@ -29,11 +24,11 @@ import static java.util.stream.Collectors.toSet; /** * @author bjorncs */ -public class TransportSecurityOptionsJsonSerializer { +class TransportSecurityOptionsJsonSerializer { private static final ObjectMapper mapper = new ObjectMapper(); - public TransportSecurityOptions deserialize(InputStream in) { + TransportSecurityOptions deserialize(InputStream in) { try { TransportSecurityOptionsEntity entity = mapper.readValue(in, TransportSecurityOptionsEntity.class); return toTransportSecurityOptions(entity); @@ -42,7 +37,7 @@ public class TransportSecurityOptionsJsonSerializer { } } - public void serialize(OutputStream out, TransportSecurityOptions options) { + void serialize(OutputStream out, TransportSecurityOptions options) { try { mapper.writerWithDefaultPrettyPrinter().writeValue(out, toTransportSecurityOptionsEntity(options)); } catch (IOException e) { diff --git a/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityUtils.java b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityUtils.java index cbd3857d2d5..21d97613f95 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityUtils.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityUtils.java @@ -18,6 +18,7 @@ public class TransportSecurityUtils { public static final String CONFIG_FILE_ENVIRONMENT_VARIABLE = "VESPA_TLS_CONFIG_FILE"; public static final String INSECURE_MIXED_MODE_ENVIRONMENT_VARIABLE = "VESPA_TLS_INSECURE_MIXED_MODE"; public static final String INSECURE_AUTHORIZATION_MODE_ENVIRONMENT_VARIABLE = "VESPA_TLS_INSECURE_AUTHORIZATION_MODE"; + public static final String CAPABILITIES_ENV_VAR = "VESPA_TLS_CAPABILITIES_ENFORCEMENT_MODE"; private TransportSecurityUtils() {} @@ -49,6 +50,12 @@ public class TransportSecurityUtils { .orElse(AuthorizationMode.defaultValue()); } + public static CapabilityMode getCapabilityMode() { + return getEnvironmentVariable(System.getenv(), CAPABILITIES_ENV_VAR) + .map(CapabilityMode::fromConfigValue) + .orElse(CapabilityMode.defaultValue()); + } + public static Optional<Path> getConfigFile() { return getConfigFile(System.getenv()); } diff --git a/security-utils/src/main/java/com/yahoo/security/tls/TrustAllX509TrustManager.java b/security-utils/src/main/java/com/yahoo/security/tls/TrustAllX509TrustManager.java deleted file mode 100644 index b0303620cf7..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/TrustAllX509TrustManager.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedTrustManager; -import java.net.Socket; -import java.security.cert.X509Certificate; - -/** - * A {@link X509ExtendedTrustManager} that accepts all server certificates. - * - * @author bjorncs - */ -public class TrustAllX509TrustManager extends X509ExtendedTrustManager { - @Override public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) { failWhenUsedOnServer(); } - @Override public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { failWhenUsedOnServer(); } - @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { failWhenUsedOnServer(); } - - @Override public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) {} - @Override public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) {} - @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {} - @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - - private static void failWhenUsedOnServer() { - throw new IllegalStateException("TrustAllX509TrustManager cannot be used on server, only client"); - } -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/TrustManagerUtils.java b/security-utils/src/main/java/com/yahoo/security/tls/TrustManagerUtils.java deleted file mode 100644 index 4172e337789..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/TrustManagerUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls; - -import com.yahoo.security.KeyStoreBuilder; -import com.yahoo.security.KeyStoreType; - -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509ExtendedTrustManager; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; - -/** - * Utility methods for constructing {@link X509ExtendedTrustManager}. - * - * @author bjorncs - */ -public class TrustManagerUtils { - - public static X509ExtendedTrustManager createDefaultX509TrustManager(KeyStore truststore) { - try { - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(truststore); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - return Arrays.stream(trustManagers) - .filter(manager -> manager instanceof X509ExtendedTrustManager) - .map(X509ExtendedTrustManager.class::cast) - .findFirst() - .orElseThrow(() -> new RuntimeException("No X509ExtendedTrustManager in " + Arrays.asList(trustManagers))); - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } - } - - public static X509ExtendedTrustManager createDefaultX509TrustManager(List<X509Certificate> certificates) { - return createDefaultX509TrustManager( - KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withCertificateEntries("cert", certificates) - .build()); - } - - public static X509ExtendedTrustManager createDefaultX509TrustManager() { - return createDefaultX509TrustManager((KeyStore) null); - } -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/UriGlobPattern.java b/security-utils/src/main/java/com/yahoo/security/tls/UriGlobPattern.java index b2cc0688bb9..18d18a5ab3c 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/UriGlobPattern.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/UriGlobPattern.java @@ -1,5 +1,5 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.policy; +package com.yahoo.security.tls; import java.util.Objects; 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 deleted file mode 100644 index 877ba4e74bd..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.yahoo.security.tls.authz; - -import com.yahoo.security.tls.policy.CapabilitySet; - -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Set; - -/** - * @author bjorncs - */ -public record ConnectionAuthContext(List<X509Certificate> peerCertificateChain, - CapabilitySet capabilities, - Set<String> matchedPolicies) { - - public ConnectionAuthContext { - if (peerCertificateChain.isEmpty()) throw new IllegalArgumentException("Peer certificate chain is empty"); - peerCertificateChain = List.copyOf(peerCertificateChain); - matchedPolicies = Set.copyOf(matchedPolicies); - } - - public boolean authorized() { return !capabilities.hasNone(); } - - public X509Certificate peerCertificate() { return peerCertificateChain.get(0); } - -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/package-info.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/package-info.java deleted file mode 100644 index 5066026757d..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author bjorncs - */ -@ExportPackage -package com.yahoo.security.tls.authz; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/security-utils/src/main/java/com/yahoo/security/tls/https/package-info.java b/security-utils/src/main/java/com/yahoo/security/tls/https/package-info.java deleted file mode 100644 index 91a1672e19f..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/https/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author bjorncs - */ -@ExportPackage -package com.yahoo.security.tls.https; - -import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/package-info.java b/security-utils/src/main/java/com/yahoo/security/tls/json/package-info.java deleted file mode 100644 index be7ec33bf04..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/json/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author bjorncs - */ -@ExportPackage -package com.yahoo.security.tls.json; - -import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/package-info.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/package-info.java deleted file mode 100644 index 61ce90654f8..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * @author bjorncs - */ -@ExportPackage -package com.yahoo.security.tls.policy; - -import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file |