I found that when accessing a web application that uses client certificate authentication run on Tomcat/APR (on Windows) with Firefox or Chrome, the client cert is "lost" after a short while. To the app it appears the client certificate was not sent.
Example code (JSP fragment):
User client cert data:
<%= ((java.security.cert.X509Certificate[])
request.getAttribute("javax.servlet.request.X509Certificate"))[0].
getSubjectX500Principal().toString()%>
After a few refreshes of the page (where it will show the client certificate DN) the page will fail with a NullPointerException as request.getAttribute will return null. It usually happens in less than a minute. To be more precise: when reloading about once per second, the problem occurs almost every time after 30 seconds. After that each request will fail the same way, until I restart tomcat (or restart Firefox, or just clear "Active Logins" in Firefox and re-select the certificate on a new connection). After the restart the problem always returns (and goes away for 30 seconds if I restart again).
This happens with Firefox (v39 and v40) and Chrome (v44), but not with IE v11.
It also occurs with different versions of tomcat and Java (and OS bitness).
A test case using latest versions is:
- download and extract apache-tomcat-8.0.24-windows-x64.zip
- in the webapps folder create a folder named cert, there create a file named ccertA.jsp that contains the above code snippet
in server.xml add a line:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" secure="true" scheme="https" maxThreads="150" URIEncoding="UTF-8" SSLVerifyClient="optional" SSLProtocol="TLSv1+TLSv1.1+TLSv1.2" SSLPassword="testing" SSLEnabled="true" SSLCertificateKeyFile="C:/your_server_key_private.pem" SSLCertificateFile="C:/ your_server_key _public.pem" SSLCACertificateFile="C:/supported_client_CAs.pem" />
start tomcat by executing startup.bat
- open the page https://localhost:8443/cert/ccertA.jsp and keep refreshing it every few seconds
(see the bug linked below for a complete testcase with all the needed files, including certificate files)
If I don't use APR (by deleting the tcnative-1.dll file and adapting the connector syntax for JSSE) the problem does not happen.
Tried versions, all having the issue:
- apache-tomcat-8.0.24-windows-x64 (also 32 bit version)
- apache-tomcat-6.0.44-windows-x64
- Java 1.6.0 Updates 12 and 45
- Java 1.8 Update 51
- Windows 7 Pro SP1 64 bit
- Windows 7 Pro SP1 32 bit
- Windows 8.1 Pro 64 bit
- Windows 10 Home 64 bit
- Firefox versions 39.0 39.0.3 and 44
- Chrome v44
- Ubuntu 14.04 LTS 64 bit / tomcat 7.0.52-1ubuntu0.3 / libapr1:amd64 1.5.0-1 / libtcnative-1:amd64 1.1.29-1
A similar issue was discussed on the tomcat-users mailing list in 2010: Client certificate gone after 1 minute timeout (SSL, APR) but with no solution. I posted there myself recently ( Firefox SSL with APR - losing client certificate has a bit more details), but it is basically just my monologue.
Edit: Certificate info
Originally I tested with a server certificate issued by my private testing CA. Now I also tried with a "real" certificate issued by trusted CA. (I used my personal certificate. The browser complained about the hostname mitmatch which I clicked away).
Edit: bug report
Reported as Bug 58244 - two way SSL loses client certificate after a few requests
Suggestions on how to debug the issue are welcome.
I had too many issues with using client certificates with java apps (on client side as well as on a server). APR helps but it has issues of its own. Eventually, I decided to stop trying and now I offload SSL processing to a proxy in front of the app. Both Apache and Nginx work well in this role.