/**
* 证书有效性验证,后台将证书链以byte[]数组集合的形式传入
* @param certChain 后台传入的证书链
* @param cert2Verify 本地需要验证的证书
* @return
*/
public int certificateValidate(List<byte[]> certChain, byte[] cert2Verify) {
List<X509Certificate> certss = new ArrayList<>();
CertificateFactory certificatefactory;
X509Certificate cert;
InputStream input;
try {
certificatefactory = CertificateFactory.getInstance("X.509");
//转换为inputstream,并将此inputstream转为X509Certificate的类型加入到list集合中,用于后续的
//排序
input = new ByteArrayInputStream(cert2Verify);
cert = (X509Certificate) certificatefactory.generateCertificate(input);
certss.add(cert);
//将证书链中的每一层节点转换为X509Certificate类型并加入到集合中
for (byte[] b : certChain) {
input = new ByteArrayInputStream(b);
cert = (X509Certificate) certificatefactory.generateCertificate(input);
certss.add(cert);
}
//排序,为什么需要排序?因为后台传入过来的证书链并不一定是按照验证顺序进行排序的,
//所以需要进行排序后验证
List<X509Certificate> certs = order(certss);
//进行长度判断,如果验证证书链排序过程中,出现问题直接验证失败
if (certs.size() != certss.size()) {
Log.e("123", "证书链校验失败");
return 1;
}
//验证
verifyCerts(certs);
Log.e("123", "证书验证成功");
return 0;
} catch (CertificateException e) {
e.printStackTrace();
Log.e("123", "证书无效");
return 1;
} catch (Exception e) {
e.printStackTrace();
Log.e("123", "证书无效");
return 0;
}
}
/**
* 找到证书父节点
* @param parents
* @param child
* @return
*/
private X509Certificate findParent(List<X509Certificate> parents, X509Certificate child) {
//获取到需要找到父节点证书的颁布者
Principal p = child.getIssuerDN();
Principal subjectDN = child.getSubjectDN();
//如果证书的颁发者与颁发给是一样的,说明此证书没有父节点,为最外层证书
if (p.equals(subjectDN)) {
return null;
}
for (int i = 0; i < parents.size(); i++) {
X509Certificate parent = parents.get(i);
if (p.equals(parent.getSubjectDN())) {
return parent;
}
}
return null;
}
/**
* 排序
* @param certss
* @return
*/
private List<X509Certificate> order(List<X509Certificate> certss) {
List<X509Certificate> certInOder = new ArrayList<>();
X509Certificate cert2Verify = certss.get(0);
certInOder.add(cert2Verify);
for (int i = 0; i < certss.size(); i++) {
//找到父节点
X509Certificate parent = findParent(certss, cert2Verify);
if (parent == null) {
break;
} else {
//找到父节点证书后加入到集合中,并把找到的证书作为子证书,去寻找它的父节点
certInOder.add(parent);
cert2Verify = parent;
}
}
return certInOder;
}
/**
* 证书有效性验证
* @param certs
* @throws Exception
*/
private static void verifyCerts(List<X509Certificate> certs) throws Exception {
int n = certs.size();
for (int i = 0; i < n - 1; i++) {
X509Certificate cert = certs.get(i);
X509Certificate issuer = (X509Certificate) certs.get(i + 1);
//验证,这里的验证需要是排序好的
cert.verify(issuer.getPublicKey());
}
//自己验证自己,此步可以不要
X509Certificate last = (X509Certificate) certs.get(n - 1);
last.verify(last.getPublicKey());
}
验证代码示例:
private String getKeyFromCRT() {
Log.e("===========PublicKey", "getKeyFromCRT()");
String key = "";
// String key1 = "";
CertificateFactory certificatefactory;
X509Certificate Cert;
InputStream bais;
InputStream bais1;
InputStream bais2;
PublicKey pk1;
try {
certificatefactory = CertificateFactory.getInstance("X.509");
//读取放在项目中assets文件夹下的.crt文件;你可以读取绝对路径文件下的crt,返回一个InputStream(或其子类)。
//证书链
bais = getAssets().open("2.cer");
bais1 = getAssets().open("1.cer");
//需要验证的证书
bais2 = getAssets().open("cn.crt");
//将inputstream转换为byte数组
List<byte[]> bytes = new ArrayList<>();
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = bais.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] b = swapStream.toByteArray();
//添加到集合
bytes.add(b);
ByteArrayOutputStream swapStre = new ByteArrayOutputStream();
byte[] buff1 = new byte[100];
int rc1 = 0;
while ((rc1 = bais1.read(buff1, 0, 100)) > 0) {
swapStre.write(buff1, 0, rc1);
}
byte[] b1 = swapStre.toByteArray();
bytes.add(b1);
ByteArrayOutputStream swapStre2 = new ByteArrayOutputStream();
byte[] buff2 = new byte[100];
int rc3 = 0;
while ((rc3 = bais2.read(buff2, 0, 100)) > 0) {
swapStre2.write(buff2, 0, rc3);
}
byte[] b3 = swapStre2.toByteArray();
certificate.getCertificateInfo(b3);
//验证
certificate.certificateValidate(bytes,b3);