背景:本来是使用某个公司的jar包解析x.509证书,但他的包被扫描的时候却发现了很多安全漏洞,所以要使用其他方式对x.509证书进行解析,我解析的是前端传过来的一个字符串,类似于这样的“MIICMjCCAZsCCQD3/xw1j77JATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJD”,据网上说,x.509的文本其实是这样的-----BEGIN CERTIFICATE----- MIICMjCCAZsCCQD3/xw1j77JATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJD.....省略----END CERTIFICATE-----。也就是说,前端是传给我中间的字符串。但网上的资源比较少,因此在这里总结一下,供后面的人知晓。
有关x.509和Base64的相关知识可以去网上查,因为代码用了这方面的知识。采用解析x509格式的包为java.sercurity,使用了反射的技术,反射会导致元空间内存变大,而且是在运行时编译,会影响性能,一般要少用。这里是因为我想获取的数据存在类似于递归的对象中,java.sercurity并没有提供获得该对象的接口(可能有,只是我懒得再细找了~),我只能使用反射。
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import sun.misc.BASE64Decoder;
import sun.security.x509.X500Name;
import sun.security.x509.X509AttributeName;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
/**
* 解析X509证书字符串
*/
public class X509StringRecord {
public static void main(String[] args) throws IOException, CertificateException, ClassNotFoundException, IllegalAccessException {
//模仿前端获得的X509证书格式的字符串,自己替换自己的,后面还省略了很多字符串串
String signed_data="MIICMjCCAZsCCQD3/xw1j77JATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJD";
//身份证号
String IDcord="";
//姓名
String name;
//我解码的字符串存储X509这个类中,等下会使用反射,哇,这里是X500Name
X500Name x500Name=null;
//存储前端传的参数通过base64进行解码的结果
byte[] signedContent=null;
BASE64Decoder decoder=new BASE64Decoder();
signedContent=decoder.decodeBuffer(signed_data);
//CertificateFactory解析是一个InputStream类型的对象,使用ByteArrayInputStream进行转换
ByteArrayInputStream bain=new ByteArrayInputStream(signedContent);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
//这里不能用generateCertificate(bain);,它限制了inputStream的长度。应该用generateCertificates(bain);
//另外,我这个例子这里报错应该是证书格式不符合,因为涉及到隐私,截取了部分,替换成自己的吧,
List<? extends Certificate> certificates=(List<? extends Certificate>) cf.generateCertificates(bain);
Iterator iterator=certificates.iterator();
while(iterator.hasNext()){
X509CertImpl x509Cert=(X509CertImpl) iterator.next();
//通过反射获得X509CertInfo的对象
Class x509CertImpl=Class.forName("sun.security.x509.X509CertImpl");
Field[] fsX509CertImplFields=x509CertImpl.getDeclaredFields();
for(Field fs509CertImplField:fsX509CertImplFields){
//设置属性可达,不然会报访问私有属性异常
fs509CertImplField.setAccessible(true);
if("info".equals(fs509CertImplField.getName())){
//得到对应X509CertImpl对象中的X509CertInfo属性值
X509CertInfo certInfo=(X509CertInfo) fs509CertImplField.get(x509Cert);
//通过反射获得X500Name对象
Class classX509CertInfo=Class.forName("sun.security.x509.X509CertInfo");
Field[] fsX509CertInfoFields=classX509CertInfo.getDeclaredFields();
for(Field fsX509CertInfoField:fsX509CertInfoFields){
//得到对应X509CertImpl对象中的X509CertInfo属性值
fsX509CertInfoField.setAccessible(true);
if("subject".equals(fsX509CertInfoField.getName())){
x500Name=(X500Name) fsX509CertInfoField.get(certInfo);
break;
}
}
break;
}
}
}
if(x500Name!=null){
//输出结果类似于CN=字符串,OU=TrustMore安全网关,O=T1,c=CN
System.out.println(x500Name);
}
}
}