Google
 
Web unafbapune.blogspot.com

Friday, April 11, 2008

 

Tomcat 5.5 SSL Programming Puzzle

Assuming SSL client side authentication is enabled in Tomcat 5.5, how can a webapp go about retrieving the underlying client's X509 certificate of the SSL socket ?

Browsing through the Tomcat source code, such information can be found in the SSL session, which unfortunately seems totally unreachable from the servlet layer.

Well, thanks to reflection, below is one such solution. Do you know of a better one ?

    /** 
* Returns the requester's X509 SSL certificate(s) of the given request;
* or null if no such certificate can be determined.
*/
static X509Certificate[] getPeerCertificates(HttpServletRequest req) {
// rip open the tomcat specific request object to retrieve the peer SSL cert(s)
try
{ // Dig out the org.apache.catalina.connector.Request object
Field f = req.getClass().getDeclaredField("request");
f.setAccessible(true);
Object catalinaConnectorRequest = f.get(req);

// Dig out the org.apache.coyote.Request object
// by invoking org.apache.catalina.connector.Request.getCoyoteRequest()
Method getCoyoteRequestMethod = catalinaConnectorRequest.getClass().getMethod("getCoyoteRequest");
Object coyoteRequest = getCoyoteRequestMethod.invoke(catalinaConnectorRequest);

// Dig out the proper class loader
Class coyoteRequestClass = coyoteRequest.getClass();
ClassLoader classLoader = coyoteRequestClass.getClassLoader();

// Dig out the ActionCode class loaded by the approprate class loader
Class actionCodeClass = classLoader.loadClass("org.apache.coyote.ActionCode");

// Refer to the ActionCode.ACTION_REQ_SSL_CERTIFICATE
Field actionReqSslCertField = actionCodeClass.getDeclaredField("ACTION_REQ_SSL_CERTIFICATE");
Object actionReqSslCert = actionReqSslCertField.get(null);

// Invoke org.apache.coyote.Request.action(ActionCode.ACTION_REQ_SSL_CERTIFICATE, null)
Method actionMethod = coyoteRequestClass.getMethod("action", actionReqSslCert.getClass(), Object.class);
actionMethod.invoke(coyoteRequest, actionReqSslCert, null);

// Dig out the SSLSupport class loaded by the approprate class loader
Class sslSupportClass = classLoader.loadClass("org.apache.tomcat.util.net.SSLSupport");

// Refer to the SSLSupport.CERTIFICATE_KEY
Field sslSupportCertKeyField = sslSupportClass.getDeclaredField("CERTIFICATE_KEY");
Object sslSupportCertKey = sslSupportCertKeyField.get(null);

// Invoke org.apache.coyote.Request.getAttribute(SSLSupport.CERTIFICATE_KEY)
Method getAttributeMethod = coyoteRequest.getClass()
.getMethod("getAttribute", sslSupportCertKey.getClass());
return (X509Certificate[])getAttributeMethod.invoke(coyoteRequest, sslSupportCertKey);
} catch(Throwable t) {
}
return null;
}
It turns out there is a much simpler way to solve this problem. According to the spec (section SRV.4.7), if there is an SSL certificate associated with the request, it must be exposed by the servlet container to the servlet programmer as an array of objects of type java.security.cert.X509Certificate and accessible via a ServletRequest attribute of javax.servlet.request.X509Certificate.

Thanks to Mark Thomas for pointing this out.

Thursday, April 03, 2008

 

On Frugality

Be contra-variant in what you take, but covariant in what you give. In other words, take less and give more.

This page is powered by Blogger. Isn't yours?