什么是证书链
打开浏览器的IE的证书页面
自上而下,就是一条证书链
- xxCAROOT
- XXCa
- 不原透露姓名的刘XX
我这里都是代码片断,还扯到一个大的gradle工程,除了一个放证书地址的,别的自己加一下,可以编译成功的,就不放github地址了(也许以后我会补上...)
验证书链的时候,只是确定上一个证书是下一个证书的发布者、上一个证书用私钥签了下一个证书。
// gradle配置
// https://mvnrepository.com/artifact/org.json/json
compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.54'
compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.54'
compile 'commons-codec:commons-codec:1.10'
testCompile group: 'junit', name: 'junit', version: '4.11'
//调用时,是这么干的
// 我提供一个Verify及GetCertMsg及一个Certhelper StringUtil里的证书自己填吧
boolean result= Verify.verify(CertHelper.getCertificate(StringUtil.xxxx_CERT_PATH),
GetCertMsg.getCertificateChain(),
GetCertMsg.getX509CRL(StringUtil.xxx_CRT_PATH),
GetCertMsg.getSubjectDNname(CertHelper.getCertificate(StringUtil.SERVLET_CERT_PATH)));
//验一下
public static boolean verify(X509Certificate X509certificateRoot,
X509Certificate[] X509CertificateChain, X509CRL X509crl, String stringTarget) {
//声明list,存储证书链中证书主体信息
ArrayList list = new ArrayList();
//沿证书链自上而下,验证证书的所有者是下一个证书的颁布者
Principal principalLast = null;
for (int i = 0; i < X509CertificateChain.length; i++) {//遍历arX509certificate
X509Certificate x509Certificate = X509CertificateChain[i];
//获取发布者标识
Principal principalIssuer = x509Certificate.getIssuerDN();
//获取证书的主体标识
Principal principalSubject = x509Certificate.getSubjectDN();
//保存证书的序列号
list.add(x509Certificate.getSerialNumber());
if (principalLast != null) {
//验证证书的颁布者是上一个证书的所有者
if (principalIssuer.equals(principalLast)) {
try {
//获取上个证书的公钥
PublicKey publickey = X509CertificateChain[i - 1].getPublicKey();
//验证是否已使用与指定公钥相应的私钥签署了此证书
X509CertificateChain[i].verify(publickey);
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
principalLast = principalSubject;
}
if (X509crl != null) {
try {
//获取CRL中所有的项
Set setEntries = X509crl.getRevokedCertificates();
if (setEntries == null && setEntries.isEmpty() == false) {
Iterator iterator = setEntries.iterator();
while (iterator.hasNext()) {
X509CRLEntry X509crlentry = (X509CRLEntry) iterator.next();
if (list.contains(X509crlentry.getSerialNumber())) return false;
}
}
} catch (Exception e) {
return false;
}
}
//证明证书链中的第一个证书由用户所信任的CA颁布
try {
PublicKey publickey = X509certificateRoot.getPublicKey();
X509CertificateChain[0].verify(publickey);
} catch (Exception e) {
return false;
}
//证明证书链中的最后一个证书的所有者正是现在通信对象
Principal principalSubject = X509CertificateChain[X509CertificateChain.length - 1].getSubjectDN();
if (!stringTarget.equals(principalSubject.getName())) return false;
//验证证书链里每个证书是否在有效期里
Date date = new Date();
for (int i = 0; i < X509CertificateChain.length; i++) {
try {
X509CertificateChain[i].checkValidity(date);
} catch (Exception e) {
return false;
}
}
return true;
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.cert.*;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Set;
public class GetCertMsg {
//获得证书链的方法
public static X509Certificate[] getCertificateChain() throws CertificateException, IOException{
return new X509Certificate[]{
Certool.getCertificate(StringUtil.KOALCA_CERT_PATH),
Certool.getCertificate(StringUtil.SERVLET_CERT_PATH)
};
}
//获得吊销列表的方法
public static X509CRL getX509CRL(String filePath) throws FileNotFoundException, CertificateException, CRLException{
FileInputStream fis = new FileInputStream(filePath);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL) cf.generateCRL(fis);
/**
* 显示吊销列表
*/
Set tSet = crl.getRevokedCertificates();
Iterator tIterator = tSet.iterator();
while (tIterator.hasNext()) {
X509CRLEntry tEntry = (X509CRLEntry) tIterator.next();
String sn = tEntry.getSerialNumber().toString(16).toUpperCase();
String issName = crl.getIssuerDN().toString();
String time = new SimpleDateFormat("yyyyMMddHHmmss").format(tEntry
.getRevocationDate());
//我们公司的比较长,我都不打印了...
/*System.out.println(sn);
System.out.println(issName);
System.out.println(time);
System.out.println("***************************");*/
}
return crl;
}
//获得目标证书主体名
public static String getSubjectDNname(X509Certificate cert){
return cert.getSubjectDN().getName();
}
}
import java.io.*;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class Certool {
/*
* 通过 CertificateFactory和绝对路径获取X509证书
* X509Certificate是 Certificate的子类
*/
public static X509Certificate getCertificate(String path)
throws CertificateException, IOException {
CertificateFactory cf = CertificateFactory.getInstance("x509");
InputStream is = new FileInputStream(new File(path));
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
is.close();
return cert;
}
public static boolean storeCertificate(String storepath, String password, X509Certificate cert, String certAlias) {
try {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(storepath), password.toCharArray());
keyStore.setCertificateEntry(certAlias, cert);
keyStore.store(new FileOutputStream(storepath), password.toCharArray());
return true;
} catch (Exception ex) {
System.out.println("储存证书失败!");
return false;
}
}
}