# 第 10 篇:X.509 憑證格式 - 數位世界的身份證 ## 前言:憑證到底是什麼? 還記得我們在系列二學到的「信任鏈」嗎?當時我們說:裝置有一組公私鑰對,但伺服器怎麼知道這個公鑰真的屬於這個裝置?答案就是:**數位憑證**。 在第 6 篇,我們看到 CBOR 可以包裝資料,而在實際應用中(例如 App Attest),CBOR 裡面會有個欄位叫 `x5c`,裡面裝的就是「憑證鏈」。 這些憑證用 **X.509 格式**儲存,它實現了我們之前學過的所有概念: - 用 **數位簽章**來保證真實性 - 實現了 **信任鏈**的架構 - 包含 **公鑰**和身份資訊 本文將用最簡單的方式解釋:憑證是什麼、為什麼看起來像亂碼、以及如何理解憑證的結構。 ## 從現實世界理解:身份證的設計 ### 🪪 實體身份證的結構 想想你的身份證,上面有什麼資訊? ``` 身份證 ├── 照片(證明是你本人) ├── 姓名 ├── 身份證字號 ├── 出生日期 ├── 發證日期 ├── 有效期限 └── 發證機關的印章 ``` **為什麼需要這些資訊?** - ✅ 照片:確認是你本人 - ✅ 姓名、字號:識別你是誰 - ✅ 有效期限:過期了就要換新的 - ✅ 發證機關印章:證明這張身份證是真的 ### 💳 數位憑證的結構 X.509 數位憑證就像數位世界的身份證: ``` X.509 憑證 ├── 公鑰(相當於照片) ├── 持有者資訊(誰的憑證) ├── 序號(憑證編號) ├── 有效期限(什麼時候過期) ├── 發行者資訊(誰發的憑證) └── 數位簽章(CA 的印章) ``` **核心概念:** - 📸 **公鑰** = 你的照片(證明身份的關鍵) - 📝 **持有者資訊** = 你的姓名(這個憑證屬於誰) - 🏢 **發行者** = 發證機關(誰發的) - ✍️ **數位簽章** = 政府印章(證明憑證真實性) ## X.509 憑證的三層結構 ### 📦 憑證的外層包裝 X.509 憑證分成三個主要部分: ``` X.509 Certificate │ ├── tbsCertificate(憑證本體 - To Be Signed) │ └── 所有要被簽章的內容都在這裡 │ ├── signatureAlgorithm(簽章演算法) │ └── 說明用什麼演算法簽章 │ └── signatureValue(簽章值) └── CA 用私鑰產生的數位簽章 ``` **為什麼這樣設計?** ``` 類比:郵寄重要文件 📄 文件本體(tbsCertificate) ├── 包含所有重要資訊 └── 這是要被保護的內容 🖊️ 簽名方式說明(signatureAlgorithm) └── 「我用鋼筆簽的」vs「我用印章蓋的」 ✍️ 實際簽名(signatureValue) └── 你的親筆簽名或印章 ``` **驗證時的流程:** 1. 取出憑證本體(tbsCertificate) 2. 計算它的 hash 值 3. 用 CA 的公鑰驗證簽章值(signatureValue) 4. 如果驗證通過 → 憑證內容沒有被竄改 ✅ ## 憑證本體(tbsCertificate)的欄位 ### 📋 完整的欄位清單 ``` tbsCertificate ├── version(版本) ├── serialNumber(序號) ├── signature(簽章演算法) ├── issuer(發行者) ├── validity(有效期限) ├── subject(持有者) ├── subjectPublicKeyInfo(公鑰資訊) └── extensions(擴展欄位)- v3 才有 ``` 讓我們逐一理解每個欄位的作用: ### 1. Version(版本) ``` version: 3 種版本 v1 (0) - 1988 年 ├── 最基本的欄位 └── 已過時 v2 (1) - 1993 年 ├── 增加唯一識別碼欄位 └── 很少使用 v3 (2) - 1996 年 ⭐ 現在都用這個 ├── 支援 Extensions(擴展欄位) └── 功能最完整 ``` **為什麼重要?** - Extensions 讓憑證可以包含額外資訊(例如:用途限制、App ID 等) - 現代系統基本上都用 v3 ### 2. Serial Number(序號) ``` serialNumber: 每張憑證的唯一編號 例如: ├── 0x1a2b3c4d5e6f ├── 0x1234567890abcdef └── 由 CA 分配,確保唯一 ``` **用途:** - 識別特定的憑證 - 撤銷憑證時用序號指定 - 類似身份證字號 ### 3. Signature(簽章演算法) ``` signature: 說明用什麼演算法簽章 常見演算法: ├── ecdsa-with-SHA256(橢圓曲線 + SHA-256) ├── sha256WithRSAEncryption(RSA + SHA-256) └── sha384WithRSAEncryption(RSA + SHA-384) ``` **為什麼需要?** - 驗證簽章時需要知道用什麼演算法 - 不同演算法有不同的驗證流程 ### 4. Issuer(發行者) ``` issuer: 誰簽發這張憑證 格式:Distinguished Name (DN) ├── CN (Common Name): 主要名稱 ├── O (Organization): 組織 ├── OU (Organizational Unit): 部門 ├── C (Country): 國家 └── 其他欄位... 範例: CN=Apple App Attestation CA 1 O=Apple Inc. C=US ``` **為什麼重要?** - 建立信任鏈的關鍵 - 驗證時需要找到對應的 CA 憑證 ### 5. Validity(有效期限) ``` validity: 憑證的有效時間範圍 ├── notBefore: 開始時間 └── notAfter: 結束時間 範例: notBefore: 2024-01-15 00:00:00 UTC notAfter: 2025-01-15 23:59:59 UTC ``` **為什麼需要有效期限?** ``` 假設憑證永久有效: 1. 私鑰洩漏了 2. 駭客可以永遠使用這個憑證 3. 無法有效撤銷 有了有效期限: 1. 定期更換憑證 2. 即使洩漏,影響時間有限 3. 過期自動失效 ``` ### 6. Subject(持有者) ``` subject: 這張憑證屬於誰 格式:Distinguished Name (DN)(同 Issuer) 範例: 一般網站憑證: CN=www.google.com O=Google LLC C=US App Attest 憑證: CN=6d2ac4845f13...(Key ID) ``` **與 Issuer 的關係:** ``` 憑證鏈範例: 根憑證: subject: CN=Apple Root CA issuer: CN=Apple Root CA(自己簽自己) 中繼憑證: subject: CN=Apple App Attestation CA 1 issuer: CN=Apple Root CA 葉憑證: subject: CN=6d2ac4845f13... issuer: CN=Apple App Attestation CA 1 ``` **驗證邏輯:** - 葉憑證的 `issuer` 應該等於中繼憑證的 `subject` - 中繼憑證的 `issuer` 應該等於根憑證的 `subject` ### 7. Subject Public Key Info(公鑰資訊 SPKI) ``` subjectPublicKeyInfo: 憑證的核心價值 ├── algorithm(演算法) │ ├── 演算法類型(EC / RSA) │ └── 參數(P-256 / P-384 等) └── subjectPublicKey(公鑰數據) └── 實際的公鑰 bits ``` **這是憑證存在的核心理由!** ``` 憑證的目的就是: 「證明這個公鑰是真的」 流程: 1. 裝置產生金鑰對 2. 把公鑰給 CA 3. CA 驗證後,把公鑰包在憑證裡 4. CA 用自己的私鑰簽章整張憑證 5. 任何人都可以: ├── 看到公鑰(公開的) ├── 驗證 CA 簽章(確認憑證真實性) └── 信任這個公鑰 ``` **公鑰資訊範例:** ``` algorithm: id-ecPublicKey parameters: prime256v1 (P-256) publicKey: 04 a1 b2 c3 d4 e5 f6 ...(65 bytes) └── 04 表示未壓縮格式 └── 接下來是 X 和 Y 座標各 32 bytes ``` ### 8. Extensions(擴展欄位) ``` extensions: v3 才有,提供額外功能 標準擴展: ├── basicConstraints: 是否為 CA 憑證 ├── keyUsage: 金鑰用途 ├── extKeyUsage: 延伸用途 ├── subjectAltName: 替代名稱 └── ... 自訂擴展: └── 各廠商可定義專屬 OID ``` #### 常見擴展說明 **Basic Constraints(基本限制)** ``` 用途:標示這是否為 CA 憑證 範例: ├── cA: TRUE → 這是 CA 憑證,可以簽發其他憑證 └── cA: FALSE → 這是終端憑證,不能簽發憑證 ``` **Key Usage(金鑰用途)** ``` 用途:限制公鑰可以做什麼 範例: ├── digitalSignature: 可用於數位簽章 ├── keyEncipherment: 可用於金鑰加密 ├── keyCertSign: 可用於簽發憑證 └── cRLSign: 可用於簽發撤銷清單 ``` **Extended Key Usage(延伸金鑰用途)** ``` 用途:更具體的用途限制 範例: ├── serverAuth: TLS 伺服器認證 ├── clientAuth: TLS 客戶端認證 ├── codeSigning: 程式碼簽章 └── emailProtection: 電子郵件保護 ``` ## 憑證鏈在 X.509 中的實現 在系列二第4篇,我們學過信任鏈的概念:**根 CA → 中繼 CA → 終端憑證**。現在我們來看這個概念如何透過 X.509 憑證的欄位實現。 ### 🔗 憑證鏈的欄位關係 憑證鏈的關鍵在於 `subject` 和 `issuer` 欄位的配對: ``` 根憑證: subject: CN=Apple Root CA issuer: CN=Apple Root CA ← 自己簽自己 basicConstraints: cA=TRUE ← 可以簽發其他憑證 中繼憑證: subject: CN=Apple App Attestation CA 1 issuer: CN=Apple Root CA ← 由根憑證簽發 basicConstraints: cA=TRUE ← 可以簽發憑證 葉憑證: subject: CN=6d2ac4845f13... issuer: CN=Apple App Attestation CA 1 ← 由中繼憑證簽發 basicConstraints: cA=FALSE ← 不能簽發憑證 ``` ### 🔍 如何驗證憑證鏈? 利用 X.509 欄位進行驗證: **步驟 1:配對 subject 和 issuer** ``` 葉憑證的 issuer == 中繼憑證的 subject ✅ 中繼憑證的 issuer == 根憑證的 subject ✅ ``` **步驟 2:驗證數位簽章** ``` 用中繼憑證的 publicKey 驗證葉憑證的 signature ✅ 用根憑證的 publicKey 驗證中繼憑證的 signature ✅ ``` **步驟 3:檢查 basicConstraints** ``` 中繼憑證的 cA=TRUE(可以簽發憑證)✅ 葉憑證的 cA=FALSE(不能簽發憑證)✅ ``` **步驟 4:檢查有效期限** ``` 所有憑證的 validity 都在有效範圍內 ✅ ``` ### 📋 實際範例 當你收到一個憑證鏈 `[cert0, cert1]`: ```python # 1. 檢查鏈的連續性 assert cert0.issuer == cert1.subject assert cert1.issuer == trusted_root.subject # 2. 驗證簽章 verify_signature(cert0, cert1.public_key) # 用上一層的公鑰驗證 verify_signature(cert1, trusted_root.public_key) # 3. 檢查約束 assert cert1.extensions.basicConstraints.cA == True assert cert0.extensions.basicConstraints.cA == False # 4. 檢查有效期 assert cert0.not_before <= now <= cert0.not_after assert cert1.not_before <= now <= cert1.not_after ``` > 💡 **關於信任鏈的概念**:為什麼需要這樣的結構?如何建立信任?請參考系列二第4篇《公開金鑰與信任鏈概念》。 ## 實務操作:查看憑證內容 ### 💻 使用 OpenSSL ```bash # 查看 PEM 格式憑證 openssl x509 -in certificate.pem -text -noout # 查看 DER 格式憑證 openssl x509 -in certificate.der -inform DER -text -noout # 輸出範例: Certificate: Data: Version: 3 (0x2) Serial Number: 1234567890 Signature Algorithm: ecdsa-with-SHA256 Issuer: CN=Apple App Attestation CA Validity Not Before: Jan 15 00:00:00 2024 GMT Not After : Jan 15 23:59:59 2025 GMT Subject: CN=Apple App Attestation Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:a1:b2:c3... ``` ### 🌐 線上工具 ``` 推薦工具: ├── https://lapo.it/asn1js/ │ └── 視覺化 ASN.1 結構 ├── https://certlogik.com/decoder/ │ └── 線上憑證解析器 └── https://www.sslshopper.com/certificate-decoder.html └── 快速查看憑證資訊 ``` ### 📚 使用程式庫 **Python:** ```python from cryptography import x509 from cryptography.hazmat.backends import default_backend # 讀取 DER 格式 with open('cert.der', 'rb') as f: cert_data = f.read() cert = x509.load_der_x509_certificate(cert_data, default_backend()) # 查看資訊 print(f"Subject: {cert.subject}") print(f"Issuer: {cert.issuer}") print(f"Not Before: {cert.not_valid_before}") print(f"Not After: {cert.not_valid_after}") ``` **PHP:** ```php // PHP 原生支援 $certData = file_get_contents('cert.der'); $parsed = openssl_x509_parse($certData); echo "Subject: " . $parsed['subject']['CN'] . "\n"; echo "Issuer: " . $parsed['issuer']['CN'] . "\n"; ``` ## 本文小結 ✅ **X.509 是憑證格式的標準**:定義憑證應該包含哪些欄位 ✅ **憑證 = 公鑰 + 身份 + CA 簽章**:證明公鑰的真實性 ✅ **ASN.1 DER 編碼**:憑證的二進位包裝格式 ✅ **憑證鏈**:根 → 中繼 → 葉,層層建立信任 ✅ **實務工具**:OpenSSL / 線上工具 / 程式庫 ### 🎓 與前面文章的連結 **系列二《數位簽章》→ 憑證的核心技術** - 每張憑證都有 CA 的數位簽章 - 實現身份驗證和完整性保護 **系列二第7篇《信任鏈》→ 憑證鏈的具體實現** - 根憑證 → 中繼憑證 → 葉憑證 - 這就是信任鏈的實際應用 **第9篇《CBOR》→ 憑證的傳輸方式** - 憑證用 DER 編碼 - 裝在 CBOR 的 `x5c` 欄位傳輸 ### 📊 重點整理 | 項目 | 說明 | |------|------| | **憑證格式** | X.509 | | **編碼方式** | ASN.1 DER | | **核心價值** | 證明公鑰的真實性 | | **信任來源** | CA 數位簽章 | | **信任鏈** | 根 → 中繼 → 葉 | ## 為什麼需要理解 ASN.1? 到這裡,我們已經理解了 X.509 憑證的邏輯結構:包含哪些欄位、每個欄位的作用、憑證鏈如何運作。 **但還有一個問題:** 當你實際查看憑證檔案時,看到的是這樣: ``` 30 82 02 cc 30 82 02 34 a0 03 02 01 02 02 10 1a 2b 3c 4d... ``` 而不是容易閱讀的結構。這就是因為憑證使用 **ASN.1 DER 編碼**儲存。 **為什麼要用這種「亂碼」格式?** - 跨平台標準:不同系統都能解讀 - 確保唯一性:同樣內容只有一種編碼方式 - 數位簽章需要:hash 計算結果必須一致 **你需要理解編碼細節嗎?** 大部分情況下不需要!使用工具就能查看和處理憑證。但如果你想: - 理解憑證為什麼是二進位格式 - 知道 DER、BER、PEM 的差異 - 深入實作憑證解析 那麼下一篇《第11篇:ASN.1 與編碼格式》會詳細解釋這些內容。 ## 下一篇預告 第11篇《ASN.1 與編碼格式》將解答: - 為什麼憑證看起來像亂碼? - ASN.1 是如何定義資料結構的? - DER、BER、PEM 有什麼差異? - 如何在不同格式間轉換? **學習建議:** - 如果你只想「使用」憑證 → 可以跳過第8篇,直接看後續應用篇 - 如果你想「理解底層」→ 建議閱讀第8篇 --- ## 💡 補充資料 ### 常見問題 **Q: 我一定要深入理解 ASN.1 嗎?** A: 不用!使用現成函式庫就可以了。理解概念比理解編碼細節更重要。 **Q: 憑證和公鑰有什麼不同?** A: 公鑰只是一串數字,憑證是「公鑰 + 身份 + CA 簽章」的完整包裝。 **Q: 為什麼憑證會過期?** A: 安全考量。限制私鑰洩漏的影響範圍,強制定期更新。 **Q: PEM 和 DER 有什麼不同?** A: - **DER**:純二進位(`30 82 02 cc...`) - **PEM**:DER 的 Base64 + 標頭(`-----BEGIN CERTIFICATE-----`) ### 實用資源 - [OpenSSL 文件](https://www.openssl.org/docs/) - [RFC 5280 - X.509 規格](https://tools.ietf.org/html/rfc5280) - [Apple CA 憑證下載](https://www.apple.com/certificateauthority/) - [線上 ASN.1 解析器](https://lapo.it/asn1js/)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.