I configured tomcat to use SSL client-certificate authentication and i need to access the client certificate contained in the request. To do this, i use: Object cert = request.getAttribute("javax.servlet.request.X509Certificate"); If i do not use the APR components, this works correctly. If i use the APR components, instead, the object returned by the previous statement is always null. The authentication itself works correctly (for instance if CA not valid, certificate expired, etc..) in both cases. For use the APR components, i just put the binary files downloaded at: http://tomcat.heanet.ie/native/1.1.1/binaries/win32/ in the bin directory of my tomcat installation, according the guide found on tomcat site: http://tomcat.apache.org/tomcat-5.5-doc/apr.html This is the SSL HTTP connector extract from my server.xml (non APR version): <Connector port="443" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="want" sslProtocol="TLS" truststoreFile="./tomcat5keystore.jks" truststorePass="xxx" keystoreFile="./tomcat5keystore.jks" keystorePass="xxx" /> This is the SSL HTTP connector extract from my server.xml (non APR version): <Connector port="443" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="want" SSLEngine="on" SSLVerifyClient="optional" SSLCertificateFile="${catalina.base}/cert.crt" SSLCertificateKeyFile="${catalina.base}/key.pem" SSLCACertificateFile="${catalina.base}/ca_postecom.crt" SSLPassword="xxx" />
Is it working with SSLVerifyClient="require"
(In reply to comment #1) > Is it working with > SSLVerifyClient="require" No, same behaviour described before. Non-APR: client-certificate authentication works, certificate obtained in request. APR: client-certificate authentication works, but no certificate in request.
I have the same problem on Apache 2.054, Fedora 4, Tomcat 5.0.30-5jpp_6fc and mod_jk.i386 1.2.6-3jpp_4fc All these packages are installed via yum When I try to get the client cert from the request (javax.servlet.request.X509Certificate) it fails and I get this message in catalina.out : org.apache.jk.server.JkCoyoteHandler action(org.apache.coyote.ActionCode, java.lang.Object) SEVERE: Certificate convertion failed I have found no work arround
yes, i got this behaviour too. i tryed with all SSLVerifyClient options and SSLVerifyDepth but still certifcate dont get forwared to request. i guess problem is in: org.apache.coyote.http11.Http11AprProcessor else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE) else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE)
I have the same problem (Tomcat 6.0.2, Tomcat-Native 1.1.7-win32, Windows XPSP2, OpenSSL 0.9.8d, APR from Apache-2.2.3). 1) when I HTTP-GET some sample servlet from browser (IE, FireFox), Http11APRProcessor doesn't insert user certificate into request object 2) when I use "openssl s_client", everything's fine Simple debug reveals one problem - in request from browser, there is no data in: int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN) and so there is no cert chain in: byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); but there IS client's certificate in (my added sample line): SSLSocket.getInfoB(socket, org.apache.tomcat.jni.SSL.SSL_INFO_CLIENT_CERT) and it is the client's certificate. I think the problem is with not looking for data under key "org.apache.tomcat.jni.SSL.SSL_INFO_CLIENT_CERT" but only under "org.apache.tomcat.jni.SSL.SSL_INFO_CLIENT_CERT_CHAIN"... with regards Grzegorz Grzybek
If you have tested a patch to also consider SSL_INFO_CLIENT_CERT if the chain is empty, you can submit it.
Created attachment 19196 [details] Patch to look for client's certificate in Http11AprProcessor This patch searches for client's certificate when there is no client's certificate chain under SSL.SSL_INFO_CLIENT_CERT_CHAIN key. When SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN) returns 0 (not -1), client's cert is retrieved using SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT).
I forgot - this patch is for tomcat 6.0.2, it could also be applied to e.g. 5.5.20 (with changed line numbers). Grzegorz Grzybek
Re-opening since the patch has yet to be applied.
Seems like this one http://issues.apache.org/bugzilla/show_bug.cgi?id=41382 is the same issue. The patch given with #41382 was designed for 5.5.20 and fixes also the bug-replication (bug copy/paste?) found a few lines down in the code. It has been tested at Sparus Software with various scenarios (e.g.: SSL client does not give a cert chain, gives a cert chain, etc) If I am not mistaken, the patch given with #37869 seems incorrect as it replaces an incorrect behaviour (only giving certification chain excluding client certificate) with another incorrect behaviour (only giving client cert but not the certificate chain, see servlet spec for details of what the correct behavior is)
*** Bug 41382 has been marked as a duplicate of this bug. ***
Created attachment 19425 [details] A patch making the behavior consistent with Servlet spec 2.3 (for v5.5.20) Same as patch in #41382 Fixes issues in patch "19196: Patch to look for client's certificate in Http11AprProcessor"
Comment on attachment 19196 [details] Patch to look for client's certificate in Http11AprProcessor Nigdy nie myślę o przyszłości. Nadchodzi ona wystarczająco szybko.
Comment on attachment 19425 [details] A patch making the behavior consistent with Servlet spec 2.3 (for v5.5.20) >Index: connectors/http11/src/java/org/apache/coyote/http11/Http11AprProcessor.java >=================================================================== >--- Http11AprProcessor.java (revision 496746) >+++ Http11AprProcessor.java (working copy) >@@ -1095,16 +1095,29 @@ > (AprEndpoint.CIPHER_SUITE_KEY, sslO); > } > // Client certificate chain if present >+ ////////////////////////////////////////////////// >+ // CP: does not include client certificate, only CA certificates >+ // see documentation of SSL_get_peer_cert_chain() in openssl and sslinfo.c in native APR code >+ // SSL_get_peer_cert_chain() returns a pointer to STACKOF(X509) certificates forming the certificate chain of the peer. >+ // If called on the client side, the stack also contains the peer's certificate; >+ // if called on the server side, the peer's certificate must be obtained separately using SSL_get_peer_certificate(3). >+ // If the peer did not present a certificate, NULL is returned. >+ // > int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); >+ // retrieve client certificate >+ byte[] clientCert = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT); > X509Certificate[] certs = null; >- if (certLength > 0) { >- certs = new X509Certificate[certLength]; >+ if (clientCert != null) { >+ certs = new X509Certificate[certLength+1]; // add one for the client certificate >+ >+ CertificateFactory cf = >+ CertificateFactory.getInstance("X.509"); >+ >+ certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert)); >+ > for (int i = 0; i < certLength; i++) { > byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); >- CertificateFactory cf = >- CertificateFactory.getInstance("X.509"); >- ByteArrayInputStream stream = new ByteArrayInputStream(data); >- certs[i] = (X509Certificate) cf.generateCertificate(stream); >+ certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data)); > } > } > if (certs != null) { >@@ -1142,16 +1155,29 @@ > // Renegociate certificates > SSLSocket.renegotiate(socket); > // Client certificate chain if present >+ ////////////////////////////////////////////////// >+ // CP: does not include client certificate, only CA certificates >+ // see documentation of SSL_get_peer_cert_chain() in openssl and sslinfo.c in native APR code >+ // SSL_get_peer_cert_chain() returns a pointer to STACKOF(X509) certificates forming the certificate chain of the peer. >+ // If called on the client side, the stack also contains the peer's certificate; >+ // if called on the server side, the peer's certificate must be obtained separately using SSL_get_peer_certificate(3). >+ // If the peer did not present a certificate, NULL is returned. >+ // > int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); >+ // retrieve client certificate >+ byte[] clientCert = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT); > X509Certificate[] certs = null; >- if (certLength > 0) { >- certs = new X509Certificate[certLength]; >+ if (clientCert != null) { >+ certs = new X509Certificate[certLength+1]; // add one for the client certificate >+ >+ CertificateFactory cf = >+ CertificateFactory.getInstance("X.509"); >+ >+ certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert)); >+ > for (int i = 0; i < certLength; i++) { > byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); >- CertificateFactory cf = >- CertificateFactory.getInstance("X.509"); >- ByteArrayInputStream stream = new ByteArrayInputStream(data); >- certs[i] = (X509Certificate) cf.generateCertificate(stream); >+ certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data)); > } > } > if (certs != null) {
I see that 6.0 was patched. Will this be applied to 5.5 as well?
*** Bug 39637 has been marked as a duplicate of this bug. ***
This has been fixed in 5.5.x and will be included in 5.5.28 onwards