java实现解析x509数字证书DN的各项属性,并校验DN是否符合标准

目录


前言

公司产品中一个业务需要解析证书DN的各项属性,并提取某项属性的属性值。之前的实现是将DN作为字符串进行操作,以逗号split之后遍历取出各项属性,再以等号split取出某项属性值。在碰到某个DN中有一个逗号(,)的特殊格式后就会导致数组越界的问题。这种方式很不可取,遂查资料写了以下两种方式。


一、使用 javax.naming.ldap.LdapName 类

		LdapName ln = null;
        try {
            ln = new LdapName(dn);
        } catch (InvalidNameException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        for(Rdn rdn : ln.getRdns()) {
            System.out.println("LdapName--Type-- "+rdn.getType());
            System.out.println("LdapName--Value-- "+rdn.getValue());
        }

这个方法是在网上查到,容易实现,不用引入其他jar包,是java自带的方法。符合RFC 2253规定的,类似于CN = Steve Kille,O = Isode Limited,C = CN这种格式的字符串都能解析。但在这个业务场景下,该方法的缺点是不能判断某个属性是否是证书DN中规定的属性。比如CNTest = Steve Kille,O = Isode Limited,C = CN,标准的证书DN项中没有CNTest 这一项,但是这种方法同样可以解析出来。

二、使用 org.bouncycastle.asn1.x500.X500Name 类(推荐)

基于以上原因,考虑到产品中的实际业务使用,翻阅bouncycastle的源码,写了如下方法。

maven引入

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.51</version>
        </dependency>

代码如下

	private static Map<String, String> parseDNToMap(String dn) {
        
        if(StrUtil.isBlank(dn)) {
            return null;
        }
        
        Map<String, String> resMap = new HashMap<String, String>();
        
        X500Name x500Name = new X500Name(dn);
        
        RDN[] rdNs = x500Name.getRDNs();
        for (int i = 0; i < rdNs.length; i++) {
            
            AttributeTypeAndValue first = rdNs[i].getFirst();
			//获取属性名的oid
            ASN1ObjectIdentifier type = first.getType();
            
            //将属性名的oid转换为属性名
            String typeString = BCStyle.INSTANCE.oidToDisplayName(type).toUpperCase();
            //或使用RFC4519Style.INSTANCE.oidToDisplayName(type).toUpperCase();
            
            //获取属性值
            String valueString = first.getValue().toString();
            
            resMap.put(typeString, valueString);
        }
        
        return resMap;
    }

如果有非标准规定的属性名,会抛出异常如下

Exception in thread "main" java.lang.IllegalArgumentException: Unknown object id - CNTest - passed to distinguished name
	at org.bouncycastle.asn1.x500.style.IETFUtils.decodeAttrName(Unknown Source)
	at org.bouncycastle.asn1.x500.style.BCStyle.attrNameToOID(Unknown Source)
	at org.bouncycastle.asn1.x500.style.IETFUtils.rDNsFromString(Unknown Source)
	at org.bouncycastle.asn1.x500.style.BCStyle.fromString(Unknown Source)
	at org.bouncycastle.asn1.x500.X500Name.<init>(Unknown Source)
	at org.bouncycastle.asn1.x500.X500Name.<init>(Unknown Source)
	at com.certTest.x509NameTest.main(x509NameTest.java:86)


总结

以上两种方法亲测有效,如果只是要解析DN各项,第一种方法更方便。如果同时需要校验DN是否符合标准可选用第二种。

上一篇:x509 证书链验证


下一篇:rancher证书过期X509:certificate has expired or is not ye valid