技術文章

混合憑證時代:用 Luna HSM 實作後量子認證機構 (PQC CA)

深入解析 NG-CA:Luna HSM 託管金鑰、同時支援 non-composite (ITU-T X.509 雙軌) 與 composite (draft-ietf-lamps-pq-composite-sigs-19) 兩種 hybrid 簽章模式的企業級 PQC CA。含 OpenSSL 3.5 / 4.0 互通實測、17 種演算法 (RSA / ECC / ML-DSA / SLH-DSA / FN-DSA / ML-KEM)、ACME v2、OCSP、Delta CRL,以及 2026 年 9 月的標準最新狀態。

作者:Orson Wang更新於 2026/9/11
#PQC#後量子密碼學#CA#PKI#X.509#混合憑證#OpenSSL#ML-DSA#ML-KEM#SLH-DSA#Luna HSM#ACME#Composite Signature#RFC 9794
混合憑證時代:用 Luna HSM 實作後量子認證機構 (PQC CA)

前言

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

瀏覽器與公開 PKI 現況(2026 年 9 月)

金鑰交換:已經是多數

混合後量子金鑰交換早已從實驗變成預設。Chrome 116(2023-08)先上 X25519Kyber768,Chrome 131(2024-11)換成標準版 X25519MLKEM768(FIPS 203)。到 2025 年 10 月,Cloudflare 網路上過半的人類發起流量已使用後量子金鑰協商,2026 年更超過六成(來源:Cloudflare 2025 報告Cloudflare Radar)。OpenSSL 3.5 起也把 hybrid KEM 排進 TLS 預設群組,伺服器端幾乎不需額外設定。

效能代價很小:TLS 握手時間增加約 4%,server→client 多 1.1kB、client→server 多 1.2kB。

憑證簽章:仍卡在公開信任這一關

項目狀態(2026-09)
ML-DSA 在 TLS 1.3 的簽章協商draft-ietf-tls-mldsa-05 已獲 IESG 核准(Informational),待出 RFC
公開 TLS 憑證可否用 ML-DSACA/B Forum 尚無通過的 Baseline Requirements ballot
主流瀏覽器預設不協商 ML-DSA 伺服器憑證
替代路線Merkle Tree Certificates(draft-10)、TLS Trust Anchor Identifiers(draft-04)仍在草案階段

阻力仍然是尺寸。ML-DSA-44 的簽章 2,420 bytes、公鑰 1,312 bytes,對照 ECDSA P-256 的 ~64 / 65 bytes 差了兩個數量級;本文後面用 OpenSSL 實測的一張 ML-DSA-65 自簽根憑證,DER 就要 5,532 bytes。整條鏈換成 ML-DSA 遠超 TLS 握手的舒適區,Chrome 團隊因此把力氣放在 Merkle Tree Certificates —— 用不到 1kB 的 Merkle proof 取代多數簽章,而不是單純換演算法。

這對 NG-CA 的意義

公開 TLS 簽發在 2026 年仍不是選項。PQC CA 現階段的落點是私有 PKI、企業 mTLS、程式碼簽章與 S/MIME —— 這些場景的信任錨由組織自己控制,不必等 Root Program 投票。NG-CA 的準備是:

  • 支援混合憑證(ECDSA P-256 + ML-DSA-65),在效能與安全之間取得平衡
  • composite 與 non-composite 兩種模式並存,讓同一套 CA 能同時服務老裝置與新建基礎設施
  • 演算法與格式跟著 IETF LAMPS 走,等公開信任的門打開時不必重做

實作邊界:應用層、HSM 與 OpenSSL 生態

NG-CA 的關鍵設計決策不在程式語言,而在信任邊界切在哪裡:

層次由誰負責理由
受 FIPS 規範的金鑰與密碼學運算Thales Luna HSM(FIPS 140-3 Level 3)私鑰不落地,認證邊界清楚
尚未進 HSM 的 PQC(SLH-DSA / FN-DSA)應用層軟體實作Luna 韌體未支援,先以軟體補齊演算法矩陣
憑證與 CRL 的 ASN.1 組裝、策略、稽核應用層不涉及密碼學模組認證範圍
對外互通驗證OpenSSL 3.5 / 4.0、Bouncy Castle用生態主力實作當裁判,而不是自我驗證

應用層以 Rust 撰寫(x509-cert 組 ASN.1、自有 luna-cryptoki crate 包 PKCS#11 v3.0 FFI),但這是工程偏好,不是架構主張 —— 同一套邊界用 Go、Java 或 C 都能實作。真正不可替換的只有兩件事:私鑰只存在於 HSM,以及憑證格式必須能被主流實作解讀。

值得澄清一個常見誤解:建 PQC CA 不需要「擺脫 OpenSSL」。OpenSSL 自 3.5 起已原生支援 ML-KEM、ML-DSA 與 SLH-DSA,是今天最重要的 PQC 互通對象;NG-CA 與它是互補關係,不是取代關係。後面的互通實測會說明這條互通線的界線落在哪裡。

金鑰素材的型別邊界

金鑰來源分成 HSM 與軟體兩種,用 enum 在型別系統強制區分:

pub enum KeyMaterial {
    /// 軟體實作的真實私鑰位元組(SLH-DSA / FN-DSA)
    Software(Vec<u8>),
    /// HSM-backed 私鑰的 CKA_LABEL UTF-8 bytes;實際私鑰永不離開 HSM
    HsmLabel(Vec<u8>),
}

RSA / ECC / ML-DSA / ML-KEM 的金鑰生命週期完全託管給 Luna HSM,應用層只持有 CKA_LABEL。SLH-DSA 與 FN-DSA 因 Luna 韌體尚未支援,仍走軟體實作(pqcrypto / RustCrypto)。這個區分若只用 Vec<u8> 表示,把 HSM label 誤當 PKCS#8 DER 解析會在執行期才爆炸。


NG-CA 架構設計

系統整體架構(六層 + Luna HSM Bridge)

NG-CA Architecture with Luna HSM

整體系統分為六層,L5 HSM Bridge 是 2026 年導入的關鍵層,把 RSA / ECC / ML-DSA / ML-KEM 的金鑰生命週期完全託管給 Luna HSM,金鑰素材以前述 KeyMaterial enum 區分 HSM 與軟體兩種來源。

模組架構概要

核心模組backend/src/):

  • crypto/:密碼學核心層 — RSA / ECC / ML-DSA (PqcProvider) / SLH-DSA / FN-DSA / ML-KEM / Hybrid (兩種模式) + X.509 / CSR / Name Constraints
  • hsm/:Luna HSM bridge — luna-cryptoki 包裝、connection pool、CKM_RSA_PKCS / CKM_ECDSA_SHA* / CKM_ML_DSA / CKM_ML_KEM_* mechanism 對映
  • api/:RESTful API 層(CA 管理、憑證管理、verify-chain、錯誤處理)
  • acme/:ACME v2 協議實作(RFC 8555,HTTP-01,JWS ES256/RS256 驗證)
  • ocsp/:OCSP 實作(RFC 6960,含 Nonce 擴展、next_update、moka cache)
  • validation/:Name Constraints、CSR Validator、台灣身份檢核
  • metrics/:Prometheus exporter(25+ 指標)
  • db/:SQLx (SQLite) — ng-ca.db 業務資料、audit.db SOC2 稽核
  • audit/:稽核日誌寫入(actor / action / resource / status / metadata)

前端技術架構

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 整合實現

標準狀態一覽(2026 年 9 月)

PQC PKI 的標準地景在 2025–2026 年變動很大,幾份 NG-CA 原本引用的草案已經出 RFC,也有一份至今沒動。撰稿時的實況:

標準狀態(2026-09)對 PQC CA 的意義
FIPS 203 / 204 / 205已定案(2024-08)ML-KEM / ML-DSA / SLH-DSA 的演算法基準
FIPS 206(FN-DSA)仍標示 in development,NIST 連 initial public draft 都尚未公開FN-DSA 只能當實驗性支援,不可作為合規宣稱
RFC 9881 — ML-DSA in X.509Proposed StandardML-DSA 憑證的 OID 與 SPKI 編碼依據
RFC 9909 — SLH-DSA in X.509Proposed StandardSLH-DSA 憑證編碼依據
RFC 9935 — ML-KEM in X.509(2026-03)Proposed Standard取代原先引用的 draft-ietf-lamps-kyber-certificates
RFC 9882 — ML-DSA in CMSProposed Standard程式碼簽章 / S/MIME 路線的依據
RFC 9794 — PQ/T hybrid 術語Informational(2025-06)non-composite 與 composite 的用語來源
draft-ietf-lamps-pq-composite-sigs-19已通過 IESG,在 RFC Editor queue(First Edit),尚未取號composite 模式的對齊版本;技術內容已凍結
draft-ietf-lamps-pq-composite-kem-21仍在 WG(2026-09 更新)composite KEM 尚未穩定,NG-CA 不實作
ITU-T X.509 (2019) §9.8 alt 擴充已生效的 ITU-T 標準non-composite 三個擴充(2.5.29.72/73/74)的唯一規範來源
draft-truskovsky-lamps-pq-hybrid-x509已終止,IETF 不再推進引用 alt 擴充時不應再指向 IETF 草案
CA/B Forum TLS BR尚無允許 ML-DSA 的 ballot 通過公開 TLS 的 PQC 簽發仍未開放

兩點值得特別記住:

  1. composite 的技術內容已凍結(draft-19 在 RFC Editor 手上),現在對齊它不會再被大改;但它與早期草案差異很大,見下文的編碼說明。
  2. FIPS 206 的進度比多數人以為的慢。NIST 於 2025 年 8 月把草案送審,但到 2026 年 9 月,CSRC 上仍沒有 FIPS 206 的出版頁面。任何把 FN-DSA 寫進合規文件的計畫都該假設它還會再等一年。

17 個演算法、5 大類別總覽

NG-CA 的演算法支援對齊 FIPS 203/204/205,以及 RFC 9794/9881/9909/9935 等 X.509 編碼規範。FN-DSA 所依據的 FIPS 206 至今仍未定案,實作細節見標準狀態一覽

類別演算法NIST 等級BackendOID簽章 / 公鑰大小
Traditional
FIPS 186-5
RSA-2048Luna HSM1.2.840.113549.1.1.11256 B sig
RSA-3072Luna HSM同上384 B sig
RSA-4096Luna HSM同上512 B sig
ECDSA P-256Luna HSM1.2.840.10045.3.1.7~64 B sig
ECDSA P-384Luna HSM1.3.132.0.34~96 B sig
ECDSA P-521Luna HSM1.3.132.0.35~132 B sig
PQ 簽章 · lattice
FIPS 204 / RFC 9881
ML-DSA-44Level 2Luna HSM2.16.840.1.101.3.4.3.172,420 B sig
ML-DSA-65Level 3Luna HSM2.16.840.1.101.3.4.3.183,309 B sig
ML-DSA-87Level 5Luna HSM2.16.840.1.101.3.4.3.194,627 B sig
PQ 簽章 · hash-based
FIPS 205 / RFC 9909
SLH-DSA-SHA2-128sLevel 1軟體2.16.840.1.101.3.4.3.207,856 B sig
SLH-DSA-SHA2-192sLevel 3軟體2.16.840.1.101.3.4.3.2216,224 B sig
SLH-DSA-SHA2-256sLevel 5軟體2.16.840.1.101.3.4.3.2429,792 B sig
PQ 簽章 · FALCON
FIPS 206 尚在制定
FN-DSA-512Level 1軟體待 IETF 登記~666 B sig
FN-DSA-1024Level 5軟體待 IETF 登記~1,280 B sig
PQ KEM
FIPS 203 / RFC 9935
ML-KEM-512Level 1Luna HSM2.16.840.1.101.3.4.4.1800 B pk
ML-KEM-768Level 3Luna HSM2.16.840.1.101.3.4.4.21,184 B pk
ML-KEM-1024Level 5Luna HSM2.16.840.1.101.3.4.4.31,568 B pk

ECDSA 欄位列的是曲線 OID(prime256v1 等),簽章演算法 OID 另有 ecdsa-with-SHA* 一組。RSA 三種金鑰長度共用 sha256WithRSAEncryption,實際可搭配的 hash 見後文「RSA Hash 演算法擴展」。

在這 17 個演算法之上,HybridHybridDualSignature 兩種混合模式各自把一組傳統金鑰與一組 ML-DSA 金鑰綁在同一張憑證上,不算獨立演算法。

Backend 邊界規則

  • Luna HSM 7.8+ 已支援 RSA、ECC、ML-DSA、ML-KEM 的硬體 keygen 與簽章/encap,所有此類金鑰皆走 HSM。
  • SLH-DSA / FN-DSA Luna 尚未支援,落到軟體實作(pqcrypto-sphincsplus / pqcrypto-falcon)。
  • ML-KEM 為 KEM 演算法,KeyUsage 只能是 keyEncipherment,不可用於數位簽章;NG-CA 在 keygen 與用途檢查時都會拒絕誤用。

ML-DSA 詳解(最常用的 PQC 簽章)

FIPS 204 / RFC 9881

模式NIST 等級公鑰私鑰簽章OID
ML-DSA-44 (原 Dilithium2)Level 21,312 B2,544 B2,420 B2.16.840.1.101.3.4.3.17
ML-DSA-65 (原 Dilithium3)Level 31,952 B4,000 B3,309 B2.16.840.1.101.3.4.3.18
ML-DSA-87 (原 Dilithium5)Level 52,592 B5,632 B4,627 B2.16.840.1.101.3.4.3.19

HSM-backed 流程(Luna 7.8+)

  1. 金鑰產生:呼叫 CKM_ML_DSA_KEY_PAIR_GEN,私鑰留在 HSM,回傳 CKA_LABEL 與公鑰位元組
  2. 公鑰編碼:以 SPKI 標準格式(AlgorithmIdentifier + BitString)寫入 PEM;AlgorithmIdentifier 的 parameters MUST be absent(RFC 9881 §3)
  3. 簽章:從應用層送入 CKM_ML_DSAC_SignInit + C_Sign,HSM 內部完成簽章運算,私鑰不離開硬體
  4. 驗證:軟體側完成(pqcrypto-mldsa),因驗證只需公鑰,沒有金鑰外洩風險

OID 自動識別:解析 SPKI 時從 AlgorithmIdentifier 對照三組固定 OID 即可決定演算法版本,不需要額外 metadata。

混合憑證 (Hybrid Certificates) — 兩種並存模式

NG-CA 同時實作 RFC 9794 定義的兩種 hybrid 模式。這是相對於早期版本(只實作自訂 [ecc_len][ecc_sig][pqc_sig] 連接格式)的重大標準化升級:

NG-CA Hybrid Modes Comparison

模式NG-CA enumRFC 9794 術語X.509 表現客戶端要求
non-compositeAlgorithm::Hybridnon-composite主簽章 + ITU-T v3 alt-sig extensions(OID 2.5.29.72/73/74舊 client 只驗主簽即可連線
compositeAlgorithm::HybridDualSignaturecomposite單一複合 OID(1.3.6.1.5.5.7.6.*)+ 兩段簽章串接於單一 BIT STRING必須是 hybrid-aware client

兩種模式分別解決不同情境:

  • non-composite(漸進式遷移友好):適合需要與既有 PKI 共存、不能切斷舊裝置連線的場景。BSI 對德國關鍵基礎設施的 hybrid 強制要求恰好對應這條路。
  • composite(draft-ietf-lamps-pq-composite-sigs-19):適合純新建的 PQC 基礎設施。簽章與公鑰各是兩段組件的原始串接,直接放進 X.509 既有的 BIT STRING 欄位;靠固定前綴與 per-algorithm label 防跨組合 spoofing。對協議層透明,不需要新增 alt-sig 處理邏輯 —— 但代價是驗證端必須認得那個複合 OID,沒有向下相容的餘地。

Hybrid 金鑰對產生

兩種模式都需要兩組金鑰 — 但因 RSA / ECC / ML-DSA 全部已 HSM-backed,私鑰側其實是兩個 CKA_LABEL

pub struct HybridKeyPair {
    pub traditional: KeyPair,  // RSA / ECC / Ed25519,KeyMaterial::HsmLabel
    pub pqc:         KeyPair,  // ML-DSA-44/65/87,KeyMaterial::HsmLabel
}

產生流程

  1. 呼叫 EccProvider::generate()(或 RSA)→ Luna CKM_*_KEY_PAIR_GENKeyMaterial::HsmLabel(label_a)
  2. 呼叫 PqcProvider::generate(MlDsa65) → Luna CKM_ML_DSA_KEY_PAIR_GENKeyMaterial::HsmLabel(label_b)
  3. 組成 HybridKeyPair,DB 只儲存兩個 label 與兩份 SPKI 公鑰

資料庫欄位(cas 表)

  • algorithm = 'Hybrid''HybridDualSignature'(區分兩種模式)
  • public_key_pem = 傳統公鑰 SPKI
  • pqc_public_key_pem = ML-DSA 公鑰 SPKI
  • private_key_bytes / pqc_private_key_bytes = HSM 上對應的 CKA_LABEL UTF-8 bytes(不是真私鑰

雙重簽章運算

兩種模式的 sign/verify 介面相同(都吃 tbs_data: &[u8] 回傳 Vec<u8>),但內部封裝不同

non-composite (Algorithm::Hybrid) —— 兩段獨立 BIT STRING,各自寫入 X.509 不同欄位:

(主) signatureValue   = Sign_ECDSA(tbsCertificate)
(副) altSignatureValue = Sign_MLDSA65(tbsCertificate)

副簽放入 v3 extension 2.5.29.74;對應的演算法 OID 放入 2.5.29.73;對應的 ML-DSA 公鑰放入 2.5.29.72(subjectAltPublicKeyInfo)。

composite (Algorithm::HybridDualSignature) —— 兩段組件原始串接,不再包 ASN.1 結構:

signatureValue   BIT STRING = mldsaSig    || tradSig
subjectPublicKey BIT STRING = mldsaPubKey || tradPubKey

draft-19 刻意採用「非 ASN.1」的串接編碼:ML-DSA 的公鑰與簽章長度固定(ML-DSA-65 為 1,952 與 3,309 bytes),解碼時依固定長度切開即可,剩下的就是傳統組件。早期草案曾用 SEQUENCE SIZE (2) OF BIT STRING,已被移除 —— 這是對齊 composite 時最容易踩到的版本差異,若拿舊草案的實作互通會直接解析失敗。

訊息 representative 的構造:composite 要求兩個組件簽同一份 M',而不是原始訊息。以 1.3.6.1.5.5.7.6.45id-MLDSA65-ECDSA-P256-SHA512)為例:

M' = Prefix || Label || len(ctx) || ctx || SHA-512(tbs_data)

Prefix = "CompositeAlgorithmSignatures2025"    -- 固定 32 bytes ASCII,全體 composite 共用
Label  = "COMPSIG-MLDSA65-ECDSA-P256-SHA512"   -- 每個 composite OID 各一組
ctx    = 應用層 context,最長 255 bytes,X.509 簽發時通常為空

mldsaSig = ML-DSA-65.Sign(sk_mldsa, M', ctx = Label)
tradSig  = ECDSA-P256-SHA256.Sign(sk_ecdsa, M')
output   = mldsaSig || tradSig

關鍵在 Label:它同時綁進 M' 與底層 ML-DSA 的 ctx,讓組件簽章無法被拆出來挪用到別的 OID 或非 composite 情境。注意區分兩者的角色 —— Prefix 是所有 composite 演算法共用的固定字串,真正區分演算法組合的是 Label,不是 per-OID 的隨機 domain separator。

依 draft-19 附錄 A,這組 OID 的公鑰為 2,017 bytes、簽章最大 3,381 bytes(ECDSA 的 DER 編碼會因去除前導零而有數 bytes 浮動)。

驗證:non-composite 由憑證解析器先處理 v3 extension、再分別走兩個 verifier;composite 由 OID 直接派發到 CompositeVerifier,內部解 SEQUENCE 後並行驗證 — 任一失敗整體失敗(沒有「向下相容只驗一邊」的選項)。詳細決策樹見下節。

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
}

混合憑證延伸欄位(依 ITU-T X.509 (2019) §9.8):

這三個擴充來自 ITU-T X.509 第八版,不是 IETF 規範。曾經對應的 IETF 草案 draft-truskovsky-lamps-pq-hybrid-x509 已經終止,因此引用 alt 擴充時應指向 ITU-T 而非 IETF LAMPS。

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 來源RFC 9881(前身為 draft-ietf-lamps-dilithium-certificates,已於 2025 年出 RFC)

建構流程

  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 公鑰與簽章

憑證驗證決策樹

NG-CA 的 verify_certificate()signatureAlgorithm OID 與 v3 extensions 分派至三條路徑 — 涵蓋 single signature、non-composite hybrid、composite hybrid 三種情境:

NG-CA Certificate Verification Flow

三條路徑摘要:

  • Lane A(Single Signature):傳統 OID 且無 alt-sig extensions,依 OID 派發 RSA / ECDSA / ML-DSA / SLH-DSA 對應 verifier。最常見,路徑最短。
  • Lane B(non-composite Hybrid):傳統 OID 但有 v3 alt-sig extensions(2.5.29.72/73/74)。先驗主簽(向下相容老 client),再從 extensions 取 PQC 公鑰與 alt-sig 補上量子安全層。如果 client 看不懂 alt-sig 它仍能信任主簽,憑證 graceful degradation。
  • Lane C(composite Hybrid)signatureAlgorithm 是 composite OID(1.3.6.1.5.5.7.6.*)。先依 OID 查到演算法配對與 label,按固定長度切開串接的兩段簽章,重算 M' 後兩個 verifier 並行驗證;任一失敗整體失敗。沒有向下相容,這是設計選擇。

完整鏈驗證(/api/v1/certificates/{serial}/verify-chain)會遞迴對 End-Entity → Intermediate → Root 每一層套用上述判斷,pathLenConstraint 也在每層檢查;moka cache(10k entries / 5min TTL)加速重複查詢。


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 格式回傳

企業級進階功能

NG-CA 在 2026 年初補上五項:Prometheus 監控、名稱約束、VA 功能增強、RSA Hash 演算法擴展,以及測試補強。

Prometheus 監控系統

實現時間:2026 年 2 月 NG-CA 整合完整的 Prometheus 監控指標系統,提供生產環境所需的全面可觀測性:

監控指標類別(25+ 個關鍵指標):

類別指標範例用途
OCSP 服務ocsp_requests_total
ocsp_request_duration_seconds
OCSP 請求量、響應延遲
Nonce 使用率追蹤
CRL 管理crl_generated_total
crl_size_bytes
Full/Delta CRL 生成統計
CRL 大小分布
憑證管理certificates_issued_total
certificates_active
簽發總數(按演算法分類)
活動憑證數量
效能指標cache_hit_rate_percent
db_query_duration_seconds
快取命中率
資料庫查詢延遲

API 端點

  • GET /metrics - Prometheus 格式指標導出

效能影響

  • CPU 開銷:<1%
  • 記憶體使用:+10-50MB
  • 每請求延遲:~1-5μs

使用場景

  • 生產環境性能監控和 SLA 追蹤
  • 容量規劃與異常檢測
  • Grafana Dashboard 視覺化

名稱約束 (Name Constraints)

實現時間:2026 年 2 月 實現 RFC 5280 名稱約束功能,允許 CA 限制其簽發的憑證只能用於特定網域、IP 或 Email 範圍:

支援的約束類型

約束類型範例驗證邏輯
DNS 網域*.example.com支援 wildcard 匹配
IP 位址192.168.0.0/16
2001:db8::/32
支援 IPv4/IPv6 CIDR
Email*@example.com支援 pattern 匹配

工作流程

  1. CA 建立時設定約束:在 permitted_subtrees/excluded_subtrees 欄位指定規則
  2. CSR 解析:提取 Subject CN 和所有 SAN(DNS、IP、Email)
  3. 簽發驗證:自動檢查 CSR 內容是否符合名稱約束
  4. 錯誤回報:明確指出違反哪一條約束規則

安全效益

  • 防止 Intermediate CA 簽發超出授權範圍的憑證
  • 支援企業內部 CA 的網域隔離策略
  • 符合 RFC 5280 §4.2.1.10 標準

VA 功能增強套件

實現時間:2026 年 2 月

完成憑證驗證功能:

1. OCSP Nonce 擴展(RFC 6960 §4.4.1)

功能:防止 OCSP 重放攻擊

  • 在 OCSP 請求中提取 Nonce 擴展
  • 在響應中回顯相同的 Nonce
  • 確保響應的時效性

安全效益:攻擊者無法重用舊的 OCSP 響應

2. 憑證狀態快取機制

技術實現

  • 使用 moka 記憶體快取庫
  • TTL:5 分鐘
  • 容量:10,000 條目

效能提升

  • OCSP 查詢速度提升 10 倍
  • 資料庫負載降低 80-90%

3. 憑證路徑驗證 API(RFC 5280 §6)

功能:完整的憑證鏈驗證

  • 遞迴建構信任鏈(End-Entity → Intermediate → Root)
  • 路徑長度約束檢查(pathLenConstraint
  • 驗證每一層簽章有效性

API 端點

  • GET /api/v1/certificates/{serial}/verify-chain

使用場景

  • 驗證憑證是否由信任的 Root CA 簽發
  • 檢查憑證鏈的完整性
  • 偵測中間人攻擊

4. Delta CRL 支援(RFC 5280 §5.2.4)

功能:增量撤銷清單生成

  • 只包含自上次 Full CRL 後的新撤銷憑證
  • 版本追蹤系統(Base CRL Number)
  • 支援標準和混合簽章

效能優化

  • CRL 傳輸量減少 95-99%
  • 降低頻寬成本和客戶端處理負擔

API 端點

  • GET /api/v1/ca/{id}/crl/delta

RSA Hash 演算法擴展

實現時間:2026 年 2 月

擴展 RSA 簽章的 hash 演算法支援,適用於所有 RSA 金鑰大小(2048/3072/4096):

新增支援

  • SHA-384
  • SHA-512
  • SHA3-384
  • SHA3-512

應用場景

  • 高安全需求環境(政府、金融機構)
  • 符合特定合規要求(如 CNSA 2.0)
  • RSA-4096 與 SHA-512 組合提供 256-bit 安全等級

測試通過率提升

成果

  • 2026 年 1 月:71/71 測試通過(100%)
  • 整體測試涵蓋率:99%+

測試類別

  • 密碼學核心測試(11/11)
  • OCSP 增強測試(全部通過)
  • Delta CRL 測試(全部通過)
  • 路徑驗證測試(全部通過)
  • 名稱約束測試(全部通過)

ACME v2 協議整合

ACME 協議概述

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

ACME v2 完整流程(HTTP-01 Challenge)

NG-CA 已實作 RFC 8555 主要端點,目前以 HTTP-01 為主要驗證方式。完整訊息流程如下:

NG-CA ACME v2 Sequence

關鍵實作細節:

  • JWS 防重放:每個請求帶上一個 nonce(從 acme_nonces 表取出後立即標記為 used),任何重複使用的 nonce 都會被拒絕。
  • JWS 演算法:目前生產支援 ES256(ECDSA P-256)與 RS256(RSA-2048+ PKCS#1 v1.5);EdDSA 規劃中。
  • HTTP-01 驗證:NG-CA server 主動向 http://<domain>/.well-known/acme-challenge/{token} 發 GET,比對 key authorization = token || '.' || base64url(SHA-256(JWK))
  • 狀態機acme_orders.statuspending → ready → processing → valid|invalid,每次轉換寫入 audit_logs
  • PQC roadmap:composite OID 的 ACME 簽發已可透過 finalize 階段傳入 hybrid CSR;CA/B Forum 對 TLS BR 的 PQC 修訂預計 2026-2027 落地後可開放公開簽發。
  • 為什麼非要 ACME 自動化:TLS / Code Signing 整個產業正快速縮短憑證有效期 — Code Signing 從 39 月降到 460 天、TLS 預計 2029 年降至 47 天。NG-CA 把 ACME v2 列為核心模組,正是因為人工續期在 47-day 週期下根本不可行;PQC 演算法輪替(ML-DSA → SLH-DSA / FN-DSA)疊加在這條趨勢上,自動化簽發 + 撤銷管線是 PQC CA 不可妥協的基礎能力。

支援的 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

測試案例A123456789F131104093 通過,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 對齊(HSM 整合後現況)

2026 年初的 Phase A-C HSM 整合完成後,FIPS 140-3 遵循度從原型期的 2/10 大幅提升 — 因為所有受 FIPS 規範的密碼學運算都委派給 Thales Luna HSM(FIPS 140-3 Level 3 認證模組),NG-CA 應用層只剩編排與資料整合:

項目現況認證來源
密碼學模組RSA / ECC / ML-DSA / ML-KEM 在 Luna 內運算Luna HSM FIPS 140-3 Level 3
金鑰儲存CKA_LABEL only;私鑰永不離開 HSMHSM 物理保護
隨機數產生Luna HSM 內部的 hardware RNG(FIPS 通過)Luna 認證
軟體 PQCSLH-DSA / FN-DSA 走 RustCrypto/pqcryptoNIST 標準參考實作(待 CMVP 認證)
自我測試Luna 開機自檢;NG-CA 啟動時 connection probeHSM POST + 應用層健檢
稽核SOC2-ready audit.db,每次 sign / issue / revoke 寫入RFC 5424 等級結構化日誌
演算法支援全 FIPS 186-5 + FIPS 203/204;SLH-DSA 走軟體實作,FN-DSA 待 FIPS 206 定案NIST 最新標準

剩餘缺口(路線圖)

  • SLH-DSA / FN-DSA HSM 化:等待 Luna 後續韌體開放(一旦支援,現有 KeyMaterial enum 切換即可,API 不變)
  • CMVP 系統認證:Luna 已認證,但「NG-CA + Luna 整合」整體仍需走 ISO/IEC 17025 流程
  • FIPS 140-3 Level 4:物理破壞偵測,預計搭配 Luna 高階機型

私鑰生命週期:永不離開 HSM

舊版 NG-CA 計畫用 AES-256-GCM 加密私鑰後存進 SQLite,這個方案在 Phase B 完成後已完全廢棄。所有受 FIPS 規範的金鑰(RSA / ECC / ML-DSA / ML-KEM)走以下生命週期:

1. keygen   → Luna PKCS#11 C_GenerateKeyPair
              ├─ 私鑰留在 HSM partition,標記為 CKA_PRIVATE = true
              └─ 應用層只取得 CKA_LABEL(UTF-8 string)與公鑰位元組
2. 儲存     → ng-ca.db.cas.private_key_bytes = CKA_LABEL(不是私鑰!)
3. sign     → C_SignInit(CKA_LABEL) + C_Sign(message)
              簽章運算在 HSM 內完成;應用層只看到輸出 bytes
4. 銷毀     → C_DestroyObject(CKA_LABEL);DB 行同步刪除

KeyMaterial enum 把這層語意搬到型別系統 — 若呼叫端嘗試把 HsmLabel(...) 餵進 PKCS#8 解析器,會在編譯期被擋下。對 SLH-DSA / FN-DSA 等仍走軟體實作的演算法,私鑰才以 KeyMaterial::Software(...) 形式儲存(短期內仍考慮上層加密儲存)。

生產環境的 HSM 配置

HSM_MODULE_PATH=/usr/safenet/lunaclient/lib/libCryptoki2_64.so
HSM_SLOT_ID=0
HSM_PIN=<透過 systemd LoadCredential secret manager>
HSM_POOL_SIZE=16

HSM_POOL_SIZE 控制 connection pool 上限(預設 16),實測在 6 vCPU 機器上能達到 ~4000 sig/s(ECDSA P-256)。


測試與驗證

測試涵蓋率

整體統計(2026 年 5 月)71/71 測試通過(100%) — 從 v0.2 的 53/54 升級到 v1.0 後保持滿分

測試套件重點驗證位置
密碼學核心RSA / ECC / ML-DSA / SLH-DSA / FN-DSA / ML-KEM 完整 keygen-sign-verifybackend/tests/coverage_tests.rs
HSM 整合測試luna-cryptoki keygen、CKM_* mechanism、connection poolbackend/tests/hsm_*.rs
Hybrid 雙模式non-composite + composite 兩條路徑各自簽發/驗證backend/tests/hybrid_*.rs
API 端點CA CRUD、issue、revoke、verify-chainbackend/tests/api_tests.rs
ACME 協議完整 RFC 8555 流程 + JWS ES256 / RS256backend/tests/acme_*.rs
OCSP 增強Nonce 擴展、moka cache、next_updatebackend/tests/ocsp_enhanced_tests.rs
Delta CRLbase CRL number、增量產出backend/tests/delta_crl_tests.rs
路徑驗證多層 chain、pathLenConstraintbackend/tests/path_validation_tests.rs
名稱約束DNS / IP / Email permitted/excludedbackend/tests/name_constraints_tests.rs
負面測試偽造簽章、過期憑證、撤銷後存取backend/tests/negative_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. 雙重簽章:產生複合簽章(composite 模式為 mldsaSig || tradSig 串接)
  3. 驗證複合簽章格式:ML-DSA 段長度固定,切開後檢查 ECDSA 段長度是否落在合理範圍(~70-72 bytes DER)
  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 互通性驗證(3.5 / 4.0)

OpenSSL 是 PQC 憑證能否被真實世界接受的第一道關卡。它的 PQC 支援時間線:

版本發布與 PQC CA 相關的變化
3.5(LTS,支援至 2030-04)2025-04-08原生 ML-KEM / ML-DSA / SLH-DSA,不需 provider;TLS 預設群組改以 hybrid KEM 為先
3.62025-10CMS 支援 KEMRecipientInfo(RFC 9629)與 ML-KEM;FIPS provider 對 SLH-DSA 金鑰匯入做 PCT
4.02026-04-14新增 ML-DSA-MU(external-mu)摘要、LMS 簽章驗證與 SPKI 編解碼;CMS 支援無外部摘要的簽章方案(ML-DSA / Ed25519);TLS 預設 sigalg 把三個 ML-DSA 排在最前,並改用 IANA 正式名稱

撰稿時最新修補版為 4.0.2 與 3.6.4(皆 2026-08-25)。以下三組實測在 OpenSSL 3.5.5 上執行。

實測一:pure ML-DSA 憑證完全互通

openssl genpkey -algorithm ML-DSA-65 -out mldsa65-ca.key
openssl req -new -x509 -key mldsa65-ca.key -days 365 \
  -subj "/CN=NG-CA ML-DSA-65 Root" -out mldsa65-ca.pem
openssl verify -CAfile mldsa65-ca.pem mldsa65-ca.pem
# mldsa65-ca.pem: OK

ML-DSA 是 one-shot 簽章、不吃外部摘要,所以不能加 -sha256;OpenSSL 會直接把 signatureAlgorithm 寫成 ML-DSA-65(OID 2.16.840.1.101.3.4.3.18,依 RFC 9881)。

這張根憑證的 DER 是 5,532 bytes。同樣欄位的 ECDSA P-256 根憑證只要數百 bytes —— 憑證鏈膨脹不是理論問題,是量出來的。

實測二:non-composite hybrid 憑證驗得過,但 alt 簽章被忽略

把 ML-DSA-65 的 SPKI、演算法 OID 與 alt 簽章分別放進 2.5.29.72/73/74,主簽仍是 ECDSA P-256:

openssl verify -CAfile hybrid-ca.pem hybrid-ca.pem
# hybrid-ca.pem: OK

openssl x509 -in hybrid-ca.pem -noout -text
#   X509v3 Subject Alternative Public Key Info:
#       0...0...`.H.e...........
#   X509v3 Alternative Signature Algorithm:
#       0...`.H.e....
#   X509v3 Alternative Signature Value:
#       .......)....9..T.P.Tk...b6...

兩個結論:

  1. OpenSSL 認得這三個擴充的名稱(OID 表內已收錄),但只把內容當不透明位元組印出來 —— 它不解碼、不驗證 alt 簽章。
  2. openssl verify 會通過,是因為三個擴充標記為 non-critical,OpenSSL 依 RFC 5280 忽略未處理的非關鍵擴充。這正是 non-composite 模式「向下相容」的機制本體:舊驗證器不是懂得略過,而是根本沒看見。

代價要算清楚。那張憑證從 ECDSA 的數百 bytes 漲到 5,758 bytes,卻沒有為 OpenSSL 端帶來任何量子安全性 —— 多出來的 5kB 只是為了讓未來的驗證器有東西可驗。要真正拿到量子安全,驗證方必須自行實作 ITU-T X.509 (2019) §9.8 的流程:重組 TBS、剔除 2.5.29.74 後以 alt 公鑰驗章。NG-CA 的 Lane B 做的就是這件事。

實測三:composite 目前沒有 OpenSSL 生態可互通

composite 的處境正好相反 —— 格式乾淨,但沒人驗得動:

  • OpenSSL 沒有原生 composite ML-DSA:3.5.5 上 openssl list -signature-algorithms 沒有任何 1.3.6.1.5.5.7.6.*,4.0 的 CHANGES 也未新增(4.0 提到的 composite 指的是 RSA-SHA2-256 這類「演算法+摘要」組合,與 PQ composite 無關)。
  • oqs-provider 自 0.10.0 起移除了 composite 簽章支援(並在 OpenSSL ≥ 3.5 環境下停用自身的 ML-KEM / ML-DSA,以避免與原生實作衝突)。曾經能用 oqs-provider 驗 composite 憑證的做法,現在已經行不通。
  • 目前 composite 的主要互通對象是 Bouncy Castle(Java 與 C# 均已支援 IANA 正式 OID)以及建構於其上的 EJBCA。

把三組實測攤成一張矩陣,落差的位置就很清楚:

PQC 憑證互通矩陣:四種格式對三類驗證端的驗證結果

最右欄與最左欄的對比是整篇文章的重點。務實的結論是:今天要跟 OpenSSL 世界互通,pure ML-DSA 比任何 hybrid 模式都順。hybrid 的價值在遷移期的風險管理,不在互通性。

composite 對 HSM 的隱性約束

draft-19 的序列化規定會直接反噬 HSM 設計。composite 私鑰定義為 ML-DSA 的 32-byte seed 與傳統私鑰的串接,而且規範明文禁止在 composite 與 non-composite 之間、或兩個 composite 之間重用任何組件金鑰材料。兩個後果:

  1. 若 HSM 只保存展開後的 ML-DSA 私鑰、不支援 seed 形式的產生與匯出,composite 金鑰就無法用標準格式備份或遷移到別的實作。
  2. 「同一把 ML-DSA 金鑰同時服務兩種 hybrid 模式」這種省事做法不合規,兩種模式必須各自 keygen、各自持有獨立的 HSM label。

這類約束在草案文字裡只佔幾行,但決定了 HSM 整合能不能做。導入 composite 前,先確認韌體的 CKM_ML_DSA_KEY_PAIR_GEN 是否支援 seed 語意。

CSR 與憑證簽發互通

一般的 ACME / CSR 流程不需要任何特殊處理:

# 用 OpenSSL 產生 ML-DSA-65 的 CSR
openssl genpkey -algorithm ML-DSA-65 -out ee.key
openssl req -new -key ee.key -subj "/CN=pqc.example.tw" -out ee.csr

# 送進 NG-CA 的 POST /api/v1/ca/{ca_id}/issue,取回 certificate_pem 後驗鏈
openssl verify -CAfile ca.pem ee.pem

回歸測試腳本(scripts/verify_openssl.sh)把上述三組實測固定下來:取得 Root CA 憑證、以 openssl x509 檢查結構、以 openssl verify 驗自簽與憑證鏈、產生 CSR 並簽發、確認 alt 擴充存在且不影響驗證結果。


未來發展

SLH-DSA / FN-DSA HSM 化

目標時程:跟隨 Luna 韌體 roadmap(Thales 預計 2026-2027 上線)

主要工作項目

  1. 等待 Luna 釋出 CKM_SLH_DSA_*CKM_FN_DSA_* mechanism
  2. luna-cryptoki crate 補上對應 wrapper
  3. SlhDsaProvider / FnDsaProvider 改為 dispatch(軟體 fallback + HSM 優先)
  4. 應用層完全無感(KeyMaterial::SoftwareHsmLabel 自動切換)

CA/B Forum TLS BR PQC 對齊

現況(2026-09):CA/B Forum 尚無通過的 Baseline Requirements ballot 允許 ML-DSA 用於公開信任的 TLS 憑證。TLS 層的簽章協商規範(draft-ietf-tls-mldsa)已獲 IESG 核准,但憑證政策這一端還沒動。

關鍵未定點:

  • 公開 TLS 簽發是否允許 hybrid(vs. pure PQC)
  • ML-DSA-44 vs ML-DSA-65 vs ML-DSA-87 的選用基準
  • 憑證鏈總大小上限(影響 OCSP stapling 必要性)
  • Merkle Tree Certificates 會不會繞過 X.509 路線,讓 composite 在公開 PKI 失去舞台

NG-CA 準備:composite OID 已實作完成,但暫不開放公開 TLS 簽發;私有 CA、企業 mTLS 與 S/MIME 場景已可用。

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. 兩種 hybrid 模式並存:對齊 RFC 9794 — Algorithm::Hybrid(non-composite,向下相容)+ Algorithm::HybridDualSignature(composite,draft-ietf-lamps-pq-composite-sigs-19,已進 RFC Editor queue)
  2. 17 個演算法、5 大類別:RSA / ECC / ML-DSA / SLH-DSA / FN-DSA / ML-KEM 全套,從 FIPS 186-5 到 FIPS 203/204/205(FN-DSA 所依據的 FIPS 206 仍未定案);Hybrid 兩種模式是組合方式,不另計為演算法
  3. Luna HSM 託管金鑰:應用層只做編排與 ASN.1 組裝,密碼學運算交給 Luna FIPS 140-3 Level 3 硬體,私鑰永不離開 HSM
  4. 企業級功能完備:Prometheus 監控(25+ 指標)、Name Constraints、Delta CRL、verify-chain API、moka cache
  5. ACME v2 + JWS:RFC 8555 完整流程,ES256 / RS256 簽章驗證
  6. 台灣在地化:身份證 / 統編 / 組織機構代碼驗證
  7. 互通性分場景:pure ML-DSA 與 OpenSSL 3.5+ 原生互通最順;non-composite 能被 OpenSSL 驗過但 alt 簽章被忽略;composite 目前只能與 Bouncy Castle 生態互通
  8. 生產就緒:71/71 測試通過(100%)、v1.0 Released

專案資源

核心標準

實作與互通參考

部署參考

雲杉相關文章


本文最初發表於 2026-02-04,2026-09-11 再次更新

  • 新增 OpenSSL 3.5 / 4.0 互通實測(pure ML-DSA、non-composite hybrid、composite 三種情境的實際結果與憑證尺寸),並以互通矩陣圖取代原本的場景表格與首圖
  • 新增「標準狀態一覽」:RFC 9881 / 9882 / 9909 / 9935 已發布,composite-sigs draft-19 進入 RFC Editor queue,FIPS 206 仍未出公開草案
  • 修正 composite 編碼描述:draft-19 改為兩段簽章原始串接,早期草案的 SEQUENCE OF BIT STRING 已移除;補上 Prefix / Label 的正確角色
  • 修正 alt 擴充的規範來源為 ITU-T X.509 (2019) §9.8(對應 IETF 草案已終止)
  • 更新瀏覽器與公開 PKI 現況;淡化實作語言的篇幅,改以信任邊界說明架構
  • 重畫架構、hybrid 模式、驗證路徑與 ACME 四張圖,統一為單色 teal 色系;原圖的多色分類已與內容脫節
  • 演算法矩陣由圖片改為表格,並修正 SLH-DSA-SHA2-192s / 256s 的 OID(原標 .26 / .32,應為 .22 / .24

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