如何使用 OpenSSL 建立一張含有 Certificate Revocation List (CRL) 的憑證

最近因為公司在建立 ISO 27001 資訊安全管理系統,在文件管理部分就會想說要有一個高強度且具備不可否認性的數位簽章(Digital Signature)。建立一組公司用的 CA 憑證並透過這張 CA 憑證簽發給員工使用的數位憑證其實很簡單,但之前一直沒機會研究如何手工打造 CRL 憑證撤銷清單,今天研究了一下,終於可以自行簽發 CRL 憑證了。

CRL

Big Picture

由於手工打造 PKI 基礎建設牽涉到的知識相對複雜,這邊我試圖用比較簡單的方式來說明。

  • 首先,你需要先建立一個最上層、最權威的「受信任的根憑證」(Trusted Root Certification Authorities)

    以下簡稱 CA 憑證

  • 然後所有人都需要將 CA 憑證安裝到每個人的電腦中

    你可以透過許多方法將 CA 憑證派送到每台電腦中,也可以讓每個人自己下載安裝

    每個人的 個人憑證 (Personal Certificate) 都需要透過 CA 憑證進行簽章處理,才能算是一個受信任的憑證

  • 你需要準備一張 CRL 憑證,紀錄著所有「被撤銷」的憑證清單,這張憑證一樣要透過 CA 憑證簽署才是合法的、受信任的憑證

    你可以先準備好一張空白的 CRL 憑證,並且發佈到一個可公開存取的網站上,取得一個 CRL 網址

  • 開始讓員工申請個人用的數位憑證

    基本步驟就是先建立 CSR (Certificate Signing Request) 憑證簽署要求檔,然後交由 CA 進行簽署並獲得正式憑證。本篇文章不會特別講解這個過程,我之前已經有許多 OpenSSL 文章分享過這個過程。

建立 CA 憑證

建立 CA 憑證相對簡單,一個命令就可以同時建立「私鑰」與「公鑰」,而「公鑰」其實就是 CA 憑證:

openssl req -new -nodes -sha256 -utf8 -newkey rsa:2048 -keyout ca.key -x509 -days 3650 -out ca.crt

過程中要設定一些憑證屬性:

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]:Taiwan
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Duotify Inc.
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:Duotify Global Root CA
Email Address []:

這個命令會產生兩個檔案:

  1. ca.key (簽署憑證時會需要用到的私密金鑰)
  2. ca.crt (即 CA 憑證,需派送到每台電腦中)

建立一張空的 CRL 憑證

我們要建立一張 CRL 憑證,主要有以下三個步驟:

  1. 建立一個空的憑證資料庫檔 (certindex)

    這個檔案將會保存未來透過 CA 憑證簽發個人憑證時的完整記錄,未來要撤銷憑證時,也是去調整這個檔案的內容,你可以把這個檔案當成一個文字格式的資料庫。

    我們先建立空白的檔案即可:

    touch certindex
    
  2. 建立 crlnumber 檔案

    每次核發一張新的 CRL 憑證,這個 crlnumber 檔案內容的編號就會遞增(+1),你可以視為一個 CRL 憑證的序號。

    我們可以從 01 開始:

    echo 01 > crlnumber
    

    如果你可能會廢止很多憑證的話,這裡的 CRL 可能會很大,此時你很有可能會將 CRL 分段處理,因此 crlnumber 也有可能會從 1000 或 2000 開始計算,基本上這個 CRL Number 可以自由定義其編號起始點。

  3. 建立 certserial 檔案

    其實每張憑證都有個 Serial number 憑證序號,如果你不指定的話,每次核發憑證都會給一段很長的亂碼序號。如果你在建立憑證時有設定 certserial 的話,透過 OpenSSL 建立新的憑證時,就會自動用你的數字來編號,每次簽署新的憑證都會自動以此序號為主,並且會在簽署後自動累加上去 (+1)。

    echo 01 > certserial
    
  4. 建立一個 ca.conf 設定檔

    [ ca ]
    default_ca = myca
    
    [ crl_ext ]
    # issuerAltName=issuer:copy  #this would copy the issuer name to altname
    authorityKeyIdentifier=keyid:always
    
    [ myca ]
    dir = ./
    new_certs_dir = $dir
    unique_subject = no
    certificate = $dir/ca.crt
    database = $dir/certindex
    private_key = $dir/ca.key
    serial = $dir/certserial
    default_days = 730
    default_md = sha1
    policy = myca_policy
    x509_extensions = myca_extensions
    crlnumber = $dir/crlnumber
    default_crl_days = 730
    
    [ myca_policy ]
    commonName = supplied
    stateOrProvinceName = supplied
    countryName = optional
    emailAddress = optional
    organizationName = supplied
    organizationalUnitName = optional
    
    [ myca_extensions ]
    basicConstraints = CA:false
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always
    keyUsage = digitalSignature,keyEncipherment
    extendedKeyUsage = serverAuth
    crlDistributionPoints = URI:https://blog.miniasp.com/root.crl
    
  5. 簽發 DER 格式的 CRL 憑證檔 (root.crl)

    openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
    openssl crl -inform PEM -in root.crl.pem -outform DER -out root.crl
    rm root.crl.pem
    
  6. 將檔案上傳到 crlDistributionPoints 指定的網址

建立個人憑證並附上 CRL 網址

  1. 建立私密金鑰

    openssl genrsa -out will.key 4096
    
  2. 建立 CSR 憑證簽署要求檔

    建立一個 openssl.conf 設定檔,設定憑證的基本資料:

    [req]
    prompt = no
    default_md = sha256
    default_bits = 2048
    distinguished_name = dn
    
    [dn]
    C = TW
    ST = Taiwan
    L = Taipei
    O = Duotify Inc.
    OU = IT Department
    emailAddress = [email protected]
    CN = Will 保哥
    

    產生 CSR 憑證簽署要求檔

    openssl req -new -key will.key -out will.csr -config openssl.conf -utf8
    
  3. 建立一個簽署憑證時需要的擴充屬性定義檔

    假設檔名為 cert_template.conf

    basicConstraints = CA:FALSE
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always
    keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth, serverAuth
    nsCertType = client, server, email
    nsComment = "Duotify Personal Certificate"
    crlDistributionPoints = URI:https://blog.miniasp.com/root.crl
    
  4. 使用 CA 憑證核發伺服器憑證

    openssl ca -config ca.conf -notext -batch -in will.csr -out will.crt -extfile cert_template.conf
    

    核發成功後,會在 certindex 檔案看到以下內容:

    V       240831110206Z           01      unknown /CN=Will Huang/ST=Taiwan/C=TW/[email protected]/O=Duotify Inc./OU=IT
    
  5. 合併 will.key 與 will.crt 為 PFX (PKCS#12) 憑證檔 (will.pfx)

    openssl pkcs12 -export -in will.crt -inkey will.key -out will.pfx
    

撤銷現有憑證

  1. 指定要撤銷的憑證

    openssl ca -config ca.conf -revoke will.crt
    

    撤銷成功後,會在 certindex 檔案看到以下內容:

    R       240831110206Z   220901110514Z   01      unknown /CN=Will Huang/ST=Taiwan/C=TW/[email protected]/O=Duotify Inc./OU=IT
    
  2. 簽發 DER 格式的 CRL 憑證檔 (root.crl)

    # 先建立 PEM 格式的 `root.crl.pem` 憑證檔
    openssl ca -config ca.conf -gencrl -keyfile ca.key -cert ca.crt -out root.crl.pem
    # 再將 PEM 格式轉為 DER 格式的憑證檔
    openssl crl -inform PEM -in root.crl.pem -outform DER -out root.crl
    # 用不到 PEM 格式的檔案就可以砍掉
    rm root.crl.pem
    
  3. 將檔案上傳到 crlDistributionPoints 指定的網址

驗證憑證是否有效

  1. 若要驗證憑證是否有效,在 Windows 可能要先設法清除 CRL 快取才行,否則你可能會測試不出效果

    certutil -urlcache crl delete
    
  2. 如果你可以直接取得 CA 憑證與 CRL 憑證,就可以直接使用 openssl 驗證憑證是否已被撤銷,不需要事先清空快取

    # 將 DER 格式轉為 PEM 格式的憑證檔
    openssl crl -inform DER -in root.crl -outform PEM -out root.crl.pem
    # 合併 CA 憑證與 CRL 憑證
    cat ca.crt root.crl.pem > test.pem
    # 檢查 will.crt 憑證是否被撤銷
    openssl verify -extended_crl -verbose -CAfile test.pem -crl_check will.crt
    

相關連結

留言評論