前言
PKI 基礎設施的量子威脅
公開金鑰基礎建設(Public Key Infrastructure, PKI)是現代網路安全的基石,支撐著:
- HTTPS 加密通訊(全球 95%+ 網站)
- 程式碼簽章(軟體發布、App Store、Docker 映像)
- 電子郵件加密(S/MIME)
- VPN 與企業身份認證(IPsec、802.1X)
- 物聯網裝置認證(mTLS、OTA 更新)
傳統 PKI 完全依賴 RSA 與 ECDSA 簽章演算法,這些演算法在量子電腦面前將完全失效:
| 演算法 | 目前安全性 | 量子電腦攻擊 | 破解時間估算 |
|---|---|---|---|
| RSA-2048 | 112-bit 安全 | Shor’s Algorithm | ~8 小時(大型量子電腦) |
| RSA-4096 | 140-bit 安全 | Shor’s Algorithm | ~1 天 |
| ECDSA P-256 | 128-bit 安全 | Shor’s Algorithm | ~數小時 |
| ECDSA P-384 | 192-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 配置 | 客戶端要求 |
|---|---|---|---|
| 階段 1 | 2026-2028 | 混合憑證(ECDSA + ML-DSA) | 只驗證 ECDSA |
| 階段 2 | 2028-2030 | 混合憑證 | 新客戶端開始驗證雙重簽章 |
| 階段 3 | 2030-2032 | 混合憑證 | 強制雙重驗證(舊客戶端淘汰) |
| 階段 4 | 2032+ | Pure PQC(僅 ML-DSA) | 只驗證 ML-DSA |
瀏覽器支援現況
Chrome 後量子密碼學部署進度:
TLS 金鑰交換(已部署)
Google Chrome 已經在 TLS 層面部署混合後量子金鑰交換,保護網路流量免受「現在收集,未來解密」(Harvest Now, Decrypt Later) 攻擊:
| Chrome 版本 | 發布時間 | 支援演算法 | 狀態 |
|---|---|---|---|
| Chrome 116 | 2023年8月 | X25519Kyber768 | ✅ 首次部署 |
| Chrome 131 | 2024年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% 伺服器受影響
- Shellshock、POODLE、DROWN 等
- 每年平均 15+ 個重大漏洞
Pure Rust 優勢:
| 特性 | C/OpenSSL | Rust |
|---|---|---|
| 記憶體安全 | 需手動管理 | 編譯期保證 |
| 平行安全 | 手動同步 | 型別系統保證 |
| 空指標 | Segfault 風險 | 編譯期檢查(Option |
| 緩衝區溢位 | 常見漏洞 | 自動邊界檢查 |
| 釋放後使用 | Use-after-free | 生命週期系統防止 |
| 效能 | 極快 | 相同等級 |
NG-CA 技術棧:
NG-CA 架構設計
系統整體架構
模組架構概要
核心模組:
- 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 與憑證資料:
| 資料表 | 關鍵欄位 | 說明 |
|---|---|---|
| cas | id, name, algorithm | CA 實體,支援 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_len | CA 階層架構(Root/Intermediate) | |
| default_days, default_key_usage | RA 策略配置 | |
| certificates | serial_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_logs | id, 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) | 2 | 128-bit | 1,312 B | 2,544 B | 2,420 B |
| ML-DSA-65 (Dilithium3) | 3 | 192-bit | 1,952 B | 4,000 B | 3,293 B |
| ML-DSA-87 (Dilithium5) | 5 | 256-bit | 2,592 B | 5,632 B | 4,595 B |
PQC 密碼學運算邏輯:
金鑰產生流程:
- 根據演算法類型(ML-DSA-44/65/87)呼叫對應的 Dilithium 金鑰產生函數
- 公鑰編碼為標準 SPKI (SubjectPublicKeyInfo) 格式:
- 包含 AlgorithmIdentifier(ML-DSA OID)
- 包含 BitString(公鑰資料)
- PEM 標頭:
-----BEGIN PUBLIC KEY-----(標準 PKCS#8 格式)
- 私鑰以二進制 bytes 形式儲存(需加密後存入資料庫)
簽章流程:
- 從資料庫讀取私鑰 bytes 並反序列化為 Dilithium SecretKey
- 使用對應演算法的
sign()函數產生簽章 - 回傳 SignedMessage bytes
驗證流程:
- 從 PEM 格式解析公鑰(SPKI 格式)
- 從 AlgorithmIdentifier 提取 OID,自動識別演算法:
2.16.840.1.101.3.4.3.17→ ML-DSA-442.16.840.1.101.3.4.3.18→ ML-DSA-652.16.840.1.101.3.4.3.19→ ML-DSA-87
- 從 BitString 提取公鑰資料
- 使用對應演算法的
open()函數驗證簽章 - 回傳驗證結果(true/false)
混合憑證 (Hybrid Certificates) 深度解析
混合密鑰對產生
混合金鑰結構:
- HybridKeyPair:包含兩組獨立金鑰對
ecc_key:傳統 ECC P-256 金鑰對pqc_key:後量子 ML-DSA-65 金鑰對
產生流程:
- 呼叫
EccProvider::generate()產生 ECC P-256 金鑰對 - 呼叫
PqcProvider::generate()產生 ML-DSA-65 金鑰對 - 組合成
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’ 標記
雙重簽名提供程序
複合簽章格式設計:
範例(ML-DSA-65 + ECC P-256):
- 總大小: 4 + 64 + 3,293 = 3,361 bytes
雙重簽章運算邏輯:
簽章流程:
- 使用 ECC Provider 對資料產生 ECC P-256 簽章
- 使用 PQC Provider 對資料產生 ML-DSA-65 簽章
- 組合複合簽章:
- 寫入 ECC 簽章長度(4 bytes, big-endian u32)
- 寫入 ECC 簽章內容
- 寫入 PQC 簽章內容
驗證流程:
- 解析複合簽章:
- 讀取前 4 bytes 取得 ECC 簽章長度
- 根據長度切分 ECC 與 PQC 簽章
- 驗證 ECC 簽章(使用 ECC 公鑰)
- 驗證 PQC 簽章(使用 ML-DSA 公鑰)
- 雙重驗證:兩個簽章都必須有效才通過
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 Info2.5.29.73→ Alt Signature Algorithm2.5.29.74→ Alt Signature Value2.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
建構流程:
- 準備 TBS Certificate:序列化 TbsCertificate 為 DER 格式
- 產生雙重簽章:呼叫 DualSignatureProvider 產生複合簽章
- 解析簽章:從複合簽章中分離 ECC 與 PQC 簽章
- 添加三個 X.509 延伸:
Subject Alt Public Key Info:儲存 ML-DSA-65 公鑰Alt Signature Algorithm:標記 ML-DSA-65 演算法 OIDAlt Signature Value:儲存 PQC 簽章
- 組合憑證:
- 主
signatureAlgorithm使用 ECDSA with SHA-256 - 主
signature使用 ECC 簽章 - Extensions 包含 PQC 公鑰與簽章
- 主
憑證驗證流程:
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"
}
後端處理流程:
-
金鑰對產生:
- 根據
algorithm參數選擇對應的 Provider(Hybrid/MlDsa65/EccP256/Rsa2048) - 呼叫對應 Provider 的
generate()方法產生金鑰對 - 包裝成
KeyPairEnum統一介面
- 根據
-
自簽憑證建構:
- 產生隨機序號(20 bytes)
- 設定 Subject/Issuer(自簽相同)
- 計算有效期(
default_days天數) - 添加 BasicConstraints 延伸(
ca與path_len) - 添加 KeyUsage 延伸(CA 需
digitalSignature, keyCertSign, cRLSign) - 若為混合憑證,呼叫
build_hybrid_certificate()添加 PQC 延伸
-
資料庫儲存:
- 插入
cas表,儲存金鑰對(傳統與 PQC) - 儲存配置(
is_ca,path_len,default_days, Key Usage) - 取得
ca_id(auto-increment)
- 插入
-
稽核日誌:
- 記錄
create_ca操作 - 包含 CA 名稱、演算法、操作結果
- 記錄
-
回傳結果:
ca_id、CA 名稱、憑證 PEM、演算法類型
自簽憑證建構邏輯:
- 已整合至上述「後端處理流程」的第 2 步驟
Intermediate CA 支援
CA 階層架構(透過 parent_ca_id 與 path_len 控制):
| CA 層級 | parent_ca_id | path_len | 說明 |
|---|---|---|---|
| Root CA | NULL | 2 | 允許建立 2 層子 CA |
| Intermediate CA (L1) | 1 | 1 | 允許建立 1 層子 CA |
| Intermediate CA (L2) | 2 | 0 | 無法再建立子 CA(終端 CA) |
憑證鏈驗證邏輯:
- 從目標憑證開始,讀取對應的 CA 資訊
- 使用 CA 公鑰驗證憑證簽章
- 若
parent_ca_id為 NULL,表示到達 Root CA,驗證完成 - 若有
parent_ca_id,讀取父 CA 憑證,重複步驟 2-3 - 迴圈驗證整條憑證鏈,任一環節失敗則回傳 false
CSR 簽發流程
API 端點: POST /api/v1/ca/{ca_id}/issue
處理流程:
-
解析與驗證 CSR:
- 從 PEM 格式解析 CSR
- 驗證 CSR 內建簽章(確保 CSR 未被竄改)
-
讀取 CA 配置:
- 從資料庫讀取 CA 資訊(包含金鑰、策略設定)
-
應用驗證規則(可選):
- 若 CA 設定了
csr_validation_regex,驗證 Subject DN - 支援台灣身份證號/統一編號驗證(詳見下節)
- 若 CA 設定了
-
產生憑證:
- 產生隨機序號(20 bytes)
- 從 CSR 提取公鑰與 Subject
- 使用 CA 私鑰簽署憑證
- 應用 CA 預設的 Key Usage 與有效期
-
儲存與稽核:
- 插入
certificates表(狀態為 ‘Good’) - 記錄稽核日誌(
issue_cert操作) - 回傳序號與憑證 PEM
- 插入
憑證撤銷與 CRL
撤銷憑證流程:
- 更新
certificates表:設定status = 'Revoked',記錄revoked_at時間戳記 - 檢查影響行數,若為 0 則回傳憑證不存在錯誤
- 記錄稽核日誌(
revoke_cert操作) - 回傳撤銷成功訊息
CRL 產生邏輯:
- 讀取 CA 資訊與私鑰
- 查詢該 CA 所有已撤銷憑證(
status = 'Revoked') - 使用
x509-certcrate 建構 CertificateList:- 設定 CRL 簽發者(CA 名稱)
- 設定 CRL 有效期(預設 7 天)
- 逐一添加 RevokedCert 項目(序號 + 撤銷時間)
- 使用 CA 私鑰簽署 CRL
- 轉換為 PEM 格式回傳
ACME v2 協議整合
ACME 協議概述
ACME (Automatic Certificate Management Environment) 是由 Let’s Encrypt 推動的自動化憑證管理協議,已標準化為 RFC 8555。
ACME 工作流程:
支援的 ACME 端點
實作狀態(backend/src/acme/routes.rs):
| 端點 | 方法 | 功能 | 狀態 |
|---|---|---|---|
/acme/directory | GET | 取得 ACME 目錄 | 已完成 |
/acme/new-nonce | HEAD/GET | 取得 nonce | 已完成 |
/acme/new-account | POST | 註冊帳號 | 已完成 |
/acme/acct/{id} | POST-as-GET | 查詢帳號資訊 | 已完成 |
/acme/new-order | POST | 建立訂單 | 已完成 |
/acme/authz/{id} | POST-as-GET | 查詢授權狀態 | 已完成 |
/acme/chall/{id} | POST | 回應 Challenge | 部分完成 |
/acme/order/{id}/finalize | POST | 完成訂單(提交 CSR) | 規劃中 |
/acme/cert/{serial} | POST-as-GET | 下載憑證 | 已完成 |
JWS 簽名驗證
ACME 要求所有請求都使用 JWS (JSON Web Signature) 簽名(RFC 7515):
支援的演算法:
| 演算法 | 類型 | 金鑰類型 | 狀態 |
|---|---|---|---|
| ES256 | ECDSA with SHA-256 | P-256 | 已完成 |
| RS256 | RSA PKCS#1 v1.5 with SHA-256 | RSA-2048+ | 已完成 |
| EdDSA | Ed25519 | Ed25519 | 規劃中 |
JWS 驗證邏輯:
資料結構:
JwsHeader:包含alg(演算法)、nonce(防重放)、url(請求 URL)、kid(帳號 ID)、jwk(公鑰)Jwk(JSON Web Key):包含kty(金鑰類型)、EC 參數(crv,x,y)或 RSA 參數(n,e)
驗證流程:
-
解析 JWS:
- 格式為
header.payload.signature(三段 Base64 URL編碼) - 檢查格式正確性
- 格式為
-
驗證安全參數:
- 解碼 header 並檢查
nonce(防重放攻擊) - 檢查
url是否匹配請求路徑
- 解碼 header 並檢查
-
簽章驗證(依演算法):
- ES256(ECDSA P-256):
- 從 JWK 解析 P-256 公鑰(
x,y座標) - 使用
p256crate 驗證 ECDSA 簽章
- 從 JWK 解析 P-256 公鑰(
- RS256(RSA PKCS#1 v1.5):
- 從 JWK 解析 RSA 公鑰(
nmodulus,eexponent) - 使用
rsacrate 驗證 PKCS#1 v1.5 簽章
- 從 JWK 解析 RSA 公鑰(
- ES256(ECDSA P-256):
-
解碼 Payload:
- Base64 URL 解碼 payload
- 反序列化為 JSON 結構
ACME 資料庫架構
| 資料表 | 關鍵欄位 | 說明 |
|---|---|---|
| acme_nonces | nonce, created_at, used | 防重放攻擊(nonce 一次性使用) |
| acme_accounts | id, account_key_jwk, contact, status | ACME 帳號(儲存 JWK 公鑰與聯絡方式) |
| acme_orders | id, account_id, status, identifiers | 憑證訂單(狀態:pending/ready/processing/valid/invalid) |
| certificate_serial, expires | 簽發後的憑證序號與訂單過期時間 | |
| acme_authorizations | id, order_id, identifier, status | 域名授權(每個 identifier 一筆記錄) |
| challenge_type, challenge_token | Challenge 類型(http-01/dns-01)與驗證 token | |
| challenge_status, validated_at | Challenge 狀態與驗證時間 |
台灣特色驗證
身份證字號驗證
格式:1 個英文字母 + 9 個數字(範例:A123456789)
驗證邏輯(依內政部規定):
- 格式檢查:長度 10 碼,首碼英文,後 9 碼數字
- 英文字母轉數字:A=10, B=11, …, Z=35(I=34, O=35 為特殊對應)
- 拆分英文數值:轉換後的數字拆成十位數(d1)與個位數(d2)
- 權重計算:
- 權重序列:
[1, 9, 8, 7, 6, 5, 4, 3, 2, 1] - 加權總和:
d1×1 + d2×9 + digit[0]×8 + ... + digit[8]×1
- 權重序列:
- 檢查碼驗證:加權總和
% 10 == 0
測試案例:A123456789(✅)、F131104093(✅)、A123456788(❌ 檢查碼錯誤)
統一編號驗證
格式:8 個數字(範例:12345678)
驗證邏輯(依財政部規定):
- 格式檢查:長度 8 碼,全數字
- 權重計算:
- 權重序列:
[1, 2, 1, 2, 1, 2, 4, 1] - 每個
digit[i] × weight[i]的乘積拆分為十位數與個位數後加總
- 權重序列:
- 特殊規則:
- 若第 7 碼為 7,則
sum % 10 == 0或(sum + 1) % 10 == 0 - 其他情況:
sum % 10 == 0
- 若第 7 碼為 7,則
CSR Subject 驗證整合
驗證流程:
- 從 CSR 的 Subject DN 中解析 CN (Common Name)
- 根據 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 儀表板

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

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

顯示資訊:
- 憑證 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)]
加密流程:
- 從環境變數讀取主金鑰(hex 解碼)
- 產生隨機 nonce(使用
OsRng) - 使用 AES-256-GCM 加密私鑰
- 組合 nonce + ciphertext 並儲存到資料庫
解密流程:
- 從資料庫讀取加密資料
- 分離 nonce(前 12 bytes)與 ciphertext
- 使用主金鑰與 nonce 解密
- 回傳明文私鑰用於簽章操作
測試與驗證
測試涵蓋率
整體統計:53/54 測試通過 (98.1%)
| 測試套件 | 測試數 | 通過率 | 位置 |
|---|---|---|---|
| 密碼學核心測試 | 10 | 100% | backend/tests/coverage_tests.rs |
| API 端點測試 | 15 | 100% | backend/tests/api_tests.rs |
| ACME 協議測試 | 8 | 100% | backend/tests/acme_tests.rs |
| JWS 簽名測試 | 6 | 100% | backend/tests/acme_jws_tests.rs |
| 負面測試 | 7 | 100% | backend/tests/negative_tests.rs |
| 非混合 CA 測試 | 7 | 85.7% | backend/tests/non_hybrid_ca_tests.rs |
密碼學核心測試
測試案例涵蓋:
ML-DSA-65 完整工作流程測試 (test_ml_dsa_65_full_workflow):
- 金鑰對產生:驗證公鑰 PEM 與私鑰 bytes 非空,私鑰大小為 4000 bytes
- 簽章產生:驗證簽章大小為 3293 bytes(ML-DSA-65 規格)
- 簽章驗證:驗證合法簽章通過
- 負面測試:驗證偽造訊息的簽章驗證失敗
混合雙重簽章測試 (test_hybrid_dual_signature):
- 混合金鑰對產生:包含 ECC 與 ML-DSA 兩組金鑰
- 雙重簽章:產生複合簽章(格式:[ecc_len][ecc_sig][pqc_sig])
- 驗證複合簽章格式:檢查 ECC 簽章長度是否合理(0-200 bytes)
- 雙重驗證:驗證兩個簽章都有效
- 負面測試:篡改任一簽章後驗證應失敗
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):
驗證步驟:
- 取得 Root CA 憑證:從 API 下載 CA 憑證(
/api/v1/ca/1) - 驗證憑證格式:使用
openssl x509檢查憑證結構 - 驗證自簽憑證:使用
openssl verify驗證 Root CA 自簽有效性 - 產生 CSR:使用
openssl req產生測試用 CSR - 使用 NG-CA 簽發憑證:呼叫 API 端點(
POST /api/v1/ca/1/issue)簽發憑證 - 驗證憑證鏈:使用 OpenSSL 驗證憑證鏈完整性
- 檢查混合憑證延伸:確認 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 個月
主要工作項目:
- 私鑰加密儲存(AES-256-GCM)
- POST 自我測試(開機時驗證密碼學模組)
- 整合 aws-lc-rs(FIPS 認證模組)
- 完整稽核追蹤
- 文件與認證申請
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):
驗證流程:
- 提取 API Key:從請求標頭
X-API-Key取得金鑰 - 查詢租戶:使用 API Key 從
tenants表查詢對應的租戶 - 權限驗證:若 API Key 不存在或無效,回傳
401 Unauthorized - 注入租戶 ID:將租戶 ID 注入請求延伸(
req.extensions_mut()) - 繼續處理:將請求傳遞給下一個 middleware 或 handler
資料隔離:所有 CA 與憑證查詢自動過濾 tenant_id,確保租戶間資料完全隔離
結語與資源
關鍵要點
- 混合憑證 = 平滑遷移路徑:同時支援舊客戶端(ECDSA)與新客戶端(雙重驗證)
- Pure Rust = 記憶體安全:擺脫 OpenSSL 的漏洞風險
- ACME v2 = 自動化:Let’s Encrypt 相容,零人工干預
- 台灣在地化:身份證/統編驗證,符合本地需求
- Vue 3 管理介面:直觀易用,降低管理成本
專案資源
參考文件:
- NIST Post-Quantum Cryptography
- FIPS 204 (ML-DSA)
- RFC 8555 (ACME v2)
- RFC 6960 (OCSP)
- IETF Draft: Composite Signatures
延伸閱讀:
本文完成於 2026-02-03,基於 NG-CA v0.1.0、NIST FIPS 204 標準、RFC 8555 (ACME v2) 撰寫。
如有任何問題或建議,歡迎透過聯絡我們 頁面與我們聯繫。