顯示具有 Certificate 標籤的文章。 顯示所有文章
顯示具有 Certificate 標籤的文章。 顯示所有文章

2016年1月10日 星期日

OCSP & CRL 介紹

這篇主要是要談論在 PKI 架構下,如何查詢一張 X.509 憑證 ( Certificate ) 的有效性?
舉例:
  • 瀏覽器 (Browser) 如何驗證支援 SSL 連線的伺服器所使用的憑證 Certificate 是有效的。
  • 自行開發的應用程式,如何透過程式碼來查詢某張憑證是否已經被 CA 單位所撤銷 (Revoke)。
首先,我們先定義"有效的憑證":
  • 該憑證是經由公認的 CA 或是執行的系統所信任的 CA 發行的憑證。
  • 憑證的是否在有效期間內。
  • 該憑證沒有被發行憑證的 CA 所撤銷 ( Revoked )。
我們會分別以下面的主題來解釋 OCSP 和 CRL 這兩個在 PKI 架構的規範。 
  • 基本概念介紹
  • 實務上的應用
  • 優點缺點

CRL 基本概念介紹

CRL 是 Certificate Revocation List 的縮寫,顧名思義就是紀錄被CA所撤銷的憑證清單。 實際上他是一個發行憑證的 CA 用來對外公告,這個 CA 所發行的憑證,雖然憑證上的日期仍然是有效的,但有這些憑證當中,哪些是因為某些因素而被撤銷的憑證。被憑證撤銷的理由 (Reason) 很多,RFC 的規格上定義了幾個常見的理由 如下:
  • unspecified (0)
  • keyCompromise (1)
  • CACompromise (2)
  • affiliationChanged (3)
  • superseded (4)
  • cessationOfOperation (5)
  • certificateHold (6)
  • removeFromCRL (8)
  • privilegeWithdrawn (9)
  • AACompromise (10)

實際上,CRL 就是一個檔案,任何人都可以根據憑證中所指定的URI位置取得這份檔案。如果你透過工具來檢視憑證,我們可透過 OpenSSL 指令來檢視憑證內容

shell>openssl x509 -in cert.crt -text

如果發出這張憑證單位的 CA 有提供 CRL 資訊,你可以在 X.509 的 V3 Extension 找到一個
"X509v3 CRL Distribution Points" 的資訊,它會顯示一個或是一個以上的 URI,如下圖紅色標示的部分:
當你將那段URI的位置,透過工具如 wget or curl 或是瀏覽器來取得這個 CRL 檔案時,檔案的內容就可能紀錄著類似藍色箭頭所指示的內容,裡面會包含哪些憑證已經在何時被撤銷。每張憑證都具有一個 Serial Number, 他就像是憑證的身分證號碼,由發行的CA單位所管理,這些 Serial Number 必須是在這個CA單位中是唯一。然而,CRL 的檔案通常都是用DER或是PEM的編碼過的,所以你無法用一般的編輯器直接來檢視他的內容。此外,它會包含CA所簽署的簽章(Signature)資訊,如此才能證明這個CRL檔案是由 CA 單位所公告的資訊。我們可透過 OpenSSL 指令來檢視一個CRL檔案的內容

shell>openssl crl -in crl.der -text -noout

你就可以看到,類似下圖所示的內容:


此外,你可以在最下方看見一個簽章的資訊,例如下圖:

它說明了這個 CRL 檔案是由 sha256withRSAEncryption 的演算法所簽署的簽章 (Signature),因此取得這個CRL的檔案後,要拿它來判斷是否有憑證被撤銷之前,應該要驗證這個 CRL 檔案的簽章,以確保這個CRL檔案是沒有被竄改過的。那要如何驗證呢?這時要檢視 CRL extension 中的 Authority Key Identifier。這表示這個簽章要使用 Authority Key Identifier 所指定的 Public Key 來驗證。如果發行憑證的 CA 沒有特別針對 CRL 而另外指定用於 signing CRL 專屬的 certificate 時,這個 Authority Key Identifier 通常就是發行 CA 的 public key id。因此你就可以透過 CA certificate 來驗證這個CRL的簽章是否正確。

CRL extensions:
   X509v3 Authority Key Identifier: 
   keyid:51:68:FF:90:AF:02:07:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B

實務上的應用

一般來說,程式(例如: Browser 或自行開發會使用到憑證的應用程式)會根據憑證在 X.509 的 V3 Extension 找到一個"X509v3 CRL Distribution Points" 的資訊去取得這份 CRL 檔案。然而,CRL 檔案通常是由 CA 單位來定期發佈, 而 CRL的檔案中會記錄著這份CRL的有效期間,以及下次更新的時間。因此,要使用CRL 的應用程式,可以根據 CRL 的有效期間來決定是否重新取得這份CRL檔案,或是只接使用在本地端的 CRL 檔案即可。

CRL的優點

  • CA 實作CRL是相對容易的,只需要定期將被撤銷的憑證資訊更新到 CRL 之中即可。
  • CRL 取得容易,一般來說,需要 CRL 的應用程式可以直接透過 HTTP 就取得這個檔案。

CRL的缺點

  • CRL 檔案的內容可能非常大,如果 CA 單位長時間下來撤銷許多發行的憑證時,這個 CRL 檔案內容就會非常的大,可能高達25MB以上。有興趣的讀者可以參考這篇Digging Into Certificate Revocation Listsj文章。
  • CRL 檔案資訊不夠即時,可能造成安全上的空窗期。因為CRL檔案是每隔一段時間才公布,因此在下次公布CRL檔案之前,有憑證被撤銷時,要等到下次公布才能得到這個資訊。
  • 如果程式無法下載 CRL 檔案,則應用程式可能會直接信任它想要確認的憑證。

Base CRL 和 Delta CRL

由於,CRL 本身在設計上有這樣的缺點,因此後來提出另一個的解決方式稱為 Delta CRL。
Delta CRL 是指記錄部分的被撤銷的憑證資訊,而不是全部的被撤銷的憑證資訊。並且縮短了 Delta CRL 的發佈時間。舉例,原本的 CRL 發佈時間是 10 天發佈 1 次,而這個 CRL 又被稱為 Base CRL。而 Delta CRL 的發佈週期就比較短一點,可能只要 2 天就發佈一次。因此,Delta CRL 只會記錄在這 2 天內有被撤銷的憑證資訊,並且在 Delta CRL 檔案中會記錄著他的 Base CRL 是哪一個版號。而應用程式只要每2天重新抓取這個 Delta CRL檔案,加上原本的 Base CRL檔案 就可以得到完整的 CRL 資訊。

請參考下方這張圖,Base CRL 檔案中會記錄著一個 X509v3 Freshest CRL的資訊,而上面所記錄的 URI位置就是 Delta CRL檔案的位置。當你下載這個 Deltra CRL檔案後,即可發現 Delta CRL 檔案結構和 Base CRL一樣,只是 X509v3 Delta CRL Indicator 標記這個 CRL 檔案是一個 Delta CRL 檔案,此外,它記錄著是根據哪一個 Base CRL的版號,當作比對的基礎,而產生這份 Delta CRL。

OCSP

基本概念介紹

OCSP 是 Online Certificate Status Protocol 的縮寫,它目的在於提供線上動態查詢憑證的狀態。OCSP 本身提供了應用程式更多的彈性,來根據使用上的需要來查詢憑證的狀態。簡單的說就是應用程式能夠根據憑證的序號,發出OCSP請求到憑證上所記錄的 OCSP  URI 來查詢憑證的狀態。我們可以參考下面這張概念圖:

由上圖,可以看到左右兩邊橘色部分是有關數位簽章的資訊,右邊是 OCSP 的 Response 的格式示意圖,而橘色的部分是指這個 OCSP Response 內容的簽章。接收端應該要驗證這個簽章無誤後,才能夠信任這個 OCSP 的回應內容。而左邊,是發出 OCSP 請求的客戶端把請求的內容也算出了一個簽章資訊。但,並不是強制性的,這完全是根據實作 OCSP responder來決定是否要強制要求,發出 OCSP 請求的客戶端一定要產生這個簽章。

當客戶端發出請求給 OCSP Responder時候,這時可以根據憑證的狀態有3種回答 :

  • Good - 表示憑證的狀態是在有效期內,而且沒有被撤銷
  • Revoked - 表示憑證已經被撤銷
  • Unknown - 表示 OCSP Responder 無法認得這張憑證

實務上的應用

實務上就是大部份知名的瀏覽器都支援 OCSP 的實作,來驗證瀏覽的網頁伺服器所使用的HTTPS的憑證是否有效。瀏覽器連上某個網站時候,它會根據伺服器所使用的憑證內容所記錄的 OCSP Responder 位置,發出 OCSP 請求去詢問這張憑證目前的狀態,來決定是否信任這個網站。

OCSP 優點

  • 應用程式可以一次只問一張憑證的狀態即可,不需要像 CRL 把所有的撤銷的憑證資訊都下載下來。
  • 降低了發佈的時間延遲,縮短了這方面的問題。

OCSP 缺點

  • 對 OCSP Responder 的流量會相當大
  • 如果遇到不支援 OCSP 的客戶端或是連不到 OCSP Responder的情形,會造成客戶端直接信任伺服器憑證的狀況,那就會讓駭客能夠偽裝成伺服器來進行攻擊

OCSP Stapling

由於 OCSP 原本的設計方式是,會由一個 OCSP Responder 來負責回答客戶端的 OCSP 請求。然而在實務上瀏覽器為了避免要發兩次請求到不同的位置,而造成延遲,另一方面也是為了減輕 OCSP Responder的負擔,讓瀏覽器不需要每次都到 OCSP Responder來詢問。因此,發展出了另一個改良版本的做法,稱作 OCSP Stapling。它是指由伺服器端同時提供 OCSP 回應的做法。這樣瀏覽器連接到這個網站時,就不需要再發另一個請求到另一個位置的 OCSP Responder,可以在同一個連線當中就可以得到這張伺服器所使用的憑證是否還是有效。
當然,要支援 OCSP Stapling 是需要付出代價的,那就是你所架設的伺服器必須要能夠支援。目前常見的網頁伺服器都有支援,如:Windows, Apache, Nginx 等等。

Reference 




2014年3月18日 星期二

Python M2Crypto - X.509 Certificate Sign Request 與 Sign Certificate


X.509 憑證基本觀念

X.509 是由 ITU-T 所製定的 PKI 標準,它主要包含以下 4 個規範:
  1. public key certificates
  2. certificate revocation lists
  3. attribute certificates
  4. certification path validation algorithm
X.509 的憑證簽發關係的概念圖如下:


產生 Root CA Certificate

  • 產生一把 RSA key pair (public / private keys) 
  • 準備一個 Root CA 憑證, 以及所需要的資訊,並且設定有效期限(一般來說是10~20年)。
  • 設定此 Root CA 憑證的 X.509 V3 的 Extension 
  • 用此 Root CA 的 RSA private key 來簽署這個憑證( Self-Signed Root CA Certificate)
產生 Self-Signed Root CA Certificate 的基本範例程式:
 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
import M2Crypto
import time
import os
import struct
from M2Crypto import X509, EVP, ASN1

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass
    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650):
    # Setp 1: Create RSA-key pair (public/private key)
    rsa = generate_rsa_keypair(2048, 65537)
    private_key = EVP.PKey()
    private_key.assign_rsa(rsa)
    
    # Step 2-1: Prepare X.509 Certificate Signed Request
    req = X509.Request()
    req.set_pubkey(private_key)
    x509_name = req.get_subject()
    x509_name.C = root_ca_info["C"]
    x509_name.CN = root_ca_info["CN"]
    x509_name.ST = root_ca_info["ST"]
    x509_name.L = root_ca_info["L"]
    x509_name.O = root_ca_info["O"]
    x509_name.OU = root_ca_info["OU"]
    req.sign(private_key,sign_method)
    # Step 2-2: Prepare X.509 certificate
    root_ca_cert = X509.X509()
    
    serial = struct.unpack("<Q", os.urandom(8))[0]
    root_ca_cert.set_serial_number(serial)
    root_ca_cert.set_version(3)
    # Setp 2-3: Set required information of RootCA certificate
    root_ca_cert.set_issuer(x509_name)
    root_ca_cert.set_subject(root_ca_cert.get_issuer())
    root_ca_cert.set_pubkey(req.get_pubkey())  # Get the CSR's public key    

    # Step 2-4: Set Valid Date for RootCA certificate
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    root_ca_cert.set_not_before(now)
    root_ca_cert.set_not_after(expire)
    # Step 3: Add Extensions for this Root CA certificate
    root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint()))
    
    # Step 4: Use Root CA's RSA private key to sign this certificate
    root_ca_cert.sign(private_key, sign_method)
    return root_ca_cert, private_key

if __name__ == '__main__':
    # Generate a Self-Signed Root CA Certificate
    root_ca_info = {}
    root_ca_info['C'] = "TW"
    root_ca_info['CN'] = "Root CA Certificate"
    root_ca_info['ST'] = "Taiwan"
    root_ca_info['O'] = "ijeCorp Ltd."
    root_ca_info['OU'] = "Security"
    root_ca_info['L'] = "Taipei"
    
    root_ca_cert, private_key = create_self_signed_RootCA_certificate(root_ca_info)
    with open('root_ca_cert.crt', 'w') as f:
        f.write(root_ca_cert.as_pem())
    with open('root_ca_private_key.pem', 'w') as f:
        f.write(private_key.as_pem(cipher=None))
    with open('root_ca_public_key.pem', 'w') as f:
        f.write(root_ca_cert.get_pubkey().as_pem(cipher=None))


產生 Certificate Signed Certificate 

  • 產生一把 RSA key pair (public/private key)
  • 準備一個 X.509 Request 
  • 設定 X.509 Request 的資訊
  • 用 RSA private key 去簽署這個 X.509 Request
產生 Certificate Signed Certificate (CSR) 的基本範例程式:
 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
import M2Crypto
from M2Crypto import X509, EVP

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"):
    # Step 1: Create a RSA key pair (public/private key)
    rsa_keypair = generate_rsa_keypair(key_len, 65537)
    evp_private_key = EVP.PKey()
    evp_private_key.assign_rsa(rsa_keypair)
    # Step 2: Create a X.509 request 
    csr = X509.Request()
    csr.set_pubkey(evp_private_key)
    # Step 3: Set CSR information
    x509_name = csr.get_subject()
    x509_name.C = csr_info['C']
    x509_name.CN = csr_info['CN']
    x509_name.ST = csr_info['ST']
    x509_name.O = csr_info['O']
    x509_name.OU = csr_info['OU']
    x509_name.L = csr_info['L']

    # Step 4: Use RSA private key to sign it
    csr.sign(evp_private_key, sign_method)
    return csr, evp_private_key

if __name__ == '__main__':
    # Generate CSR for signed Certificate
    csr_info = {}
    csr_info['C'] = "TW"
    csr_info['CN'] = "CA-Certificate"
    csr_info['ST'] = "Taiwan"
    csr_info['O'] = "AbcCorp Ltd."
    csr_info['OU'] = "ABC-CA"
    csr_info['L'] = "Taipei"

    csr, private_key = create_Signed_Certificate_Request(csr_info);

    with open('CSR.pem', 'w') as f:
        f.write(csr.as_pem())
    with open('CSR_private_key.pem', 'w') as f:
        f.write(private_key.as_pem(cipher = None))

Root CA 或是 CA 根據 CSR 簽署一個 Certificate

  • 準備一個 X.509 的憑證
  • 設定 X.509 憑證的有效期限, 有效時間的長短根據需求而有不同
  • 設定 X.509 的 Extension 資訊
  • 根據 CSR 所提供的 subject 以及 public key 來設定 X.509 憑證
  • 使用 Root CA 或是 CA 的 RSA private key 來簽署這個 X.509 憑證
Root CA 根據 CSR 產生 Certificate 的基本範例程式:
此範例程式,只需要研讀 Line 130~133 與 Line 14~47 即可,它是直接以 Root CA 的 private key並且依據 CSR 來簽署憑證


  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
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import M2Crypto
import time
import os
import struct
from M2Crypto import X509, EVP, ASN1

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_certificate_from_CSR(rootCA_cert, rootCA_private_key, csr, days = 365):
    # Step 1: Prepare X.509 Certificate
    cert = X509.X509()
    serial = struct.unpack("<Q", os.urandom(8))[0]
    cert.set_serial_number(serial)
    cert.set_version(3)
    # Step 2: Set Expired Date
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    cert.set_not_before(now)
    cert.set_not_after(expire)
    # Step 3: Set X.509 Extensions
    cert.add_ext(X509.new_extension('nsComment', 'SSL sever'))
    cert.add_ext(X509.new_extension('keyUsage', 'Digital Signature')) 
    cert.add_ext(X509.new_extension('keyUsage', 'Key Encipherment', 1)) # 1 means critical
    cert.add_ext(X509.new_extension('keyUsage', 'Data Encipherment',1))
    cert.add_ext(X509.new_extension('keyUsage', 'Key Agreement', 1))
    cert.add_ext(X509.new_extension('extendedKeyUsage', 'clientAuth'))
    cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    cert.add_ext(X509.new_extension('subjectAltName', 'DNS:www.ijecorp.com'))
    PCI_FULL = "critical, language:Inherit all"
    PCI_LIMITED = "critical, language:1.3.6.1.4.1.3536.1.1.1.9"
    cert.add_ext(X509.new_extension('proxyCertInfo',PCI_FULL, 1))
    # Step 4: Set Subject and Public Key from CSR
    cert.set_issuer(rootCA_cert.get_issuer())
    cert.set_subject(csr.get_subject())
    cert.set_pubkey(csr.get_pubkey())
    # Step 5: Use Private Key of Root CA or CA to sign this X.509 certificate
    cert.sign(rootCA_private_key, 'sha256')

    return cert

def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"):
    # Step 1: Create a RSA key pair (public/private key)
    rsa_keypair = generate_rsa_keypair(key_len, 65537)
    evp_private_key = EVP.PKey()
    evp_private_key.assign_rsa(rsa_keypair)
    # Step 2: Create a X.509 request 
    csr = X509.Request()
    csr.set_pubkey(evp_private_key)
    # Step 3: Set CSR information
    x509_name = csr.get_subject()
    x509_name.C = csr_info['C']
    x509_name.CN = csr_info['CN']
    x509_name.ST = csr_info['ST']
    x509_name.O = csr_info['O']
    x509_name.OU = csr_info['OU']
    # Step 4: Use RSA private key to sign it
    csr.sign(evp_private_key, sign_method)
    return csr, evp_private_key

def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650):
    # Setp 1: Create RSA-key pair (public/private key)
    rsa = generate_rsa_keypair(2048, 65537)
    private_key = EVP.PKey()
    private_key.assign_rsa(rsa)
    # Step 2-1: Prepare X.509 Certificate Signed Request
    req = X509.Request()
    req.set_pubkey(private_key)
    x509_name = req.get_subject()
    x509_name.C = root_ca_info["C"]
    x509_name.CN = root_ca_info["CN"]
    x509_name.ST = root_ca_info["ST"]
    x509_name.L = root_ca_info["L"]
    x509_name.O = root_ca_info["O"]
    x509_name.OU = root_ca_info["OU"]
    req.sign(private_key,sign_method)
    # Step 2-2: Prepare X.509 certificate
    root_ca_cert = X509.X509()
    serial = struct.unpack("<Q", os.urandom(8))[0]
    root_ca_cert.set_serial_number(serial)
    root_ca_cert.set_version(3)
    # Setp 2-3: Set required information of RootCA certificate
    root_ca_cert.set_issuer(x509_name)
    root_ca_cert.set_subject(root_ca_cert.get_issuer())
    root_ca_cert.set_pubkey(req.get_pubkey())  # Get the CSR's public key    

    # Step 2-4: Set Valid Date for RootCA certificate
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    root_ca_cert.set_not_before(now)
    root_ca_cert.set_not_after(expire)
    # Step 3: Add Extensions for this Root CA certificate
    root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint()))
    
    # Step 4: Use Root CA's RSA private key to sign this certificate
    root_ca_cert.sign(private_key, sign_method)
    return root_ca_cert, private_key

if __name__ == '__main__':
    # Generate a Self-Signed Root CA Certificate
    root_ca_info = {}
    root_ca_info['C'] = "TW"
    root_ca_info['CN'] = "Root CA Certificate"
    root_ca_info['ST'] = "Taiwan"
    root_ca_info['O'] = "ijeCorp Ltd."
    root_ca_info['OU'] = "Security"
    root_ca_info['L'] = "Taipei"
    root_ca_cert, root_ca_private_key = create_self_signed_RootCA_certificate(root_ca_info)

    # Generate CSR for signed Certificate
    csr_info = {}
    csr_info['C'] = "TW"
    csr_info['CN'] = "MyCompany-Certificate"
    csr_info['ST'] = "."
    csr_info['O'] = "ijeCorp Ltd."
    csr_info['OU'] = "Security"
    csr, ca_private_key = create_Signed_Certificate_Request(csr_info);

    # Use Root CA's private key to sign a certificate from CSR
    cert = create_certificate_from_CSR(root_ca_cert, root_ca_private_key, csr)
    with open('my_cert.crt', 'w') as f:
        f.write(cert.as_pem()) 
以上的範例程式都是採用 SHA-256 是基於安全性的考量,請參考[2]

Reference:
[1] http://svn.osafoundation.org/m2crypto/trunk/contrib/SimpleX509create.py
[2] http://www.tbs-certificates.co.uk/FAQ/en/475.html


2014年3月12日 星期三

OpenSSL - 金鑰與憑證的管理

Key and Certificate Management

要讓 Web 或者 Service 能夠支援 SSL, 基本上有三個步驟:
1. 產生私有金鑰 (Private Key)
2. 產生 CSR (Certificate Signing Request), 並將 CSR 傳送給 CA
3. 把 CA 所提供的憑證 (Certificate) 安裝在 Web 或 Service的伺服器上

以下利用 OpenSSL 來說明如何完成以上 3 個步驟.

Key Generation

使用 openssl 產生私有金鑰 (private key) 的指令如下:

~$ openssl genrsa -aes256 -out private.key 2048

以下是執行後的輸出畫面, 會要求輸入Pass phrase 來保護這個 RSA private key.

Generating RSA private key, 2048 bit long modulus
.+++
.............................................+++
e is 65537 (0x10001)
Enter pass phrase for private.key:
Verifying - Enter pass phrase for private.key:


這是產生一把長度為 2048 bits 的 RSA private key, 並且使用 AES-256 與輸入的 Pass phrase 來保護這把 Private key。基本上, RSA的 Private key 長度建議至少是2048 bits才是比較安全的。執行後的結果 private.key 是一個加密後的檔案並且以 PEM 的格式儲存,內容類似以下:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,4616B291C58D187CE9787AD421E7DA80

9DbRWLR8N29lHz78aUCYWBUzDAK4e7UFfiV+A3oicaHm75FCw5hnf+3ScOUEymWk
Bz+sYKCjHTtD4fMyw4apF1/QmCn6KM+kKY4vsmOx1NXLLNhrX2SpmiZ+dsVfOg0D
IoEhw06Pzd767gy+zr8Q7JeMna1zKG7nzbIMM+WiwmiZKTErl16kyp0HH2OHSkQv
0or3cj83zswhb7VcArt52cJUhNdjkZdb3x+/bbehn5sFCMiNTc4UId5HBH84dyNC
l/KsDmdFfq8kGXhttpllz7pl8naYnamEQ0A+foaWI+MMXmMl5r5kXlDkAkCZ/y9U
LYmBLsSeMwrHVC34M+sCP8GEyeN4znAv9rb0eTs5/zkPo1V/orFxZYaQZwQ0yQn2
pUb10sD7cXrpJ4EQqPJzxOxhFAAq2C35lkYA5yrCwZiH6/Y66PvGYK1W1BMcB9B+
8t3Cn9xiNJ27HQ43oPWu6P07yxJYAPpkJMhiZ6cM1clYbi2ZrYKnajRORIoL0WgI
4d4zGYr48/Pd27ITSUxiBWIVsB8OZPGyjh3ebBGw1fe1i7iC1x/h35b+po8mk6Fg
tmIktPA9z/jUgSaorQsH9YzyA8DU4K1p3LCL4ZxHJJoEKOMv/7avQCRzm+FonWdz
e5rewtx9wNoWKSw4MPU6ozRB2tzW9RUJQeGfCgtwbjMDRQYYLmyLzPshekiR4srF
E3U1aJWwEDVTfdjlEgiB6dKzm/l1ywanBB5Ns84HSsagN7gZEBV3Y7TKlx+9Omd2
N6QIwTG42ERDmsuLlmky6Ju98yMHRNNC7ZrkLhR1c3w+KHht7cIm7VpqouNCYcjR
yhebuXpSakS4mPlYXKmFZlEgJI8NT9H1czn7XsNUE/Ty/wBlhgn5XGbmoRLg8b/L
jNqC/b3N4Xb9nWuirMmPwNf9Ja0M3MRJmjUrA3FJprHrSaJMF7SS3tHeu5vivnrP
P9vfibi8Cu2UVol3/y/gyBNGgsA2UnOz3xzPrY/22NA+VtDILIbsIukeHMGVPzdS
xE3BrgpyF68LrIg/Pb7F5XougYjW9SjuyYnQzum9XgvZGFsZJU+ENOmR+9gk8/iA
v+/RKairKW18E6kaf/9mIfYWWLHSPZyZqqo61Iho/BqO0vOSq7hd5at0KUsbtfr2
4o2cGMp5qYJxPBi5suIR3/H0bZnS72sAVPAeUGEhSi+QX9d9zQYJio8LfxsTZMZj
ArlJY3Lm9cGMEbS/n3jwC7zGE75j4aaNCTWccNWUqhF3p+QOCN3WL/yKXa1nDcx9
4AYt0UT8rHDHNVs1ylK97/e6OwV9bmhXf4shvBavvKcoSPVc2F8c/+yGWl/3BDyZ
MTTNYFN99Yll+g06DhSaQpUACbKpzHfNy83ideruLpqYLptqCEqE66pZZt08AhCg
JKNiTV6c6O09TBfwGz7Cqn+jsCsIN6iUbEOc1lEj9Ga+FtuVFy5h+nrzzSK3pA/W
mhqpnf9a0QmlfkrUBfmjCGyzQ1PnEs0Ki0PyPDISsRUewJXvWsDUoT3+k13nMfdE
hPZoPFjPA6pztnHUxUKDwx9xVmLTLHkLmu3VtWOaWl1qmZP57fMHoKjeaRYNYPN6
-----END RSA PRIVATE KEY-----

Creating Certificate Signing Requests (CSR)

為了向公開具備公信力的 CA 單位提出憑證申請, 必須要提供一個 CSR 的檔案給這個 CA單位。以下就是透過 openssl 使用先前產生的 RSA 金鑰來產生一個 CSR 的檔案,過程當中需要輸入一些相關的資料(可以參考以下範例中的黑色斜線粗體部份)
$ openssl req -new -key private.key -out CSR.csr

Enter pass phrase for private.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:.            
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ijeCorp        
Organizational Unit Name (eg, section) []:Security
Common Name (e.g. server FQDN or YOUR name) []:www.ijecorp.com
Email Address []:miller.lai@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:IM@R.O.C    
An optional company name []:ijeCorp

產生 CSR 後, 可以透過 openssl 來檢測 CSR的內容是否正確,指令如下:
~$ openssl req -text -in CSR.csr -noout

執行後的輸出結果如下:
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=TW, L=Taipei, O=ijeCorp, OU=Security, CN=www.ijecorp.com/emailAddress=miller.lai@gmail.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b2:fb:c9:5f:4c:0f:2a:11:d7:81:05:a9:e6:41:
                    43:35:b7:47:ba:be:58:42:32:ad:e9:99:be:c8:82:
                    57:73:ca:87:6c:f9:90:15:1d:4a:6d:cc:fc:81:e2:
                    2e:c2:1f:ed:fd:ae:45:cd:ce:c9:6c:43:f1:47:ef:
                    aa:8d:f8:e3:32:52:10:80:db:0a:b5:fa:be:91:87:
                    94:08:57:86:8e:6b:86:f6:63:05:2d:53:3c:c3:4c:
                    48:ad:4d:ee:f2:de:7c:68:9d:f7:01:5b:a1:99:2e:
                    69:60:b8:b1:59:4c:d8:69:7a:cf:47:bb:3c:c6:6f:
                    5d:99:08:5d:e8:5e:bd:34:e2:52:00:9c:70:62:89:
                    4b:aa:c6:8c:d7:0d:a0:fc:d7:1d:bf:18:9a:d4:e2:
                    b6:f8:26:5d:0b:bb:b0:af:4d:7e:ee:f8:22:cc:18:
                    7f:b7:a4:b4:12:c1:78:34:ed:29:30:b3:fa:93:97:
                    04:4c:a2:32:3b:f4:cb:98:52:6f:ea:11:ab:01:8d:
                    03:b6:d3:b4:cb:0e:f8:3d:cf:2f:ae:3b:51:c9:1d:
                    16:15:e2:d6:cc:8b:35:8e:df:70:c2:c5:18:b7:8f:
                    9f:42:a3:d9:99:55:c0:74:f3:ab:40:98:d0:0a:4d:
                    99:12:2e:92:5b:d6:d3:d6:73:2c:01:76:96:ea:8d:
                    fd:d5
                Exponent: 65537 (0x10001)
        Attributes:
            unstructuredName         :unable to print attribute
            challengePassword        :unable to print attribute
    Signature Algorithm: sha1WithRSAEncryption
         0b:5c:f4:d5:ae:f3:4a:4b:9b:d2:8e:e6:cd:b6:20:2c:9d:61:
         57:f3:9d:7f:95:03:71:9e:95:1b:4c:8f:ad:f8:f9:6c:c3:a6:
         32:be:6a:b9:bf:45:81:0a:6f:6d:3c:29:f6:90:00:81:73:ac:
         65:8d:19:ea:39:86:5d:8f:2b:d7:bf:2f:02:63:01:bb:87:0f:
         dd:3d:81:b2:3c:72:1c:d4:ad:9e:ba:35:e6:41:f2:2f:fb:b8:
         0e:9f:5d:26:2b:52:37:a3:7f:97:b0:35:78:a6:d4:5a:4f:df:
         32:15:9f:45:43:04:95:4e:f4:d6:71:68:57:59:b2:5b:28:e3:
         13:73:96:c8:cf:c1:df:56:e4:b0:f2:d9:ee:e2:67:7a:37:d2:
         ba:f6:17:9e:ca:6a:b2:96:6d:e8:bb:cf:ff:17:13:fb:cc:d6:
         05:95:c2:4b:f9:49:b9:67:d8:c3:39:c9:78:00:56:20:6f:d4:
         2c:5c:66:c7:a0:1b:bd:2f:5d:c7:8b:98:69:93:67:be:44:f6:
         84:b9:8b:ec:45:1b:be:b8:5b:e9:94:00:2f:1c:30:ad:5f:c1:
         57:3c:f9:11:e0:49:85:bd:93:e6:09:54:aa:94:d5:31:b4:89:
         40:8d:c3:b8:e7:f9:80:d7:71:62:dd:51:88:71:51:ed:8f:b4:
         5e:12:93:3a

在確認 CSR 內容正確後,就可以將 CSR 傳送到公認且有公信力的 CA 單位,並請求該單位為此 CSR 產生憑證 (Certificate)。一旦取得 CA 為此 CSR 產生的憑證後, 就可以將它安裝在需要支援 SSL 的伺服器上。

但是,如果只是開發階段需要測試,或只是自己的想要使用並不是要公開對外支援 SSL時候,可以自行產生一個所謂 Self-signed 的憑證。產生 Self-signed 憑證的方式如下:

~$ openssl x509 -req -days 365 -in CSR.csr -signkey private.key -out self-signed.crt

以下是執行後的輸出畫面, 會要求輸入Pass phrase 來取得 private.key 進行 sign 憑證的處理。最後產生一個 PEM 格式的憑證內容在 self-signed.crt 檔案中
Signature ok
subject=/C=TW/L=Taipei/O=ijeCorp/OU=Security/CN=www.ijecorp.com/emailAddress=miller.lai@gmail.com
Getting Private key
Enter pass phrase for private.key:

PEM格式的 self-signed.crt 的內容類似如下:
-----BEGIN CERTIFICATE-----
MIIDgjCCAmoCCQCQyr2MuBjL8jANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC
VFcxDzANBgNVBAcMBlRhaXBlaTEQMA4GA1UECgwHaWplQ29ycDERMA8GA1UECwwI
U2VjdXJpdHkxGDAWBgNVBAMMD3d3dy5pamVjb3JwLmNvbTEjMCEGCSqGSIb3DQEJ
ARYUbWlsbGVyLmxhaUBnbWFpbC5jb20wHhcNMTQwMzEyMDEzODU2WhcNMTUwMzEy
MDEzODU2WjCBgjELMAkGA1UEBhMCVFcxDzANBgNVBAcMBlRhaXBlaTEQMA4GA1UE
CgwHaWplQ29ycDERMA8GA1UECwwIU2VjdXJpdHkxGDAWBgNVBAMMD3d3dy5pamVj
b3JwLmNvbTEjMCEGCSqGSIb3DQEJARYUbWlsbGVyLmxhaUBnbWFpbC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy+8lfTA8qEdeBBanmQUM1t0e6
vlhCMq3pmb7Igldzyods+ZAVHUptzPyB4i7CH+39rkXNzslsQ/FH76qN+OMyUhCA
2wq1+r6Rh5QIV4aOa4b2YwUtUzzDTEitTe7y3nxonfcBW6GZLmlguLFZTNhpes9H
uzzGb12ZCF3oXr004lIAnHBiiUuqxozXDaD81x2/GJrU4rb4Jl0Lu7CvTX7u+CLM
GH+3pLQSwXg07Skws/qTlwRMojI79MuYUm/qEasBjQO207TLDvg9zy+uO1HJHRYV
4tbMizWO33DCxRi3j59Co9mZVcB086tAmNAKTZkSLpJb1tPWcywBdpbqjf3VAgMB
AAEwDQYJKoZIhvcNAQEFBQADggEBAIqbY8rKAJ40JIXmtJJSWrLzZ5R9OXyxKWHy
N/8Szn8oLMeSPX6Fmd2oWGbJEDuHf17l9IkbKnfDIrlW+lbVG4qY2fZmH5GA2rmP
bWMrIzXqH+NJfp9NyUhhCCT59fDrHKiGf13opR8gvOo2ft0GOQ+kZsUn/7t1GoQ9
3Ybch2CNjfob5sEQ+nGDsyg3IRFnunAzeAdKLS9h4BwZOdz2lvVnHNR4Wb/TygDZ
mVL2ntg2uWCWQvJ5QCZlyjXthtp0EeDNiJeL3ThOlsiKujuhjMrqjThZuGqvpVxO
3v46/+iqCkdGuP/C2mZqJwbNYvOoPCBCeBYMXGpDrC2VqwYULy4=
-----END CERTIFICATE-----

此外,如果想要直接從 private key 產生 self-signed 憑證也是可以, 執行的指令如下:

~$ openssl req -new -x509 -days 365 -key private.key -out self-signed-2.crt

但是, 因為 Self-signed 憑證並不是透過公認與具有公信力的 CA 所發行的憑證。因此,當 Web 伺服器是安裝 Self-signed 的憑證來支援 SSL時,一般不同的瀏覽器在第一次瀏覽此網站時,遇到 self-signed 憑證時, 會跳出類似如下圖的畫面。



無論你是透過 CA 取得憑證或是自行產生 self-signed 的憑證, 都可以透過 openssl 指令來檢測憑證的內容,透過以下的指令:
~$ openssl x509 -text -in self-signed.crt -noout

執行後輸出的憑證內容如下,因為它是 self-signed 的憑證,所以只會有基本的資訊:
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 10433359898838879218 (0x90cabd8cb818cbf2)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=TW, L=Taipei, O=ijeCorp, OU=Security, CN=www.ijecorp.com/emailAddress=miller.lai@gmail.com
        Validity
            Not Before: Mar 12 01:38:56 2014 GMT
            Not After : Mar 12 01:38:56 2015 GMT
        Subject: C=TW, L=Taipei, O=ijeCorp, OU=Security, CN=www.ijecorp.com/emailAddress=miller.lai@gmail.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b2:fb:c9:5f:4c:0f:2a:11:d7:81:05:a9:e6:41:
                    43:35:b7:47:ba:be:58:42:32:ad:e9:99:be:c8:82:
                    57:73:ca:87:6c:f9:90:15:1d:4a:6d:cc:fc:81:e2:
                    2e:c2:1f:ed:fd:ae:45:cd:ce:c9:6c:43:f1:47:ef:
                    aa:8d:f8:e3:32:52:10:80:db:0a:b5:fa:be:91:87:
                    94:08:57:86:8e:6b:86:f6:63:05:2d:53:3c:c3:4c:
                    48:ad:4d:ee:f2:de:7c:68:9d:f7:01:5b:a1:99:2e:
                    69:60:b8:b1:59:4c:d8:69:7a:cf:47:bb:3c:c6:6f:
                    5d:99:08:5d:e8:5e:bd:34:e2:52:00:9c:70:62:89:
                    4b:aa:c6:8c:d7:0d:a0:fc:d7:1d:bf:18:9a:d4:e2:
                    b6:f8:26:5d:0b:bb:b0:af:4d:7e:ee:f8:22:cc:18:
                    7f:b7:a4:b4:12:c1:78:34:ed:29:30:b3:fa:93:97:
                    04:4c:a2:32:3b:f4:cb:98:52:6f:ea:11:ab:01:8d:
                    03:b6:d3:b4:cb:0e:f8:3d:cf:2f:ae:3b:51:c9:1d:
                    16:15:e2:d6:cc:8b:35:8e:df:70:c2:c5:18:b7:8f:
                    9f:42:a3:d9:99:55:c0:74:f3:ab:40:98:d0:0a:4d:
                    99:12:2e:92:5b:d6:d3:d6:73:2c:01:76:96:ea:8d:
                    fd:d5
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha1WithRSAEncryption
         8a:9b:63:ca:ca:00:9e:34:24:85:e6:b4:92:52:5a:b2:f3:67:
         94:7d:39:7c:b1:29:61:f2:37:ff:12:ce:7f:28:2c:c7:92:3d:
         7e:85:99:dd:a8:58:66:c9:10:3b:87:7f:5e:e5:f4:89:1b:2a:
         77:c3:22:b9:56:fa:56:d5:1b:8a:98:d9:f6:66:1f:91:80:da:
         b9:8f:6d:63:2b:23:35:ea:1f:e3:49:7e:9f:4d:c9:48:61:08:
         24:f9:f5:f0:eb:1c:a8:86:7f:5d:e8:a5:1f:20:bc:ea:36:7e:
         dd:06:39:0f:a4:66:c5:27:ff:bb:75:1a:84:3d:dd:86:dc:87:
         60:8d:8d:fa:1b:e6:c1:10:fa:71:83:b3:28:37:21:11:67:ba:
         70:33:78:07:4a:2d:2f:61:e0:1c:19:39:dc:f6:96:f5:67:1c:
         d4:78:59:bf:d3:ca:00:d9:99:52:f6:9e:d8:36:b9:60:96:42:
         f2:79:40:26:65:ca:35:ed:86:da:74:11:e0:cd:88:97:8b:dd:
         38:4e:96:c8:8a:ba:3b:a1:8c:ca:ea:8d:38:59:b8:6a:af:a5:
         5c:4e:de:fe:3a:ff:e8:aa:0a:47:46:b8:ff:c2:da:66:6a:27:
         06:cd:62:f3:a8:3c:20:42:78:16:0c:5c:6a:43:ac:2d:95:ab:
         06:14:2f:2e

以下我們來觀察一個由公開 CA 所 signed 過的憑證內容, 有關 X509v3 extensions 的部分:
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:7a:a9:a8:c2:96:21:0c
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple Root CA
        Validity
            Not Before: Feb  1 22:12:15 2012 GMT
            Not After : Feb  1 22:12:15 2027 GMT
        Subject: CN=Developer ID Certification Authority, OU=Apple Certification Authority, O=Apple Inc., C=US
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:89:76:4f:06:5b:9a:41:ee:a5:23:2b:02:a3:5f:
                    d7:73:3f:c0:35:b0:8b:84:0a:3f:06:24:7f:a7:95:
                    3f:eb:4f:0e:93:af:b4:0e:d0:c8:3e:e5:6d:18:b3:
                    1f:e8:89:47:bf:d7:09:08:e4:ff:56:98:29:15:e7:
                    94:9d:b9:35:a3:0a:cd:b4:c0:e1:e2:60:f4:ca:ec:
                    29:78:45:69:69:60:6b:5f:8a:92:fc:9e:23:e6:3a:
                    c2:22:b3:31:4f:1c:ba:f2:b6:34:59:42:ee:b0:a9:
                    02:03:18:91:04:b6:b3:78:2e:33:1f:80:45:0d:45:
                    6f:bb:0e:5a:5b:7f:3a:e7:d8:08:d7:0b:0e:32:6d:
                    fb:86:36:e4:6c:ab:c4:11:8a:70:84:26:aa:9f:44:
                    d1:f1:b8:c6:7b:94:17:9b:48:f7:0b:58:16:ba:23:
                    c5:9f:15:39:7e:ca:5d:c3:32:5f:0f:e0:52:7f:40:
                    ea:be:ac:08:64:95:5b:c9:1a:9c:e5:80:ca:1f:6a:
                    44:1c:6c:3e:c4:b0:26:1f:1d:ec:7b:af:5e:a0:6a:
                    3d:47:a9:58:12:31:3f:20:76:28:6d:1d:1c:b0:c2:
                    4e:11:69:26:8b:cb:d6:d0:11:82:c9:4e:0f:f1:56:
                    74:d0:d9:08:4b:66:78:a2:ab:ac:a7:e2:d2:4c:87:
                    59:c9
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                57:17:ED:A2:CF:DC:7C:98:A1:10:E0:FC:BE:87:2D:2C:F2:E3:17:54
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Authority Key Identifier: 
                keyid:2B:D0:69:47:94:76:09:FE:F4:6B:8D:2E:40:A6:F7:47:4D:7F:08:5E

            X509v3 CRL Distribution Points: 
                URI:http://crl.apple.com/root.crl

            X509v3 Key Usage: critical
                Digital Signature, Certificate Sign, CRL Sign

 其中幾個比較重要的 X509 Extensions 相關說明如下:
X509v3 Basic Constraints 指定這個憑證是否屬於CA,另外是否為 critical 的限制。
例如:
X509v3 Basic Constraints: critical
    CA:TRUE

X509v3 Key Usage 指定這個憑證可以用來做什麼。
例如:

X509v3 Key Usage: critical
    Certificate Sign, CRL Sign

X509v3 Extended key Usage 指定這個憑證可以用在什麼操作上。
例如:
X509v3 Extended Key Usage: critical
    TLS Web Server Authentication, TLS Web Client Authentication

X509v3 CRL Distribution Points 指定CA所提供的 Revocation List 要去哪邊找。如果這個憑證是每隔一段時間就會更換的話,那麼這個設定就會非常重要。

例如:
X509v3 CRL Distribution Points: 

    Full Name:
      URI:http://www.apple.com/appleca/root.crl

X509v3 Certificate Policies 指定這個憑證是基於什麼 Policy 所簽發出來的。
例如:
X509v3 Certificate Policies: 

    Policy: 1.2.840.113635.100.5.1

      CPS: https://www.apple.com/appleca/

      User Notice:

        Explicit Text: Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.

Authority Information Access 是用來提供額外的CA資訊,以及即時驗證 certificate revocation的資料。而OCSP是指 CA's Online Certificate Status Protocol 的回應者 (responder)。
例如:
Authority Information Access:
    OCSP - URI: http://ocsp.starfieldtech.com/
    CA Issuers - URI:http://www.cert.com/resp/intermediate.crt

X509v3 Subject Key Identifier 主要在於表示這個 Certificate 包含一個特定的 Public Key。所有的CA Certificate都應該包含這個 extension, 由同一個 CA 所發出來的這些 Certificate 也要包含一個  X509v3 Authority Key Identifier 的 extension , 而它的值會和這個CA 的 Subject Key Identifier 一樣。

X509v3 Authority Key Identifier 指定這張 Certificate 是由哪一個 CA 所發出來的。

以下我們可以透過觀察 Facebook網站使用的 HTTPS Certificate來了解 Authority Key Identifier 和 Subject Key Identifier 的關係。










Root CA 是 DigCert  High  Assurance  EV Root CA 憑證的 Subject Key Identifier 和 Authority Key Identifier 分別如下:

X509v3 Subject Key Identifier: 
    B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3

X509v3 Authority Key Identifier: 

    keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3

Root CA 所簽發的 Intermediate CA - DigiCert SHA2 High Assurance Server CA 憑證的 Subject Key Identifier 和 Authority Key Identifier 分別如下:

X509v3 Subject Key Identifier: 
    51:68:FF:90:AF:02:07:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B

X509v3 Authority Key Identifier: 
    keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3

最後,由  Intermediate CA 所簽發的最後給Facebook的Web Server的憑證的 Subject Key Identifier 和 Authority Key Identifier 分別如下



X509v3 Subject Key Identifier: 
    43:09:93:40:FA:11:4B:30:33:EC:F2:87:6E:8D:71:18:CF:8A:BC:8E

X509v3 Authority Key Identifier: 
    keyid:51:68:FF:90:AF:02:07:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B

在 verify certificate chain 過程中,Facebook 的 Web Server憑證中的 Authority Key Identifier  必須要對應到 Intermediate CA憑證的 Subject Key Identifier 。而 Intermediate CA憑證的 
Authority Key Identifier 必須要對應到 Root CA 憑證的 Subject Key Identifier。

而 Root CA憑證中的Authority Key Identifier 則是對應自己的Subject Key Identifier  

最後,Certificate Chain 的存放順序必須是如下所示,Root CA一定是放在最下方,再依據簽發的順序置放:

-----BEGIN CERTIFICATE-----
Server certificate
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Intermediate certificate
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Root CA's certificate
-----END CERTIFICATE-----

Reference:
[1] Standard X.509 V3 Certificate Extensions
[2] Check Certificate Chain
[3] Creating a .pem File for SSL Certificate Installations
[4] CA建置工具:Openssl的管理與使用介紹(上)
[5] How to create SSL X.509 Certificate ?
[6] OpenSSL Cookbook