From e30bd71a17125d36e1ed96a0fb145262161390c6 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Mon, 14 Aug 2023 09:18:23 -0400 Subject: [PATCH 1/7] Add method for creating an SSLContext that merges both the trust store and custom certificates --- .../conjure/java/config/ssl/KeyStores.java | 8 ++- .../java/config/ssl/SslSocketFactories.java | 69 ++++++++++++++++--- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java index 5ed2ff463..2726ac129 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java @@ -122,6 +122,12 @@ static KeyStore createTrustStoreFromCertificates(Map KeyStore keyStore; keyStore = createKeyStore(); + addCertificatesToKeystore(certificatesByAlias, keyStore); + + return keyStore; + } + + static void addCertificatesToKeystore(Map certificatesByAlias, KeyStore keyStore) { for (Map.Entry entry : certificatesByAlias.entrySet()) { try (InputStream certIn = new ByteArrayInputStream(entry.getValue().pemCertificate().getBytes(StandardCharsets.UTF_8))) { @@ -135,8 +141,6 @@ static KeyStore createTrustStoreFromCertificates(Map e); } } - - return keyStore; } private static void addCertificatesToKeystore( diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java index ddddff50c..3e83734f8 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java @@ -18,6 +18,7 @@ import com.google.common.base.Throwables; import com.palantir.conjure.java.api.config.ssl.SslConfiguration; +import com.palantir.conjure.java.api.config.ssl.SslConfiguration.StoreType; import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.exceptions.SafeRuntimeException; import java.nio.file.Path; @@ -91,6 +92,20 @@ public static SSLSocketFactory createSslSocketFactory( return sslContext.getSocketFactory(); } + /** + * Create a {@link SSLSocketFactory} from the provided certificates and configuration. + * + * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the + * certificate as. + * @param config an {@link SslConfiguration} describing the trust store configuration + * @param provider The preferred security {@link Provider} + */ + public static SSLSocketFactory createSslSocketFactory( + Map trustCertificatesByAlias, SslConfiguration config, Provider provider) { + SSLContext sslContext = createSslContext(config, trustCertificatesByAlias, provider); + return sslContext.getSocketFactory(); + } + /** * Create an {@link SSLContext} initialized from the provided configuration. * @@ -142,6 +157,19 @@ public static SSLContext createSslContext( return createSslContext(trustManagers, new KeyManager[] {}, provider); } + /** + * Create an {@link SSLContext} initialized from the provided configuration and certificates. + * + * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the + * certificate as. + * @param config an {@link SslConfiguration} describing the trust store and key store configuration + */ + public static SSLContext createSslContext( + SslConfiguration config, Map trustCertificatesByAlias, Provider provider) { + TrustManager[] trustManagers = createMergedTrustManagers(config, trustCertificatesByAlias); + return createSslContext(trustManagers, new KeyManager[] {}, provider); + } + /** * Create an {@link SSLContext} initialized from the provided certificates. * @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom) @@ -200,6 +228,20 @@ public static TrustManager[] createTrustManagers(Map } } + /** + * Create SSL socket factory and trust manager from the given certificates, see {@link #createX509TrustManager} and + * {@link #createSslSocketFactory}. + */ + public static TrustManager[] createMergedTrustManagers( + SslConfiguration config, Map trustCertificatesByAlias) { + KeyStore keystore = getCombinedTrustStoreAndDefaultCas(config.trustStorePath(), config.trustStoreType()); + + KeyStores.addCertificatesToKeystore(trustCertificatesByAlias, keystore); + + return ConscryptCompatTrustManagers.wrap( + getTrustManagerFactory(keystore).getTrustManagers()); + } + /** * Create SSL socket factory and trust manager from the given configuration, see {@link #createX509TrustManager} and * {@link #createSslSocketFactory}. @@ -269,6 +311,23 @@ public static KeyManager[] createKeyManagers(SslConfiguration config) { private static TrustManagerFactory createTrustManagerFactory( Path trustStorePath, SslConfiguration.StoreType trustStoreType) { + KeyStore keyStore = getCombinedTrustStoreAndDefaultCas(trustStorePath, trustStoreType); + + return getTrustManagerFactory(keyStore); + } + + private static TrustManagerFactory getTrustManagerFactory(KeyStore keyStore) { + try { + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + return trustManagerFactory; + } catch (GeneralSecurityException e) { + throw Throwables.propagate(e); + } + } + + private static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { KeyStore keyStore; switch (trustStoreType) { case JKS: @@ -299,15 +358,7 @@ private static TrustManagerFactory createTrustManagerFactory( "Unable to add certificate to store", e, SafeArg.of("certificateAlias", certAlias)); } }); - - try { - TrustManagerFactory trustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(keyStore); - return trustManagerFactory; - } catch (GeneralSecurityException e) { - throw Throwables.propagate(e); - } + return keyStore; } private static KeyManagerFactory createKeyManagerFactory( From 7ca0c78f29a0f597a9f7fc88e20ab6fcf4e185f7 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Mon, 14 Aug 2023 09:28:34 -0400 Subject: [PATCH 2/7] Update doc --- .../palantir/conjure/java/config/ssl/SslSocketFactories.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java index 3e83734f8..0160fb8fe 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java @@ -162,7 +162,7 @@ public static SSLContext createSslContext( * * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the * certificate as. - * @param config an {@link SslConfiguration} describing the trust store and key store configuration + * @param config an {@link SslConfiguration} describing the trust store configuration */ public static SSLContext createSslContext( SslConfiguration config, Map trustCertificatesByAlias, Provider provider) { From 383385cfd4256e56c71884ace5fd821dd01229e4 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Mon, 14 Aug 2023 14:50:49 -0400 Subject: [PATCH 3/7] Revert top level SSLSocketFactories methods --- .../conjure/java/config/ssl/KeyStores.java | 44 ++++++++++ .../java/config/ssl/SslSocketFactories.java | 82 +------------------ 2 files changed, 45 insertions(+), 81 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java index 2726ac129..13587c494 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java @@ -20,7 +20,9 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Throwables; import com.google.common.io.BaseEncoding; +import com.palantir.conjure.java.api.config.ssl.SslConfiguration.StoreType; import com.palantir.conjure.java.config.ssl.pkcs1.Pkcs1PrivateKeyReader; +import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.exceptions.SafeRuntimeException; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; @@ -321,6 +323,48 @@ static KeyStore newKeyStoreWithEntry(KeyStore original, Optional passwor } } + /** + * Return a new {@link KeyStore} that contains the contents of the trust store and all default ca certificates. + * + * @param trustStorePath The path to the trust store. + * @param trustStoreType The type of trust store. + * @return a newly constructed key store of the type trustStoreType that contains the contents of the trust store + * and all default ca certificates. + */ + static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { + KeyStore keyStore; + switch (trustStoreType) { + case JKS: + case PKCS12: + keyStore = loadKeyStore(trustStoreType.name(), trustStorePath, Optional.empty()); + break; + case PEM: + keyStore = createTrustStoreFromCertificates(trustStorePath); + break; + case PUPPET: + Path puppetCertsDir = trustStorePath.resolve("certs"); + if (!puppetCertsDir.toFile().isDirectory()) { + throw new IllegalStateException( + String.format("Puppet certs directory did not exist at path \"%s\"", puppetCertsDir)); + } + keyStore = createTrustStoreFromCertificates(puppetCertsDir); + break; + default: + throw new IllegalStateException("Unrecognized trust store type: " + trustStoreType); + } + + // Add globally trusted root CAs + DefaultCas.getCertificates().forEach((certAlias, cert) -> { + try { + keyStore.setCertificateEntry(certAlias, cert); + } catch (KeyStoreException e) { + throw new SafeRuntimeException( + "Unable to add certificate to store", e, SafeArg.of("certificateAlias", certAlias)); + } + }); + return keyStore; + } + private static KeyStore createKeyStore() { KeyStore keyStore; try { diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java index 0160fb8fe..5e4fc895c 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java @@ -18,7 +18,6 @@ import com.google.common.base.Throwables; import com.palantir.conjure.java.api.config.ssl.SslConfiguration; -import com.palantir.conjure.java.api.config.ssl.SslConfiguration.StoreType; import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.exceptions.SafeRuntimeException; import java.nio.file.Path; @@ -92,20 +91,6 @@ public static SSLSocketFactory createSslSocketFactory( return sslContext.getSocketFactory(); } - /** - * Create a {@link SSLSocketFactory} from the provided certificates and configuration. - * - * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the - * certificate as. - * @param config an {@link SslConfiguration} describing the trust store configuration - * @param provider The preferred security {@link Provider} - */ - public static SSLSocketFactory createSslSocketFactory( - Map trustCertificatesByAlias, SslConfiguration config, Provider provider) { - SSLContext sslContext = createSslContext(config, trustCertificatesByAlias, provider); - return sslContext.getSocketFactory(); - } - /** * Create an {@link SSLContext} initialized from the provided configuration. * @@ -157,19 +142,6 @@ public static SSLContext createSslContext( return createSslContext(trustManagers, new KeyManager[] {}, provider); } - /** - * Create an {@link SSLContext} initialized from the provided configuration and certificates. - * - * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the - * certificate as. - * @param config an {@link SslConfiguration} describing the trust store configuration - */ - public static SSLContext createSslContext( - SslConfiguration config, Map trustCertificatesByAlias, Provider provider) { - TrustManager[] trustManagers = createMergedTrustManagers(config, trustCertificatesByAlias); - return createSslContext(trustManagers, new KeyManager[] {}, provider); - } - /** * Create an {@link SSLContext} initialized from the provided certificates. * @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom) @@ -228,20 +200,6 @@ public static TrustManager[] createTrustManagers(Map } } - /** - * Create SSL socket factory and trust manager from the given certificates, see {@link #createX509TrustManager} and - * {@link #createSslSocketFactory}. - */ - public static TrustManager[] createMergedTrustManagers( - SslConfiguration config, Map trustCertificatesByAlias) { - KeyStore keystore = getCombinedTrustStoreAndDefaultCas(config.trustStorePath(), config.trustStoreType()); - - KeyStores.addCertificatesToKeystore(trustCertificatesByAlias, keystore); - - return ConscryptCompatTrustManagers.wrap( - getTrustManagerFactory(keystore).getTrustManagers()); - } - /** * Create SSL socket factory and trust manager from the given configuration, see {@link #createX509TrustManager} and * {@link #createSslSocketFactory}. @@ -311,12 +269,8 @@ public static KeyManager[] createKeyManagers(SslConfiguration config) { private static TrustManagerFactory createTrustManagerFactory( Path trustStorePath, SslConfiguration.StoreType trustStoreType) { - KeyStore keyStore = getCombinedTrustStoreAndDefaultCas(trustStorePath, trustStoreType); + KeyStore keyStore = KeyStores.getCombinedTrustStoreAndDefaultCas(trustStorePath, trustStoreType); - return getTrustManagerFactory(keyStore); - } - - private static TrustManagerFactory getTrustManagerFactory(KeyStore keyStore) { try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -327,40 +281,6 @@ private static TrustManagerFactory getTrustManagerFactory(KeyStore keyStore) { } } - private static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { - KeyStore keyStore; - switch (trustStoreType) { - case JKS: - case PKCS12: - keyStore = KeyStores.loadKeyStore(trustStoreType.name(), trustStorePath, Optional.empty()); - break; - case PEM: - keyStore = KeyStores.createTrustStoreFromCertificates(trustStorePath); - break; - case PUPPET: - Path puppetCertsDir = trustStorePath.resolve("certs"); - if (!puppetCertsDir.toFile().isDirectory()) { - throw new IllegalStateException( - String.format("Puppet certs directory did not exist at path \"%s\"", puppetCertsDir)); - } - keyStore = KeyStores.createTrustStoreFromCertificates(puppetCertsDir); - break; - default: - throw new IllegalStateException("Unrecognized trust store type: " + trustStoreType); - } - - // Add globally trusted root CAs - DefaultCas.getCertificates().forEach((certAlias, cert) -> { - try { - keyStore.setCertificateEntry(certAlias, cert); - } catch (KeyStoreException e) { - throw new SafeRuntimeException( - "Unable to add certificate to store", e, SafeArg.of("certificateAlias", certAlias)); - } - }); - return keyStore; - } - private static KeyManagerFactory createKeyManagerFactory( Path keyStorePath, Optional keyStorePassword, From 33f6302b2b186029bfa160e96873938e500437c9 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Mon, 14 Aug 2023 14:55:03 -0400 Subject: [PATCH 4/7] Make public --- .../java/com/palantir/conjure/java/config/ssl/KeyStores.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java index 13587c494..3d6c5e241 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java @@ -57,7 +57,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -final class KeyStores { +public final class KeyStores { private static final Cache certCache = Caffeine.newBuilder().maximumSize(1024).softValues().build(); @@ -331,7 +331,7 @@ static KeyStore newKeyStoreWithEntry(KeyStore original, Optional passwor * @return a newly constructed key store of the type trustStoreType that contains the contents of the trust store * and all default ca certificates. */ - static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { + public static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { KeyStore keyStore; switch (trustStoreType) { case JKS: From dc0c416c51e6a0016324eed2fcf5be4c1ab1449a Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Tue, 7 Nov 2023 14:30:43 -0500 Subject: [PATCH 5/7] Revert "Make public" This reverts commit 33f6302b2b186029bfa160e96873938e500437c9. --- .../java/com/palantir/conjure/java/config/ssl/KeyStores.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java index 3d6c5e241..13587c494 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java @@ -57,7 +57,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -public final class KeyStores { +final class KeyStores { private static final Cache certCache = Caffeine.newBuilder().maximumSize(1024).softValues().build(); @@ -331,7 +331,7 @@ static KeyStore newKeyStoreWithEntry(KeyStore original, Optional passwor * @return a newly constructed key store of the type trustStoreType that contains the contents of the trust store * and all default ca certificates. */ - public static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { + static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { KeyStore keyStore; switch (trustStoreType) { case JKS: From 87ce879c7383cb322f3742e1bf01e15dc6587610 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Tue, 7 Nov 2023 14:30:44 -0500 Subject: [PATCH 6/7] Revert "Revert top level SSLSocketFactories methods" This reverts commit 383385cfd4256e56c71884ace5fd821dd01229e4. --- .../conjure/java/config/ssl/KeyStores.java | 44 ---------- .../java/config/ssl/SslSocketFactories.java | 82 ++++++++++++++++++- 2 files changed, 81 insertions(+), 45 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java index 13587c494..2726ac129 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/KeyStores.java @@ -20,9 +20,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Throwables; import com.google.common.io.BaseEncoding; -import com.palantir.conjure.java.api.config.ssl.SslConfiguration.StoreType; import com.palantir.conjure.java.config.ssl.pkcs1.Pkcs1PrivateKeyReader; -import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.exceptions.SafeRuntimeException; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; @@ -323,48 +321,6 @@ static KeyStore newKeyStoreWithEntry(KeyStore original, Optional passwor } } - /** - * Return a new {@link KeyStore} that contains the contents of the trust store and all default ca certificates. - * - * @param trustStorePath The path to the trust store. - * @param trustStoreType The type of trust store. - * @return a newly constructed key store of the type trustStoreType that contains the contents of the trust store - * and all default ca certificates. - */ - static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { - KeyStore keyStore; - switch (trustStoreType) { - case JKS: - case PKCS12: - keyStore = loadKeyStore(trustStoreType.name(), trustStorePath, Optional.empty()); - break; - case PEM: - keyStore = createTrustStoreFromCertificates(trustStorePath); - break; - case PUPPET: - Path puppetCertsDir = trustStorePath.resolve("certs"); - if (!puppetCertsDir.toFile().isDirectory()) { - throw new IllegalStateException( - String.format("Puppet certs directory did not exist at path \"%s\"", puppetCertsDir)); - } - keyStore = createTrustStoreFromCertificates(puppetCertsDir); - break; - default: - throw new IllegalStateException("Unrecognized trust store type: " + trustStoreType); - } - - // Add globally trusted root CAs - DefaultCas.getCertificates().forEach((certAlias, cert) -> { - try { - keyStore.setCertificateEntry(certAlias, cert); - } catch (KeyStoreException e) { - throw new SafeRuntimeException( - "Unable to add certificate to store", e, SafeArg.of("certificateAlias", certAlias)); - } - }); - return keyStore; - } - private static KeyStore createKeyStore() { KeyStore keyStore; try { diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java index 5e4fc895c..0160fb8fe 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java @@ -18,6 +18,7 @@ import com.google.common.base.Throwables; import com.palantir.conjure.java.api.config.ssl.SslConfiguration; +import com.palantir.conjure.java.api.config.ssl.SslConfiguration.StoreType; import com.palantir.logsafe.SafeArg; import com.palantir.logsafe.exceptions.SafeRuntimeException; import java.nio.file.Path; @@ -91,6 +92,20 @@ public static SSLSocketFactory createSslSocketFactory( return sslContext.getSocketFactory(); } + /** + * Create a {@link SSLSocketFactory} from the provided certificates and configuration. + * + * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the + * certificate as. + * @param config an {@link SslConfiguration} describing the trust store configuration + * @param provider The preferred security {@link Provider} + */ + public static SSLSocketFactory createSslSocketFactory( + Map trustCertificatesByAlias, SslConfiguration config, Provider provider) { + SSLContext sslContext = createSslContext(config, trustCertificatesByAlias, provider); + return sslContext.getSocketFactory(); + } + /** * Create an {@link SSLContext} initialized from the provided configuration. * @@ -142,6 +157,19 @@ public static SSLContext createSslContext( return createSslContext(trustManagers, new KeyManager[] {}, provider); } + /** + * Create an {@link SSLContext} initialized from the provided configuration and certificates. + * + * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the + * certificate as. + * @param config an {@link SslConfiguration} describing the trust store configuration + */ + public static SSLContext createSslContext( + SslConfiguration config, Map trustCertificatesByAlias, Provider provider) { + TrustManager[] trustManagers = createMergedTrustManagers(config, trustCertificatesByAlias); + return createSslContext(trustManagers, new KeyManager[] {}, provider); + } + /** * Create an {@link SSLContext} initialized from the provided certificates. * @see SSLContext#init(KeyManager[], TrustManager[], SecureRandom) @@ -200,6 +228,20 @@ public static TrustManager[] createTrustManagers(Map } } + /** + * Create SSL socket factory and trust manager from the given certificates, see {@link #createX509TrustManager} and + * {@link #createSslSocketFactory}. + */ + public static TrustManager[] createMergedTrustManagers( + SslConfiguration config, Map trustCertificatesByAlias) { + KeyStore keystore = getCombinedTrustStoreAndDefaultCas(config.trustStorePath(), config.trustStoreType()); + + KeyStores.addCertificatesToKeystore(trustCertificatesByAlias, keystore); + + return ConscryptCompatTrustManagers.wrap( + getTrustManagerFactory(keystore).getTrustManagers()); + } + /** * Create SSL socket factory and trust manager from the given configuration, see {@link #createX509TrustManager} and * {@link #createSslSocketFactory}. @@ -269,8 +311,12 @@ public static KeyManager[] createKeyManagers(SslConfiguration config) { private static TrustManagerFactory createTrustManagerFactory( Path trustStorePath, SslConfiguration.StoreType trustStoreType) { - KeyStore keyStore = KeyStores.getCombinedTrustStoreAndDefaultCas(trustStorePath, trustStoreType); + KeyStore keyStore = getCombinedTrustStoreAndDefaultCas(trustStorePath, trustStoreType); + return getTrustManagerFactory(keyStore); + } + + private static TrustManagerFactory getTrustManagerFactory(KeyStore keyStore) { try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -281,6 +327,40 @@ private static TrustManagerFactory createTrustManagerFactory( } } + private static KeyStore getCombinedTrustStoreAndDefaultCas(Path trustStorePath, StoreType trustStoreType) { + KeyStore keyStore; + switch (trustStoreType) { + case JKS: + case PKCS12: + keyStore = KeyStores.loadKeyStore(trustStoreType.name(), trustStorePath, Optional.empty()); + break; + case PEM: + keyStore = KeyStores.createTrustStoreFromCertificates(trustStorePath); + break; + case PUPPET: + Path puppetCertsDir = trustStorePath.resolve("certs"); + if (!puppetCertsDir.toFile().isDirectory()) { + throw new IllegalStateException( + String.format("Puppet certs directory did not exist at path \"%s\"", puppetCertsDir)); + } + keyStore = KeyStores.createTrustStoreFromCertificates(puppetCertsDir); + break; + default: + throw new IllegalStateException("Unrecognized trust store type: " + trustStoreType); + } + + // Add globally trusted root CAs + DefaultCas.getCertificates().forEach((certAlias, cert) -> { + try { + keyStore.setCertificateEntry(certAlias, cert); + } catch (KeyStoreException e) { + throw new SafeRuntimeException( + "Unable to add certificate to store", e, SafeArg.of("certificateAlias", certAlias)); + } + }); + return keyStore; + } + private static KeyManagerFactory createKeyManagerFactory( Path keyStorePath, Optional keyStorePassword, From cb7961e1223c3595afa4e3ac1aae004170c95930 Mon Sep 17 00:00:00 2001 From: Eric Alvarez Date: Tue, 7 Nov 2023 14:37:18 -0500 Subject: [PATCH 7/7] Update docs --- .../conjure/java/config/ssl/SslSocketFactories.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java index 0160fb8fe..e20230d1b 100644 --- a/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java +++ b/keystores/src/main/java/com/palantir/conjure/java/config/ssl/SslSocketFactories.java @@ -93,7 +93,7 @@ public static SSLSocketFactory createSslSocketFactory( } /** - * Create a {@link SSLSocketFactory} from the provided certificates and configuration. + * Create a {@link SSLSocketFactory} by merging the provided certificates and configuration. * * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the * certificate as. @@ -158,11 +158,12 @@ public static SSLContext createSslContext( } /** - * Create an {@link SSLContext} initialized from the provided configuration and certificates. + * Create an {@link SSLContext} by merging the provided configuration and certificates. * * @param trustCertificatesByAlias a map of X.509 certificate in PEM or DER format by the alias to load the * certificate as. * @param config an {@link SslConfiguration} describing the trust store configuration + * @param provider The preferred security {@link Provider} */ public static SSLContext createSslContext( SslConfiguration config, Map trustCertificatesByAlias, Provider provider) { @@ -229,8 +230,8 @@ public static TrustManager[] createTrustManagers(Map } /** - * Create SSL socket factory and trust manager from the given certificates, see {@link #createX509TrustManager} and - * {@link #createSslSocketFactory}. + * Create SSL socket factory and trust manager by merging the given certificates and configuration, + * see {@link #createX509TrustManager} and {@link #createSslSocketFactory}. */ public static TrustManager[] createMergedTrustManagers( SslConfiguration config, Map trustCertificatesByAlias) {