How to extract CN from X509Certificate in Java?

2020-01-24 02:44发布

I am using a SslServerSocket and client certificates and want to extract the CN from the SubjectDN from the client's X509Certificate.

At the moment I call cert.getSubjectX500Principal().getName() but this of course gives me the total formatted DN of the client. For some reason I am just interested in the CN=theclient part of the DN. Is there a way to extract this part of the DN without parsing the String myself?

17条回答
Melony?
2楼-- · 2020-01-24 02:49

Could use cryptacular which is a Java cryptographic library build on top of bouncycastle for easy use.

RDNSequence dn = new NameReader(cert).readSubject();
return dn.getValue(StandardAttributeType.CommonName);
查看更多
霸刀☆藐视天下
3楼-- · 2020-01-24 02:48

Regex expressions, are rather expensive to use. For such a simple task it will probably be an over kill. Instead you could use a simple String split:

String dn = ((X509Certificate) certificate).getIssuerDN().getName();
String CN = getValByAttributeTypeFromIssuerDN(dn,"CN=");

private String getValByAttributeTypeFromIssuerDN(String dn, String attributeType)
{
    String[] dnSplits = dn.split(","); 
    for (String dnSplit : dnSplits) 
    {
        if (dnSplit.contains(attributeType)) 
        {
            String[] cnSplits = dnSplit.trim().split("=");
            if(cnSplits[1]!= null)
            {
                return cnSplits[1].trim();
            }
        }
    }
    return "";
}
查看更多
戒情不戒烟
4楼-- · 2020-01-24 02:49

BC made the extraction much easier:

X500Principal principal = x509Certificate.getSubjectX500Principal();
X500Name x500name = new X500Name(principal.getName());
String cn = x500name.getCommonName();
查看更多
等我变得足够好
5楼-- · 2020-01-24 02:51

As an alternative to gtrak's code that does not need ''bcmail'':

    X509Certificate cert = ...;
    X500Principal principal = cert.getSubjectX500Principal();

    X500Name x500name = new X500Name( principal.getName() );
    RDN cn = x500name.getRDNs(BCStyle.CN)[0]);

    return IETFUtils.valueToString(cn.getFirst().getValue());

@Jakub: I have used your solution until my SW had to be run on Android. And Android does not implement javax.naming.ldap :-(

查看更多
神经病院院长
6楼-- · 2020-01-24 02:51

You could try using getName(X500Principal.RFC2253, oidMap) or getName(X500Principal.CANONICAL, oidMap) to see which one formats the DN string best. Maybe one of the oidMap map values will be the string you want.

查看更多
萌系小妹纸
7楼-- · 2020-01-24 02:52

here is another way. the idea is that the DN you obtain is in rfc2253 format, which is the same as used for LDAP DN. So why not reuse the LDAP API?

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

String dn = x509cert.getSubjectX500Principal().getName();
LdapName ldapDN = new LdapName(dn);
for(Rdn rdn: ldapDN.getRdns()) {
    System.out.println(rdn.getType() + " -> " + rdn.getValue());
}
查看更多
登录 后发表回答