如何从 Java 中的 X509Certificate 中提取 CN?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2914521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to extract CN from X509Certificate in Java?
提问by Martin C.
I am using a SslServerSocket
and client certificates and want to extract the CN from the SubjectDN from the client's X509Certificate
.
我正在使用SslServerSocket
客户端证书,并希望从客户端的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?
目前我打电话,cert.getSubjectX500Principal().getName()
但这当然给了我客户端的总格式化DN。出于某种原因,我只对CN=theclient
DN 部分感兴趣。有没有办法在不自己解析字符串的情况下提取 DN 的这一部分?
采纳答案by gtrak
Here's some code for the new non-deprecated BouncyCastle API. You'll need both bcmail and bcprov distributions.
这是新的未弃用的 BouncyCastle API 的一些代码。您将需要 bcmail 和 bcprov 发行版。
X509Certificate cert = ...;
X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
RDN cn = x500name.getRDNs(BCStyle.CN)[0];
return IETFUtils.valueToString(cn.getFirst().getValue());
回答by Gilbert Le Blanc
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.
您可以尝试使用getName(X500Principal.RFC2253, oidMap)或getName(X500Principal.CANONICAL, oidMap)
查看哪种格式最适合 DN 字符串。也许oidMap
地图值之一将是您想要的字符串。
回答by laz
If adding dependencies isn't a problem you can do this with Bouncy Castle'sAPI for working with X.509 certificates:
如果添加依赖项不是问题,您可以使用Bouncy Castle 的API 来处理 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);
Update
更新
At the time of this posting, this was the way to do this. As gtrak mentions in the comments however, this approach is now deprecated. See gtrak's updated codethat uses the new Bouncy Castle API.
在发布这篇文章时,这就是这样做的方式。然而,正如 gtrak 在评论中提到的,这种方法现在已被弃用。请参阅 gtrak使用新 Bouncy Castle API的更新代码。
回答by Jakub
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?
这是另一种方式。这个想法是您获得的 DN 采用 rfc2253 格式,这与用于 LDAP DN 的格式相同。那么为什么不重用 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());
}
回答by Ivin
As an alternative to gtrak's code that does not need ''bcmail'':
作为不需要 ''bcmail'' 的 gtrak 代码的替代方案:
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 :-(
@Jakub:在我的软件必须在 Android 上运行之前,我一直在使用您的解决方案。并且 Android 没有实现 javax.naming.ldap :-(
回答by G L
I have BouncyCastle 1.49, and the class it has now is org.bouncycastle.asn1.x509.Certificate. I looked into the code of IETFUtils.valueToString()
- it is doing some fancy escaping with backslashes. For a domain name it would not do anything bad, but I feel we can do better. In the cases I've look at cn.getFirst().getValue()
returns different kinds of strings that all implement ASN1String interface, which is there to provide a getString() method. So, what seems to work for me is
我有 BouncyCastle 1.49,它现在的类是 org.bouncycastle.asn1.x509.Certificate。我查看了代码IETFUtils.valueToString()
- 它正在用反斜杠进行一些花哨的转义。对于域名来说,它不会做任何坏事,但我觉得我们可以做得更好。在我看过的情况下,cn.getFirst().getValue()
返回不同类型的字符串,这些字符串都实现了 ASN1String 接口,该接口用于提供 getString() 方法。所以,似乎对我有用的是
Certificate c = ...;
RDN cn = c.getSubject().getRDNs(BCStyle.CN)[0];
return ((ASN1String)cn.getFirst().getValue()).getString();
回答by AivarsDa
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 "";
}
回答by EpicPandaForce
Indeed, thanks to gtrak
it appears that to get the client certificate and extract the CN, this most likely works.
事实上,由于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;
回答by Ghetolay
Could use cryptacular which is a Java cryptographic library build on top of bouncycastle for easy use.
可以使用 cryptacular,这是一个构建在 bouncycastle 之上的 Java 加密库,易于使用。
RDNSequence dn = new NameReader(cert).readSubject();
return dn.getValue(StandardAttributeType.CommonName);
回答by Erdem Memisyazici
One line with http://www.cryptacular.org
CertUtil.subjectCN(certificate);
JavaDoc:http://www.cryptacular.org/javadocs/org/cryptacular/util/CertUtil.html#subjectCN(java.security.cert.X509Certificate )
Maven dependency:
Maven 依赖:
<dependency>
<groupId>org.cryptacular</groupId>
<artifactId>cryptacular</artifactId>
<version>1.1.0</version>
</dependency>