===============>>#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