Read out incoming certificate in Tomcat
Asked Answered
P

2

14

i use a tomcat http connector with client-authentification. If a client start a new connection to my server and sends his certificate, can i get the certificate and read the common name from the incoming certificate out in my java code. If yes, how?

thanks adi

Pipage answered 14/8, 2012 at 2:32 Comment(1)
coderanch.com/t/438788/Security/Read-client-certificate-Servlet Look towards the end of the post. Good luck!Cilium
T
24

You can get the client certificate chain by getting the javax.servlet.request.X509Certificate attribute on your HttpServletRequest. This is an array of X509Certificates where the first one (position 0) is the actual client certificate (the rest of the chain may be present if intermediate CA certificates are required).

X509Certificate certs[] = 
    (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");
// ... Test if non-null, non-empty.

X509Certificate clientCert = certs[0];

// Get the Subject DN's X500Principal
X500Principal subjectDN = clientCert.getSubjectX500Principal();

You can then get the various RDNs (relative distinguished name) in this principal (e.g. CN) as described in this answer:

import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

String dn = subjectDN.getName();
LdapName ldapDN = new LdapName(dn);
for(Rdn rdn: ldapDN.getRdns()) {
    System.out.println(rdn.getType() + " -> " + rdn.getValue());
}

(You could also use BouncyCastle's X509Name to get each RDN.)

In an X.509 certificate, the Subject DN is an ordered sequence of RDNs, each of which is a set of AVAs (Attribute Value Assertions), for example CN=... or O=.... In principle, there can be multiple AVAs per RDN, which would cause problems here, but this is very rare. You can almost assume that there is only one AVA per RDN. (Perhaps this answer might be of interest.)

Tessitura answered 14/8, 2012 at 11:37 Comment(5)
thanks, everything worked very well by first try :-) for everybody that uses axis2 and doesn't know how to get on the HttpServletRequest: MessageContext context = MessageContext.getCurrentMessageContext(); HttpServletRequest requestProperty = (HttpServletRequest) context.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);Pipage
I am getting null for req.getAttribute("javax.servlet.request.X509Certificate"). is it required to send request from same matching domain? I tried from both local (using localhost) machine and on development server too.Analects
@Analects That probably means either (a) that your server isn't configured to request/require a client certificate or (b) the certification authorities list it sends when requesting a client cert doesn't match any of the client certificates you have on your machine. It's not really about "domain" matching but about CA matching.Tessitura
is it require mandatory to import client certificate into server keystore to extract/read some information from client certificate? I manually exported certificate from browser and then tried to read info from that and got succeed but without exporting and using req.attribute method getting null on server.Analects
@Analects It's the CA certificate that was used to issue the client certificate that you need to have in the server truststore (not keystore).Tessitura
T
1

Credit to mazaneicha:

        String cipherSuite = (String) req.getAttribute("javax.servlet.request.cipher_suite");

        if (cipherSuite != null) {
            X509Certificate certChain[] = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
            if (certChain != null) {
                for (int i = 0; i < certChaNin.length; i++) {
                    System.out.println ("Client Certificate [" + i + "] = "
                            + certChain[i].toString());
                }
            }
        }
Tubate answered 14/8, 2012 at 6:53 Comment(1)
You don't need to get and test the cipher suite first.Tessitura

© 2022 - 2024 — McMap. All rights reserved.