java读取X509拓展_java - 如何从Java中的X509Certificate中提取CN? - 堆栈内存溢出

本文介绍了如何使用Java从X509Certificate中提取CN(常见名),提供了包括使用JDK内置API、BouncyCastle库以及LdapName在内的多种解决方案,并给出了相关代码示例。
摘要由CSDN通过智能技术生成

===============>>#1 票数:90

这是另一种方式。 您的想法是您获得的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());

}

===============>>#2 票数:76 已采纳

以下是新推荐的不推荐使用的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());

===============>>#3 票数:12

如果添加依赖项不是问题,您可以使用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);

更新

在发布时,这是实现此目的的方法。 然而,正如gtrak在评论中提到的那样,这种方法现在已被弃用。 请参阅gtrak使用新Bouncy Castle API的更新代码 。

===============>>#4 票数:9

作为gtrak代码的替代品,不需要''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:我已经使用了你的解决方案,直到我的SW必须在Android上运行。 Android没有实现javax.naming.ldap :-(

===============>>#5 票数:6

CertUtil.subjectCN(certificate);

JavaDoc: http ://www.cryptacular.org/javadocs/org/cryptacular/util/CertUtil.html#subjectCN(java.security.cert.X509Certificate )

Maven依赖:

org.cryptacular

cryptacular

1.1.0

===============>>#6 票数:5

到目前为止发布的所有答案都有一些问题:大多数使用内部X500Name或外部Bounty Castle依赖项。 以下内容基于@ Jakub的答案并仅使用公共JDK API,但也提取OP所要求的CN。 它也使用Java 8,它在2017年中期,你真的应该。

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(", "))

===============>>#7 票数:3

我有BouncyCastle 1.49,它现在的类是org.bouncycastle.asn1.x509.Certificate。 我查看了IETFUtils.valueToString()的代码 - 它正在使用反斜杠进行一些花哨的转义。 对于一个域名,它不会做任何坏事,但我觉得我们可以做得更好。 在我查看cn.getFirst().getValue()的情况下, cn.getFirst().getValue()返回所有实现ASN1String接口的不同类型的字符串,它提供了一个getString()方法。 所以,似乎对我有用的是

Certificate c = ...;

RDN cn = c.getSubject().getRDNs(BCStyle.CN)[0];

return ((ASN1String)cn.getFirst().getValue()).getString();

===============>>#8 票数:2

以下是使用regex而不是cert.getSubjectX500Principal().getName() ,以防您不想依赖于BouncyCastle。

此正则表达式将解析一个可分辨的名称,为每个匹配赋予name和val一个捕获组。

当DN字符串包含逗号时,它们应该被引用 - 这个正则表达式正确处理引用和非引用字符串,并且还处理带引号的字符串中的转义引号:

(?:^|,\\s?)(?:(?[AZ]+)=(?"(?:[^"]|"")+"|[^,]+))+

这是格式很好:

(?:^|,\s?)

(?:

(?[A-Z]+)=

(?"(?:[^"]|"")+"|[^,]+)

)+

如果你想要一个正则表达式只获得CN,那么这个改编版本将会这样做:

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

===============>>#9 票数:1

实际上,多亏了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;

===============>>#10 票数:1

可以使用加密,这是一个建立在bouncycastle之上的Java加密库,以方便使用。

RDNSequence dn = new NameReader(cert).readSubject();

return dn.getValue(StandardAttributeType.CommonName);

===============>>#11 票数:1

更新:这个类是在“sun”包中,你应该谨慎使用它。 感谢Emil的评论:)

只是想分享,为了获得CN,我做:

X500Name.asX500Name(cert.getSubjectX500Principal()).getCommonName();

===============>>#12 票数:1

从证书中获取CN并不是那么简单。 以下代码肯定会对您有所帮助。

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

===============>>#13 票数:0

正则表达式使用起来相当昂贵。 对于这样一个简单的任务,它可能是一个过度杀戮。 相反,您可以使用简单的String拆分:

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

}

===============>>#14 票数:0

您可以尝试使用getName(X500Principal.RFC2253,oidMap)或getName(X500Principal.CANONICAL, oidMap)来查看哪个格式最适合DN字符串。 也许其中一个oidMap映射值将是您想要的字符串。

===============>>#15 票数:0

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

}

===============>>#16 票数:0

BC使提取更容易:

X500Principal principal = x509Certificate.getSubjectX500Principal();

X500Name x500name = new X500Name(principal.getName());

String cn = x500name.getCommonName();

===============>>#17 票数:0

对于多值属性 - 使用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;

}

}

}

}

}

ask by Martin C. translate from so

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值