Skip to content

Commit

Permalink
Allow PEM certificates to be used without a key store password
Browse files Browse the repository at this point in the history
Closes gh-31253
  • Loading branch information
wilkinsona committed Jun 24, 2022
1 parent dfb8979 commit 7abc7df
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 27 deletions.
Expand Up @@ -205,7 +205,6 @@ The following example shows setting SSL properties using PEM-encoded certificate
certificate: "classpath:my-cert.crt"
certificate-private-key: "classpath:my-cert.key"
trust-certificate: "classpath:ca-cert.crt"
key-store-password: "secret"
----

See {spring-boot-module-code}/web/server/Ssl.java[`Ssl`] for details of all of the supported properties.
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -183,6 +183,10 @@ protected void configureSsl(SslContextFactory.Server factory, Ssl ssl, SslStoreP
}
if (sslStoreProvider != null) {
try {
String keyPassword = sslStoreProvider.getKeyPassword();
if (keyPassword != null) {
factory.setKeyManagerPassword(keyPassword);
}
factory.setKeyStore(sslStoreProvider.getKeyStore());
factory.setTrustStore(sslStoreProvider.getTrustStore());
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -115,11 +115,11 @@ KeyManagerFactory getKeyManagerFactory(Ssl ssl, SslStoreProvider sslStoreProvide
? KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
: new ConfigurableAliasKeyManagerFactory(ssl.getKeyAlias(),
KeyManagerFactory.getDefaultAlgorithm());
char[] keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword().toCharArray() : null;
if (keyPassword == null && ssl.getKeyStorePassword() != null) {
keyPassword = ssl.getKeyStorePassword().toCharArray();
String keyPassword = (sslStoreProvider != null) ? sslStoreProvider.getKeyPassword() : null;
if (keyPassword == null) {
keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword() : ssl.getKeyStorePassword();
}
keyManagerFactory.init(keyStore, keyPassword);
keyManagerFactory.init(keyStore, (keyPassword != null) ? keyPassword.toCharArray() : null);
return keyManagerFactory;
}
catch (Exception ex) {
Expand Down
Expand Up @@ -93,6 +93,10 @@ protected void configureSsl(AbstractHttp11JsseProtocol<?> protocol, Ssl ssl, Ssl
configureEnabledProtocols(protocol, ssl);
if (sslStoreProvider != null) {
configureSslStoreProvider(protocol, sslHostConfig, certificate, sslStoreProvider);
String keyPassword = sslStoreProvider.getKeyPassword();
if (keyPassword != null) {
certificate.setCertificateKeyPassword(ciphers);

This comment has been minimized.

Copy link
@dreis2211

dreis2211 Jun 25, 2022

Contributor

Should this be really ciphers here, @wilkinsona ?

This comment has been minimized.

Copy link
@wilkinsona

wilkinsona Jun 25, 2022

Author Member

Nope! Thanks very much.

}
}
else {
configureSslKeyStore(certificate, ssl);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -112,11 +112,11 @@ private KeyManager[] getKeyManagers(Ssl ssl, SslStoreProvider sslStoreProvider)
SslConfigurationValidator.validateKeyAlias(keyStore, ssl.getKeyAlias());
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
char[] keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword().toCharArray() : null;
if (keyPassword == null && ssl.getKeyStorePassword() != null) {
keyPassword = ssl.getKeyStorePassword().toCharArray();
String keyPassword = (sslStoreProvider != null) ? sslStoreProvider.getKeyPassword() : null;
if (keyPassword == null) {
keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword() : ssl.getKeyStorePassword();
}
keyManagerFactory.init(keyStore, keyPassword);
keyManagerFactory.init(keyStore, (keyPassword != null) ? keyPassword.toCharArray() : null);
if (ssl.getKeyAlias() != null) {
return getConfigurableAliasKeyManagers(ssl, keyManagerFactory.getKeyManagers());
}
Expand Down
Expand Up @@ -32,7 +32,11 @@
*/
public final class CertificateFileSslStoreProvider implements SslStoreProvider {

private static final char[] NO_PASSWORD = {};
/**
* The password of the private key entry in the {@link #getKeyStore provided
* KeyStore}.
*/
private static final String KEY_PASSWORD = "";

private static final String DEFAULT_KEY_ALIAS = "spring-boot-web";

Expand All @@ -45,7 +49,7 @@ private CertificateFileSslStoreProvider(Ssl ssl) {
@Override
public KeyStore getKeyStore() throws Exception {
return createKeyStore(this.ssl.getCertificate(), this.ssl.getCertificatePrivateKey(),
this.ssl.getKeyStorePassword(), this.ssl.getKeyStoreType(), this.ssl.getKeyAlias());
this.ssl.getKeyStoreType(), this.ssl.getKeyAlias());
}

@Override
Expand All @@ -54,28 +58,31 @@ public KeyStore getTrustStore() throws Exception {
return null;
}
return createKeyStore(this.ssl.getTrustCertificate(), this.ssl.getTrustCertificatePrivateKey(),
this.ssl.getTrustStorePassword(), this.ssl.getTrustStoreType(), this.ssl.getKeyAlias());
this.ssl.getTrustStoreType(), this.ssl.getKeyAlias());
}

@Override
public String getKeyPassword() {
return KEY_PASSWORD;
}

/**
* Create a new {@link KeyStore} populated with the certificate stored at the
* specified file path and an optional private key.
* @param certPath the path to the certificate authority file
* @param keyPath the path to the private file
* @param password the key store password
* @param storeType the {@code KeyStore} type to create
* @param keyAlias the alias to use when adding keys to the {@code KeyStore}
* @return the {@code KeyStore}
*/
private KeyStore createKeyStore(String certPath, String keyPath, String password, String storeType,
String keyAlias) {
private KeyStore createKeyStore(String certPath, String keyPath, String storeType, String keyAlias) {
try {
KeyStore keyStore = KeyStore.getInstance((storeType != null) ? storeType : KeyStore.getDefaultType());
keyStore.load(null);
X509Certificate[] certificates = CertificateParser.parse(certPath);
PrivateKey privateKey = (keyPath != null) ? PrivateKeyParser.parse(keyPath) : null;
try {
addCertificates(keyStore, certificates, privateKey, password, keyAlias);
addCertificates(keyStore, certificates, privateKey, keyAlias);
}
catch (KeyStoreException ex) {
throw new IllegalStateException("Error adding certificates to KeyStore: " + ex.getMessage(), ex);
Expand All @@ -88,11 +95,10 @@ private KeyStore createKeyStore(String certPath, String keyPath, String password
}

private void addCertificates(KeyStore keyStore, X509Certificate[] certificates, PrivateKey privateKey,
String password, String keyAlias) throws KeyStoreException {
String keyAlias) throws KeyStoreException {
String alias = (keyAlias != null) ? keyAlias : DEFAULT_KEY_ALIAS;
if (privateKey != null) {
keyStore.setKeyEntry(alias, privateKey, ((password != null) ? password.toCharArray() : NO_PASSWORD),
certificates);
keyStore.setKeyEntry(alias, privateKey, KEY_PASSWORD.toCharArray(), certificates);
}
else {
for (int index = 0; index < certificates.length; index++) {
Expand All @@ -102,9 +108,10 @@ private void addCertificates(KeyStore keyStore, X509Certificate[] certificates,
}

/**
* Create a {@link SslStoreProvider} if the appropriate SSL properties are configured.
* Create an {@link SslStoreProvider} if the appropriate SSL properties are
* configured.
* @param ssl the SSL properties
* @return a {@code SslStoreProvider} or {@code null}
* @return an {@code SslStoreProvider} or {@code null}
*/
public static SslStoreProvider from(Ssl ssl) {
if (ssl != null && ssl.isEnabled()) {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -41,4 +41,13 @@ public interface SslStoreProvider {
*/
KeyStore getTrustStore() throws Exception;

/**
* Return the password of the private key in the key store.
* @return the key password
* @since 2.7.1
*/
default String getKeyPassword() {
return null;
}

}
Expand Up @@ -285,7 +285,6 @@ void sslWithPemCertificates() throws Exception {
ssl.setCertificate("classpath:test-cert.pem");
ssl.setCertificatePrivateKey("classpath:test-key.pem");
ssl.setTrustCertificate("classpath:test-cert.pem");
ssl.setKeyStorePassword("secret");
testClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector("test.p12", "secret"));
}

Expand Down
Expand Up @@ -732,7 +732,6 @@ private Ssl getSsl(String cert, String privateKey) {
ssl.setCertificate(cert);
ssl.setCertificatePrivateKey(privateKey);
ssl.setTrustCertificate(cert);
ssl.setKeyStorePassword("secret");
return ssl;
}

Expand Down

0 comments on commit 7abc7df

Please sign in to comment.