Author: markt Date: Sun Mar 6 09:33:26 2011 New Revision: 1078436 URL: http://svn.apache.org/viewvc?rev=1078436&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48208 Add custom trust manager support
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties tomcat/trunk/test/org/apache/tomcat/util/net/TestCustomSsl.java tomcat/trunk/test/org/apache/tomcat/util/net/TesterSupport.java tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/http.xml Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Sun Mar 6 09:33:26 2011 @@ -679,9 +679,13 @@ public abstract class AbstractEndpoint { private String truststoreFile = System.getProperty("javax.net.ssl.trustStore"); public String getTruststoreFile() {return truststoreFile;} public void setTruststoreFile(String s) { - String file = adjustRelativePath(s, - System.getProperty(Constants.CATALINA_BASE_PROP)); - this.truststoreFile = file; + if (s == null) { + this.truststoreFile = null; + } else { + String file = adjustRelativePath(s, + System.getProperty(Constants.CATALINA_BASE_PROP)); + this.truststoreFile = file; + } } private String truststorePass = @@ -710,6 +714,12 @@ public abstract class AbstractEndpoint { this.truststoreAlgorithm = truststoreAlgorithm; } + private String trustManagerClassName = null; + public String getTrustManagerClassName() {return trustManagerClassName;} + public void setTrustManagerClassName(String trustManagerClassName) { + this.trustManagerClassName = trustManagerClassName; + } + private String crlFile = null; public String getCrlFile() {return crlFile;} public void setCrlFile(String crlFile) { Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Sun Mar 6 09:33:26 2011 @@ -569,12 +569,12 @@ public class JSSESocketFactory implement TrustManager[] tms = null; KeyStore trustStore = getTrustStore(keystoreType, keystoreProvider); - if (trustStore != null) { + if (trustStore != null || endpoint.getTrustManagerClassName() != null) { if (crlf == null) { TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); tmf.init(trustStore); - tms = tmf.getTrustManagers(); + tms = getTrustManagers(tmf); } else { TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); @@ -583,13 +583,42 @@ public class JSSESocketFactory implement ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params); tmf.init(mfp); - tms = tmf.getTrustManagers(); + tms = getTrustManagers(tmf); } } return tms; } - + + /** + * Gets the TrustManagers either from Connector's + * <code>trustManagerClassName</code> 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 <code>PKIX</code> is supported. Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties Sun Mar 6 09:33:26 2011 @@ -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 Modified: tomcat/trunk/test/org/apache/tomcat/util/net/TestCustomSsl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/net/TestCustomSsl.java?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/net/TestCustomSsl.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/net/TestCustomSsl.java Sun Mar 6 09:33:26 2011 @@ -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 Tomca 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 Tomca assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 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()); + } + } } Modified: tomcat/trunk/test/org/apache/tomcat/util/net/TesterSupport.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/net/TesterSupport.java?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/net/TesterSupport.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/net/TesterSupport.java Sun Mar 6 09:33:26 2011 @@ -24,6 +24,7 @@ import java.security.KeyManagementExcept 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 + } + } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Sun Mar 6 09:33:26 2011 @@ -51,6 +51,14 @@ </fix> </changelog> </subsection> + <subsection name="Coyote"> + <changelog> + <add> + <bug>48208</bug>: Allow the configuration of a custom trust manager for + use in CLIENT-CERT authentication. (markt) + </add> + </changelog> + </subsection> <subsection name="Jasper"> <changelog> <fix> Modified: tomcat/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1078436&r1=1078435&r2=1078436&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/http.xml (original) +++ tomcat/trunk/webapps/docs/config/http.xml Sun Mar 6 09:33:26 2011 @@ -967,6 +967,14 @@ the default is "<code>TLS</code>".</p> </attribute> + <attribute name="trustManagerClassName" required="false"> + <p>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 <code>javax.net.ssl.X509TrustManager</code>. If this + attribute is set, the trust store attributes may be ignored. + </p> + </attribute> + <attribute name="trustMaxCertLength" required="false"> <p>The maximum number of intermediate certificates that will be allowed when validating client certificates. If not specified, the default value --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org