Skip to content

Commit 47b1c41

Browse files
Allow server.ssl properties to mix PEM and JKS certificate types
Prior to the introduction of SSL bundles, the `server.ssl` properties allowed PEM and JKS certificate files types to be mixed when configuring keystores and truststores. This was lost when adapting to SSL bundles using `WebServerSslBundle`. This commit restores the previous behavior for back compatibility. Fixes gh-39105
1 parent b796447 commit 47b1c41

File tree

2 files changed

+161
-14
lines changed

2 files changed

+161
-14
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -68,12 +68,28 @@ private static SslStoreBundle createPemStoreBundle(Ssl ssl) {
6868
return new PemSslStoreBundle(keyStoreDetails, trustStoreDetails, ssl.getKeyAlias());
6969
}
7070

71-
private static SslStoreBundle createJksStoreBundle(Ssl ssl) {
71+
private static SslStoreBundle createPemKeyStoreBundle(Ssl ssl) {
72+
PemSslStoreDetails keyStoreDetails = new PemSslStoreDetails(ssl.getKeyStoreType(), ssl.getCertificate(),
73+
ssl.getCertificatePrivateKey());
74+
return new PemSslStoreBundle(keyStoreDetails, null, ssl.getKeyAlias());
75+
}
76+
77+
private static SslStoreBundle createPemTrustStoreBundle(Ssl ssl) {
78+
PemSslStoreDetails trustStoreDetails = new PemSslStoreDetails(ssl.getTrustStoreType(),
79+
ssl.getTrustCertificate(), ssl.getTrustCertificatePrivateKey());
80+
return new PemSslStoreBundle(null, trustStoreDetails, ssl.getKeyAlias());
81+
}
82+
83+
private static SslStoreBundle createJksKeyStoreBundle(Ssl ssl) {
7284
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(ssl.getKeyStoreType(), ssl.getKeyStoreProvider(),
7385
ssl.getKeyStore(), ssl.getKeyStorePassword());
86+
return new JksSslStoreBundle(keyStoreDetails, null);
87+
}
88+
89+
private static SslStoreBundle createJksTrustStoreBundle(Ssl ssl) {
7490
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(ssl.getTrustStoreType(),
7591
ssl.getTrustStoreProvider(), ssl.getTrustStore(), ssl.getTrustStorePassword());
76-
return new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
92+
return new JksSslStoreBundle(null, trustStoreDetails);
7793
}
7894

7995
@Override
@@ -156,30 +172,55 @@ public static SslBundle get(Ssl ssl, SslBundles sslBundles, SslStoreProvider ssl
156172
}
157173

158174
private static SslStoreBundle createStoreBundle(Ssl ssl) {
159-
if (hasCertificateProperties(ssl)) {
160-
return createPemStoreBundle(ssl);
175+
KeyStore keyStore = createKeyStore(ssl);
176+
KeyStore trustStore = createTrustStore(ssl);
177+
return new WebServerSslStoreBundle(keyStore, trustStore, ssl.getKeyStorePassword());
178+
}
179+
180+
private static KeyStore createKeyStore(Ssl ssl) {
181+
if (hasPemKeyStoreProperties(ssl)) {
182+
return createPemKeyStoreBundle(ssl).getKeyStore();
183+
}
184+
else if (hasJksKeyStoreProperties(ssl)) {
185+
return createJksKeyStoreBundle(ssl).getKeyStore();
186+
}
187+
return null;
188+
}
189+
190+
private static KeyStore createTrustStore(Ssl ssl) {
191+
if (hasPemTrustStoreProperties(ssl)) {
192+
return createPemTrustStoreBundle(ssl).getTrustStore();
161193
}
162-
if (hasJavaKeyStoreProperties(ssl)) {
163-
return createJksStoreBundle(ssl);
194+
else if (hasJksTrustStoreProperties(ssl)) {
195+
return createJksTrustStoreBundle(ssl).getTrustStore();
164196
}
165-
throw new IllegalStateException("SSL is enabled but no trust material is configured");
197+
return null;
166198
}
167199

168200
static SslBundle createCertificateFileSslStoreProviderDelegate(Ssl ssl) {
169-
if (!hasCertificateProperties(ssl)) {
201+
if (!hasPemKeyStoreProperties(ssl)) {
170202
return null;
171203
}
172204
SslStoreBundle stores = createPemStoreBundle(ssl);
173205
return new WebServerSslBundle(stores, ssl.getKeyPassword(), ssl);
174206
}
175207

176-
private static boolean hasCertificateProperties(Ssl ssl) {
208+
private static boolean hasPemKeyStoreProperties(Ssl ssl) {
177209
return Ssl.isEnabled(ssl) && ssl.getCertificate() != null && ssl.getCertificatePrivateKey() != null;
178210
}
179211

180-
private static boolean hasJavaKeyStoreProperties(Ssl ssl) {
181-
return Ssl.isEnabled(ssl) && ssl.getKeyStore() != null
182-
|| (ssl.getKeyStoreType() != null && ssl.getKeyStoreType().equals("PKCS11"));
212+
private static boolean hasPemTrustStoreProperties(Ssl ssl) {
213+
return Ssl.isEnabled(ssl) && ssl.getTrustCertificate() != null;
214+
}
215+
216+
private static boolean hasJksKeyStoreProperties(Ssl ssl) {
217+
return Ssl.isEnabled(ssl) && (ssl.getKeyStore() != null
218+
|| (ssl.getKeyStoreType() != null && ssl.getKeyStoreType().equals("PKCS11")));
219+
}
220+
221+
private static boolean hasJksTrustStoreProperties(Ssl ssl) {
222+
return Ssl.isEnabled(ssl) && (ssl.getTrustStore() != null
223+
|| (ssl.getTrustStoreType() != null && ssl.getTrustStoreType().equals("PKCS11")));
183224
}
184225

185226
/**
@@ -211,4 +252,36 @@ public KeyStore getTrustStore() {
211252

212253
}
213254

255+
private static final class WebServerSslStoreBundle implements SslStoreBundle {
256+
257+
private final KeyStore keyStore;
258+
259+
private final KeyStore trustStore;
260+
261+
private final String keyStorePassword;
262+
263+
private WebServerSslStoreBundle(KeyStore keyStore, KeyStore trustStore, String keyStorePassword) {
264+
Assert.state(keyStore != null || trustStore != null, "SSL is enabled but no trust material is configured");
265+
this.keyStore = keyStore;
266+
this.trustStore = trustStore;
267+
this.keyStorePassword = keyStorePassword;
268+
}
269+
270+
@Override
271+
public KeyStore getKeyStore() {
272+
return this.keyStore;
273+
}
274+
275+
@Override
276+
public KeyStore getTrustStore() {
277+
return this.trustStore;
278+
}
279+
280+
@Override
281+
public String getKeyStorePassword() {
282+
return this.keyStorePassword;
283+
}
284+
285+
}
286+
214287
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/WebServerSslBundleTests.java

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -95,6 +95,25 @@ void whenFromJksPropertiesWithPkcs11StoreType() {
9595
.withMessageContaining("must be empty or null for PKCS11 hardware key stores");
9696
}
9797

98+
@Test
99+
void whenFromPkcs11Properties() {
100+
Ssl ssl = new Ssl();
101+
ssl.setKeyStoreType("PKCS11");
102+
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
103+
ssl.setTrustStoreType("PKCS11");
104+
ssl.setTrustStoreProvider(MockPkcs11SecurityProvider.NAME);
105+
ssl.setKeyPassword("password");
106+
ssl.setClientAuth(Ssl.ClientAuth.NONE);
107+
SslBundle bundle = WebServerSslBundle.get(ssl);
108+
assertThat(bundle).isNotNull();
109+
assertThat(bundle.getProtocol()).isEqualTo("TLS");
110+
SslBundleKey key = bundle.getKey();
111+
assertThat(key.getPassword()).isEqualTo("password");
112+
SslStoreBundle stores = bundle.getStores();
113+
assertThat(stores.getKeyStore()).isNotNull();
114+
assertThat(stores.getTrustStore()).isNotNull();
115+
}
116+
98117
@Test
99118
void whenFromPemProperties() {
100119
Ssl ssl = new Ssl();
@@ -122,6 +141,61 @@ void whenFromPemProperties() {
122141
assertThat(options.getEnabledProtocols()).containsExactly("TLSv1.1", "TLSv1.2");
123142
}
124143

144+
@Test
145+
void whenPemKeyStoreAndJksTrustStoreProperties() {
146+
Ssl ssl = new Ssl();
147+
ssl.setCertificate("classpath:test-cert.pem");
148+
ssl.setCertificatePrivateKey("classpath:test-key.pem");
149+
ssl.setKeyStoreType("PKCS12");
150+
ssl.setKeyPassword("password");
151+
ssl.setTrustStore("classpath:test.p12");
152+
ssl.setTrustStorePassword("secret");
153+
ssl.setTrustStoreType("PKCS12");
154+
ssl.setClientAuth(Ssl.ClientAuth.NONE);
155+
ssl.setCiphers(new String[] { "ONE", "TWO", "THREE" });
156+
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
157+
ssl.setProtocol("TLSv1.1");
158+
SslBundle bundle = WebServerSslBundle.get(ssl);
159+
assertThat(bundle).isNotNull();
160+
SslBundleKey key = bundle.getKey();
161+
assertThat(key.getAlias()).isNull();
162+
assertThat(key.getPassword()).isEqualTo("password");
163+
SslStoreBundle stores = bundle.getStores();
164+
assertThat(stores.getKeyStorePassword()).isNull();
165+
assertThat(stores.getKeyStore()).isNotNull();
166+
assertThat(stores.getTrustStore()).isNotNull();
167+
SslOptions options = bundle.getOptions();
168+
assertThat(options.getCiphers()).containsExactly("ONE", "TWO", "THREE");
169+
assertThat(options.getEnabledProtocols()).containsExactly("TLSv1.1", "TLSv1.2");
170+
}
171+
172+
@Test
173+
void whenJksKeyStoreAndPemTrustStoreProperties() {
174+
Ssl ssl = new Ssl();
175+
ssl.setKeyStore("classpath:test.p12");
176+
ssl.setKeyStoreType("PKCS12");
177+
ssl.setKeyPassword("password");
178+
ssl.setTrustCertificate("classpath:test-cert-chain.pem");
179+
ssl.setTrustStorePassword("secret");
180+
ssl.setTrustStoreType("PKCS12");
181+
ssl.setClientAuth(Ssl.ClientAuth.NONE);
182+
ssl.setCiphers(new String[] { "ONE", "TWO", "THREE" });
183+
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
184+
ssl.setProtocol("TLSv1.1");
185+
SslBundle bundle = WebServerSslBundle.get(ssl);
186+
assertThat(bundle).isNotNull();
187+
SslBundleKey key = bundle.getKey();
188+
assertThat(key.getAlias()).isNull();
189+
assertThat(key.getPassword()).isEqualTo("password");
190+
SslStoreBundle stores = bundle.getStores();
191+
assertThat(stores.getKeyStorePassword()).isNull();
192+
assertThat(stores.getKeyStore()).isNotNull();
193+
assertThat(stores.getTrustStore()).isNotNull();
194+
SslOptions options = bundle.getOptions();
195+
assertThat(options.getCiphers()).containsExactly("ONE", "TWO", "THREE");
196+
assertThat(options.getEnabledProtocols()).containsExactly("TLSv1.1", "TLSv1.2");
197+
}
198+
125199
@Test
126200
@Deprecated(since = "3.1.0", forRemoval = true)
127201
@SuppressWarnings("removal")

0 commit comments

Comments
 (0)