Как извлечь CN из сертификата X509 в Java? - PullRequest
78 голосов
/ 26 мая 2010

Я использую SslServerSocket и клиентские сертификаты и хочу извлечь CN из SubjectDN клиента из X509Certificate.

В данный момент я звоню cert.getSubjectX500Principal().getName(), но это, конечно, дает мне полное отформатированное DN клиента. Почему-то меня просто интересует часть CN=theclient DN. Есть ли способ извлечь эту часть DN, не разбирая саму строку?

Ответы [ 17 ]

1 голос
/ 10 ноября 2014

Действительно, благодаря gtrak оказывается, что для получения сертификата клиента и извлечения CN, это, скорее всего, работает.

    X509Certificate[] certs = (X509Certificate[]) httpServletRequest
        .getAttribute("javax.servlet.request.X509Certificate");
    X509Certificate cert = certs[0];
    X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(cert.getEncoded());
    X500Name x500Name = x509CertificateHolder.getSubject();
    RDN[] rdns = x500Name.getRDNs(BCStyle.CN);
    RDN rdn = rdns[0];
    String name = IETFUtils.valueToString(rdn.getFirst().getValue());
    return name;
1 голос
/ 28 мая 2015

Может использовать cryptacular, который представляет собой криптографическую библиотеку Java, построенную поверх bouncycastle, для легкого использования.

RDNSequence dn = new NameReader(cert).readSubject();
return dn.getValue(StandardAttributeType.CommonName);
0 голосов
/ 09 ноября 2017

до н.э. сделало извлечение намного проще:

X500Principal principal = x509Certificate.getSubjectX500Principal();
X500Name x500name = new X500Name(principal.getName());
String cn = x500name.getCommonName();
0 голосов
/ 23 декабря 2016

X500Name является внутренней реализацией JDK, однако вы можете использовать отражение.

public String getCN(String formatedDN) throws Exception{
    Class<?> x500NameClzz = Class.forName("sun.security.x509.X500Name");
    Constructor<?> constructor = x500NameClzz.getConstructor(String.class);
    Object x500NameInst = constructor.newInstance(formatedDN);
    Method method = x500NameClzz.getMethod("getCommonName", null);
    return (String)method.invoke(x500NameInst, null);
}
0 голосов
/ 24 июля 2014

Выражения регулярных выражений, довольно дорогие в использовании. Для такой простой задачи это, вероятно, будет чрезмерным убийством. Вместо этого вы можете использовать простое разбиение строки:

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 "";
}
0 голосов
/ 11 июня 2019

Для многозначных атрибутов - с использованием LDAP API ...

        X509Certificate testCertificate = ....

        X500Principal principal = testCertificate.getSubjectX500Principal(); // return subject DN
        String dn = null;
        if (principal != null)
        {
            String value = principal.getName(); // return String representation of DN in RFC 2253
            if (value != null && value.length() > 0)
            {
                dn = value;
            }
        }

        if (dn != null)
        {
            LdapName ldapDN = new LdapName(dn);
            for (Rdn rdn : ldapDN.getRdns())
            {
                Attributes attributes = rdn != null
                    ? rdn.toAttributes()
                    : null;

                Attribute attribute = attributes != null
                    ? attributes.get("CN")
                    : null;
                if (attribute != null)
                {
                    NamingEnumeration<?> values = attribute.getAll();
                    while (values != null && values.hasMoreElements())
                    {
                        Object o = values.next();
                        if (o != null && o instanceof String)
                        {
                            String cnValue = (String) o;
                        }
                    }
                }
            }
        }
0 голосов
/ 26 мая 2010

Вы можете попробовать использовать getName (X500Principal.RFC2253, oidMap) или getName(X500Principal.CANONICAL, oidMap), чтобы увидеть, какой формат лучше всего подходит для строки DN. Возможно, одним из значений карты oidMap будет нужная вам строка.

...