titledborder - uso de border en java




¿Cómo extraer CN de X509Certificate en Java? (11)

A continuación, le mostramos cómo hacerlo usando una expresión regular sobre cert.getSubjectX500Principal().getName() , en caso de que no quiera tomar una dependencia en BouncyCastle.

Esta expresión regular analizará un nombre completo, dando name y val a los grupos de captura para cada coincidencia.

Cuando las cadenas de DN contienen comas, están destinadas a ser citadas: esta expresión regular maneja correctamente las cadenas entrecomilladas y sin comillas, y también maneja las comillas escapadas en las cadenas entrecomilladas:

(?:^|,\s?)(?:(?<name>[AZ]+)=(?<val>"(?:[^"]|"")+"|[^,]+))+

Aquí está muy bien formateado:

(?:^|,\s?)
(?:
    (?<name>[A-Z]+)=
    (?<val>"(?:[^"]|"")+"|[^,]+)
)+

Aquí hay un enlace para que pueda verlo en acción: https://regex101.com/r/zfZX3f/2

Si desea que una expresión regular obtenga solo el CN, entonces esta versión adaptada lo hará:

(?:^|,\s?)(?:CN=(?<val>"(?:[^"]|"")+"|[^,]+))

Estoy utilizando un SslServerSocket y certificados de cliente y quiero extraer el CN ​​del SubjectDN del X509Certificate del cliente.

En este momento llamo a cert.getSubjectX500Principal().getName() pero esto, por supuesto, me da el DN formateado total del cliente. Por alguna razón, solo estoy interesado en la parte CN=theclient del DN. ¿Hay alguna forma de extraer esta parte del DN sin analizar el String por mí mismo?



BC hizo la extracción mucho más fácil:

X500Principal principal = x509Certificate.getSubjectX500Principal();
X500Name x500name = new X500Name(principal.getName());
String cn = x500name.getCommonName();

Como alternativa al código de gtrak que no necesita '' 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: He utilizado su solución hasta que mi SW tuvo que ejecutarse en Android. Y Android no implementa javax.naming.ldap :-(


Expresiones Regex, son bastante caros de usar. Para una tarea tan simple, probablemente sea una muerte excesiva. En cambio, podrías usar una simple secuencia de cadenas:

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 "";
}

La obtención de CN del certificado no es tan simple. El siguiente código definitivamente te ayudará.

String certificateURL = "C://XYZ.cer";      //just pass location

CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate testCertificate = (X509Certificate)cf.generateCertificate(new FileInputStream(certificateURL));
String certificateName = X500Name.asX500Name((new X509CertImpl(testCertificate.getEncoded()).getSubjectX500Principal())).getCommonName();

Podría usar cryptacular, que es una biblioteca criptográfica de Java construida sobre bouncycastle para facilitar su uso.

RDNSequence dn = new NameReader(cert).readSubject();
return dn.getValue(StandardAttributeType.CommonName);

Si agregar dependencias no es un problema, puede hacerlo con la API de Bouncy Castle para trabajar con certificados X.509:

import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.PrincipalUtil;
import org.bouncycastle.jce.X509Principal;

...

final X509Principal principal = PrincipalUtil.getSubjectX509Principal(cert);
final Vector<?> values = principal.getValues(X509Name.CN);
final String cn = (String) values.get(0);

Actualizar

En el momento de esta publicación, esta era la manera de hacer esto. Sin embargo, como gtrak menciona en los comentarios, este enfoque ahora está en desuso. Vea el código actualizado de gtrak que usa la nueva API de Bouncy Castle.


Todas las respuestas publicadas hasta ahora tienen algún problema: la mayoría usa el nombre de X500Name interno o la dependencia de Bounty Castle externa. A continuación, se basa en la respuesta de @Jakub y utiliza solo la API pública de JDK, pero también extrae el CN ​​según lo solicitado por el OP. También usa Java 8, que a mediados de 2017, realmente deberías.

Stream.of(certificate)
    .map(cert -> cert.getSubjectX500Principal().getName())
    .flatMap(name -> {
        try {
            return new LdapName(name).getRdns().stream()
                    .filter(rdn -> rdn.getType().equalsIgnoreCase("cn"))
                    .map(rdn -> rdn.getValue().toString());
        } catch (InvalidNameException e) {
            log.warn("Failed to get certificate CN.", e);
            return Stream.empty();
        }
    })
    .collect(joining(", "))


aquí hay otra manera. la idea es que el DN que obtenga esté en formato rfc2253, que es el mismo que el utilizado para LDAP DN. Entonces, ¿por qué no reutilizar la API de LDAP?

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());
}






x509