This is an automated email from the ASF dual-hosted git repository. michaelo pushed a commit to branch 8.5.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/8.5.x by this push: new 8768cb1607 BZ 66670: Add SSLHostConfig#certificateKeyPasswordFile and SSLHostConfig#certificateKeystorePasswordFile 8768cb1607 is described below commit 8768cb160766487e43f861de9ded9d527fd9d334 Author: Michael Osipov <micha...@apache.org> AuthorDate: Wed Sep 27 11:23:19 2023 +0200 BZ 66670: Add SSLHostConfig#certificateKeyPasswordFile and SSLHostConfig#certificateKeystorePasswordFile --- .../coyote/http11/AbstractHttp11Protocol.java | 34 ++++++++++++++++ java/org/apache/tomcat/util/net/SSLHostConfig.java | 34 +++++++++++++++- .../tomcat/util/net/SSLHostConfigCertificate.java | 27 ++++++++++++- java/org/apache/tomcat/util/net/SSLUtilBase.java | 47 ++++++++++++++++++---- java/org/apache/tomcat/util/net/jsse/PEMFile.java | 31 ++++++++++++-- .../tomcat/util/net/openssl/OpenSSLContext.java | 17 +++++++- test/org/apache/tomcat/util/net/TestSsl.java | 22 +++++++++- test/org/apache/tomcat/util/net/TesterSupport.java | 12 +++++- .../apache/tomcat/util/net/jsse/TestPEMFile.java | 39 +++++++++++++++--- test/org/apache/tomcat/util/net/jsse/key-password | 1 + test/org/apache/tomcat/util/net/key-password | 1 + test/org/apache/tomcat/util/net/keystore-password | 1 + webapps/docs/changelog.xml | 4 ++ webapps/docs/config/http.xml | 20 ++++++++- 14 files changed, 267 insertions(+), 23 deletions(-) diff --git a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java index 8e4f3efe98..18005783e2 100644 --- a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java +++ b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java @@ -1013,6 +1013,17 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> { } + public String getKeystorePassFile() { + registerDefaultSSLHostConfig(); + return defaultSSLHostConfig.getCertificateKeystorePasswordFile(); + } + + public void setKeystorePassFile(String certificateKeystorePasswordFile) { + registerDefaultSSLHostConfig(); + defaultSSLHostConfig.setCertificateKeystorePasswordFile(certificateKeystorePasswordFile); + } + + public String getKeyPass() { registerDefaultSSLHostConfig(); return defaultSSLHostConfig.getCertificateKeyPassword(); @@ -1023,6 +1034,18 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> { defaultSSLHostConfig.setCertificateKeyPassword(certificateKeyPassword); } + + public String getKeyPassFile() { + registerDefaultSSLHostConfig(); + return defaultSSLHostConfig.getCertificateKeyPasswordFile(); + } + + public void setKeyPassFile(String certificateKeyPasswordFile) { + registerDefaultSSLHostConfig(); + defaultSSLHostConfig.setCertificateKeyPasswordFile(certificateKeyPasswordFile); + } + + public String getSSLPassword() { registerDefaultSSLHostConfig(); return defaultSSLHostConfig.getCertificateKeyPassword(); @@ -1034,6 +1057,17 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> { } + public String getSSLPasswordFile() { + registerDefaultSSLHostConfig(); + return defaultSSLHostConfig.getCertificateKeyPasswordFile(); + } + + public void setSSLPasswordFile(String certificateKeyPasswordFile) { + registerDefaultSSLHostConfig(); + defaultSSLHostConfig.setCertificateKeyPasswordFile(certificateKeyPasswordFile); + } + + public String getCrlFile() { registerDefaultSSLHostConfig(); return defaultSSLHostConfig.getCertificateRevocationListFile(); diff --git a/java/org/apache/tomcat/util/net/SSLHostConfig.java b/java/org/apache/tomcat/util/net/SSLHostConfig.java index 7563015373..c9b921026e 100644 --- a/java/org/apache/tomcat/util/net/SSLHostConfig.java +++ b/java/org/apache/tomcat/util/net/SSLHostConfig.java @@ -306,12 +306,29 @@ public class SSLHostConfig implements Serializable { return defaultCertificate.getCertificateKeyPassword(); } } + + public void setCertificateKeyPassword(String certificateKeyPassword) { registerDefaultCertificate(); defaultCertificate.setCertificateKeyPassword(certificateKeyPassword); } + public String getCertificateKeyPasswordFile() { + if (defaultCertificate == null) { + return null; + } else { + return defaultCertificate.getCertificateKeyPasswordFile(); + } + } + + + public void setCertificateKeyPasswordFile(String certificateKeyPasswordFile) { + registerDefaultCertificate(); + defaultCertificate.setCertificateKeyPasswordFile(certificateKeyPasswordFile); + } + + public void setCertificateRevocationListFile(String certificateRevocationListFile) { this.certificateRevocationListFile = certificateRevocationListFile; } @@ -595,6 +612,19 @@ public class SSLHostConfig implements Serializable { } + public String getCertificateKeystorePasswordFile() { + if (defaultCertificate == null) { + return null; + } else { + return defaultCertificate.getCertificateKeystorePasswordFile(); + } + } + public void setCertificateKeystorePasswordFile(String certificateKeystorePasswordFile) { + registerDefaultCertificate(); + defaultCertificate.setCertificateKeystorePasswordFile(certificateKeystorePasswordFile); + } + + public String getCertificateKeystoreProvider() { if (defaultCertificate == null) { return null; @@ -752,7 +782,7 @@ public class SSLHostConfig implements Serializable { if (truststoreFile != null){ try { result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(), - getTruststoreFile(), getTruststorePassword()); + getTruststoreFile(), getTruststorePassword(), null); } catch (IOException ioe) { Throwable cause = ioe.getCause(); if (cause instanceof UnrecoverableKeyException) { @@ -761,7 +791,7 @@ public class SSLHostConfig implements Serializable { cause); // Re-try result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(), - getTruststoreFile(), null); + getTruststoreFile(), null, null); } else { // Something else went wrong - re-throw throw ioe; diff --git a/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java b/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java index ff635bf588..0c0ebb7274 100644 --- a/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java +++ b/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java @@ -59,10 +59,12 @@ public class SSLHostConfigCertificate implements Serializable { private final SSLHostConfig sslHostConfig; private final Type type; private String certificateKeyPassword = null; + private String certificateKeyPasswordFile = null; // JSSE private String certificateKeyAlias; private String certificateKeystorePassword = DEFAULT_KEYSTORE_PASSWORD; + private String certificateKeystorePasswordFile = null; private String certificateKeystoreFile = DEFAULT_KEYSTORE_FILE; private String certificateKeystoreProvider = DEFAULT_KEYSTORE_PROVIDER; private String certificateKeystoreType = DEFAULT_KEYSTORE_TYPE; @@ -131,6 +133,16 @@ public class SSLHostConfigCertificate implements Serializable { } + public String getCertificateKeyPasswordFile() { + return certificateKeyPasswordFile; + } + + + public void setCertificateKeyPasswordFile(String certificateKeyPasswordFile) { + this.certificateKeyPasswordFile = certificateKeyPasswordFile; + } + + // JSSE public void setCertificateKeyAlias(String certificateKeyAlias) { @@ -171,6 +183,19 @@ public class SSLHostConfigCertificate implements Serializable { } + public void setCertificateKeystorePasswordFile(String certificateKeystorePasswordFile) { + sslHostConfig.setProperty( + "Certificate.certificateKeystorePasswordFile", SSLHostConfig.Type.JSSE); + setStoreType("Certificate.certificateKeystorePasswordFile", StoreType.KEYSTORE); + this.certificateKeystorePasswordFile = certificateKeystorePasswordFile; + } + + + public String getCertificateKeystorePasswordFile() { + return certificateKeystorePasswordFile; + } + + public void setCertificateKeystoreProvider(String certificateKeystoreProvider) { sslHostConfig.setProperty( "Certificate.certificateKeystoreProvider", SSLHostConfig.Type.JSSE); @@ -208,7 +233,7 @@ public class SSLHostConfigCertificate implements Serializable { if (result == null && storeType == StoreType.KEYSTORE) { result = SSLUtilBase.getStore(getCertificateKeystoreType(), getCertificateKeystoreProvider(), getCertificateKeystoreFile(), - getCertificateKeystorePassword()); + getCertificateKeystorePassword(), getCertificateKeystorePasswordFile()); } return result; diff --git a/java/org/apache/tomcat/util/net/SSLUtilBase.java b/java/org/apache/tomcat/util/net/SSLUtilBase.java index 89dd4d9c9c..d300737f69 100644 --- a/java/org/apache/tomcat/util/net/SSLUtilBase.java +++ b/java/org/apache/tomcat/util/net/SSLUtilBase.java @@ -16,9 +16,12 @@ */ package org.apache.tomcat.util.net; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.KeyStore; import java.security.cert.CRL; @@ -175,10 +178,10 @@ public abstract class SSLUtilBase implements SSLUtil { /* - * Gets the key- or truststore with the specified type, path, and password. + * Gets the key- or truststore with the specified type, path, password and password file. */ static KeyStore getStore(String type, String provider, String path, - String pass) throws IOException { + String pass, String passFile) throws IOException { KeyStore ks = null; InputStream istream = null; @@ -211,9 +214,21 @@ public abstract class SSLUtilBase implements SSLUtil { // - for JKS or PKCS12 only use null if pass is null // (because JKS will auto-switch to PKCS12) char[] storePass = null; - if (pass != null && (!"".equals(pass) || + String passToUse = null; + if (passFile != null) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader( + ConfigFileLoader.getInputStream(passFile), + StandardCharsets.UTF_8))) { + passToUse = reader.readLine(); + } + } else { + passToUse = pass; + } + + if (passToUse != null && (!"".equals(passToUse) || "JKS".equalsIgnoreCase(type) || "PKCS12".equalsIgnoreCase(type))) { - storePass = pass.toCharArray(); + storePass = passToUse.toCharArray(); } KeyStoreUtil.load(ks, istream, storePass); } @@ -272,9 +287,13 @@ public abstract class SSLUtilBase implements SSLUtil { public KeyManager[] getKeyManagers() throws Exception { String keyAlias = certificate.getCertificateKeyAlias(); String algorithm = sslHostConfig.getKeyManagerAlgorithm(); + String keyPassFile = certificate.getCertificateKeyPasswordFile(); String keyPass = certificate.getCertificateKeyPassword(); // This has to be here as it can't be moved to SSLHostConfig since the // defaults vary between JSSE and OpenSSL. + if (keyPassFile == null) { + keyPassFile = certificate.getCertificateKeystorePasswordFile(); + } if (keyPass == null) { keyPass = certificate.getCertificateKeystorePassword(); } @@ -293,8 +312,22 @@ public abstract class SSLUtilBase implements SSLUtil { * required key works around that. * Other keys stores (hardware, MS, etc.) will be used as is. */ + char[] keyPassArray = null; + String keyPassToUse = null; + if (keyPassFile != null) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader( + ConfigFileLoader.getInputStream(keyPassFile), + StandardCharsets.UTF_8))) { + keyPassToUse = reader.readLine(); + } + } else { + keyPassToUse = keyPass; + } - char[] keyPassArray = keyPass.toCharArray(); + if (keyPassToUse != null) { + keyPassArray = keyPassToUse.toCharArray(); + } KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); if (kmf.getProvider().getInfo().contains("FIPS")) { @@ -313,7 +346,7 @@ public abstract class SSLUtilBase implements SSLUtil { PEMFile privateKeyFile = new PEMFile( certificate.getCertificateKeyFile() != null ? certificate.getCertificateKeyFile() : certificate.getCertificateFile(), - keyPass); + keyPass, keyPassFile, null); PEMFile certificateFile = new PEMFile(certificate.getCertificateFile()); Collection<Certificate> chain = new ArrayList<>(); @@ -330,7 +363,7 @@ public abstract class SSLUtilBase implements SSLUtil { // Switch to in-memory key store ksUsed = KeyStore.getInstance("JKS"); ksUsed.load(null, null); - ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPass.toCharArray(), + ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPassArray, chain.toArray(new Certificate[0])); } else { if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { diff --git a/java/org/apache/tomcat/util/net/jsse/PEMFile.java b/java/org/apache/tomcat/util/net/jsse/PEMFile.java index 6aee8ce84c..e6fc76a1ce 100644 --- a/java/org/apache/tomcat/util/net/jsse/PEMFile.java +++ b/java/org/apache/tomcat/util/net/jsse/PEMFile.java @@ -102,15 +102,30 @@ public class PEMFile { this(filename, ConfigFileLoader.getInputStream(filename), password, keyAlgorithm); } + public PEMFile(String filename, String password, String passwordFilename, String keyAlgorithm) + throws IOException, GeneralSecurityException { + this(filename, ConfigFileLoader.getInputStream(filename), password, + passwordFilename, passwordFilename != null ? ConfigFileLoader.getInputStream(passwordFilename) : null, + keyAlgorithm); + } + + public PEMFile(String filename, InputStream fileStream, String password, String keyAlgorithm) + throws IOException, GeneralSecurityException { + this(filename, fileStream, password, null, null, keyAlgorithm); + } + /** * @param filename the filename to mention in error messages, not used for anything else. * @param fileStream the stream containing the pem(s). * @param password password to load the pem objects. + * @param passwordFilename the password filename to mention in error messages, not used for anything else. + * @param passwordFileStream stream containing the password to load the pem objects. * @param keyAlgorithm the algorithm to help to know how to load the objects (guessed if null). * @throws IOException if input can't be read. * @throws GeneralSecurityException if input can't be parsed/loaded. */ - public PEMFile(String filename, InputStream fileStream, String password, String keyAlgorithm) + public PEMFile(String filename, InputStream fileStream, String password, String passwordFilename, + InputStream passwordFileStream, String keyAlgorithm) throws IOException, GeneralSecurityException { List<Part> parts = new ArrayList<>(); try (BufferedReader reader = @@ -141,6 +156,16 @@ public class PEMFile { } } + String passwordToUse = null; + if (passwordFileStream != null) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(passwordFileStream, StandardCharsets.UTF_8))) { + passwordToUse = reader.readLine(); + } + } else { + passwordToUse = password; + } + for (Part part : parts) { switch (part.type) { case Part.PRIVATE_KEY: @@ -150,7 +175,7 @@ public class PEMFile { privateKey = part.toPrivateKey(null, "EC", Format.RFC5915, filename); break; case Part.ENCRYPTED_PRIVATE_KEY: - privateKey = part.toPrivateKey(password, keyAlgorithm, Format.PKCS8, filename); + privateKey = part.toPrivateKey(passwordToUse, keyAlgorithm, Format.PKCS8, filename); break; case Part.RSA_PRIVATE_KEY: if (part.algorithm == null) { @@ -158,7 +183,7 @@ public class PEMFile { // (probably default) key password provided. privateKey = part.toPrivateKey(null, keyAlgorithm, Format.PKCS1, filename); } else { - privateKey = part.toPrivateKey(password, keyAlgorithm, Format.PKCS1, filename); + privateKey = part.toPrivateKey(passwordToUse, keyAlgorithm, Format.PKCS1, filename); } break; case Part.CERTIFICATE: diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java b/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java index cba63f00f6..7f83a3bd75 100644 --- a/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java +++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java @@ -16,6 +16,9 @@ */ package org.apache.tomcat.util.net.openssl; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.security.SecureRandom; @@ -469,10 +472,22 @@ public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext { // Load Server key and certificate if (certificate.getCertificateFile() != null) { // Set certificate + String passwordToUse = null; + if (certificate.getCertificateKeyPasswordFile() != null) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader( + new FileInputStream( + SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyPasswordFile())), + StandardCharsets.UTF_8))) { + passwordToUse = reader.readLine(); + } + } else { + passwordToUse = certificate.getCertificateKeyPassword(); + } SSLContext.setCertificate(ctx, SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()), SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()), - certificate.getCertificateKeyPassword(), getCertificateIndex(certificate)); + passwordToUse, getCertificateIndex(certificate)); // Set certificate chain file SSLContext.setCertificateChainFile(ctx, SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false); diff --git a/test/org/apache/tomcat/util/net/TestSsl.java b/test/org/apache/tomcat/util/net/TestSsl.java index 4cc71b3005..9fade38f48 100644 --- a/test/org/apache/tomcat/util/net/TestSsl.java +++ b/test/org/apache/tomcat/util/net/TestSsl.java @@ -173,7 +173,7 @@ public class TestSsl extends TomcatBaseTest { ctxt.addApplicationListener(WsContextListener.class.getName()); TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_KEYPASS_JKS, - TesterSupport.JKS_PASS, TesterSupport.JKS_KEY_PASS); + TesterSupport.JKS_PASS, null, TesterSupport.JKS_KEY_PASS, null); tomcat.start(); ByteChunk res = getUrl("https://localhost:" + getPort() + @@ -183,6 +183,26 @@ public class TestSsl extends TomcatBaseTest { TesterSupport.getLastClientAuthRequestedIssuerCount() == 0); } + @Test + public void testKeyPassFile() throws Exception { + TesterSupport.configureClientSsl(); + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File(getBuildDirectory(), "webapps/examples"); + Context ctxt = tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); + ctxt.addApplicationListener(WsContextListener.class.getName()); + + TesterSupport.initSsl(tomcat, TesterSupport.LOCALHOST_KEYPASS_JKS, + null, TesterSupport.JKS_PASS_FILE, null, TesterSupport.JKS_KEY_PASS_FILE); + + tomcat.start(); + ByteChunk res = getUrl("https://localhost:" + getPort() + + "/examples/servlets/servlet/HelloWorldExample"); + Assert.assertTrue(res.toString().indexOf("<a href=\"../helloworld.html\">") > 0); + Assert.assertTrue("Checking no client issuer has been requested", + TesterSupport.getLastClientAuthRequestedIssuerCount() == 0); + } @Test public void testRenegotiateWorks() throws Exception { diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java b/test/org/apache/tomcat/util/net/TesterSupport.java index 454a749b53..fe05118d28 100644 --- a/test/org/apache/tomcat/util/net/TesterSupport.java +++ b/test/org/apache/tomcat/util/net/TesterSupport.java @@ -77,7 +77,9 @@ public final class TesterSupport { public static final String LOCALHOST_RSA_JKS = SSL_DIR + "localhost-rsa.jks"; public static final String LOCALHOST_KEYPASS_JKS = SSL_DIR + "localhost-rsa-copy1.jks"; public static final String JKS_PASS = "changeit"; + public static final String JKS_PASS_FILE = SSL_DIR + "keystore-password"; public static final String JKS_KEY_PASS = "tomcatpass"; + public static final String JKS_KEY_PASS_FILE = SSL_DIR + "key-password"; public static final String CA_CERT_PEM = SSL_DIR + CA_ALIAS + "-cert.pem"; public static final String LOCALHOST_EC_CERT_PEM = SSL_DIR + "localhost-ec-cert.pem"; public static final String LOCALHOST_EC_KEY_PEM = SSL_DIR + "localhost-ec-key.pem"; @@ -129,11 +131,11 @@ public final class TesterSupport { } public static void initSsl(Tomcat tomcat) { - initSsl(tomcat, LOCALHOST_RSA_JKS, null, null); + initSsl(tomcat, LOCALHOST_RSA_JKS, null, null, null, null); } protected static void initSsl(Tomcat tomcat, String keystore, - String keystorePass, String keyPass) { + String keystorePass, String keystorePassFile, String keyPass, String keyPassFile) { Connector connector = tomcat.getConnector(); connector.setSecure(true); @@ -157,9 +159,15 @@ public final class TesterSupport { sslHostConfig.setSslProtocol("tls"); certificate.setCertificateKeystoreFile(new File(keystore).getAbsolutePath()); sslHostConfig.setTruststoreFile(new File(CA_JKS).getAbsolutePath()); + if (keystorePassFile != null) { + certificate.setCertificateKeystorePasswordFile(new File(keystorePassFile).getAbsolutePath()); + } if (keystorePass != null) { certificate.setCertificateKeystorePassword(keystorePass); } + if (keyPassFile != null) { + certificate.setCertificateKeyPasswordFile(new File(keyPassFile).getAbsolutePath()); + } if (keyPass != null) { certificate.setCertificateKeyPassword(keyPass); } diff --git a/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java b/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java index 2ee54e26e1..6dd125c7a8 100644 --- a/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java +++ b/test/org/apache/tomcat/util/net/jsse/TestPEMFile.java @@ -19,13 +19,21 @@ package org.apache.tomcat.util.net.jsse; import java.io.File; import java.io.IOException; import java.security.PrivateKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +@RunWith(Parameterized.class) public class TestPEMFile { private static final String KEY_PASSWORD = "changeit"; + private static final String KEY_PASSWORD_FILE = "key-password"; private static final String KEY_PKCS1 = "key-pkcs1.pem"; private static final String KEY_ENCRYPTED_PKCS1_DES_CBC = "key-encrypted-pkcs1-des-cbc.pem"; @@ -33,16 +41,34 @@ public class TestPEMFile { private static final String KEY_ENCRYPTED_PKCS1_AES256 = "key-encrypted-pkcs1-aes256.pem"; private static final String KEY_ENCRYPTED_PKCS8 = "key-encrypted-pkcs8.pem"; + @Parameterized.Parameters + public static Collection<Object[]> parameters() { + List<Object[]> parameterSets = new ArrayList<>(); + + parameterSets.add(new Object[] { KEY_PASSWORD, null }); + parameterSets.add(new Object[] { null, KEY_PASSWORD_FILE }); + parameterSets.add(new Object[] { KEY_PASSWORD, KEY_PASSWORD_FILE }); + + return parameterSets; + } + + + @Parameter(0) + public String password; + + @Parameter(1) + public String passwordFile; + @Test public void testKeyPkcs1() throws Exception { - testKey(KEY_PKCS1, null); + testKey(KEY_PKCS1, null, null); } @Test public void testKeyPkcs1WithUnnecessaryPassword() throws Exception { - testKey(KEY_PKCS1, "ignore-me"); + testKey(KEY_PKCS1, "ignore-me", null); } @@ -71,18 +97,21 @@ public class TestPEMFile { private void testKeyEncrypted(String file) throws Exception { - testKey(file, KEY_PASSWORD); + testKey(file, password, passwordFile); } - private void testKey(String file, String password) throws Exception { - PEMFile pemFile = new PEMFile(getPath(file), password); + private void testKey(String file, String password, String passwordFile) throws Exception { + PEMFile pemFile = new PEMFile(getPath(file), password, getPath(passwordFile), null); PrivateKey pk = pemFile.getPrivateKey(); Assert.assertNotNull(pk); } private String getPath(String file) throws IOException { + if (file == null) { + return null; + } String packageName = this.getClass().getPackage().getName(); String path = packageName.replace(".", File.separator); File f = new File("test" + File.separator + path + File.separator + file); diff --git a/test/org/apache/tomcat/util/net/jsse/key-password b/test/org/apache/tomcat/util/net/jsse/key-password new file mode 100644 index 0000000000..5bbaf87581 --- /dev/null +++ b/test/org/apache/tomcat/util/net/jsse/key-password @@ -0,0 +1 @@ +changeit \ No newline at end of file diff --git a/test/org/apache/tomcat/util/net/key-password b/test/org/apache/tomcat/util/net/key-password new file mode 100644 index 0000000000..05557f9168 --- /dev/null +++ b/test/org/apache/tomcat/util/net/key-password @@ -0,0 +1 @@ +tomcatpass \ No newline at end of file diff --git a/test/org/apache/tomcat/util/net/keystore-password b/test/org/apache/tomcat/util/net/keystore-password new file mode 100644 index 0000000000..5bbaf87581 --- /dev/null +++ b/test/org/apache/tomcat/util/net/keystore-password @@ -0,0 +1 @@ +changeit \ No newline at end of file diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 04a45d6980..cccd9de7b2 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -107,6 +107,10 @@ <section name="Tomcat 8.5.96 (schultz)" rtext="in development"> <subsection name="Catalina"> <changelog> + <add> + <bug>66670</bug>: Add <code>SSLHostConfig#certificateKeyPasswordFile</code> and + <code>SSLHostConfig#certificateKeystorePasswordFile</code>. (michaelo) + </add> <fix> <bug>67667</bug>: <code>TLSCertificateReloadListener</code> prints unreadable rendering of <code>X509Certificate#getNotAfter()</code>. (michaelo) diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml index cc64907ee9..bc76a13f8c 100644 --- a/webapps/docs/config/http.xml +++ b/webapps/docs/config/http.xml @@ -1571,7 +1571,18 @@ certificate from the specified file.</p> <p>If not specified, the default behaviour for JSSE is to use the <strong>certificateKeystorePassword</strong>. For OpenSSL the default - behaviour is not to use a password.</p> + behaviour is not to use a password, but OpenSSL will prompt for one, + if required.</p> + </attribute> + + <attribute name="certificateKeyPasswordFile" required="false"> + <p>The password file used to access the private key associated with the server + certificate from the specified file. This attribute takes precedence over + <strong>certificateKeyPassword</strong>.</p> + <p>If not specified, the default behaviour for JSSE is to use the + <strong>certificateKeystorePasswordFile</strong>. For OpenSSL the default + behaviour is not to use a password (file), but OpenSSL will prompt for one, + if required.</p> </attribute> <attribute name="certificateKeystoreFile" required="false"> @@ -1597,6 +1608,13 @@ <code>changeit</code> will be used.</p> </attribute> + <attribute name="certificateKeystorePasswordFile" required="false"> + <p>JSSE only.</p> + <p>The password file to use to access the keystore containing the server's + private key and certificate. This attribute takes precedence over + <strong>certificateKeystorePassword</strong>.</p> + </attribute> + <attribute name="certificateKeystoreProvider" required="false"> <p>JSSE only.</p> <p>The name of the keystore provider to be used for the server --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org