13

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

mavis
  • 3,100
  • 3
  • 24
  • 32
adihubba
  • 155
  • 1
  • 1
  • 8
  • http://www.coderanch.com/t/438788/Security/Read-client-certificate-Servlet Look towards the end of the post. Good luck! – mazaneicha Aug 14 '12 at 03:15

2 Answers2

23

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.)

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • 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); – adihubba Aug 15 '12 at 00:32
  • 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. – TechnoCrat Dec 27 '17 at 07:12
  • @TechnoCrat 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. – Bruno Dec 27 '17 at 11:57
  • 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. – TechnoCrat Dec 27 '17 at 12:19
  • @TechnoCrat It's the CA certificate that was used to issue the client certificate that you need to have in the server truststore (not keystore). – Bruno Dec 27 '17 at 15:51
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());
                }
            }
        }