技術文章

混合憑證時代:Pure Rust 實作後量子認證機構 (PQC CA)

深入探討如何使用 Pure Rust 構建支援混合憑證(ECC + ML-DSA 雙重簽名)的企業級後量子 CA 系統,包含 X.509 延伸設計、ACME v2 協議整合、Vue 3 管理介面與完整的安全性考量

作者:Orson Wang
#PQC #後量子密碼學 #CA #PKI #X.509 #混合憑證 #Rust #ML-DSA #ACME #憑證管理

前言

PKI 基礎設施的量子威脅

公開金鑰基礎建設(Public Key Infrastructure, PKI)是現代網路安全的基石,支撐著:

  • HTTPS 加密通訊(全球 95%+ 網站)
  • 程式碼簽章(軟體發布、App Store、Docker 映像)
  • 電子郵件加密(S/MIME)
  • VPN 與企業身份認證(IPsec、802.1X)
  • 物聯網裝置認證(mTLS、OTA 更新)

傳統 PKI 完全依賴 RSAECDSA 簽章演算法,這些演算法在量子電腦面前將完全失效

演算法目前安全性量子電腦攻擊破解時間估算
RSA-2048112-bit 安全Shor’s Algorithm~8 小時(大型量子電腦)
RSA-4096140-bit 安全Shor’s Algorithm~1 天
ECDSA P-256128-bit 安全Shor’s Algorithm~數小時
ECDSA P-384192-bit 安全Shor’s Algorithm~1 天

危機時間點

  • 2030-2035 年:預估為 RSA/ECDSA 安全終結
  • 現在(2026):必須立即開始遷移準備
  • 遷移週期:企業 PKI 遷移通常需要 3-5 年

混合憑證的必要性

問題:如果今天全面切換到後量子憑證(Pure PQC),會發生什麼?

災難性後果

  • 舊版瀏覽器(Chrome 90 以前、Safari 14 以前)無法驗證
  • 嵌入式裝置(路由器、IoT)韌體無法更新
  • 舊系統(Windows 7、Android 8)完全失去連線能力
  • 全球數億台裝置瞬間「斷網」

混合憑證解決方案

混合憑證 = 傳統演算法(ECDSA P-256)+ 後量子演算法(ML-DSA-65)

驗證策略:
- 舊客戶端:只驗證 ECDSA → 可以連線(量子不安全)
- 新客戶端:雙重驗證 ECDSA + ML-DSA → 量子安全!
- 升級路徑:逐步淘汰舊客戶端,最終只要求 ML-DSA

平滑遷移時間表

階段時間CA 配置客戶端要求
階段 12026-2028混合憑證(ECDSA + ML-DSA)只驗證 ECDSA
階段 22028-2030混合憑證新客戶端開始驗證雙重簽章
階段 32030-2032混合憑證強制雙重驗證(舊客戶端淘汰)
階段 42032+Pure PQC(僅 ML-DSA)只驗證 ML-DSA

瀏覽器支援現況

Chrome 後量子密碼學部署進度

TLS 金鑰交換(已部署)

Google Chrome 已經在 TLS 層面部署混合後量子金鑰交換,保護網路流量免受「現在收集,未來解密」(Harvest Now, Decrypt Later) 攻擊:

Chrome 版本發布時間支援演算法狀態
Chrome 1162023年8月X25519Kyber768✅ 首次部署
Chrome 1312024年11月X25519 + ML-KEM-768(FIPS 203)✅ 切換到標準版本

部署成果(來源:Cloudflare 2025 報告):

  • 📊 38% 的人類 HTTPS 流量已使用混合 PQC 握手(2025年3月)
  • 效能影響:TLS 握手時間增加 4%(server→client +1.1kB,client→server +1.2kB)

憑證簽章(規劃中)

相較於金鑰交換,後量子憑證簽章的部署面臨更大挑戰:

技術障礙

  • ML-DSA-44 簽章大小:2,420 bytes(傳統 ECDSA P-256 僅 ~64 bytes)
  • ML-DSA-44 公鑰大小:1,312 bytes(ECDSA P-256 僅 65 bytes)
  • 憑證鏈膨脹:X.509 憑證鏈可能超過 10kB,嚴重影響 TLS 握手效能

Chrome 團隊策略(來源:Chromium PQC PKI 設計文件):

  • 🎯 效能目標:TLS 握手時間增加不超過 10%
  • 🔬 研究方向:Merkle Tree Certificates (MTC),可將多數簽章替換為 <800 bytes 的 Merkle proof
  • 部署時程
    • 2025年底:部分 Root Program 試點接受 ML-DSA-87 一年期憑證
    • 2026年:第一批 PQC 憑證出現(試驗性質)
    • 2027年:PQC 憑證廣泛可用,被主流瀏覽器信任
    • 2030年:NIST 建議所有 TLS 1.3 應完全使用 ML-KEM + ML-DSA

NG-CA 的應對策略

  • ✅ 支援混合憑證(ECDSA P-256 + ML-DSA-65),在效能與安全間取得平衡
  • ✅ 複合簽章格式可靈活調整(目前 3,361 bytes,未來可切換至 ML-DSA-44 降至 ~2,500 bytes)
  • ✅ 遵循 IETF draft-ietf-lamps-pq-composite-sigs 標準,確保未來相容性

為什麼選擇 Pure Rust(擺脫 OpenSSL)

傳統 CA 系統的問題

大多數 CA 系統(如 EJBCA、Dogtag、Boulder)都依賴 OpenSSL:

// OpenSSL 的記憶體安全問題範例
char buffer[256];
strcpy(buffer, user_input);  //  Buffer Overflow

歷史漏洞CVE 列表):

  • Heartbleed (CVE-2014-0160):全球 17% 伺服器受影響
  • ShellshockPOODLEDROWN
  • 每年平均 15+ 個重大漏洞

Pure Rust 優勢

特性C/OpenSSLRust
記憶體安全需手動管理編譯期保證
平行安全手動同步型別系統保證
空指標Segfault 風險編譯期檢查(Option
緩衝區溢位常見漏洞自動邊界檢查
釋放後使用Use-after-free生命週期系統防止
效能極快相同等級

NG-CA 技術棧

Mermaid diagram

NG-CA 架構設計

系統整體架構

Mermaid diagram

模組架構概要

核心模組

  • crypto/:密碼學核心層(RSA、ECC、PQC、混合密鑰、X.509 建構)
  • api/:RESTful API 層(CA 管理、憑證管理、錯誤處理)
  • acme/:ACME v2 協議實作(RFC 8555,JWS 簽名驗證)
  • ocsp/:OCSP 協議實作(RFC 6960,ASN.1 編碼)
  • db/:資料庫層(CA、Certificate 模型)
  • audit/:SOC2 稽核日誌

前端技術架構

Vue 3 + TypeScript 實作

  • 頁面組件:Dashboard(儀表板)、CaList(CA 管理)、CertList(憑證管理)
  • 功能組件:CreateCaDialog(CA 建立)、IssueCertDialog(憑證簽發)、CertDetailDialog(憑證詳情)
  • 狀態管理:Pinia Store(CA 與憑證資料)
  • 路由管理:Vue Router(頁面導航)
  • API 層:Axios 客戶端(RESTful API 呼叫)
  • 工具函數:日期格式化、表單驗證

資料庫架構

業務資料庫 (ng-ca.db) - CA 與憑證資料

資料表關鍵欄位說明
casid, name, algorithmCA 實體,支援 RSA/ECC/ML-DSA/Hybrid 演算法
public_key_pem, pqc_public_key_pem傳統與 PQC 公鑰(混合模式雙公鑰)
private_key_bytes, pqc_private_key_bytes加密儲存的私鑰資料
parent_ca_id, is_ca, path_lenCA 階層架構(Root/Intermediate)
default_days, default_key_usageRA 策略配置
certificatesserial_number, subject, issuer_id已簽發憑證索引
pem, status, not_before, not_after憑證內容與狀態(Good/Revoked)
revoked_at撤銷時間戳記

索引策略idx_cert_status(狀態查詢)、idx_cert_issuer(CA 關聯)、idx_cert_subject(主體查詢)

稽核資料庫 (audit.db) - SOC2 合規日誌

資料表關鍵欄位說明
audit_logsid, timestamp, actor_ip操作時間與來源 IP
action, resource_type, resource_id操作類型(create_ca/issue_cert/revoke_cert)與目標資源
status, metadata操作結果與額外資訊(JSON)

索引策略idx_audit_timestamp(時間範圍查詢)、idx_audit_action(操作類型統計)


PQC 整合實現

支援的後量子演算法

ML-DSA (Dilithium) - FIPS 204 標準

模式NIST 規約安全級別公鑰大小私鑰大小簽章大小
ML-DSA-44 (Dilithium2)2128-bit1,312 B2,544 B2,420 B
ML-DSA-65 (Dilithium3)3192-bit1,952 B4,000 B3,293 B
ML-DSA-87 (Dilithium5)5256-bit2,592 B5,632 B4,595 B

PQC 密碼學運算邏輯

金鑰產生流程

  1. 根據演算法類型(ML-DSA-44/65/87)呼叫對應的 Dilithium 金鑰產生函數
  2. 公鑰編碼為標準 SPKI (SubjectPublicKeyInfo) 格式:
    • 包含 AlgorithmIdentifier(ML-DSA OID)
    • 包含 BitString(公鑰資料)
    • PEM 標頭:-----BEGIN PUBLIC KEY-----(標準 PKCS#8 格式)
  3. 私鑰以二進制 bytes 形式儲存(需加密後存入資料庫)

簽章流程

  1. 從資料庫讀取私鑰 bytes 並反序列化為 Dilithium SecretKey
  2. 使用對應演算法的 sign() 函數產生簽章
  3. 回傳 SignedMessage bytes

驗證流程

  1. 從 PEM 格式解析公鑰(SPKI 格式)
  2. 從 AlgorithmIdentifier 提取 OID,自動識別演算法:
    • 2.16.840.1.101.3.4.3.17 → ML-DSA-44
    • 2.16.840.1.101.3.4.3.18 → ML-DSA-65
    • 2.16.840.1.101.3.4.3.19 → ML-DSA-87
  3. 從 BitString 提取公鑰資料
  4. 使用對應演算法的 open() 函數驗證簽章
  5. 回傳驗證結果(true/false)

混合憑證 (Hybrid Certificates) 深度解析

混合密鑰對產生

混合金鑰結構

  • HybridKeyPair:包含兩組獨立金鑰對
    • ecc_key:傳統 ECC P-256 金鑰對
    • pqc_key:後量子 ML-DSA-65 金鑰對

產生流程

  1. 呼叫 EccProvider::generate() 產生 ECC P-256 金鑰對
  2. 呼叫 PqcProvider::generate() 產生 ML-DSA-65 金鑰對
  3. 組合成 HybridKeyPair 結構

資料庫儲存

  • public_key_pem → ECC 公鑰(PEM 格式)
  • pqc_public_key_pem → ML-DSA 公鑰(PEM 格式)
  • private_key_bytes → ECC 私鑰(加密 BLOB)
  • pqc_private_key_bytes → ML-DSA 私鑰(加密 BLOB)
  • algorithm → ‘Hybrid’ 標記

雙重簽名提供程序

複合簽章格式設計

Mermaid diagram

範例(ML-DSA-65 + ECC P-256)

  • 總大小: 4 + 64 + 3,293 = 3,361 bytes

雙重簽章運算邏輯

簽章流程

  1. 使用 ECC Provider 對資料產生 ECC P-256 簽章
  2. 使用 PQC Provider 對資料產生 ML-DSA-65 簽章
  3. 組合複合簽章:
    • 寫入 ECC 簽章長度(4 bytes, big-endian u32)
    • 寫入 ECC 簽章內容
    • 寫入 PQC 簽章內容

驗證流程

  1. 解析複合簽章:
    • 讀取前 4 bytes 取得 ECC 簽章長度
    • 根據長度切分 ECC 與 PQC 簽章
  2. 驗證 ECC 簽章(使用 ECC 公鑰)
  3. 驗證 PQC 簽章(使用 ML-DSA 公鑰)
  4. 雙重驗證:兩個簽章都必須有效才通過

X.509 延伸欄位(ITU-T X.509 Extensions)

標準 X.509 憑證結構

Certificate ::= SEQUENCE {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING
}

TBSCertificate ::= SEQUENCE {
    version              [0] EXPLICIT Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    signature            AlgorithmIdentifier,
    issuer               Name,
    validity             Validity,
    subject              Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    extensions           [3] EXPLICIT Extensions OPTIONAL
}

混合憑證延伸欄位(基於 IETF Draft):

extensions [3] EXPLICIT SEQUENCE {
    -- 1. Subject Alt Public Key Info (OID 2.5.29.72)
    Extension {
        extnID     = id-ce-subjectAltPublicKeyInfo,
        critical   = FALSE,
        extnValue  = OCTET STRING (containing ML-DSA-65 public key)
    },

    -- 2. Alt Signature Algorithm (OID 2.5.29.73)
    Extension {
        extnID     = id-ce-altSignatureAlgorithm,
        critical   = FALSE,
        extnValue  = AlgorithmIdentifier (ML-DSA-65 algorithm)
    },

    -- 3. Alt Signature Value (OID 2.5.29.74)
    Extension {
        extnID     = id-ce-altSignatureValue,
        critical   = FALSE,
        extnValue  = BIT STRING (ML-DSA-65 signature)
    }
}

混合憑證建構邏輯(使用 x509-cert crate):

關鍵 OID 定義

  • 2.5.29.72 → Subject Alt Public Key Info
  • 2.5.29.73 → Alt Signature Algorithm
  • 2.5.29.74 → Alt Signature Value
  • 2.16.840.1.101.3.4.3.17 → ML-DSA-44 演算法
  • 2.16.840.1.101.3.4.3.18 → ML-DSA-65 演算法
  • 2.16.840.1.101.3.4.3.19 → ML-DSA-87 演算法

ML-DSA OID 來源IETF draft-ietf-lamps-dilithium-certificates

建構流程

  1. 準備 TBS Certificate:序列化 TbsCertificate 為 DER 格式
  2. 產生雙重簽章:呼叫 DualSignatureProvider 產生複合簽章
  3. 解析簽章:從複合簽章中分離 ECC 與 PQC 簽章
  4. 添加三個 X.509 延伸
    • Subject Alt Public Key Info:儲存 ML-DSA-65 公鑰
    • Alt Signature Algorithm:標記 ML-DSA-65 演算法 OID
    • Alt Signature Value:儲存 PQC 簽章
  5. 組合憑證
    • signatureAlgorithm 使用 ECDSA with SHA-256
    • signature 使用 ECC 簽章
    • Extensions 包含 PQC 公鑰與簽章

憑證驗證流程

Mermaid diagram

CA 功能實作

Root CA 建立

API 端點: POST /api/v1/ca

請求體

{
  "name": "Example Root CA",
  "algorithm": "Hybrid",             // Rsa2048/EccP256/MlDsa65/Hybrid
  "is_ca": true,                     // BasicConstraints.cA
  "path_len": 2,                     // 允許 2 層 Intermediate CA
  "default_days": 3650,              // 預設憑證有效期 10 年
  "use_v3_extensions": true,
  "default_key_usage": "digitalSignature,keyCertSign,cRLSign",
  "default_extended_key_usage": "serverAuth,clientAuth"
}

後端處理流程

  1. 金鑰對產生

    • 根據 algorithm 參數選擇對應的 Provider(Hybrid/MlDsa65/EccP256/Rsa2048)
    • 呼叫對應 Provider 的 generate() 方法產生金鑰對
    • 包裝成 KeyPairEnum 統一介面
  2. 自簽憑證建構

    • 產生隨機序號(20 bytes)
    • 設定 Subject/Issuer(自簽相同)
    • 計算有效期(default_days 天數)
    • 添加 BasicConstraints 延伸(capath_len
    • 添加 KeyUsage 延伸(CA 需 digitalSignature, keyCertSign, cRLSign
    • 若為混合憑證,呼叫 build_hybrid_certificate() 添加 PQC 延伸
  3. 資料庫儲存

    • 插入 cas 表,儲存金鑰對(傳統與 PQC)
    • 儲存配置(is_ca, path_len, default_days, Key Usage)
    • 取得 ca_id(auto-increment)
  4. 稽核日誌

    • 記錄 create_ca 操作
    • 包含 CA 名稱、演算法、操作結果
  5. 回傳結果

    • ca_id、CA 名稱、憑證 PEM、演算法類型

自簽憑證建構邏輯

  • 已整合至上述「後端處理流程」的第 2 步驟

Intermediate CA 支援

CA 階層架構(透過 parent_ca_idpath_len 控制):

CA 層級parent_ca_idpath_len說明
Root CANULL2允許建立 2 層子 CA
Intermediate CA (L1)11允許建立 1 層子 CA
Intermediate CA (L2)20無法再建立子 CA(終端 CA)

憑證鏈驗證邏輯

  1. 從目標憑證開始,讀取對應的 CA 資訊
  2. 使用 CA 公鑰驗證憑證簽章
  3. parent_ca_id 為 NULL,表示到達 Root CA,驗證完成
  4. 若有 parent_ca_id,讀取父 CA 憑證,重複步驟 2-3
  5. 迴圈驗證整條憑證鏈,任一環節失敗則回傳 false

CSR 簽發流程

API 端點: POST /api/v1/ca/{ca_id}/issue

處理流程

  1. 解析與驗證 CSR

    • 從 PEM 格式解析 CSR
    • 驗證 CSR 內建簽章(確保 CSR 未被竄改)
  2. 讀取 CA 配置

    • 從資料庫讀取 CA 資訊(包含金鑰、策略設定)
  3. 應用驗證規則(可選):

    • 若 CA 設定了 csr_validation_regex,驗證 Subject DN
    • 支援台灣身份證號/統一編號驗證(詳見下節)
  4. 產生憑證

    • 產生隨機序號(20 bytes)
    • 從 CSR 提取公鑰與 Subject
    • 使用 CA 私鑰簽署憑證
    • 應用 CA 預設的 Key Usage 與有效期
  5. 儲存與稽核

    • 插入 certificates 表(狀態為 ‘Good’)
    • 記錄稽核日誌(issue_cert 操作)
    • 回傳序號與憑證 PEM

憑證撤銷與 CRL

撤銷憑證流程

  1. 更新 certificates 表:設定 status = 'Revoked',記錄 revoked_at 時間戳記
  2. 檢查影響行數,若為 0 則回傳憑證不存在錯誤
  3. 記錄稽核日誌(revoke_cert 操作)
  4. 回傳撤銷成功訊息

CRL 產生邏輯

  1. 讀取 CA 資訊與私鑰
  2. 查詢該 CA 所有已撤銷憑證(status = 'Revoked'
  3. 使用 x509-cert crate 建構 CertificateList:
    • 設定 CRL 簽發者(CA 名稱)
    • 設定 CRL 有效期(預設 7 天)
    • 逐一添加 RevokedCert 項目(序號 + 撤銷時間)
  4. 使用 CA 私鑰簽署 CRL
  5. 轉換為 PEM 格式回傳

ACME v2 協議整合

ACME 協議概述

ACME (Automatic Certificate Management Environment) 是由 Let’s Encrypt 推動的自動化憑證管理協議,已標準化為 RFC 8555

ACME 工作流程

Mermaid diagram

支援的 ACME 端點

實作狀態backend/src/acme/routes.rs):

端點方法功能狀態
/acme/directoryGET取得 ACME 目錄已完成
/acme/new-nonceHEAD/GET取得 nonce已完成
/acme/new-accountPOST註冊帳號已完成
/acme/acct/{id}POST-as-GET查詢帳號資訊已完成
/acme/new-orderPOST建立訂單已完成
/acme/authz/{id}POST-as-GET查詢授權狀態已完成
/acme/chall/{id}POST回應 Challenge部分完成
/acme/order/{id}/finalizePOST完成訂單(提交 CSR)規劃中
/acme/cert/{serial}POST-as-GET下載憑證已完成

JWS 簽名驗證

ACME 要求所有請求都使用 JWS (JSON Web Signature) 簽名RFC 7515):

支援的演算法

演算法類型金鑰類型狀態
ES256ECDSA with SHA-256P-256已完成
RS256RSA PKCS#1 v1.5 with SHA-256RSA-2048+已完成
EdDSAEd25519Ed25519規劃中

JWS 驗證邏輯

資料結構

  • JwsHeader:包含 alg(演算法)、nonce(防重放)、url(請求 URL)、kid(帳號 ID)、jwk(公鑰)
  • Jwk(JSON Web Key):包含 kty(金鑰類型)、EC 參數(crv, x, y)或 RSA 參數(n, e

驗證流程

  1. 解析 JWS

    • 格式為 header.payload.signature(三段 Base64 URL編碼)
    • 檢查格式正確性
  2. 驗證安全參數

    • 解碼 header 並檢查 nonce(防重放攻擊)
    • 檢查 url 是否匹配請求路徑
  3. 簽章驗證(依演算法):

    • ES256(ECDSA P-256)
      • 從 JWK 解析 P-256 公鑰(x, y 座標)
      • 使用 p256 crate 驗證 ECDSA 簽章
    • RS256(RSA PKCS#1 v1.5)
      • 從 JWK 解析 RSA 公鑰(n modulus, e exponent)
      • 使用 rsa crate 驗證 PKCS#1 v1.5 簽章
  4. 解碼 Payload

    • Base64 URL 解碼 payload
    • 反序列化為 JSON 結構

ACME 資料庫架構

資料表關鍵欄位說明
acme_noncesnonce, created_at, used防重放攻擊(nonce 一次性使用)
acme_accountsid, account_key_jwk, contact, statusACME 帳號(儲存 JWK 公鑰與聯絡方式)
acme_ordersid, account_id, status, identifiers憑證訂單(狀態:pending/ready/processing/valid/invalid)
certificate_serial, expires簽發後的憑證序號與訂單過期時間
acme_authorizationsid, order_id, identifier, status域名授權(每個 identifier 一筆記錄)
challenge_type, challenge_tokenChallenge 類型(http-01/dns-01)與驗證 token
challenge_status, validated_atChallenge 狀態與驗證時間

台灣特色驗證

身份證字號驗證

格式:1 個英文字母 + 9 個數字(範例:A123456789

驗證邏輯(依內政部規定):

  1. 格式檢查:長度 10 碼,首碼英文,後 9 碼數字
  2. 英文字母轉數字:A=10, B=11, …, Z=35(I=34, O=35 為特殊對應)
  3. 拆分英文數值:轉換後的數字拆成十位數(d1)與個位數(d2)
  4. 權重計算
    • 權重序列:[1, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    • 加權總和:d1×1 + d2×9 + digit[0]×8 + ... + digit[8]×1
  5. 檢查碼驗證:加權總和 % 10 == 0

測試案例A123456789(✅)、F131104093(✅)、A123456788(❌ 檢查碼錯誤)

統一編號驗證

格式:8 個數字(範例:12345678

驗證邏輯(依財政部規定):

  1. 格式檢查:長度 8 碼,全數字
  2. 權重計算
    • 權重序列:[1, 2, 1, 2, 1, 2, 4, 1]
    • 每個 digit[i] × weight[i] 的乘積拆分為十位數與個位數後加總
  3. 特殊規則
    • 若第 7 碼為 7,則 sum % 10 == 0(sum + 1) % 10 == 0
    • 其他情況:sum % 10 == 0

CSR Subject 驗證整合

驗證流程

  1. 從 CSR 的 Subject DN 中解析 CN (Common Name)
  2. 根據 CA 的 csr_validation_regex 設定選擇驗證方法:
    • "TW_ID" → 台灣身份證字號驗證
    • "TW_TAX_ID" → 統一編號驗證
    • "TW_ORG_ID" → 組織機構代碼驗證
    • 自定義 regex → 使用正則表達式比對 CN

使用情境

  • CA 管理員在建立 CA 時設定 csr_validation_regex
  • 簽發憑證時自動檢查 CSR 的 CN 是否符合規則
  • 驗證失敗則拒絕簽發憑證

前端管理介面

Vue 3 技術棧

核心依賴

  • Vue 3.5 + TypeScript:組件化架構
  • Vue Router 4:頁面路由管理
  • Pinia 3:狀態管理
  • Axios:HTTP 客戶端(含自動重試)
  • Vite 6:開發伺服器與建置工具
  • Tailwind CSS 4:樣式框架
  • Lucide Icons:圖示庫

儀表板組件

主要功能 (Dashboard.vue):

資料展示

  • 統計卡片:顯示 CA 總數、已簽發憑證數、已撤銷憑證數(使用 StatCard 可復用組件)
  • CA 列表表格:展示所有 CA,包含名稱、演算法類型(顏色徽章)、CA 類型、建立時間

互動功能

  • onMounted:載入統計資料與 CA 列表(呼叫 /api/v1/stats/api/v1/ca
  • algorithmBadgeClass():根據演算法類型回傳對應的 Tailwind CSS class(Hybrid=紫色、ML-DSA=藍色、ECC=綠色、RSA=灰色)
  • downloadCRL():下載指定 CA 的 CRL(呼叫 /api/v1/ca/{id}/crl,透過 Blob 觸發瀏覽器下載)

實際介面截圖

以下是 NG-CA 管理介面的實際畫面:

Dashboard 儀表板

NG-CA Dashboard 儀表板

主要功能

  • 統計卡片:顯示 CA 總數、已簽發憑證數、已撤銷憑證數
  • CA 列表:展示所有 CA,標示演算法類型(Hybrid/ML-DSA/ECC)
  • 快速操作:下載 CRL、查看 CA 詳情

CA 列表視圖

NG-CA CA 列表

顯示資訊

  • CA 名稱與 ID
  • 演算法類型(使用顏色徽章區分)
    • 🟣 紫色:Hybrid (ECC + ML-DSA)
    • 🔵 藍色:ML-DSA-65
    • 🟢 綠色:ECC P-256
  • CA 類型(Root CA / Intermediate CA)
  • 建立時間
  • 操作按鈕(下載憑證、下載 CRL、撤銷)

憑證列表視圖

NG-CA 憑證列表

顯示資訊

  • 憑證 Subject(Common Name)
  • 簽發 CA
  • 有效期限(起始/結束日期)
  • 憑證狀態(✅ 有效 / ❌ 已撤銷 / ⏰ 即將過期)
  • 操作(下載憑證、撤銷憑證、查看詳情)

CA 建立對話框

表單欄位 (CreateCaDialog.vue):

  • CA 名稱:文字輸入(必填)
  • 演算法選擇:下拉選單(Hybrid/ML-DSA-65/ECC P-256/RSA-2048)
  • CA 類型:核取方塊(是否為 CA 憑證)
  • 路徑長度限制:數字輸入(僅 CA 憑證,0-5 層)
  • 預設有效期:數字輸入(1-3650 天)

互動邏輯

  • handleSubmit():呼叫 POST /api/v1/ca 建立 CA
  • 成功後顯示 Toast 通知,關閉對話框,重新載入頁面
  • 錯誤處理:顯示 API 回傳的錯誤訊息或預設「建立失敗」
  • 提交期間禁用按鈕,顯示「建立中…」載入狀態

安全性與合規

FIPS 140-3 考量

目前評分: 2/10 (原型階段)

項目目前狀態改進建議
密碼學模組RustCrypto 未通過 CMVP 驗證整合 aws-lc-rs(已通過認證)
金鑰儲存明文儲存私鑰使用 AES-256-GCM 加密私鑰
隨機數產生使用 OS 提供的 CSPRNG符合要求
自我測試無開機自我測試實作 POST (Power-On Self Test)
稽核SOC2 稽核日誌符合要求

改進路徑

Level 1(短期 - 3 個月):

  • 使用 AES-256-GCM 加密私鑰後儲存到資料庫
  • 主金鑰透過環境變數提供(CA_MASTER_KEY

Level 2(中期 - 6 個月):

  • 整合 aws-lc-rs(AWS 的 FIPS 認證模組)
  • 實作 POST 自我測試

Level 3(長期 - 12 個月):

  • 完整 HSM 整合(如 Thales Luna HSM)
  • FIPS 140-3 Level 3 認證申請

私鑰保護策略

目前問題:私鑰明文儲存在 SQLite 資料庫中,可直接讀取

加密儲存方案

  • 演算法:AES-256-GCM
  • 主金鑰來源:環境變數 CA_MASTER_KEY(32 bytes hex)
  • Nonce 處理:每次加密產生隨機 nonce(12 bytes),與密文一起儲存
  • 儲存格式[nonce (12 bytes)][ciphertext (variable)]

加密流程

  1. 從環境變數讀取主金鑰(hex 解碼)
  2. 產生隨機 nonce(使用 OsRng
  3. 使用 AES-256-GCM 加密私鑰
  4. 組合 nonce + ciphertext 並儲存到資料庫

解密流程

  1. 從資料庫讀取加密資料
  2. 分離 nonce(前 12 bytes)與 ciphertext
  3. 使用主金鑰與 nonce 解密
  4. 回傳明文私鑰用於簽章操作

測試與驗證

測試涵蓋率

整體統計53/54 測試通過 (98.1%)

測試套件測試數通過率位置
密碼學核心測試10100%backend/tests/coverage_tests.rs
API 端點測試15100%backend/tests/api_tests.rs
ACME 協議測試8100%backend/tests/acme_tests.rs
JWS 簽名測試6100%backend/tests/acme_jws_tests.rs
負面測試7100%backend/tests/negative_tests.rs
非混合 CA 測試785.7%backend/tests/non_hybrid_ca_tests.rs

密碼學核心測試

測試案例涵蓋

ML-DSA-65 完整工作流程測試 (test_ml_dsa_65_full_workflow):

  1. 金鑰對產生:驗證公鑰 PEM 與私鑰 bytes 非空,私鑰大小為 4000 bytes
  2. 簽章產生:驗證簽章大小為 3293 bytes(ML-DSA-65 規格)
  3. 簽章驗證:驗證合法簽章通過
  4. 負面測試:驗證偽造訊息的簽章驗證失敗

混合雙重簽章測試 (test_hybrid_dual_signature):

  1. 混合金鑰對產生:包含 ECC 與 ML-DSA 兩組金鑰
  2. 雙重簽章:產生複合簽章(格式:[ecc_len][ecc_sig][pqc_sig])
  3. 驗證複合簽章格式:檢查 ECC 簽章長度是否合理(0-200 bytes)
  4. 雙重驗證:驗證兩個簽章都有效
  5. 負面測試:篡改任一簽章後驗證應失敗

RSA 與 ECC 工作流程測試

  • RSA-2048/3072/4096:驗證金鑰產生、簽章大小(256/384/512 bytes)、簽章驗證
  • ECC P-256/384/521:驗證金鑰產生、簽章大小(~64/96/132 bytes)、簽章驗證

X.509 憑證建構測試

  • 基本 X.509 欄位:序號、Subject、Issuer、有效期
  • BasicConstraints 延伸:CA 標記、路徑長度限制
  • KeyUsage 延伸:digitalSignature、keyCertSign、cRLSign
  • 混合憑證延伸:Subject Alt Public Key Info、Alt Signature Algorithm、Alt Signature Value

OpenSSL 互通性驗證

驗證腳本scripts/verify_openssl.sh):

驗證步驟

  1. 取得 Root CA 憑證:從 API 下載 CA 憑證(/api/v1/ca/1
  2. 驗證憑證格式:使用 openssl x509 檢查憑證結構
  3. 驗證自簽憑證:使用 openssl verify 驗證 Root CA 自簽有效性
  4. 產生 CSR:使用 openssl req 產生測試用 CSR
  5. 使用 NG-CA 簽發憑證:呼叫 API 端點(POST /api/v1/ca/1/issue)簽發憑證
  6. 驗證憑證鏈:使用 OpenSSL 驗證憑證鏈完整性
  7. 檢查混合憑證延伸:確認 PQC 延伸欄位存在(OID 2.5.29.72/73/74)

驗證結果

  • Root CA 自簽驗證通過
  • 憑證鏈驗證通過(OpenSSL 相容)
  • 混合憑證延伸欄位正確(Subject Alt Public Key Info、Alt Signature Algorithm、Alt Signature Value)

未來發展

FIPS 140-3 Level 1 合規

目標時程:3-6 個月

主要工作項目

  1. 私鑰加密儲存(AES-256-GCM)
  2. POST 自我測試(開機時驗證密碼學模組)
  3. 整合 aws-lc-rs(FIPS 認證模組)
  4. 完整稽核追蹤
  5. 文件與認證申請

gRPC API

動機:支援微服務架構與高效能 RPC

API 設計proto/ca.proto):

syntax = "proto3";

package ng_ca.v1;

service CaService {
  rpc CreateCa(CreateCaRequest) returns (CreateCaResponse);
  rpc IssueCertificate(IssueCertificateRequest) returns (IssueCertificateResponse);
  rpc RevokeCertificate(RevokeCertificateRequest) returns (RevokeCertificateResponse);
  rpc GetCRL(GetCRLRequest) returns (GetCRLResponse);
}

message CreateCaRequest {
  string name = 1;
  Algorithm algorithm = 2;
  bool is_ca = 3;
  optional uint32 path_len = 4;
  uint32 default_days = 5;
}

enum Algorithm {
  ALGORITHM_UNSPECIFIED = 0;
  RSA_2048 = 1;
  RSA_3072 = 2;
  RSA_4096 = 3;
  ECC_P256 = 4;
  ECC_P384 = 5;
  ECC_P521 = 6;
  ML_DSA_44 = 7;
  ML_DSA_65 = 8;
  ML_DSA_87 = 9;
  HYBRID = 10;
}

message CreateCaResponse {
  int64 ca_id = 1;
  string certificate_pem = 2;
}

message IssueCertificateRequest {
  int64 ca_id = 1;
  string csr_pem = 2;
  uint32 days = 3;
  bool is_ca = 4;
  optional uint32 path_len = 5;
}

message IssueCertificateResponse {
  string serial_number = 1;
  string certificate_pem = 2;
}

多租戶支援

資料隔離設計

-- 新增租戶表
CREATE TABLE tenants (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    api_key TEXT NOT NULL UNIQUE,
    created_at TEXT DEFAULT (datetime('now'))
);

-- CA 表添加租戶關聯
ALTER TABLE cas ADD COLUMN tenant_id INTEGER REFERENCES tenants(id);

-- 憑證表添加租戶關聯
ALTER TABLE certificates ADD COLUMN tenant_id INTEGER REFERENCES tenants(id);

-- Row-Level Security
CREATE INDEX idx_ca_tenant ON cas(tenant_id);
CREATE INDEX idx_cert_tenant ON certificates(tenant_id);

API 認證邏輯tenant_auth_middleware):

驗證流程

  1. 提取 API Key:從請求標頭 X-API-Key 取得金鑰
  2. 查詢租戶:使用 API Key 從 tenants 表查詢對應的租戶
  3. 權限驗證:若 API Key 不存在或無效,回傳 401 Unauthorized
  4. 注入租戶 ID:將租戶 ID 注入請求延伸(req.extensions_mut()
  5. 繼續處理:將請求傳遞給下一個 middleware 或 handler

資料隔離:所有 CA 與憑證查詢自動過濾 tenant_id,確保租戶間資料完全隔離


結語與資源

關鍵要點

  1. 混合憑證 = 平滑遷移路徑:同時支援舊客戶端(ECDSA)與新客戶端(雙重驗證)
  2. Pure Rust = 記憶體安全:擺脫 OpenSSL 的漏洞風險
  3. ACME v2 = 自動化:Let’s Encrypt 相容,零人工干預
  4. 台灣在地化:身份證/統編驗證,符合本地需求
  5. Vue 3 管理介面:直觀易用,降低管理成本

專案資源

參考文件

延伸閱讀


本文完成於 2026-02-03,基於 NG-CA v0.1.0、NIST FIPS 204 標準、RFC 8555 (ACME v2) 撰寫。

如有任何問題或建議,歡迎透過聯絡我們 頁面與我們聯繫。