獲取數字證書相關資訊,證書鏈有效性驗證,RSA加密和解密功能之證書鏈有效性驗證
阿新 • • 發佈:2019-01-03
/** * 證書有效性驗證,後臺將證書鏈以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);