From 737631ab3d28861535f33f8c1539c03b5d9b8369 Mon Sep 17 00:00:00 2001
From: markt trustManagerClassName attribute (if set) else from the
+ * {@link TrustManagerFactory}.
+ * @return The TrustManagers to use for this connector.
+ * @throws NoSuchAlgorithmException
+ * @throws ClassNotFoundException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ */
+ protected TrustManager[] getTrustManagers(TrustManagerFactory tmf)
+ throws NoSuchAlgorithmException, ClassNotFoundException,
+ InstantiationException, IllegalAccessException {
+
+ String className = endpoint.getTrustManagerClassName();
+ if(className != null && className.length() > 0) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ Class> clazz = classLoader.loadClass(className);
+ if(!(TrustManager.class.isAssignableFrom(clazz))){
+ throw new InstantiationException(sm.getString(
+ "jsse.invalidTrustManagerClassName", className));
+ }
+ Object trustManagerObject = clazz.newInstance();
+ TrustManager trustManager = (TrustManager) trustManagerObject;
+ return new TrustManager[]{ trustManager };
+ }
+ return tmf.getTrustManagers();
+ }
+
/**
* Return the initialization parameters for the TrustManager.
* Currently, only the default PKIX is supported.
diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
index 69302278b..5e8ce34f2 100644
--- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
@@ -16,4 +16,5 @@
jsse.alias_no_key_entry=Alias name {0} does not identify a key entry
jsse.keystore_load_failed=Failed to load keystore type {0} with path {1} due to {2}
jsse.invalid_ssl_conf=SSL configuration is invalid due to {0}
-jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
\ No newline at end of file
+jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
+jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager
\ No newline at end of file
diff --git a/test/org/apache/tomcat/util/net/TestCustomSsl.java b/test/org/apache/tomcat/util/net/TestCustomSsl.java
index d9c383b55..d532bbfdb 100644
--- a/test/org/apache/tomcat/util/net/TestCustomSsl.java
+++ b/test/org/apache/tomcat/util/net/TestCustomSsl.java
@@ -17,12 +17,15 @@
package org.apache.tomcat.util.net;
import java.io.File;
+import java.net.SocketException;
-import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.jsse.TesterBug50640SslImpl;
@@ -35,16 +38,8 @@ public class TestCustomSsl extends TomcatBaseTest {
public void testCustomSslImplementation() throws Exception {
- try {
- SSLContext sc = SSLContext.getInstance("SSL");
- sc.init(null, TesterSupport.getTrustManagers(),
- new java.security.SecureRandom());
- javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(
- sc.getSocketFactory());
- } catch (Exception e) {
- e.printStackTrace();
- }
-
+ TesterSupport.configureClientSsl();
+
Tomcat tomcat = getTomcatInstance();
Connector connector = tomcat.getConnector();
if (connector.getProtocolHandlerClassName().contains("Apr")) {
@@ -76,4 +71,70 @@ public class TestCustomSsl extends TomcatBaseTest {
assertTrue(res.toString().indexOf("Hello World!
") > 0);
}
+ public void testCustomTrustManager1() throws Exception {
+ doTestCustomTrustManager(false);
+ }
+
+ public void testCustomTrustManager2() throws Exception {
+ doTestCustomTrustManager(true);
+ }
+
+ private void doTestCustomTrustManager(boolean serverTrustAll)
+ throws Exception {
+
+ if (!TesterSupport.RFC_5746_SUPPORTED) {
+ // Make sure SSL renegotiation is not disabled in the JVM
+ System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
+ }
+
+ Tomcat tomcat = getTomcatInstance();
+
+ if (!TesterSupport.isRenegotiationSupported(getTomcatInstance())) {
+ return;
+ }
+
+ TesterSupport.configureClientCertContext(tomcat);
+
+ // Override the defaults
+ ProtocolHandler handler = tomcat.getConnector().getProtocolHandler();
+ if (handler instanceof AbstractHttp11JsseProtocol) {
+ ((AbstractHttp11JsseProtocol) handler).setTruststoreFile(null);
+ } else {
+ // Unexpected
+ fail("Unexpected handler type");
+ }
+ if (serverTrustAll) {
+ tomcat.getConnector().setAttribute("trustManagerClassName",
+ "org.apache.tomcat.util.net.TesterSupport$TrustAllCerts");
+ }
+
+ // Start Tomcat
+ tomcat.start();
+
+ TesterSupport.configureClientSsl();
+
+ // Unprotected resource
+ ByteChunk res =
+ getUrl("https://localhost:" + getPort() + "/unprotected");
+ assertEquals("OK", res.toString());
+
+ // Protected resource
+ res.recycle();
+ int rc = -1;
+ try {
+ rc = getUrl("https://localhost:" + getPort() + "/protected", res,
+ null, null);
+ } catch (SocketException expected1) {
+ // Ignore
+ } catch (SSLHandshakeException expected2) {
+ // Ignore
+ }
+ if (serverTrustAll) {
+ assertEquals(200, rc);
+ assertEquals("OK", res.toString());
+ } else {
+ assertTrue(rc != 200);
+ assertEquals("", res.toString());
+ }
+ }
}
diff --git a/test/org/apache/tomcat/util/net/TesterSupport.java b/test/org/apache/tomcat/util/net/TesterSupport.java
index 127a41e6a..ee133425b 100644
--- a/test/org/apache/tomcat/util/net/TesterSupport.java
+++ b/test/org/apache/tomcat/util/net/TesterSupport.java
@@ -24,6 +24,7 @@ import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -31,6 +32,7 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -226,4 +228,24 @@ public final class TesterSupport {
resp.getWriter().print("CONTENT-MISMATCH-" + read);
}
}
+
+ public static class TrustAllCerts implements X509TrustManager {
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs,
+ String authType) {
+ // NOOP - Trust everything
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs,
+ String authType) {
+ // NOOP - Trust everything
+ }
+ }
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index c7e43d37c..d5641f802 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -51,6 +51,14 @@
+ TLS".
The name of a custom trust manager class to use to validate client
+ certificates. The class must have a zero argument constructor and must
+ also implement javax.net.ssl.X509TrustManager. If this
+ attribute is set, the trust store attributes may be ignored.
+
The maximum number of intermediate certificates that will be allowed when validating client certificates. If not specified, the default value -- 2.11.0