憑證金鑰使用擴展與限制

Certificate Key Usage Extensions and Constraints

X.509 憑證的擴展欄位(Extensions)是控制憑證用途和行為的關鍵機制。透過正確設定這些擴展,可以精確限制憑證的使用範圍,提高 PKI 架構的安全性。本文將深入探討 Key Usage、Extended Key Usage、Basic Constraints 等重要擴展欄位的設定與應用。

X.509 憑證擴展概述

什麼是憑證擴展?

X.509 v3 憑證引入了擴展機制,允許在憑證中加入額外的資訊。每個擴展都包含三個部分:

1
2
3
4
5
6
7
+------------------------------------------+
|            擴展結構                       |
+------------------------------------------+
| OID (Object Identifier)  - 擴展的唯一識別 |
| Critical Flag            - 是否為關鍵擴展 |
| Value                    - 擴展的實際值   |
+------------------------------------------+

關鍵擴展(Critical Extensions)

當擴展被標記為 Critical 時:

  • 必須處理:應用程式必須理解並處理該擴展
  • 驗證失敗:如果無法識別關鍵擴展,必須拒絕該憑證
  • 安全保障:確保重要的限制不會被忽略
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
擴展處理流程:

+------------------+
| 讀取憑證擴展     |
+--------+---------+
         |
         v
+------------------+     Yes    +------------------+
| 是否為關鍵擴展? | ---------->| 能否理解此擴展? |
+--------+---------+            +--------+---------+
         | No                            |
         v                               v
+------------------+            +------------------+
| 選擇性處理擴展   |            | Yes: 處理擴展    |
+------------------+            | No: 拒絕憑證     |
                                +------------------+

常見的擴展類型

擴展名稱OID說明
Key Usage2.5.29.15定義金鑰的基本用途
Extended Key Usage2.5.29.37定義金鑰的擴展用途
Basic Constraints2.5.29.19CA 標記和路徑長度限制
Subject Alternative Name2.5.29.17主體別名
Authority Key Identifier2.5.29.35簽發者金鑰識別
Subject Key Identifier2.5.29.14主體金鑰識別
CRL Distribution Points2.5.29.31CRL 發布位置
Authority Information Access1.3.6.1.5.5.7.1.1CA 資訊存取點

Key Usage 擴展欄位

Key Usage 概述

Key Usage 擴展定義了憑證中公開金鑰的基本用途。這是一個 bit string,每個位元代表一種特定的用途。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Key Usage Bits (9 位元):

Bit 0: digitalSignature    - 數位簽章
Bit 1: nonRepudiation      - 不可否認性(contentCommitment)
Bit 2: keyEncipherment     - 金鑰加密
Bit 3: dataEncipherment    - 資料加密
Bit 4: keyAgreement        - 金鑰協商
Bit 5: keyCertSign         - 憑證簽發
Bit 6: cRLSign             - CRL 簽發
Bit 7: encipherOnly        - 僅加密(與 keyAgreement 配合)
Bit 8: decipherOnly        - 僅解密(與 keyAgreement 配合)

各用途詳細說明

digitalSignature(數位簽章)

用於驗證數位簽章,不包括憑證或 CRL 的簽章。

適用場景:

  • TLS/SSL 用戶端驗證
  • 電子郵件簽章(S/MIME)
  • 程式碼簽章
  • 文件簽章
1
2
# 檢視憑證的 Key Usage
openssl x509 -in cert.crt -text -noout | grep -A1 "Key Usage"

nonRepudiation / contentCommitment(不可否認性)

用於需要長期驗證的簽章,防止簽署者事後否認。

適用場景:

  • 法律文件簽署
  • 合約簽署
  • 電子交易簽章

keyEncipherment(金鑰加密)

用於加密對稱金鑰或其他金鑰材料。

適用場景:

  • RSA 金鑰交換(TLS 1.2 及更早版本)
  • 加密傳輸的對稱金鑰
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
TLS RSA 金鑰交換:

用戶端                              伺服器
   |                                   |
   |  1. 產生隨機的 Pre-Master Secret  |
   |                                   |
   |  2. 用伺服器公鑰加密              |
   |  -------------------------------->|
   |                                   |  3. 用私鑰解密
   |                                   |
   |  4. 雙方計算 Master Secret        |
   |                                   |

dataEncipherment(資料加密)

直接用於加密使用者資料(非金鑰材料)。

適用場景:

  • 直接加密小量資料
  • 加密設定檔或密碼

keyAgreement(金鑰協商)

用於金鑰協商協定(如 Diffie-Hellman)。

適用場景:

  • ECDH 金鑰交換
  • DH 金鑰交換
  • TLS 1.3 金鑰協商

keyCertSign(憑證簽發)

用於簽發其他憑證,僅 CA 憑證應設定此位元。

注意事項:

  • 必須與 Basic Constraints 的 CA:TRUE 配合使用
  • 未設定此位元的憑證不能簽發其他憑證

cRLSign(CRL 簽發)

用於簽發憑證撤銷清單(CRL)。

適用場景:

  • CA 憑證簽發 CRL
  • 專用的 CRL 簽發憑證

encipherOnly 和 decipherOnly

與 keyAgreement 配合使用,限制金鑰協商的方向。

1
2
encipherOnly + keyAgreement:僅能用於加密方向的金鑰協商
decipherOnly + keyAgreement:僅能用於解密方向的金鑰協商

Key Usage 組合範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+------------------------+------------------------------------------+
| 憑證類型               | 常見 Key Usage 組合                       |
+------------------------+------------------------------------------+
| TLS 伺服器(RSA)      | digitalSignature, keyEncipherment         |
| TLS 伺服器(ECDSA)    | digitalSignature                          |
| TLS 用戶端             | digitalSignature, keyAgreement            |
| CA 憑證                | keyCertSign, cRLSign                      |
| 程式碼簽章             | digitalSignature                          |
| S/MIME 加密            | keyEncipherment                           |
| S/MIME 簽章            | digitalSignature, nonRepudiation          |
+------------------------+------------------------------------------+

Extended Key Usage 擴展

EKU 概述

Extended Key Usage(EKU)提供更精細的用途控制,指定憑證可用於哪些特定應用程式或服務。

1
2
3
4
5
6
7
8
9
Extended Key Usage 結構:

+------------------------------------------+
| Extended Key Usage                        |
+------------------------------------------+
| OID 1: serverAuth (1.3.6.1.5.5.7.3.1)    |
| OID 2: clientAuth (1.3.6.1.5.5.7.3.2)    |
| ...                                       |
+------------------------------------------+

常見 EKU 值

EKU 名稱OID說明
serverAuth1.3.6.1.5.5.7.3.1TLS 伺服器驗證
clientAuth1.3.6.1.5.5.7.3.2TLS 用戶端驗證
codeSigning1.3.6.1.5.5.7.3.3程式碼簽章
emailProtection1.3.6.1.5.5.7.3.4電子郵件保護(S/MIME)
timeStamping1.3.6.1.5.5.7.3.8時間戳記
OCSPSigning1.3.6.1.5.5.7.3.9OCSP 回應簽章
msCodeCom1.3.6.1.4.1.311.2.1.21Microsoft 商業程式碼簽章
msCodeInd1.3.6.1.4.1.311.2.1.22Microsoft 個人程式碼簽章
msSmartcardLogin1.3.6.1.4.1.311.20.2.2Microsoft 智慧卡登入

Key Usage 與 EKU 的關係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Key Usage 和 EKU 的搭配:

+------------------+     +------------------+
|   Key Usage      |     | Extended Key     |
|   (基本用途)     |     | Usage (特定用途) |
+------------------+     +------------------+
         |                        |
         v                        v
    低階控制                 高階控制
    定義基本操作             定義應用場景

驗證邏輯:
1. 首先檢查 Key Usage 是否允許操作
2. 接著檢查 EKU 是否符合應用需求
3. 兩者都必須通過才能使用憑證

EKU 設定範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# TLS 伺服器憑證
extendedKeyUsage = serverAuth

# TLS 雙向驗證憑證
extendedKeyUsage = serverAuth, clientAuth

# 程式碼簽章憑證
extendedKeyUsage = codeSigning

# 電子郵件憑證(簽章和加密)
extendedKeyUsage = emailProtection

# OCSP 回應者憑證
extendedKeyUsage = OCSPSigning

anyExtendedKeyUsage

OID:2.5.29.37.0

當設定 anyExtendedKeyUsage 時,憑證可用於任何目的。但這會降低安全性,建議僅用於測試環境。

1
2
# 不建議在生產環境使用
extendedKeyUsage = anyExtendedKeyUsage

Basic Constraints 與 CA 標記

Basic Constraints 概述

Basic Constraints 擴展定義憑證是否為 CA 憑證,以及 CA 可簽發的憑證層級深度。

1
2
3
4
5
6
7
8
Basic Constraints 結構:

+------------------------------------------+
| Basic Constraints                         |
+------------------------------------------+
| CA: TRUE/FALSE                           |
| pathLenConstraint: 0, 1, 2, ... (選用)   |
+------------------------------------------+

CA 標記

CA:TRUE

  • 憑證可作為 CA 使用
  • 可簽發其他憑證
  • 通常配合 keyCertSign 的 Key Usage

CA:FALSE

  • 終端實體憑證(End Entity Certificate)
  • 不能簽發其他憑證
  • 用於伺服器、用戶端、程式碼簽章等

pathLenConstraint(路徑長度限制)

限制此 CA 以下可以有多少層 CA。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
路徑長度限制範例:

根 CA (pathLen: 2)
    |
    +-- 中繼 CA Level 1 (pathLen: 1)
    |       |
    |       +-- 中繼 CA Level 2 (pathLen: 0)
    |               |
    |               +-- 終端憑證 (CA:FALSE)
    |               +-- 終端憑證 (CA:FALSE)
    |               X-- 不能再簽發 CA 憑證
    |
    +-- 中繼 CA Level 1 (pathLen: 0)
            |
            +-- 終端憑證 (CA:FALSE)
            X-- 不能再簽發 CA 憑證

pathLenConstraint 值的意義

pathLen 值意義
未設定無限制,可簽發任意層級的 CA
0只能簽發終端憑證,不能簽發 CA
1可簽發 1 層 CA(該 CA 只能簽終端憑證)
2可簽發 2 層 CA

Basic Constraints 設定範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 根 CA(無路徑限制)
basicConstraints = critical, CA:TRUE

# 中繼 CA(最多再簽 1 層 CA)
basicConstraints = critical, CA:TRUE, pathlen:1

# 簽發 CA(只能簽終端憑證)
basicConstraints = critical, CA:TRUE, pathlen:0

# 終端實體憑證
basicConstraints = critical, CA:FALSE

為什麼 Basic Constraints 應設為 Critical?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
安全考量:

如果 Basic Constraints 不是 Critical:
+------------------+
| 終端憑證         |  <-- 攻擊者取得此憑證
| CA:FALSE         |
| (非 Critical)    |
+------------------+
         |
         v
+------------------+
| 惡意軟體忽略     |  <-- 不支援此擴展的軟體
| Basic Constraints|      可能接受其簽發的憑證
+------------------+
         |
         v
+------------------+
| 偽造的子憑證     |  <-- 安全漏洞!
+------------------+

解決方案:
- 將 Basic Constraints 設為 Critical
- 確保所有驗證軟體都會檢查此擴展

Subject Alternative Name

SAN 概述

Subject Alternative Name(SAN)擴展允許一張憑證關聯多個身份識別。這是現代憑證中最常用的擴展之一。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Subject Alternative Name 結構:

+------------------------------------------+
| Subject Alternative Name                  |
+------------------------------------------+
| DNS: example.com                         |
| DNS: www.example.com                     |
| DNS: api.example.com                     |
| IP: 192.168.1.100                        |
| Email: admin@example.com                 |
| URI: https://example.com/auth            |
+------------------------------------------+

SAN 類型

類型說明範例
DNS網域名稱DNS:www.example.com
IPIP 位址IP:192.168.1.100
Email電子郵件地址email:user@example.com
URI統一資源識別碼URI:https://example.com
dirName目錄名稱dirName:CN=example

CN vs SAN

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
傳統方式(已過時):
+------------------+
| Subject          |
| CN=www.example.com|  <-- 舊方法:使用 CN 存放域名
+------------------+

現代方式(推薦):
+------------------+
| Subject          |
| CN=Example Corp  |  <-- CN 存放組織名稱
+------------------+
| SAN              |
| DNS:example.com  |  <-- SAN 存放域名
| DNS:www.example.com|
+------------------+

注意:
- Chrome 58+ 已不再使用 CN 作為域名驗證
- 必須使用 SAN 擴展
- 建議 CN 使用組織名稱或主要域名

萬用字元憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
萬用字元規則:

有效的萬用字元:
*.example.com     -> 匹配 www.example.com, api.example.com
                  -> 不匹配 example.com
                  -> 不匹配 www.sub.example.com

無效的萬用字元:
www.*.com         -> 不允許
*.*.example.com   -> 不允許
example.*         -> 不允許

建議的 SAN 設定:
DNS:example.com
DNS:*.example.com

多域名(Multi-Domain)憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 一張憑證保護多個域名
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = example.org
DNS.4 = www.example.org
DNS.5 = api.example.com
IP.1 = 10.0.0.1
IP.2 = 10.0.0.2

常見憑證類型與對應設定

TLS 伺服器憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
+------------------------------------------+
| TLS Server Certificate                    |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature                     |
|   - keyEncipherment (RSA only)           |
|                                          |
| Extended Key Usage:                       |
|   - serverAuth                           |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
|                                          |
| Subject Alternative Name:                 |
|   - DNS: example.com                     |
|   - DNS: www.example.com                 |
+------------------------------------------+

TLS 用戶端憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
+------------------------------------------+
| TLS Client Certificate                    |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature                     |
|                                          |
| Extended Key Usage:                       |
|   - clientAuth                           |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
|                                          |
| Subject Alternative Name:                 |
|   - Email: user@example.com              |
+------------------------------------------+

雙向 TLS(mTLS)憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
+------------------------------------------+
| mTLS Certificate (Server + Client)        |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature                     |
|   - keyEncipherment                      |
|                                          |
| Extended Key Usage:                       |
|   - serverAuth                           |
|   - clientAuth                           |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
+------------------------------------------+

程式碼簽章憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
+------------------------------------------+
| Code Signing Certificate                  |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature                     |
|                                          |
| Extended Key Usage:                       |
|   - codeSigning                          |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
+------------------------------------------+

S/MIME 電子郵件憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
+------------------------------------------+
| S/MIME Email Certificate                  |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature (簽章)              |
|   - keyEncipherment (加密)               |
|   - nonRepudiation (不可否認)            |
|                                          |
| Extended Key Usage:                       |
|   - emailProtection                      |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
|                                          |
| Subject Alternative Name:                 |
|   - Email: user@example.com              |
+------------------------------------------+

中繼 CA 憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
+------------------------------------------+
| Intermediate CA Certificate               |
+------------------------------------------+
| Key Usage:                               |
|   - keyCertSign                          |
|   - cRLSign                              |
|                                          |
| Extended Key Usage: (選用)                |
|   - 不設定或限制特定用途                  |
|                                          |
| Basic Constraints:                        |
|   - CA:TRUE                              |
|   - pathlen:0 (只能簽終端憑證)           |
+------------------------------------------+

OCSP 簽發憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
+------------------------------------------+
| OCSP Responder Certificate                |
+------------------------------------------+
| Key Usage:                               |
|   - digitalSignature                     |
|                                          |
| Extended Key Usage:                       |
|   - OCSPSigning                          |
|                                          |
| Basic Constraints:                        |
|   - CA:FALSE                             |
|                                          |
| OCSP No Check: (選用)                     |
|   - 存在此擴展表示不需檢查此憑證的撤銷狀態 |
+------------------------------------------+

OpenSSL 設定範例

完整的 OpenSSL 設定檔

建立 /etc/ssl/openssl-extensions.cnf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# OpenSSL 擴展設定檔

# 根 CA 擴展
[ v3_ca ]
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

# 中繼 CA 擴展(只能簽終端憑證)
[ v3_intermediate_ca ]
basicConstraints = critical, CA:TRUE, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
authorityInfoAccess = caIssuers;URI:http://ca.example.com/root.crt
crlDistributionPoints = URI:http://crl.example.com/root.crl

# TLS 伺服器憑證擴展
[ v3_server ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
authorityInfoAccess = OCSP;URI:http://ocsp.example.com, caIssuers;URI:http://ca.example.com/intermediate.crt
crlDistributionPoints = URI:http://crl.example.com/intermediate.crl

# TLS 用戶端憑證擴展
[ v3_client ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

# 雙向 TLS 憑證擴展
[ v3_server_client ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

# 程式碼簽章憑證擴展
[ v3_codesign ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = codeSigning
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

# S/MIME 電子郵件憑證擴展
[ v3_email ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment, nonRepudiation
extendedKeyUsage = emailProtection
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always

# OCSP 簽發憑證擴展
[ v3_ocsp ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = OCSPSigning
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
noCheck = ignored

# SAN 設定區塊
[ alt_names ]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
IP.1 = 10.0.0.1

產生根 CA 憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 產生根 CA 私鑰
openssl genrsa -aes256 -out rootCA.key 4096

# 產生根 CA 憑證
openssl req -x509 -new -nodes \
    -key rootCA.key \
    -sha256 \
    -days 7300 \
    -out rootCA.crt \
    -extensions v3_ca \
    -config openssl-extensions.cnf \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=Example Root CA"

產生中繼 CA 憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 產生中繼 CA 私鑰
openssl genrsa -aes256 -out intermediateCA.key 4096

# 產生 CSR
openssl req -new \
    -key intermediateCA.key \
    -out intermediateCA.csr \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=Example Intermediate CA"

# 使用根 CA 簽發中繼 CA 憑證
openssl x509 -req \
    -in intermediateCA.csr \
    -CA rootCA.crt \
    -CAkey rootCA.key \
    -CAcreateserial \
    -out intermediateCA.crt \
    -days 3650 \
    -sha256 \
    -extensions v3_intermediate_ca \
    -extfile openssl-extensions.cnf

產生 TLS 伺服器憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 產生伺服器私鑰
openssl genrsa -out server.key 2048

# 產生 CSR(使用設定檔定義 SAN)
openssl req -new \
    -key server.key \
    -out server.csr \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=www.example.com"

# 使用中繼 CA 簽發伺服器憑證
openssl x509 -req \
    -in server.csr \
    -CA intermediateCA.crt \
    -CAkey intermediateCA.key \
    -CAcreateserial \
    -out server.crt \
    -days 365 \
    -sha256 \
    -extensions v3_server \
    -extfile openssl-extensions.cnf

# 或者使用命令列指定 SAN
openssl x509 -req \
    -in server.csr \
    -CA intermediateCA.crt \
    -CAkey intermediateCA.key \
    -CAcreateserial \
    -out server.crt \
    -days 365 \
    -sha256 \
    -extfile <(cat <<EOF
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:example.com, DNS:www.example.com, DNS:api.example.com, IP:10.0.0.1
EOF
)

產生用戶端憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 產生用戶端私鑰
openssl genrsa -out client.key 2048

# 產生 CSR
openssl req -new \
    -key client.key \
    -out client.csr \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=User Name/emailAddress=user@example.com"

# 簽發用戶端憑證
openssl x509 -req \
    -in client.csr \
    -CA intermediateCA.crt \
    -CAkey intermediateCA.key \
    -CAcreateserial \
    -out client.crt \
    -days 365 \
    -sha256 \
    -extensions v3_client \
    -extfile openssl-extensions.cnf

產生 ECDSA 憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 產生 ECDSA 私鑰
openssl ecparam -genkey -name prime256v1 -out server-ecdsa.key

# 產生 CSR
openssl req -new \
    -key server-ecdsa.key \
    -out server-ecdsa.csr \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=Example Corp/CN=www.example.com"

# 簽發憑證(ECDSA 不需要 keyEncipherment)
openssl x509 -req \
    -in server-ecdsa.csr \
    -CA intermediateCA.crt \
    -CAkey intermediateCA.key \
    -CAcreateserial \
    -out server-ecdsa.crt \
    -days 365 \
    -sha256 \
    -extfile <(cat <<EOF
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = DNS:example.com, DNS:www.example.com
EOF
)

驗證與檢查方法

檢視憑證詳細資訊

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 檢視完整憑證內容
openssl x509 -in cert.crt -text -noout

# 僅檢視擴展欄位
openssl x509 -in cert.crt -text -noout | grep -A20 "X509v3 extensions"

# 檢視 Key Usage
openssl x509 -in cert.crt -text -noout | grep -A1 "Key Usage"

# 檢視 Extended Key Usage
openssl x509 -in cert.crt -text -noout | grep -A2 "Extended Key Usage"

# 檢視 Basic Constraints
openssl x509 -in cert.crt -text -noout | grep -A1 "Basic Constraints"

# 檢視 Subject Alternative Name
openssl x509 -in cert.crt -text -noout | grep -A5 "Subject Alternative Name"

驗證憑證鏈

1
2
3
4
5
6
7
8
9
# 驗證完整憑證鏈
openssl verify -CAfile rootCA.crt -untrusted intermediateCA.crt server.crt

# 驗證憑證並顯示詳細資訊
openssl verify -verbose -CAfile ca-bundle.crt server.crt

# 建立完整的 CA Bundle
cat intermediateCA.crt rootCA.crt > ca-bundle.crt
openssl verify -CAfile ca-bundle.crt server.crt

線上憑證檢查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 連接伺服器並顯示憑證資訊
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
    openssl x509 -text -noout

# 顯示完整憑證鏈
openssl s_client -connect example.com:443 -servername example.com -showcerts

# 檢查憑證到期日
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
    openssl x509 -noout -dates

# 檢查 SAN
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
    openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

使用 OpenSSL 驗證用途

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 驗證憑證是否可用於 SSL 伺服器
openssl verify -purpose sslserver -CAfile ca-bundle.crt server.crt

# 驗證憑證是否可用於 SSL 用戶端
openssl verify -purpose sslclient -CAfile ca-bundle.crt client.crt

# 驗證憑證是否可用於 S/MIME 簽章
openssl verify -purpose smimesign -CAfile ca-bundle.crt email.crt

# 可用的 purpose 選項
# sslclient, sslserver, nssslserver, smimesign, smimeencrypt, crlsign, any, ocsphelper, timestampsign

檢查 Key Usage 與 EKU 相容性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash
# check_cert_usage.sh - 檢查憑證用途設定

CERT=$1

if [ -z "$CERT" ]; then
    echo "Usage: $0 <certificate.crt>"
    exit 1
fi

echo "=== 憑證用途分析 ==="
echo ""

# 檢查 Basic Constraints
echo "Basic Constraints:"
openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep -A1 "Basic Constraints" | tail -1
echo ""

# 檢查 Key Usage
echo "Key Usage:"
openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep -A1 "Key Usage" | tail -1
echo ""

# 檢查 Extended Key Usage
echo "Extended Key Usage:"
openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep -A2 "Extended Key Usage" | tail -2
echo ""

# 檢查 SAN
echo "Subject Alternative Name:"
openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep -A5 "Subject Alternative Name" | tail -5
echo ""

# 判斷憑證類型
echo "=== 憑證類型判斷 ==="
IS_CA=$(openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep "CA:TRUE")
HAS_SERVER_AUTH=$(openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep "TLS Web Server Authentication")
HAS_CLIENT_AUTH=$(openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep "TLS Web Client Authentication")
HAS_CODE_SIGN=$(openssl x509 -in "$CERT" -text -noout 2>/dev/null | grep "Code Signing")

if [ -n "$IS_CA" ]; then
    echo "- CA 憑證"
fi
if [ -n "$HAS_SERVER_AUTH" ]; then
    echo "- 可用於 TLS 伺服器"
fi
if [ -n "$HAS_CLIENT_AUTH" ]; then
    echo "- 可用於 TLS 用戶端"
fi
if [ -n "$HAS_CODE_SIGN" ]; then
    echo "- 可用於程式碼簽章"
fi

使用 cfssl 工具檢查

1
2
3
4
5
6
7
8
# 安裝 cfssl
go install github.com/cloudflare/cfssl/cmd/...@latest

# 檢視憑證資訊
cfssl certinfo -cert server.crt

# 以 JSON 格式輸出
cfssl certinfo -cert server.crt | jq .

憑證健康檢查清單

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
+----------------------------------------+
| 憑證健康檢查清單                        |
+----------------------------------------+

[ ] 基本驗證
    [ ] 憑證格式正確(PEM/DER)
    [ ] 憑證尚未過期
    [ ] 憑證已經生效
    [ ] 私鑰與憑證匹配

[ ] 信任鏈
    [ ] 完整的憑證鏈
    [ ] 中繼憑證正確
    [ ] 根憑證受信任
    [ ] 沒有過期的鏈上憑證

[ ] 擴展欄位
    [ ] Basic Constraints 正確設定
    [ ] Key Usage 符合用途
    [ ] Extended Key Usage 符合應用
    [ ] SAN 包含所有必要的域名
    [ ] Critical 擴展正確標記

[ ] 安全性
    [ ] 使用強加密演算法(SHA-256+)
    [ ] 足夠的金鑰長度(RSA 2048+, ECDSA 256+)
    [ ] 合理的有效期限
    [ ] 未被撤銷
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 完整的憑證健康檢查腳本
#!/bin/bash
# cert_health_check.sh

CERT=$1
KEY=$2
CA_BUNDLE=$3

echo "=== 憑證健康檢查 ==="

# 檢查憑證有效期
echo -e "\n[1] 有效期檢查"
openssl x509 -in "$CERT" -noout -dates
NOT_AFTER=$(openssl x509 -in "$CERT" -noout -enddate | cut -d= -f2)
EXPIRE_EPOCH=$(date -d "$NOT_AFTER" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRE_EPOCH - NOW_EPOCH) / 86400 ))
echo "剩餘天數: $DAYS_LEFT"

# 檢查私鑰匹配
if [ -n "$KEY" ]; then
    echo -e "\n[2] 私鑰匹配檢查"
    CERT_MOD=$(openssl x509 -in "$CERT" -noout -modulus 2>/dev/null | md5sum)
    KEY_MOD=$(openssl rsa -in "$KEY" -noout -modulus 2>/dev/null | md5sum)
    if [ "$CERT_MOD" = "$KEY_MOD" ]; then
        echo "結果: 匹配"
    else
        echo "結果: 不匹配 (錯誤!)"
    fi
fi

# 檢查憑證鏈
if [ -n "$CA_BUNDLE" ]; then
    echo -e "\n[3] 憑證鏈驗證"
    openssl verify -CAfile "$CA_BUNDLE" "$CERT"
fi

# 檢查加密演算法
echo -e "\n[4] 加密演算法"
openssl x509 -in "$CERT" -noout -text | grep "Signature Algorithm" | head -1
openssl x509 -in "$CERT" -noout -text | grep "Public-Key"

# 檢查擴展
echo -e "\n[5] 關鍵擴展"
openssl x509 -in "$CERT" -noout -text | grep -E "(Basic Constraints|Key Usage|Extended Key Usage)" | head -5

總結

X.509 憑證的擴展欄位是控制憑證行為和安全性的關鍵機制。正確理解和設定這些擴展,對於建立安全的 PKI 架構至關重要。

重點回顧:

  • Key Usage 定義金鑰的基本操作權限(簽章、加密、金鑰協商等)
  • Extended Key Usage 指定憑證可用於哪些特定應用(TLS、程式碼簽章等)
  • Basic Constraints 區分 CA 和終端憑證,並限制 CA 層級深度
  • Subject Alternative Name 允許一張憑證關聯多個身份識別
  • 關鍵擴展(Critical)必須被所有驗證軟體正確處理
  • 不同類型的憑證需要不同的擴展組合

建議的最佳實踐:

  1. 始終將 Basic Constraints 設為 Critical
  2. 根據實際用途設定適當的 Key Usage 和 EKU
  3. 使用 SAN 而非 CN 來指定域名
  4. 定期驗證已簽發憑證的擴展設定
  5. 維護清晰的 OpenSSL 設定檔以確保一致性

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy