From a9e317a5dd2370866bc5c519d522a824cf118c8e Mon Sep 17 00:00:00 2001 From: Arnstein Ressem Date: Mon, 18 Feb 2019 19:10:00 +0100 Subject: Revert "Bjorncs/jdisc mixed mode preparations" --- .../java/com/yahoo/security/SslContextBuilder.java | 66 ++++----- .../security/tls/AutoReloadingX509KeyManager.java | 150 --------------------- .../com/yahoo/security/tls/DefaultTlsContext.java | 90 +++++-------- .../com/yahoo/security/tls/KeyManagerUtils.java | 49 ------- .../yahoo/security/tls/MutableX509KeyManager.java | 106 --------------- .../security/tls/MutableX509TrustManager.java | 70 ---------- .../yahoo/security/tls/ReloadingTlsContext.java | 98 ++------------ .../java/com/yahoo/security/tls/TlsContext.java | 7 - .../com/yahoo/security/tls/TrustManagerUtils.java | 50 ------- .../tls/authz/PeerAuthorizerTrustManager.java | 22 ++- .../authz/PeerAuthorizerTrustManagersFactory.java | 8 +- .../tls/AutoReloadingX509KeyManagerTest.java | 84 ------------ .../security/tls/MutableX509KeyManagerTest.java | 65 --------- .../security/tls/MutableX509TrustManagerTest.java | 59 -------- 14 files changed, 107 insertions(+), 817 deletions(-) delete mode 100644 security-utils/src/main/java/com/yahoo/security/tls/AutoReloadingX509KeyManager.java delete mode 100644 security-utils/src/main/java/com/yahoo/security/tls/KeyManagerUtils.java delete mode 100644 security-utils/src/main/java/com/yahoo/security/tls/MutableX509KeyManager.java delete mode 100644 security-utils/src/main/java/com/yahoo/security/tls/MutableX509TrustManager.java delete mode 100644 security-utils/src/main/java/com/yahoo/security/tls/TrustManagerUtils.java delete mode 100644 security-utils/src/test/java/com/yahoo/security/tls/AutoReloadingX509KeyManagerTest.java delete mode 100644 security-utils/src/test/java/com/yahoo/security/tls/MutableX509KeyManagerTest.java delete mode 100644 security-utils/src/test/java/com/yahoo/security/tls/MutableX509TrustManagerTest.java (limited to 'security-utils/src') diff --git a/security-utils/src/main/java/com/yahoo/security/SslContextBuilder.java b/security-utils/src/main/java/com/yahoo/security/SslContextBuilder.java index 1ef4df9c7bc..09a5a87138f 100644 --- a/security-utils/src/main/java/com/yahoo/security/SslContextBuilder.java +++ b/security-utils/src/main/java/com/yahoo/security/SslContextBuilder.java @@ -1,14 +1,11 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.security; -import com.yahoo.security.tls.KeyManagerUtils; -import com.yahoo.security.tls.TrustManagerUtils; - import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedKeyManager; -import javax.net.ssl.X509ExtendedTrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -22,17 +19,14 @@ import java.util.List; import static java.util.Collections.singletonList; /** - * A builder for {@link SSLContext}. - * * @author bjorncs */ public class SslContextBuilder { - private KeyStoreSupplier trustStoreSupplier = () -> null; - private KeyStoreSupplier keyStoreSupplier = () -> null; + private KeyStoreSupplier trustStoreSupplier; + private KeyStoreSupplier keyStoreSupplier; private char[] keyStorePassword; - private TrustManagerFactory trustManagerFactory = TrustManagerUtils::createDefaultX509TrustManager; - private KeyManagerFactory keyManagerFactory = KeyManagerUtils::createDefaultX509KeyManager; + private TrustManagersFactory trustManagersFactory = SslContextBuilder::createDefaultTrustManagers; public SslContextBuilder() {} @@ -100,21 +94,18 @@ public class SslContextBuilder { return this; } - public SslContextBuilder withTrustManagerFactory(TrustManagerFactory trustManagersFactory) { - this.trustManagerFactory = trustManagersFactory; - return this; - } - - public SslContextBuilder withKeyManagerFactory(KeyManagerFactory keyManagerFactory) { - this.keyManagerFactory = keyManagerFactory; + public SslContextBuilder withTrustManagerFactory(TrustManagersFactory trustManagersFactory) { + this.trustManagersFactory = trustManagersFactory; return this; } public SSLContext build() { try { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); - TrustManager[] trustManagers = new TrustManager[] { trustManagerFactory.createTrustManager(trustStoreSupplier.get()) }; - KeyManager[] keyManagers = new KeyManager[] { keyManagerFactory.createKeyManager(keyStoreSupplier.get(), keyStorePassword) }; + TrustManager[] trustManagers = + trustStoreSupplier != null ? createTrustManagers(trustManagersFactory, trustStoreSupplier) : null; + KeyManager[] keyManagers = + keyStoreSupplier != null ? createKeyManagers(keyStoreSupplier, keyStorePassword) : null; sslContext.init(keyManagers, trustManagers, null); return sslContext; } catch (GeneralSecurityException e) { @@ -124,6 +115,27 @@ public class SslContextBuilder { } } + private static TrustManager[] createTrustManagers(TrustManagersFactory trustManagersFactory, KeyStoreSupplier trustStoreSupplier) + throws GeneralSecurityException, IOException { + KeyStore truststore = trustStoreSupplier.get(); + return trustManagersFactory.createTrustManagers(truststore); + } + + private static TrustManager[] createDefaultTrustManagers(KeyStore truststore) throws GeneralSecurityException { + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(truststore); + return trustManagerFactory.getTrustManagers(); + } + + private static KeyManager[] createKeyManagers(KeyStoreSupplier keyStoreSupplier, char[] password) + throws GeneralSecurityException, IOException { + KeyManagerFactory keyManagerFactory = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStoreSupplier.get(), password); + return keyManagerFactory.getKeyManagers(); + } + private static KeyStore createTrustStore(List caCertificates) { KeyStoreBuilder trustStoreBuilder = KeyStoreBuilder.withType(KeyStoreType.JKS); for (int i = 0; i < caCertificates.size(); i++) { @@ -137,19 +149,11 @@ public class SslContextBuilder { } /** - * A factory interface for creating {@link X509ExtendedTrustManager}. - */ - @FunctionalInterface - public interface TrustManagerFactory { - X509ExtendedTrustManager createTrustManager(KeyStore truststore) throws GeneralSecurityException; - } - - /** - * A factory interface for creating {@link X509ExtendedKeyManager}. + * A factory interface that is similar to {@link TrustManagerFactory}, but is an interface instead of a class. */ @FunctionalInterface - public interface KeyManagerFactory { - X509ExtendedKeyManager createKeyManager(KeyStore truststore, char[] password) throws GeneralSecurityException; + public interface TrustManagersFactory { + TrustManager[] createTrustManagers(KeyStore truststore) throws GeneralSecurityException; } } 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 0dae185995c..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/AutoReloadingX509KeyManager.java +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2019 Oath Inc. 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 javax.net.ssl.SSLEngine; -import javax.net.ssl.X509ExtendedKeyManager; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.Socket; -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.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 { - - 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); - } - - private static KeyStore createKeystore(Path privateKey, Path certificateChain) { - try { - return KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withKeyEntry( - "default", - KeyUtils.fromPemEncodedPrivateKey(Files.readString(privateKey)), - X509CertificateUtils.certificateListFromPem(Files.readString(certificateChain))) - .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/DefaultTlsContext.java b/security-utils/src/main/java/com/yahoo/security/tls/DefaultTlsContext.java index c9c326df9ed..2befd50332a 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 @@ -7,7 +7,7 @@ import com.yahoo.security.tls.policy.AuthorizedPeers; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; +import java.nio.file.Path; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.Arrays; @@ -38,8 +38,7 @@ public class DefaultTlsContext implements TlsContext { private static final Logger log = Logger.getLogger(DefaultTlsContext.class.getName()); private final SSLContext sslContext; - private final String[] validCiphers; - private final String[] validProtocols; + private final List acceptedCiphers; public DefaultTlsContext(List certificates, PrivateKey privateKey, @@ -47,77 +46,49 @@ public class DefaultTlsContext implements TlsContext { AuthorizedPeers authorizedPeers, AuthorizationMode mode, List acceptedCiphers) { - this(createSslContext(certificates, privateKey, caCertificates, authorizedPeers, mode), - acceptedCiphers); + this.sslContext = createSslContext(certificates, privateKey, caCertificates, authorizedPeers, mode); + this.acceptedCiphers = acceptedCiphers; } - - public DefaultTlsContext(SSLContext sslContext, List acceptedCiphers) { - this.sslContext = sslContext; - this.validCiphers = getAllowedCiphers(sslContext, acceptedCiphers); - this.validProtocols = getAllowedProtocols(sslContext); + public DefaultTlsContext(Path tlsOptionsConfigFile, AuthorizationMode mode) { + TransportSecurityOptions options = TransportSecurityOptions.fromJsonFile(tlsOptionsConfigFile); + this.sslContext = createSslContext(options, mode); + this.acceptedCiphers = options.getAcceptedCiphers(); } + @Override + public SSLEngine createSslEngine() { + SSLEngine sslEngine = sslContext.createSSLEngine(); + restrictSetOfEnabledCiphers(sslEngine, acceptedCiphers); + restrictTlsProtocols(sslEngine); + return sslEngine; + } - private static String[] getAllowedCiphers(SSLContext sslContext, List acceptedCiphers) { - String[] supportedCipherSuites = sslContext.getSupportedSSLParameters().getCipherSuites(); - String[] validCipherSuites = Arrays.stream(supportedCipherSuites) + private static void restrictSetOfEnabledCiphers(SSLEngine sslEngine, List acceptedCiphers) { + String[] validCipherSuites = Arrays.stream(sslEngine.getSupportedCipherSuites()) .filter(suite -> ALLOWED_CIPHER_SUITES.contains(suite) && (acceptedCiphers.isEmpty() || acceptedCiphers.contains(suite))) .toArray(String[]::new); if (validCipherSuites.length == 0) { throw new IllegalStateException( String.format("None of the allowed cipher suites are supported " + "(allowed-cipher-suites=%s, supported-cipher-suites=%s, accepted-cipher-suites=%s)", - ALLOWED_CIPHER_SUITES, List.of(supportedCipherSuites), acceptedCiphers)); + ALLOWED_CIPHER_SUITES, List.of(sslEngine.getSupportedCipherSuites()), acceptedCiphers)); } - log.log(Level.FINE, () -> String.format("Allowed cipher suites that are supported: %s", List.of(validCipherSuites))); - return validCipherSuites; + log.log(Level.FINE, () -> String.format("Allowed cipher suites that are supported: %s", Arrays.toString(validCipherSuites))); + sslEngine.setEnabledCipherSuites(validCipherSuites); } - private static String[] getAllowedProtocols(SSLContext sslContext) { - String[] supportedProtocols = sslContext.getSupportedSSLParameters().getProtocols(); - String[] validProtocols = Arrays.stream(supportedProtocols) + private static void restrictTlsProtocols(SSLEngine sslEngine) { + String[] validProtocols = Arrays.stream(sslEngine.getSupportedProtocols()) .filter(ALLOWED_PROTOCOLS::contains) .toArray(String[]::new); if (validProtocols.length == 0) { throw new IllegalArgumentException( String.format("None of the allowed protocols are supported (allowed-protocols=%s, supported-protocols=%s)", - ALLOWED_PROTOCOLS, List.of(supportedProtocols))); + ALLOWED_PROTOCOLS, Arrays.toString(sslEngine.getSupportedProtocols()))); } - log.log(Level.FINE, () -> String.format("Allowed protocols that are supported: %s", List.of(validProtocols))); - return validProtocols; - } - - @Override - public SSLContext context() { - return sslContext; - } - - @Override - public SSLParameters parameters() { - return createSslParameters(); - } - - @Override - public SSLEngine createSslEngine() { - SSLEngine sslEngine = sslContext.createSSLEngine(); - sslEngine.setSSLParameters(createSslParameters()); - return sslEngine; - } - - @Override - public SSLEngine createSslEngine(String peerHost, int peerPort) { - SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort); - sslEngine.setSSLParameters(createSslParameters()); - return sslEngine; - } - - private SSLParameters createSslParameters() { - SSLParameters newParameters = sslContext.getDefaultSSLParameters(); - newParameters.setCipherSuites(validCiphers); - newParameters.setProtocols(validProtocols); - newParameters.setNeedClientAuth(true); - return newParameters; + log.log(Level.FINE, () -> String.format("Allowed protocols that are supported: %s", Arrays.toString(validProtocols))); + sslEngine.setEnabledProtocols(validProtocols); } private static SSLContext createSslContext(List certificates, @@ -138,5 +109,16 @@ public class DefaultTlsContext implements TlsContext { return builder.build(); } + private static SSLContext createSslContext(TransportSecurityOptions options, AuthorizationMode mode) { + SslContextBuilder builder = new SslContextBuilder(); + options.getCertificatesFile() + .ifPresent(certificates -> builder.withKeyStore(options.getPrivateKeyFile().get(), certificates)); + options.getCaCertificatesFile().ifPresent(builder::withTrustStore); + if (mode != AuthorizationMode.DISABLE) { + options.getAuthorizedPeers().ifPresent( + authorizedPeers -> builder.withTrustManagerFactory(new PeerAuthorizerTrustManagersFactory(authorizedPeers, mode))); + } + return builder.build(); + } } 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 2e48de3c01f..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/KeyManagerUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Oath Inc. 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 " + List.of(keyManagers))); - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } - } - - public static X509ExtendedKeyManager createDefaultX509KeyManager(PrivateKey privateKey, List 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 e5e56f7a181..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509KeyManager.java +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Oath Inc. 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 { - - // Not using ThreadLocal as we want the x509 key manager instances to be collected - // when either the thread dies or the MutableX509KeyManager instance is collected (latter not the case for ThreadLocal). - private final WeakHashMap threadLocalManager = new WeakHashMap<>(); - private volatile X509ExtendedKeyManager currentManager; - - public MutableX509KeyManager(KeyStore keystore, char[] password) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(keystore, password); - } - - public MutableX509KeyManager() { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(); - } - - public void updateKeystore(KeyStore keystore, char[] password) { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(keystore, password); - } - - public void useDefaultKeystore() { - this.currentManager = KeyManagerUtils.createDefaultX509KeyManager(); - } - - @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() { - X509ExtendedKeyManager currentManager = this.currentManager; - threadLocalManager.put(Thread.currentThread(), currentManager); - return currentManager; - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - return getThreadLocalManager() - .getCertificateChain(alias); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - return getThreadLocalManager() - .getPrivateKey(alias); - } - - private X509ExtendedKeyManager getThreadLocalManager() { - 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 ed424480d26..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/MutableX509TrustManager.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Oath Inc. 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/ReloadingTlsContext.java b/security-utils/src/main/java/com/yahoo/security/tls/ReloadingTlsContext.java index b57105f54f9..5add13e067d 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/ReloadingTlsContext.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/ReloadingTlsContext.java @@ -1,28 +1,13 @@ // Copyright 2018 Yahoo Holdings. 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.SslContextBuilder; -import com.yahoo.security.X509CertificateUtils; -import com.yahoo.security.tls.authz.PeerAuthorizerTrustManager; - -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.X509ExtendedTrustManager; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.security.KeyStore; -import java.security.cert.X509Certificate; import java.time.Duration; -import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; @@ -38,9 +23,8 @@ public class ReloadingTlsContext implements TlsContext { private static final Logger log = Logger.getLogger(ReloadingTlsContext.class.getName()); private final Path tlsOptionsConfigFile; - private final TlsContext tlsContext; - private final MutableX509TrustManager trustManager = new MutableX509TrustManager(); - private final MutableX509KeyManager keyManager = new MutableX509KeyManager(); + private final AuthorizationMode mode; + private final AtomicReference currentTlsContext; private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> { Thread thread = new Thread(runnable, "tls-context-reloader"); @@ -50,77 +34,19 @@ public class ReloadingTlsContext implements TlsContext { public ReloadingTlsContext(Path tlsOptionsConfigFile, AuthorizationMode mode) { this.tlsOptionsConfigFile = tlsOptionsConfigFile; - TransportSecurityOptions options = TransportSecurityOptions.fromJsonFile(tlsOptionsConfigFile); - reloadCryptoMaterial(options, trustManager, keyManager); - this.tlsContext = createDefaultTlsContext(options, mode, trustManager, keyManager); - this.scheduler.scheduleAtFixedRate(new CryptoMaterialReloader(), + this.mode = mode; + this.currentTlsContext = new AtomicReference<>(new DefaultTlsContext(tlsOptionsConfigFile, mode)); + this.scheduler.scheduleAtFixedRate(new SslContextReloader(), UPDATE_PERIOD.getSeconds()/*initial delay*/, UPDATE_PERIOD.getSeconds(), TimeUnit.SECONDS); } - private static void reloadCryptoMaterial(TransportSecurityOptions options, - MutableX509TrustManager trustManager, - MutableX509KeyManager keyManager) { - if (options.getCaCertificatesFile().isPresent()) { - trustManager.updateTruststore(loadTruststore(options.getCaCertificatesFile().get())); - } else { - trustManager.useDefaultTruststore(); - } - - if (options.getPrivateKeyFile().isPresent() && options.getCertificatesFile().isPresent()) { - keyManager.updateKeystore(loadKeystore(options.getPrivateKeyFile().get(), options.getCertificatesFile().get()), new char[0]); - } else { - keyManager.useDefaultKeystore(); - } - } - - private static KeyStore loadTruststore(Path caCertificateFile) { - try { - List caCertificates = X509CertificateUtils.certificateListFromPem(Files.readString(caCertificateFile)); - KeyStoreBuilder trustStoreBuilder = KeyStoreBuilder.withType(KeyStoreType.PKCS12); - for (int i = 0; i < caCertificates.size(); i++) { - trustStoreBuilder.withCertificateEntry("cert-" + i, caCertificates.get(i)); - } - return trustStoreBuilder.build(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static KeyStore loadKeystore(Path privateKeyFile, Path certificatesFile) { - try { - return KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withKeyEntry( - "default", - KeyUtils.fromPemEncodedPrivateKey(Files.readString(privateKeyFile)), - X509CertificateUtils.certificateListFromPem(Files.readString(certificatesFile))) - .build(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static DefaultTlsContext createDefaultTlsContext(TransportSecurityOptions options, - AuthorizationMode mode, - MutableX509TrustManager mutableTrustManager, - MutableX509KeyManager mutableKeyManager) { - SSLContext sslContext = new SslContextBuilder() - .withKeyManagerFactory((ignoredKeystore, ignoredPassword) -> mutableKeyManager) - .withTrustManagerFactory( - ignoredTruststore -> options.getAuthorizedPeers() - .map(authorizedPeers -> (X509ExtendedTrustManager) new PeerAuthorizerTrustManager(authorizedPeers, mode, mutableTrustManager)) - .orElse(mutableTrustManager)) - .build(); - return new DefaultTlsContext(sslContext, options.getAcceptedCiphers()); + @Override + public SSLEngine createSslEngine() { + return currentTlsContext.get().createSslEngine(); } - // Wrapped methods from TlsContext - @Override public SSLContext context() { return tlsContext.context(); } - @Override public SSLParameters parameters() { return tlsContext.parameters(); } - @Override public SSLEngine createSslEngine() { return tlsContext.createSslEngine(); } - @Override public SSLEngine createSslEngine(String peerHost, int peerPort) { return tlsContext.createSslEngine(peerHost, peerPort); } - @Override public void close() { try { @@ -131,13 +57,13 @@ public class ReloadingTlsContext implements TlsContext { } } - private class CryptoMaterialReloader implements Runnable { + private class SslContextReloader implements Runnable { @Override public void run() { try { - reloadCryptoMaterial(TransportSecurityOptions.fromJsonFile(tlsOptionsConfigFile), trustManager, keyManager); + currentTlsContext.set(new DefaultTlsContext(tlsOptionsConfigFile, mode)); } catch (Throwable t) { - log.log(Level.SEVERE, String.format("Failed to reload crypto material (path='%s'): %s", tlsOptionsConfigFile, t.getMessage()), t); + log.log(Level.SEVERE, String.format("Failed to load SSLContext (path='%s'): %s", tlsOptionsConfigFile, t.getMessage()), t); } } } diff --git a/security-utils/src/main/java/com/yahoo/security/tls/TlsContext.java b/security-utils/src/main/java/com/yahoo/security/tls/TlsContext.java index b315dd00b31..58687a0ba8f 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/TlsContext.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/TlsContext.java @@ -3,7 +3,6 @@ package com.yahoo.security.tls; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; /** * A simplified version of {@link SSLContext} modelled as an interface. @@ -12,14 +11,8 @@ import javax.net.ssl.SSLParameters; */ public interface TlsContext extends AutoCloseable { - SSLContext context(); - - SSLParameters parameters(); - SSLEngine createSslEngine(); - SSLEngine createSslEngine(String peerHost, int peerPort); - @Override default void close() {} } 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 f114b672ed8..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/TrustManagerUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Oath Inc. 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 " + List.of(trustManagers))); - } catch (GeneralSecurityException e) { - throw new RuntimeException(e); - } - } - - public static X509ExtendedTrustManager createDefaultX509TrustManager(List certificates) { - KeyStoreBuilder truststoreBuilder = KeyStoreBuilder.withType(KeyStoreType.PKCS12); - for (int i = 0; i < certificates.size(); i++) { - truststoreBuilder.withCertificateEntry("cert-" + i, certificates.get(i)); - } - KeyStore truststore = truststoreBuilder.build(); - return createDefaultX509TrustManager(truststore); - } - - public static X509ExtendedTrustManager createDefaultX509TrustManager() { - return createDefaultX509TrustManager((KeyStore) null); - } -} 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 eee2e502183..80acc940a99 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 @@ -3,12 +3,14 @@ package com.yahoo.security.tls.authz; import com.yahoo.security.X509CertificateUtils; import com.yahoo.security.tls.AuthorizationMode; -import com.yahoo.security.tls.TrustManagerUtils; import com.yahoo.security.tls.policy.AuthorizedPeers; import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509ExtendedTrustManager; import java.net.Socket; +import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -37,8 +39,22 @@ public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager { this.defaultTrustManager = defaultTrustManager; } - public PeerAuthorizerTrustManager(AuthorizedPeers authorizedPeers, AuthorizationMode mode, KeyStore truststore) { - this(authorizedPeers, mode, TrustManagerUtils.createDefaultX509TrustManager(truststore)); + public static TrustManager[] wrapTrustManagersFromKeystore(AuthorizedPeers authorizedPeers, AuthorizationMode mode, KeyStore keystore) throws GeneralSecurityException { + TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + factory.init(keystore); + return wrapTrustManagers(authorizedPeers, mode, factory.getTrustManagers()); + } + + public static TrustManager[] wrapTrustManagers(AuthorizedPeers authorizedPeers, AuthorizationMode mode, TrustManager[] managers) { + TrustManager[] wrappedManagers = new TrustManager[managers.length]; + for (int i = 0; i < managers.length; i++) { + if (managers[i] instanceof X509ExtendedTrustManager) { + wrappedManagers[i] = new PeerAuthorizerTrustManager(authorizedPeers, mode, (X509ExtendedTrustManager) managers[i]); + } else { + wrappedManagers[i] = managers[i]; + } + } + return wrappedManagers; } @Override diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManagersFactory.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManagersFactory.java index 6ec8450c035..c0a3b4e41a5 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManagersFactory.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManagersFactory.java @@ -5,12 +5,14 @@ import com.yahoo.security.SslContextBuilder; import com.yahoo.security.tls.AuthorizationMode; import com.yahoo.security.tls.policy.AuthorizedPeers; +import javax.net.ssl.TrustManager; +import java.security.GeneralSecurityException; import java.security.KeyStore; /** * @author bjorncs */ -public class PeerAuthorizerTrustManagersFactory implements SslContextBuilder.TrustManagerFactory { +public class PeerAuthorizerTrustManagersFactory implements SslContextBuilder.TrustManagersFactory { private final AuthorizedPeers authorizedPeers; private AuthorizationMode mode; @@ -20,7 +22,7 @@ public class PeerAuthorizerTrustManagersFactory implements SslContextBuilder.Tru } @Override - public PeerAuthorizerTrustManager createTrustManager(KeyStore truststore) { - return new PeerAuthorizerTrustManager(authorizedPeers, mode, truststore); + public TrustManager[] createTrustManagers(KeyStore truststore) throws GeneralSecurityException { + return PeerAuthorizerTrustManager.wrapTrustManagersFromKeystore(authorizedPeers, mode, truststore); } } diff --git a/security-utils/src/test/java/com/yahoo/security/tls/AutoReloadingX509KeyManagerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/AutoReloadingX509KeyManagerTest.java deleted file mode 100644 index 139d5313074..00000000000 --- a/security-utils/src/test/java/com/yahoo/security/tls/AutoReloadingX509KeyManagerTest.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 Oath Inc. 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.KeyAlgorithm; -import com.yahoo.security.KeyUtils; -import com.yahoo.security.SignatureAlgorithm; -import com.yahoo.security.X509CertificateBuilder; -import com.yahoo.security.X509CertificateUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import javax.security.auth.x500.X500Principal; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.KeyPair; -import java.security.Principal; -import java.security.cert.X509Certificate; -import java.time.Instant; -import java.util.concurrent.ScheduledExecutorService; - -import static java.time.temporal.ChronoUnit.DAYS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.verify; - -/** - * @author bjorncs - */ -public class AutoReloadingX509KeyManagerTest { - private static final X500Principal SUBJECT = new X500Principal("CN=dummy"); - - @Rule - public TemporaryFolder tempDirectory = new TemporaryFolder(); - - @Test - public void crypto_material_is_reloaded_when_scheduler_task_is_executed() throws IOException { - KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC); - Path privateKeyFile = tempDirectory.newFile().toPath(); - Files.writeString(privateKeyFile, KeyUtils.toPem(keyPair.getPrivate())); - - Path certificateFile = tempDirectory.newFile().toPath(); - BigInteger serialNumberInitialCertificate = BigInteger.ONE; - X509Certificate initialCertificate = generateCertificate(keyPair, serialNumberInitialCertificate); - Files.writeString(certificateFile, X509CertificateUtils.toPem(initialCertificate)); - - ScheduledExecutorService scheduler = Mockito.mock(ScheduledExecutorService.class); - ArgumentCaptor updaterTaskCaptor = ArgumentCaptor.forClass(Runnable.class); - - AutoReloadingX509KeyManager keyManager = new AutoReloadingX509KeyManager(privateKeyFile, certificateFile, scheduler); - verify(scheduler).scheduleAtFixedRate(updaterTaskCaptor.capture(), anyLong(), anyLong(), any()); - - String[] initialAliases = keyManager.getClientAliases(keyPair.getPublic().getAlgorithm(), new Principal[]{SUBJECT}); - X509Certificate[] certChain = keyManager.getCertificateChain(initialAliases[0]); - assertThat(certChain).hasSize(1); - assertThat(certChain[0].getSerialNumber()).isEqualTo(serialNumberInitialCertificate); - - BigInteger serialNumberUpdatedCertificate = BigInteger.TWO; - X509Certificate updatedCertificate = generateCertificate(keyPair, serialNumberUpdatedCertificate); - Files.writeString(certificateFile, X509CertificateUtils.toPem(updatedCertificate)); - - updaterTaskCaptor.getValue().run(); // run update task in ReloadingX509KeyManager - - String[] updatedAliases = keyManager.getClientAliases(keyPair.getPublic().getAlgorithm(), new Principal[]{SUBJECT}); - X509Certificate[] updatedCertChain = keyManager.getCertificateChain(updatedAliases[0]); - assertThat(updatedCertChain).hasSize(1); - assertThat(updatedCertChain[0].getSerialNumber()).isEqualTo(serialNumberUpdatedCertificate); - } - - private static X509Certificate generateCertificate(KeyPair keyPair, BigInteger serialNumber) { - return X509CertificateBuilder.fromKeypair(keyPair, - SUBJECT, - Instant.EPOCH, - Instant.EPOCH.plus(1, DAYS), - SignatureAlgorithm.SHA256_WITH_ECDSA, - serialNumber) - .build(); - } -} \ No newline at end of file diff --git a/security-utils/src/test/java/com/yahoo/security/tls/MutableX509KeyManagerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/MutableX509KeyManagerTest.java deleted file mode 100644 index 30e54d3c09d..00000000000 --- a/security-utils/src/test/java/com/yahoo/security/tls/MutableX509KeyManagerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 Oath Inc. 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.KeyAlgorithm; -import com.yahoo.security.KeyStoreBuilder; -import com.yahoo.security.KeyStoreType; -import com.yahoo.security.KeyUtils; -import com.yahoo.security.SignatureAlgorithm; -import com.yahoo.security.X509CertificateBuilder; -import org.junit.Test; - -import javax.security.auth.x500.X500Principal; -import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.Principal; -import java.security.cert.X509Certificate; -import java.time.Instant; - -import static java.time.temporal.ChronoUnit.DAYS; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author bjorncs - */ -public class MutableX509KeyManagerTest { - - private static final X500Principal SUBJECT = new X500Principal("CN=dummy"); - - @Test - public void key_manager_can_be_updated_with_new_certificate() { - KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC); - - BigInteger serialNumberInitialCertificate = BigInteger.ONE; - KeyStore initialKeystore = generateKeystore(keyPair, serialNumberInitialCertificate); - - MutableX509KeyManager keyManager = new MutableX509KeyManager(initialKeystore, new char[0]); - - String[] initialAliases = keyManager.getClientAliases(keyPair.getPublic().getAlgorithm(), new Principal[]{SUBJECT}); - assertThat(initialAliases).hasSize(1); - X509Certificate[] certChain = keyManager.getCertificateChain(initialAliases[0]); - assertThat(certChain).hasSize(1); - assertThat(certChain[0].getSerialNumber()).isEqualTo(serialNumberInitialCertificate); - - BigInteger serialNumberUpdatedCertificate = BigInteger.TWO; - KeyStore updatedKeystore = generateKeystore(keyPair, serialNumberUpdatedCertificate); - keyManager.updateKeystore(updatedKeystore, new char[0]); - - String[] updatedAliases = keyManager.getClientAliases(keyPair.getPublic().getAlgorithm(), new Principal[]{SUBJECT}); - assertThat(updatedAliases).hasSize(1); - X509Certificate[] updatedCertChain = keyManager.getCertificateChain(updatedAliases[0]); - assertThat(updatedCertChain).hasSize(1); - assertThat(updatedCertChain[0].getSerialNumber()).isEqualTo(serialNumberUpdatedCertificate); - } - - private static KeyStore generateKeystore(KeyPair keyPair, BigInteger serialNumber) { - X509Certificate certificate = X509CertificateBuilder.fromKeypair( - keyPair, SUBJECT, Instant.EPOCH, Instant.EPOCH.plus(1, DAYS), SignatureAlgorithm.SHA256_WITH_ECDSA, serialNumber) - .build(); - return KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withKeyEntry("default", keyPair.getPrivate(), certificate) - .build(); - } - -} \ No newline at end of file diff --git a/security-utils/src/test/java/com/yahoo/security/tls/MutableX509TrustManagerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/MutableX509TrustManagerTest.java deleted file mode 100644 index 4c4ea332818..00000000000 --- a/security-utils/src/test/java/com/yahoo/security/tls/MutableX509TrustManagerTest.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Oath Inc. 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.KeyAlgorithm; -import com.yahoo.security.KeyStoreBuilder; -import com.yahoo.security.KeyStoreType; -import com.yahoo.security.KeyUtils; -import com.yahoo.security.SignatureAlgorithm; -import com.yahoo.security.X509CertificateBuilder; -import org.junit.Test; - -import javax.security.auth.x500.X500Principal; -import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.cert.X509Certificate; -import java.time.Instant; - -import static java.time.temporal.ChronoUnit.DAYS; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author bjorncs - */ -public class MutableX509TrustManagerTest { - - @Test - public void key_manager_can_be_updated_with_new_certificate() { - KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC); - - X509Certificate initialCertificate = generateCertificate(new X500Principal("CN=issuer1"), keyPair); - KeyStore initialTruststore = generateTruststore(initialCertificate); - - MutableX509TrustManager trustManager = new MutableX509TrustManager(initialTruststore); - - X509Certificate[] initialAcceptedIssuers = trustManager.getAcceptedIssuers(); - assertThat(initialAcceptedIssuers).containsExactly(initialCertificate); - - X509Certificate updatedCertificate = generateCertificate(new X500Principal("CN=issuer2"), keyPair); - KeyStore updatedTruststore = generateTruststore(updatedCertificate); - trustManager.updateTruststore(updatedTruststore); - - X509Certificate[] updatedAcceptedIssuers = trustManager.getAcceptedIssuers(); - assertThat(updatedAcceptedIssuers).containsExactly(updatedCertificate); - } - - private static X509Certificate generateCertificate(X500Principal issuer, KeyPair keyPair) { - return X509CertificateBuilder.fromKeypair( - keyPair, issuer, Instant.EPOCH, Instant.EPOCH.plus(1, DAYS), SignatureAlgorithm.SHA256_WITH_ECDSA, BigInteger.ONE) - .build(); - } - - private static KeyStore generateTruststore(X509Certificate certificate) { - return KeyStoreBuilder.withType(KeyStoreType.PKCS12) - .withCertificateEntry("default", certificate) - .build(); - } - -} \ No newline at end of file -- cgit v1.2.3