From 493987fc1a2dc894ecb9563c11a16e95032a39c8 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Fri, 23 Jun 2023 14:40:42 -0600 Subject: [PATCH] Allow key password to be set for a PemSslStoreBundle Closes gh-35983 --- .../boot/ssl/pem/PemSslStoreBundle.java | 18 ++++++++++++- .../boot/ssl/pem/PemSslStoreBundleTests.java | 26 +++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreBundle.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreBundle.java index dee4651852a..251ff0b5279 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreBundle.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreBundle.java @@ -42,6 +42,8 @@ public class PemSslStoreBundle implements SslStoreBundle { private final String keyAlias; + private final String keyPassword; + /** * Create a new {@link PemSslStoreBundle} instance. * @param keyStoreDetails the key store details @@ -59,9 +61,22 @@ public class PemSslStoreBundle implements SslStoreBundle { */ public PemSslStoreBundle(PemSslStoreDetails keyStoreDetails, PemSslStoreDetails trustStoreDetails, String keyAlias) { + this(keyStoreDetails, trustStoreDetails, keyAlias, null); + } + + /** + * Create a new {@link PemSslStoreBundle} instance. + * @param keyStoreDetails the key store details + * @param trustStoreDetails the trust store details + * @param keyAlias the key alias to use or {@code null} to use a default alias + * @param keyPassword the password to use for the key + */ + public PemSslStoreBundle(PemSslStoreDetails keyStoreDetails, PemSslStoreDetails trustStoreDetails, String keyAlias, + String keyPassword) { this.keyAlias = keyAlias; this.keyStoreDetails = keyStoreDetails; this.trustStoreDetails = trustStoreDetails; + this.keyPassword = keyPassword; } @Override @@ -104,7 +119,8 @@ public class PemSslStoreBundle implements SslStoreBundle { throws KeyStoreException { String alias = (this.keyAlias != null) ? this.keyAlias : DEFAULT_KEY_ALIAS; if (privateKey != null) { - keyStore.setKeyEntry(alias, privateKey, null, certificates); + keyStore.setKeyEntry(alias, privateKey, (this.keyPassword != null) ? this.keyPassword.toCharArray() : null, + certificates); } else { for (int index = 0; index < certificates.length; index++) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreBundleTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreBundleTests.java index 61f5c4983bd..29c22a27e0c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreBundleTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreBundleTests.java @@ -33,6 +33,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ class PemSslStoreBundleTests { + private static final char[] EMPTY_KEY_PASSWORD = new char[] {}; + @Test void whenNullStores() { PemSslStoreDetails keyStoreDetails = null; @@ -117,6 +119,18 @@ class PemSslStoreBundleTests { assertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey("PKCS12", "ssl")); } + @Test + void whenHasKeyStoreDetailsAndTrustStoreDetailsAndKeyPassword() { + PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem") + .withPrivateKey("classpath:test-key.pem"); + PemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate("classpath:test-cert.pem") + .withPrivateKey("classpath:test-key.pem"); + PemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails, "test-alias", "keysecret"); + assertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey("test-alias", "keysecret".toCharArray())); + assertThat(bundle.getTrustStore()) + .satisfies(storeContainingCertAndKey("test-alias", "keysecret".toCharArray())); + } + private Consumer storeContainingCert(String keyAlias) { return storeContainingCert(KeyStore.getDefaultType(), keyAlias); } @@ -127,7 +141,7 @@ class PemSslStoreBundleTests { assertThat(keyStore.getType()).isEqualTo(keyStoreType); assertThat(keyStore.containsAlias(keyAlias)).isTrue(); assertThat(keyStore.getCertificate(keyAlias)).isNotNull(); - assertThat(keyStore.getKey(keyAlias, new char[] {})).isNull(); + assertThat(keyStore.getKey(keyAlias, EMPTY_KEY_PASSWORD)).isNull(); }); } @@ -136,12 +150,20 @@ class PemSslStoreBundleTests { } private Consumer storeContainingCertAndKey(String keyStoreType, String keyAlias) { + return storeContainingCertAndKey(keyStoreType, keyAlias, EMPTY_KEY_PASSWORD); + } + + private Consumer storeContainingCertAndKey(String keyAlias, char[] keyPassword) { + return storeContainingCertAndKey(KeyStore.getDefaultType(), keyAlias, keyPassword); + } + + private Consumer storeContainingCertAndKey(String keyStoreType, String keyAlias, char[] keyPassword) { return ThrowingConsumer.of((keyStore) -> { assertThat(keyStore).isNotNull(); assertThat(keyStore.getType()).isEqualTo(keyStoreType); assertThat(keyStore.containsAlias(keyAlias)).isTrue(); assertThat(keyStore.getCertificate(keyAlias)).isNotNull(); - assertThat(keyStore.getKey(keyAlias, new char[] {})).isNotNull(); + assertThat(keyStore.getKey(keyAlias, keyPassword)).isNotNull(); }); }