首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 數位憑證操作完整指南:從讀取、驗證到簽發

     編輯:Java 相關知識

前言

Java 憑證 API(java.security.cert、javax.security.auth.x500 等)提供了豐富的功能來處理 X.509 數位憑證與金鑰庫。本文系統整理十大常見操作場景,附帶可直接參考的代碼片段,幫助開發者快速實現憑證管理功能。

一、核心 API 概覽

  • CertificateFactory:憑證工廠,支援 X.509 格式生成 Certificate 物件。
  • KeyStore:金鑰庫抽象,預設類型 JKS(Java KeyStore),亦支援 PKCS12。
  • X509Certificate:X.509 憑證介面,提供版本、序號、主體、簽發者、有效期、公鑰、簽名驗證等方法。
  • X509CertImpl、X509CertInfo(Sun 內部類):用於構建、修改憑證細節(如簽發者、序號、演算法、有效期)並簽名。

二、從文件讀取憑證

CertificateFactory cf = CertificateFactory.getInstance("X.509");
try (FileInputStream in = new FileInputStream("out.csr")) {
    Certificate cert = cf.generateCertificate(in);
    System.out.println(cert.toString());
}

三、從金鑰庫直接讀取憑證

String password = "123456";
try (FileInputStream in = new FileInputStream(".keystore")) {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(in, password.toCharArray());
    Certificate cert = ks.getCertificate("myAlias"); // 別名
}

四、顯示憑證詳細資訊

X509Certificate x509 = (X509Certificate) cert;
System.out.println("版本號: " + x509.getVersion());
System.out.println("序列號: " + x509.getSerialNumber().toString(16));
System.out.println("主體名: " + x509.getSubjectX500Principal());
System.out.println("簽發者: " + x509.getIssuerX500Principal());
System.out.println("有效期起: " + x509.getNotBefore());
System.out.println("有效期迄: " + x509.getNotAfter());
System.out.println("簽名演算法: " + x509.getSigAlgName());

// 公鑰編碼
byte[] pkEnc = x509.getPublicKey().getEncoded();
System.out.println("公鑰 (Base64): " + Base64.getEncoder().encodeToString(pkEnc));

五、列出金鑰庫所有條目

try (FileInputStream in = new FileInputStream(".keystore")) {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(in, "123456".toCharArray());
    Enumeration aliases = ks.aliases();
    while (aliases.hasMoreElements()) {
        String alias = aliases.nextElement();
        Certificate c = ks.getCertificate(alias);
        System.out.println("Alias: " + alias + ", Type: " + c.getType());
    }
}

六、修改金鑰庫儲存密碼

try (FileInputStream in = new FileInputStream(".keystore")) {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(in, "123456".toCharArray());
}
try (FileOutputStream out = new FileOutputStream(".keystore")) {
    ks.store(out, "654321".toCharArray());
}

七、修改條目密鑰密碼與新增條目

String storePass = "123456";
String oldKeyPass = "123456";
String newKeyPass = "654321";
String alias = "myAlias";

try (FileInputStream in = new FileInputStream(".keystore")) {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(in, storePass.toCharArray());

    Certificate[] chain = ks.getCertificateChain(alias);
    PrivateKey pk = (PrivateKey) ks.getKey(alias, oldKeyPass.toCharArray());

    // 修改密碼或新增條目(若 alias 不存在則新增)
    ks.setKeyEntry(alias, pk, newKeyPass.toCharArray(), chain);

    try (FileOutputStream out = new FileOutputStream(".keystore")) {
        ks.store(out, storePass.toCharArray());
    }
}

八、檢查別名存在性與刪除條目

try (FileInputStream in = new FileInputStream(".keystore")) {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(in, storePass.toCharArray());

    if (ks.containsAlias("sage")) {
        ks.deleteEntry("sage");
        try (FileOutputStream out = new FileOutputStream(".keystore")) {
            ks.store(out, storePass.toCharArray());
        }
    }
}

九、CA 簽發數位憑證(完整流程)

  1. 載入 CA 憑證與私鑰:從金鑰庫取得 caroot 條目的憑證鏈與私鑰。
  2. 提取簽發者資訊:解析 CA 憑證獲取 X500Name 類型的主體名作為新憑證的簽發者。
  3. 載入待簽發 CSR:使用 CertificateFactory 讀取 user.csr 獲取 X509CertInfo。
  4. 設定新憑證屬性:
    • 有效期:CertificateValidity(如 3000 天)
    • 序列號:CertificateSerialNumber(可用時間戳)
    • 簽發者:步驟 2 的 X500Name
    • 簽名演算法:AlgorithmId.md5WithRSAEncryption_oid(建議改用 SHA256withRSA)
  5. 簽名並存入金鑰庫:
    X509CertImpl newCert = new X509CertImpl(certInfo);
    newCert.sign(caPrivateKey, "SHA256withRSA"); // 推薦更安全演算法
    ks.setCertificateEntry("user_signed", newCert);
    ks.store(new FileOutputStream("newstore"), "newpass".toCharArray());
    

十、憑證驗證

1. 有效期驗證

X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream("aa.crt"));
try {
    cert.checkValidity(new Date()); // 當前時間
    System.out.println("憑證在有效期內");
} catch (CertificateExpiredException e) {
    System.out.println("憑證已過期: " + e.getMessage());
} catch (CertificateNotYetValidException e) {
    System.out.println("憑證尚未生效: " + e.getMessage());
}

2. 簽名驗證(需 CA 公鑰)

Certificate caCert = cf.generateCertificate(new FileInputStream("caroot.crt"));
PublicKey caPubKey = caCert.getPublicKey();

try {
    cert.verify(caPubKey);
    System.out.println("簽名驗證通過");
} catch (Exception e) {
    System.out.println("簽名驗證失敗: " + e.getMessage());
}

最佳實踐提醒

  • 避免使用 Sun 內部類(sun.security.x509.*),優先考慮 Bouncy Castle 等標準庫構建/解析憑證,確保跨 JDK 版本相容。
  • 簽名演算法 建議使用 SHA256withRSA 或 SHA384withECDSA,棄用 MD5/SHA1。
  • 金鑰庫類型 新專案優先選擇 PKCS12(業界標準,跨平台),而非專有的 JKS。
  • 密碼管理 生產環境切勿硬編碼密碼,應從環境變數、配置中心或 HSM 獲取。

掌握上述操作,即可應對絕大多數 Java 憑證管理需求。實際專案中建議封裝為工具類或引入成熟庫(如 Keycloak、Bouncy Castle)提升安全性與維護性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved