diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemContent.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemContent.java index ec0a0905c5..9d70459836 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemContent.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemContent.java @@ -52,11 +52,7 @@ final class PemContent { return PemCertificateParser.parse(this.text); } - List getPrivateKeys() { - return PemPrivateKeyParser.parse(this.text); - } - - List getPrivateKeys(String password) { + PrivateKey getPrivateKeys(String password) { return PemPrivateKeyParser.parse(this.text, password); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java index 1d9c06b244..068ae51f62 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java @@ -69,10 +69,6 @@ final class PemPrivateKeyParser { private static final String SEC1_EC_FOOTER = "-+END\\s+EC\\s+PRIVATE\\s+KEY[^-]*-+"; - private static final String PKCS1_DSA_HEADER = "-+BEGIN\\s+DSA\\s+PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+"; - - private static final String PKCS1_DSA_FOOTER = "-+END\\s+DSA\\s+PRIVATE\\s+KEY[^-]*-+"; - private static final String BASE64_TEXT = "([a-z0-9+/=\\r\\n]+)"; public static final int BASE64_TEXT_GROUP = 1; @@ -87,9 +83,6 @@ final class PemPrivateKeyParser { "RSASSA-PSS", "EC", "DSA", "EdDSA", "XDH")); parsers.add(new PemParser(PKCS8_ENCRYPTED_HEADER, PKCS8_ENCRYPTED_FOOTER, PemPrivateKeyParser::createKeySpecForPkcs8Encrypted, "RSA", "RSASSA-PSS", "EC", "DSA", "EdDSA", "XDH")); - parsers.add(new PemParser(PKCS1_DSA_HEADER, PKCS1_DSA_FOOTER, (bytes, password) -> { - throw new IllegalStateException("Unsupported private key format"); - })); PEM_PARSERS = Collections.unmodifiableList(parsers); } @@ -179,7 +172,7 @@ final class PemPrivateKeyParser { * @param text the text to parse * @return the parsed private key */ - static List parse(String text) { + static PrivateKey parse(String text) { return parse(text, null); } @@ -190,23 +183,22 @@ final class PemPrivateKeyParser { * @param password the password used to decrypt an encrypted private key * @return the parsed private key */ - static List parse(String text, String password) { + static PrivateKey parse(String text, String password) { if (text == null) { return null; } - List keys = new ArrayList<>(); try { for (PemParser pemParser : PEM_PARSERS) { PrivateKey privateKey = pemParser.parse(text, password); if (privateKey != null) { - keys.add(privateKey); + return privateKey; } } + throw new IllegalStateException("Unrecognized private key format"); } catch (Exception ex) { throw new IllegalStateException("Error loading private key file: " + ex.getMessage(), ex); } - return List.copyOf(keys); } /** @@ -247,7 +239,7 @@ final class PemPrivateKeyParser { catch (InvalidKeySpecException | NoSuchAlgorithmException ex) { } } - throw new IllegalStateException("Unrecognized private key format"); + return null; } } 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 14077cdbb2..c1db6b4d9a 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 @@ -155,9 +155,7 @@ public class PemSslStoreBundle implements SslStoreBundle { if (pemContent == null) { return null; } - List privateKeys = pemContent.getPrivateKeys(details.privateKeyPassword()); - Assert.state(!CollectionUtils.isEmpty(privateKeys), "Loaded private keys are empty"); - return privateKeys.get(0); + return pemContent.getPrivateKeys(details.privateKeyPassword()); } private static X509Certificate[] loadCertificates(PemSslStoreDetails details) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemPrivateKeyParserTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemPrivateKeyParserTests.java index c61396a63c..431dca2af4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemPrivateKeyParserTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemPrivateKeyParserTests.java @@ -28,7 +28,6 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.core.io.ClassPathResource; -import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -51,7 +50,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseTraditionalPkcs8(String file, String algorithm) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/pkcs8/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm); @@ -64,7 +63,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseTraditionalPkcs1(String file, String algorithm) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/pkcs1/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs1/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm); @@ -78,11 +77,11 @@ class PemPrivateKeyParserTests { // @formatter:on void shouldNotParseUnsupportedTraditionalPkcs1(String file) { assertThatIllegalStateException() - .isThrownBy(() -> parse(read("org/springframework/boot/web/server/pkcs1/" + file))) + .isThrownBy(() -> PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs1/" + file))) .withMessageContaining("Error loading private key file") .withCauseInstanceOf(IllegalStateException.class) .havingCause() - .withMessageContaining("Unsupported private key format"); + .withMessageContaining("Unrecognized private key format"); } @ParameterizedTest @@ -101,7 +100,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseEcPkcs8(String file, String curveName, String oid) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/pkcs8/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo("EC"); @@ -136,7 +135,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseEdDsaPkcs8(String file) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/pkcs8/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo("EdDSA"); @@ -150,7 +149,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseXdhPkcs8(String file) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/pkcs8/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo("XDH"); @@ -172,7 +171,7 @@ class PemPrivateKeyParserTests { }) // @formatter:on void shouldParseEcSec1(String file, String curveName, String oid) throws IOException { - PrivateKey privateKey = parse(read("org/springframework/boot/web/server/sec1/" + file)); + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/sec1/" + file)); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo("EC"); @@ -200,8 +199,8 @@ class PemPrivateKeyParserTests { } @Test - void parseWithNonKeyTextWillReturnEmptyArray() throws Exception { - assertThat(PemPrivateKeyParser.parse(read("test-banner.txt"))).isEmpty(); + void parseWithNonKeyTextWillThrowException() { + assertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read("test-banner.txt"))); } @ParameterizedTest @@ -219,10 +218,16 @@ class PemPrivateKeyParserTests { // openssl pkcs8 -topk8 -in -out -v2 // -passout pass:test // where is aes128 or aes256 +<<<<<<< HEAD String content = read("org/springframework/boot/web/server/pkcs8/" + file); List privateKeys = PemPrivateKeyParser.parse(content, "test"); assertThat(privateKeys).isNotEmpty(); PrivateKey privateKey = privateKeys.get(0); +======= + PrivateKey privateKey = PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs8/" + file), + "test"); + assertThat(privateKey).isNotNull(); +>>>>>>> parent of 32e6ce210e1 (Allow PemPrivateKeyParser to parse multiple keys) assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); assertThat(privateKey.getAlgorithm()).isEqualTo(algorithm); } @@ -251,18 +256,21 @@ class PemPrivateKeyParserTests { } @Test - void shouldNotParseEncryptedSec1() throws Exception { + void shouldNotParseEncryptedSec1() { // created with: // openssl ecparam -genkey -name prime256v1 | openssl ec -aes-128-cbc -out // prime256v1-aes-128-cbc.key - assertThat(PemPrivateKeyParser - .parse(read("org/springframework/boot/web/server/sec1/prime256v1-aes-128-cbc.key"), "test")).isEmpty(); + assertThatIllegalStateException() + .isThrownBy(() -> PemPrivateKeyParser + .parse(read("org/springframework/boot/web/server/sec1/prime256v1-aes-128-cbc.key"), "test")) + .withMessageContaining("Unrecognized private key format"); } @Test void shouldNotParseEncryptedPkcs1() throws Exception { // created with: // openssl genrsa -aes-256-cbc -out rsa-aes-256-cbc.key +<<<<<<< HEAD assertThat(PemPrivateKeyParser.parse(read("org/springframework/boot/web/server/pkcs1/rsa-aes-256-cbc.key"), "test")) .isEmpty(); @@ -271,6 +279,12 @@ class PemPrivateKeyParserTests { private PrivateKey parse(String key) { List keys = PemPrivateKeyParser.parse(key); return (!ObjectUtils.isEmpty(keys)) ? keys.get(0) : null; +======= + assertThatIllegalStateException() + .isThrownBy(() -> PemPrivateKeyParser + .parse(read("org/springframework/boot/web/server/pkcs1/rsa-aes-256-cbc.key"), "test")) + .withMessageContaining("Unrecognized private key format"); +>>>>>>> parent of 32e6ce210e1 (Allow PemPrivateKeyParser to parse multiple keys) } private String read(String path) throws IOException {