Ich verwende ein SslServerSocket
und Client-Zertifikate und möchte den CN aus dem SubjectDN aus dem Client extrahieren X509Certificate
.
Im Moment rufe ich an, cert.getSubjectX500Principal().getName()
aber dies gibt mir natürlich den gesamten formatierten DN des Clients. Aus irgendeinem Grund interessiert mich nur der CN=theclient
Teil des DN. Gibt es eine Möglichkeit, diesen Teil des DN zu extrahieren, ohne den String selbst zu analysieren?
java
ssl
x509certificate
x509
Martin C.
quelle
quelle
Antworten:
Hier ist ein Code für die neue nicht veraltete BouncyCastle-API. Sie benötigen sowohl bcmail- als auch bcprov-Distributionen.
quelle
IETFUtils.valueToString
scheint kein korrektes Ergebnis zu liefern. Ich habe einen CN, der aufgrund der Basis-64-Codierung (zAAECAwQFBgcICQoLDA0ODw==
. B. ) einige Gleichheitszeichen enthält . DievalueToString
Methode fügt dem Ergebnis Schrägstriche hinzu. StattdessentoString
scheint die Verwendung zu funktionieren. Es ist schwierig festzustellen, dass dies tatsächlich eine korrekte Verwendung der API ist.Hier ist ein anderer Weg. Die Idee ist, dass der DN, den Sie erhalten, im Format rfc2253 vorliegt, das dem für LDAP-DN verwendeten entspricht. Warum also nicht die LDAP-API wiederverwenden?
quelle
String commonName = new LdapName(certificate.getSubjectX500Principal().getName()).getRdns().stream() .filter(i -> i.getType().equalsIgnoreCase("CN")).findFirst().get().getValue().toString();
CN
(aka2.5.4.3
)Rdn#getValue()
aString
. Für benutzerdefinierte Typen ist das Ergebnis jedochbyte[]
(möglicherweise basierend auf einer internen codierten Darstellung, beginnend mit#
). Ofc,byte[]
->String
ist möglich, enthält aber zusätzliche (unvorhersehbare) Zeichen. Ich habe dies mit @ laz-Lösungen gelöst, die auf BC basieren, weil es dies korrekt verarbeitet und dekodiertString
.Wenn das Hinzufügen von Abhängigkeiten kein Problem darstellt, können Sie dies mit der API von Bouncy Castle für die Arbeit mit X.509-Zertifikaten tun :
Aktualisieren
Zum Zeitpunkt dieser Veröffentlichung war dies der Weg, dies zu tun. Wie gtrak in den Kommentaren erwähnt, ist dieser Ansatz jetzt veraltet. Siehe den aktualisierten Code von gtrak , der die neue Bouncy Castle-API verwendet.
quelle
Als Alternative zu gtraks Code, der kein "bcmail" benötigt:
@Jakub: Ich habe Ihre Lösung verwendet, bis meine SW auf Android ausgeführt werden musste. Und Android implementiert javax.naming.ldap nicht :-(
quelle
X500Name x500Name = new X500Name(cert.getSubjectX500Principal().getName()); String cn = x500Name.getCommonName();
IETFUtils.valueToString
gibt den Wert in maskierter Form zurück. Ich fand einfach aufrufen.toString()
statt für mich arbeiten.Eine Zeile mit http://www.cryptacular.org
JavaDoc: http://www.cryptacular.org/javadocs/org/cryptacular/util/CertUtil.html#subjectCN(java.security.cert.X509Certificate)
Maven-Abhängigkeit:
quelle
Alle bisher veröffentlichten Antworten haben ein Problem: Die meisten verwenden die interne
X500Name
oder externe Bounty Castle-Abhängigkeit. Das Folgende baut auf der Antwort von @ Jakub auf und verwendet nur die öffentliche JDK-API, extrahiert aber auch den CN, wie vom OP gefordert. Es wird auch Java 8 verwendet, das Mitte 2017 stehen sollte.quelle
Hier erfahren Sie
cert.getSubjectX500Principal().getName()
, wie Sie einen regulären Ausdruck verwenden , falls Sie keine Abhängigkeit von BouncyCastle übernehmen möchten.Diese Regex analysiert für jedes Match einen eindeutigen Namen, eine Angabe
name
undval
eine Erfassungsgruppe.Wenn DN-Zeichenfolgen Kommas enthalten, sollen sie in Anführungszeichen gesetzt werden. Dieser reguläre Ausdruck behandelt sowohl Zeichenfolgen in Anführungszeichen als auch Zeichenfolgen in Anführungszeichen korrekt und behandelt maskierte Anführungszeichen in Zeichenfolgen in Anführungszeichen:
(?:^|,\s?)(?:(?<name>[A-Z]+)=(?<val>"(?:[^"]|"")+"|[^,]+))+
Hier ist schön formatiert:
Hier ist ein Link, damit Sie ihn in Aktion sehen können: https://regex101.com/r/zfZX3f/2
Wenn Sie möchten, dass ein Regex nur den CN erhält , dann wird diese angepasste Version dies tun:
(?:^|,\s?)(?:CN=(?<val>"(?:[^"]|"")+"|[^,]+))
quelle
Ich habe BouncyCastle 1.49 und die Klasse, die es jetzt hat, ist org.bouncycastle.asn1.x509.Certificate. Ich habe mir den Code von
IETFUtils.valueToString()
- es ist etwas Besonderes, mit Backslashes zu entkommen. Für einen Domainnamen würde es nichts Schlechtes tun, aber ich denke, wir können es besser machen. In den Fällen, die ich mir angesehen habe, werdencn.getFirst().getValue()
verschiedene Arten von Zeichenfolgen zurückgegeben, die alle die ASN1String-Schnittstelle implementieren, die eine getString () -Methode bereitstellt. Was für mich zu funktionieren scheint, istquelle
UPDATE: Diese Klasse befindet sich im "sun" -Paket und sollte mit Vorsicht verwendet werden. Danke Emil für den Kommentar :)
Ich wollte nur teilen, um die CN zu bekommen, ich mache:
Zu Emil Lundbergs Kommentar siehe: Warum Entwickler keine Programme schreiben sollten, die "Sun" -Pakete nennen
quelle
X500Name
, eine interne proprietäre API zu sein, die in zukünftigen Versionen möglicherweise entfernt wird.In der Tat
gtrak
funktioniert dies höchstwahrscheinlich, um das Client-Zertifikat zu erhalten und den CN zu extrahieren.quelle
Könnte Cryptacular verwenden, eine kryptografische Java-Bibliothek, die zur einfachen Verwendung auf Bouncycastle aufgebaut ist.
quelle
Das Abrufen von CN aus dem Zertifikat ist nicht so einfach. Der folgende Code wird Ihnen definitiv helfen.
quelle
Eine weitere Möglichkeit, mit einfachem Java umzugehen:
quelle
Regex-Ausdrücke sind ziemlich teuer in der Verwendung. Für solch eine einfache Aufgabe wird es wahrscheinlich ein Over-Kill sein. Stattdessen können Sie einen einfachen String-Split verwenden:
quelle
\,
oder Anführungszeichen.X500Name ist eine interne Implementierung von JDK. Sie können jedoch Reflection verwenden.
quelle
Sie können versuchen, getName (X500Principal.RFC2253, oidMap) zu verwenden oder herauszufinden,
getName(X500Principal.CANONICAL, oidMap)
welches die DN-Zeichenfolge am besten formatiert. Möglicherweise ist einer deroidMap
Kartenwerte die gewünschte Zeichenfolge.quelle
BC machte die Extraktion viel einfacher:
quelle
.getCommonName()
Methode in X500Name finden .sun.security.x509.X500Name
- was, wie andere Antworten einige Jahre zuvor festgestellt haben, nicht dokumentiert ist und auf das man sich nicht verlassen kann?org.bouncycastle.asn1.x500.X500Name
Klasse verlinkt , das diese Methode nicht zeigt ...Für mehrwertige Attribute - mit LDAP-API ...
quelle