From 4a8a0657929658916db8bd2586cbfb1a85532431 Mon Sep 17 00:00:00 2001 From: markt Date: Sun, 13 Mar 2011 14:01:34 +0000 Subject: [PATCH] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50887 Add support for configuring the JSSE provider used to convert client certificates. Based on a patch by pknopp. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1081117 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/catalina/valves/LocalStrings.properties | 2 ++ java/org/apache/catalina/valves/SSLValve.java | 17 +++++++++++++- .../org/apache/coyote/AbstractProtocolHandler.java | 14 ++++++++++++ .../apache/coyote/ajp/AbstractAjpProcessor.java | 26 ++++++++++++++++++++-- java/org/apache/coyote/ajp/AjpAprProtocol.java | 1 + java/org/apache/coyote/ajp/AjpProtocol.java | 1 + .../apache/coyote/http11/Http11AprProcessor.java | 23 ++++++++++++++++++- .../apache/coyote/http11/Http11AprProtocol.java | 1 + webapps/docs/changelog.xml | 8 +++++++ webapps/docs/config/ajp.xml | 11 +++++++++ webapps/docs/config/http.xml | 11 +++++++++ 11 files changed, 111 insertions(+), 4 deletions(-) diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties index dbb51865f..7317e632e 100644 --- a/java/org/apache/catalina/valves/LocalStrings.properties +++ b/java/org/apache/catalina/valves/LocalStrings.properties @@ -41,6 +41,8 @@ errorReportValve.rootCauseInLogs=The full stack trace of the root cause is avail # Remote IP valve remoteIpValve.syntax=Invalid regular expressions [{0}] provided. +sslValve.invalidProvider=The SSL provider specified on the connector associated with this request of [{0}] is invalid. The certificate data could not be processed. + # HTTP status reports http.100=The client may continue ({0}). http.101=The server is switching protocols according to the "Upgrade" header ({0}). diff --git a/java/org/apache/catalina/valves/SSLValve.java b/java/org/apache/catalina/valves/SSLValve.java index e8d145345..c02322099 100644 --- a/java/org/apache/catalina/valves/SSLValve.java +++ b/java/org/apache/catalina/valves/SSLValve.java @@ -19,6 +19,7 @@ package org.apache.catalina.valves; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -27,6 +28,8 @@ import javax.servlet.ServletException; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; /** * When using mod_proxy_http, the client SSL information is not included in the @@ -59,6 +62,8 @@ import org.apache.catalina.connector.Response; */ public class SSLValve extends ValveBase { + private static final Log log = LogFactory.getLog(SSLValve.class); + //------------------------------------------------------ Constructor public SSLValve() { @@ -91,14 +96,24 @@ public class SSLValve extends ValveBase { // ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes("UTF-8")); ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes()); X509Certificate jsseCerts[] = null; + String providerName = (String) request.getConnector().getProperty( + "clientCertProvider"); try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertificateFactory cf; + if (providerName == null) { + cf = CertificateFactory.getInstance("X.509"); + } else { + cf = CertificateFactory.getInstance("X.509", providerName); + } X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); jsseCerts = new X509Certificate[1]; jsseCerts[0] = cert; } catch (java.security.cert.CertificateException e) { System.out.println("SSLValve failed " + strcerts); System.out.println("SSLValve failed " + e); + } catch (NoSuchProviderException e) { + log.error(sm.getString( + "sslValve.invalidProvider", providerName), e); } request.setAttribute(Globals.CERTIFICATES_ATTR, jsseCerts); } diff --git a/java/org/apache/coyote/AbstractProtocolHandler.java b/java/org/apache/coyote/AbstractProtocolHandler.java index 5d0fa561b..c5284908e 100644 --- a/java/org/apache/coyote/AbstractProtocolHandler.java +++ b/java/org/apache/coyote/AbstractProtocolHandler.java @@ -109,6 +109,20 @@ public abstract class AbstractProtocolHandler implements ProtocolHandler, } + /** + * When client certificate information is presented in a form other than + * instances of {@link java.security.cert.X509Certificate} it needs to be + * converted before it can be used and this property controls which JSSE + * provider is used to perform the conversion. For example it is used with + * the AJP connectors, the HTTP APR connector and with the + * {@link org.apache.catalina.valves.SSLValve}. If not specified, the + * default provider will be used. + */ + protected String clientCertProvider = null; + public String getClientCertProvider() { return clientCertProvider; } + public void setClientCertProvider(String s) { this.clientCertProvider = s; } + + // ---------------------- Properties that are passed through to the EndPoint @Override diff --git a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java index 7c3fdc9f7..7e5b86e4d 100644 --- a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java +++ b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java @@ -20,6 +20,7 @@ package org.apache.coyote.ajp; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetAddress; +import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.concurrent.Executor; @@ -205,6 +206,19 @@ public abstract class AbstractAjpProcessor implements ActionHook, Processor { } + /** + * When client certificate information is presented in a form other than + * instances of {@link java.security.cert.X509Certificate} it needs to be + * converted before it can be used and this property controls which JSSE + * provider is used to perform the conversion. For example it is used with + * the AJP connectors, the HTTP APR connector and with the + * {@link org.apache.catalina.valves.SSLValve}. If not specified, the + * default provider will be used. + */ + protected String clientCertProvider = null; + public String getClientCertProvider() { return clientCertProvider; } + public void setClientCertProvider(String s) { this.clientCertProvider = s; } + // --------------------------------------------------------- Public Methods @@ -294,8 +308,13 @@ public abstract class AbstractAjpProcessor implements ActionHook, Processor { certData.getLength()); // Fill the elements. try { - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); + CertificateFactory cf; + if (clientCertProvider == null) { + cf = CertificateFactory.getInstance("X.509"); + } else { + cf = CertificateFactory.getInstance("X.509", + clientCertProvider); + } while(bais.available() > 0) { X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); @@ -312,6 +331,9 @@ public abstract class AbstractAjpProcessor implements ActionHook, Processor { } catch (java.security.cert.CertificateException e) { getLog().error(sm.getString("ajpprocessor.certs.fail"), e); return; + } catch (NoSuchProviderException e) { + getLog().error(sm.getString("ajpprocessor.certs.fail"), e); + return; } request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts); } diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java index 30a526994..2d862d9a4 100644 --- a/java/org/apache/coyote/ajp/AjpAprProtocol.java +++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java @@ -266,6 +266,7 @@ public class AjpAprProtocol extends AbstractAjpProtocol { processor.setAdapter(proto.adapter); processor.setTomcatAuthentication(proto.tomcatAuthentication); processor.setRequiredSecret(proto.requiredSecret); + processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } diff --git a/java/org/apache/coyote/ajp/AjpProtocol.java b/java/org/apache/coyote/ajp/AjpProtocol.java index d5fd00efb..95dcafd03 100644 --- a/java/org/apache/coyote/ajp/AjpProtocol.java +++ b/java/org/apache/coyote/ajp/AjpProtocol.java @@ -221,6 +221,7 @@ public class AjpProtocol extends AbstractAjpProtocol { processor.setTomcatAuthentication(proto.tomcatAuthentication); processor.setRequiredSecret(proto.requiredSecret); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); + processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } diff --git a/java/org/apache/coyote/http11/Http11AprProcessor.java b/java/org/apache/coyote/http11/Http11AprProcessor.java index 3eca711bd..0471e97aa 100644 --- a/java/org/apache/coyote/http11/Http11AprProcessor.java +++ b/java/org/apache/coyote/http11/Http11AprProcessor.java @@ -139,6 +139,21 @@ public class Http11AprProcessor extends AbstractHttp11Processor { return endpoint; } + + /** + * When client certificate information is presented in a form other than + * instances of {@link java.security.cert.X509Certificate} it needs to be + * converted before it can be used and this property controls which JSSE + * provider is used to perform the conversion. For example it is used with + * the AJP connectors, the HTTP APR connector and with the + * {@link org.apache.catalina.valves.SSLValve}. If not specified, the + * default provider will be used. + */ + protected String clientCertProvider = null; + public String getClientCertProvider() { return clientCertProvider; } + public void setClientCertProvider(String s) { this.clientCertProvider = s; } + + // --------------------------------------------------------- Public Methods @@ -531,7 +546,13 @@ public class Http11AprProcessor extends AbstractHttp11Processor { X509Certificate[] certs = null; if (clientCert != null && certLength > -1) { certs = new X509Certificate[certLength + 1]; - CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertificateFactory cf; + if (clientCertProvider == null) { + cf = CertificateFactory.getInstance("X.509"); + } else { + cf = CertificateFactory.getInstance("X.509", + clientCertProvider); + } certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert)); for (int i = 0; i < certLength; i++) { byte[] data = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java index 83591917f..1581fd18e 100644 --- a/java/org/apache/coyote/http11/Http11AprProtocol.java +++ b/java/org/apache/coyote/http11/Http11AprProtocol.java @@ -418,6 +418,7 @@ public class Http11AprProtocol extends AbstractHttp11Protocol { processor.setSocketBuffer(proto.getSocketBuffer()); processor.setMaxSavePostSize(proto.getMaxSavePostSize()); processor.setServer(proto.getServer()); + processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 211c49b9d..48a5b1d56 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -56,6 +56,14 @@ + + + + 50887: Add support for configuring the JSSE provider used to + convert client certificates. Based on a patch by pknopp. (markt) + + + diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml index c5cb35bbd..4a11231a6 100644 --- a/webapps/docs/config/ajp.xml +++ b/webapps/docs/config/ajp.xml @@ -268,6 +268,17 @@ interface.

+ +

When client certificate information is presented in a form other than + instances of java.security.cert.X509Certificate it needs to + be converted before it can be used and this property controls which JSSE + provider is used to perform the conversion. For example it is used with + the AJP connectors, the HTTP APR connector and + with the + org.apache.catalina.valves.SSLValve.If not specified, the default + provider will be used.

+
+

The number of milliseconds during which the sockets used by this Connector will linger when they are closed. diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml index 9902b177a..534ed4ce0 100644 --- a/webapps/docs/config/http.xml +++ b/webapps/docs/config/http.xml @@ -893,6 +893,17 @@ constraint that uses CLIENT-CERT authentication.

+ +

When client certificate information is presented in a form other than + instances of java.security.cert.X509Certificate it needs to + be converted before it can be used and this property controls which JSSE + provider is used to perform the conversion. For example it is used with + the AJP connectors, the HTTP APR connector and + with the + org.apache.catalina.valves.SSLValve. If not specified, the default + provider will be used.

+
+

The certificate revocation list to be used to verify client certificates. If not defined, client certificates will not be checked -- 2.11.0