110 votes

Comment extraire la NC d'un certificat X509 en Java ?

J'utilise un SslServerSocket et les certificats du client et veulent extraire le CN du SubjectDN du certificat du client. X509Certificate .

Au moment où j'appelle cert.getSubjectX500Principal().getName() mais cela me donne bien sûr le DN total formaté du client. Pour une raison quelconque, je ne m'intéresse qu'au CN=theclient partie du DN. Existe-t-il un moyen d'extraire cette partie du DN sans analyser la chaîne moi-même ?

0 votes

2 votes

@AhmadAbdelghany Vous vous rendez compte que ma question date d'environ un an et demi plus tôt que celle qui est liée ? Donc, si c'est le cas, l'autre est un doublon de la mienne :-)

0 votes

C'est une bonne chose. Je signalerai l'autre.

105voto

gtrak Points 2345

Voici un peu de code pour la nouvelle API BouncyCastle non dépréciée. Vous aurez besoin des distributions bcmail et bcprov.

X509Certificate cert = ...;

X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
RDN cn = x500name.getRDNs(BCStyle.CN)[0];

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

11 votes

@grak, j'aimerais savoir comment vous avez trouvé cette solution. Il est certain qu'en regardant la documentation de l'API, je n'aurais jamais été capable de trouver cette solution.

8 votes

Oui, je partage ce sentiment... J'ai dû poser la question sur la liste de diffusion.

7 votes

Notez que ce code sur la version actuelle (23 octobre 2012) de BouncyCastle (1.47) nécessite également la distribution bcpkix.

101voto

Jakub Points 726

L'idée est que le DN que vous obtenez est au format rfc2253, qui est le même que celui utilisé pour le DN LDAP. Alors pourquoi ne pas réutiliser l'API 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());
}

1 votes

Un raccourci utile si vous utilisez Spring : LdapUtils.getStringValue(ldapDN, "cn") ;

0 votes

Je vous prie de bien vouloir examiner ma question : stackoverflow.com/questions/40613147/

0 votes

En tout cas, pour le cas sur lequel je travaille, le CN est le suivant à l'intérieur un RDN à attributs multiples. En d'autres termes, la solution proposée n'itère pas sur les attributs du RDN. Elle devrait le faire !

14voto

laz Points 12212

Si l'ajout de dépendances n'est pas un problème, vous pouvez le faire avec Château gonflable API pour travailler avec des certificats 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);

Mise à jour

Au moment de la publication de cet article, c'était la façon de procéder. Cependant, comme le mentionne gtrak dans les commentaires, cette approche est désormais obsolète. Voir l'article de gtrak code mis à jour qui utilise la nouvelle API du château gonflable.

1 votes

Il semble que X509Name soit obsolète dans Bouncycastle 1.46, et qu'ils aient l'intention d'utiliser x500Name. Savez-vous quelque chose à ce sujet ou l'alternative prévue pour faire la même chose ?

0 votes

En regardant la nouvelle API, j'ai du mal à comprendre comment atteindre le même objectif que le code ci-dessus. Peut-être que les archives de la liste de diffusion Bouncycastle pourraient avoir une réponse. Je mettrai à jour cette réponse si j'y parviens.

0 votes

J'ai le même problème. N'hésitez pas à me faire savoir si vous avez trouvé quelque chose. Voici ce que j'ai obtenu : x500name = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(cert)) ; RDN cn = x500name.getRDNs(BCStyle.CN)[0] ;

12voto

Ivin Points 472

Comme alternative au code de gtrak qui n'a pas besoin de ''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 : J'ai utilisé votre solution jusqu'à ce que mon logiciel doive être exécuté sur Android. Et Android n'implémente pas javax.naming.ldap :-(

1 votes

C'est exactement la même raison pour laquelle j'ai trouvé cette solution : le portage sur Android...

10 votes

Je ne sais pas quand cela a changé, mais cela fonctionne maintenant : X500Name x500Name = new X500Name(cert.getSubjectX500Principal().getName()); String cn = x500Name.getCommonName(); (en utilisant java 8)

0 votes

Je vous prie de bien vouloir examiner ma question : stackoverflow.com/questions/40613147/

0voto

Gilbert Le Blanc Points 25590

Vous pouvez essayer d'utiliser getName(X500Principal.RFC2253, oidMap) ou getName(X500Principal.CANONICAL, oidMap) pour voir lequel formate le mieux la chaîne DN. Peut-être que l'un des oidMap Les valeurs de la carte seront les chaînes de caractères que vous souhaitez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X