﻿# 如何使用 OpenSSL 工具產製 CSR 憑證要求檔並成功申請正式 TLS 憑證

我們公司有經銷代理 TWCA 網站伺服器憑證，每隔一段時間都會有一些死忠的客戶跟我們定期續約購買，但這個過程很多人沒有經驗，經常搞不清楚該如何申請。如果你是開發人員，透過 [mkcert](https://github.com/FiloSottile/mkcert) 建立**自簽憑證**完全沒有難度，但是若要申請一個**正式憑證**就不是很多人能清楚步驟了。這篇文章我打算來解說一個完整的憑證申請流程，讓每個人都可以輕鬆掌握。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/b74f64de5adf47883356-173604519-edf61ea1-f240-403b-9465-8891e33fb5f3.jpg)

### 安裝 OpenSSL 工具

[OpenSSL](https://www.openssl.org/) 是一個跨平台工具，在 Linux 是內建的，而在 Windows 上安裝也十分簡單。

-   透過 [Chocolatey](https://chocolatey.org/install) 安裝 [OpenSSL.Light](https://community.chocolatey.org/packages/OpenSSL.Light) 套件
    
    ```powershell
    choco upgrade OpenSSL.Light -y
    ```
    
-   直接使用 Git for Windows 內建的 OpenSSL 工具
    
    預設你只要安裝 Git for Windows 就會內含 `openssl` 工具程式，預設執行檔路徑如下：
    
    ```powershell
    C:\Program Files\Git\usr\bin\openssl.exe
    ```
    
    > 請記得設定 `PATH` 環境變數，加入 `C:\Program Files\Git\usr\bin` 這個路徑即可！
    

以下可以檢查 `openssl` 命令列工具版本：

```bash
PS> openssl version
OpenSSL 3.0.3 3 May 2022 (Library: OpenSSL 3.0.3 3 May 2022)
```

### 準備申請 SSL/TLS 憑證

1.  先想清楚你想要申請的 SSL/TLS 憑證上要顯示哪些資訊
    
    一般來說，申請一張 SSL/TLS 憑證需要提供以下 6 個欄位，這些資訊會寫入**憑證**的 `Subject` 屬性中，所以非常重要。
    
    ![憑證資訊](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/dd87524608d9db19a178-173601965-8ec410e2-d247-450a-a701-63a61f68b998.png)
    
    以下是填寫時的範例：
    
    -   一般名稱 (CN) (Common Name)
        
        `www.miniasp.com.tw`
        
        > 這是最重要的欄位，絕對不能寫錯，請填寫你想申請的網站域名([FQDN](https://zh.m.wikipedia.org/zh-tw/%E5%AE%8C%E6%95%B4%E7%B6%B2%E5%9F%9F%E5%90%8D%E7%A8%B1))！
        
    -   組織名稱 (O) (Organization)
        
        `DUOTIFY INC.`
        
        > 這是通常是寫上你的公司名稱，建議寫英文，大小寫皆可。
        
    -   組織單位 (OU) (Ogranization Unit)
        
        `IT`
        
        > 這個欄位沒有很重要，通常是指**部門名稱**，但其實你想寫什麼名稱都可以，我自己都統一寫 `IT` 就好！
        
    -   所在位置 (L) (Location)
        
        `Taipei`
        
        > 這個欄位可以寫你公司的總部位置，我通常都會寫**城市名稱**。
        
    -   州別/省分 (ST) (State)
        
        `Taiwan`
        
        > 臺灣沒有**省分**的概念，但此欄位必填，所以我通常都會寫上 `Taiwan` 字樣。
        
    -   國家 (C) (Country)
        
        `TW`
        
        > 這裡請寫上國家代碼，必須全部大寫，可參考 [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) 編碼。
        
2.  建立一個文字格式的 OpenSSL 設定檔：`ssl.conf`
    
    ```ini
    [req]
    prompt = no
    default_md = sha256
    default_bits = 2048
    distinguished_name = dn
    x509_extensions = v3_req
    
    [dn]
    C = TW
    ST = Taiwan
    L = Taipei
    O = DUOTIFY INC.
    OU = IT
    CN = www.miniasp.com.tw
    
    [v3_req]
    ```
    
    > 這個檔案你只需要調整 `[dn]` 的部分，替換成你申請時事先準備好的 6 個欄位資料！
    
3.  建立 CSR (Certificate Signing Request) 憑證要求檔 (`PKCS#10`)
    
    建立私密金鑰並同時建立 CSR (Certificate Signing Request) 憑證要求檔：
    
    ```bash
    openssl req -new -nodes -sha256 -utf8 -newkey rsa:2048 -keyout server.key -out server.csr -config ssl.conf
    ```
    
    > 這個命令會產生 1 個私密金鑰 `server.key` 與 1 個 CSR 憑證要求檔 `server.csr`，兩個檔案都非常重要！
    
    你可以透過以下指令查看 CSR (Certificate Signing Request) 憑證要求檔內容
    
    ```bash
    openssl req -in server.csr -noout -text
    ```
    
    > 線上版: [CSR Decoder](https://www.sslshopper.com/csr-decoder.html)
    
4.  請將 `server.csr` 寄給我們 (申購憑證的廠商)，就可以開始進行申購 SSL/TLS 憑證的程序了！
    
    從我們經銷商的角度來看，也只是將這個 `server.csr` 憑證要求檔寄給 TWCA 而已，等他們檢核內容無誤後，核發**正式憑證**給我們。
    

### 取得伺服器憑證並產製 PFX (PKCS#12) 憑證檔

申購到憑證之後，你會收到類似以下的郵件：

![TWCA SSL伺服器數位憑證下載通知](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/077f1daab71504490f9a-173594247-d01126a7-b4f7-4cca-abf0-84d54aed47e9.png)

郵件的附件會有一個 `cert.zip` 壓縮檔，裡面包含了完整的**憑證鏈**，其內容如下：

![cert.zip](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/4d54bab218d0447778d9-173594814-b0caad01-4204-46b9-90af-7b7e380ce2c8.png)

這三個檔案分別用途如下：

1.  根憑證 (Root Certificate)
    
    `root.cer`
    
    通常不需要特別使用，因為信任的根憑證老早就在每個人的電腦或瀏覽器中了！
    
2.  中繼憑證 (Intermediate Certificate)
    
    `uca.cer`
    
    有些伺服器需要將中繼憑證一並安裝到網站伺服器中才能運作，因此你日後可能會用上。
    
3.  伺服器憑證 (Server Certificate)
    
    `server.cer`
    
    這個檔案是最主要的憑證檔！
    

由於 PKI 基礎建設，需要一個**公開憑證** (`server.cer`) 與一個**私密金鑰** (`server.key`) 才能運作，因此你必須同時擁有這兩個檔案，才能完成整個 TLS 加解密的過程。

在 Linux 作業系統下，大部分的 Web Server 網站伺服器，都需要讓你指定這兩個檔案的路徑，外加一個**金鑰密碼**才能運作，如果你希望**網站伺服器**在啟動的時候不要人工輸入密碼，那麼你就不應該對你的**私密金鑰**加密。**但是你就要做好私密金鑰的保存與管理。**

在 Windows 作業系統下，主要是使用 IIS 為主，但是 IIS 並不使用 PEM 格式的**憑證檔**與**私密金鑰檔**，因此你需要將這兩個檔案合併成一個 [PKCS#12](https://zh.wikipedia.org/zh-tw/PKCS_12) 格式的 PFX 檔案(`*.pfx`)。不過，格式轉換之前，建議要將 `cert.zip` 壓縮檔中的三個憑證，全部都先合併成一個憑證檔！其步驟如下：

1.  先合併憑證檔
    
    PowerShell
    
    ```powershell
    Get-Content server.cer, uca.cer, root.cer | Out-File -Encoding ascii -FilePath server-combined.cer
    ```
    
    Bash
    
    ```bash
    cat server.cer uca.cer root.cer > server-combined.cer
    ```
    
2.  轉換檔案格式的命令如下：
    
    使用預設轉換
    
    ```bash
    openssl pkcs12 -export -in server-combined.cer -inkey server.key -out server.pfx
    Enter Export Password:
    ```
    
    使用 TripleDES 加密演算法 (若要上傳憑證到 Azure Web App 需要用這段命令產生 PFX 檔案) (OpenSSL 3+)
    
    ```bash
    openssl pkcs12 -export -in server-combined.cer -inkey server.key -out server.pfx -legacy -provider-path "C:\Program Files\OpenSSL\bin"
    Enter Export Password:
    ```
    

> 注意: 由於 PKCS#12 規格上提到產製 `*.pfx` 檔案時，強制規定必須設定一組密碼，所以在匯出的時候一定要設定密碼。

如此以來，這整個過程你已經擁有了 4 個檔案，分別是：

1.  `server.key` (私密金鑰) (使用 `PEM` 格式) (無密碼保護)
2.  `server.cer` (憑證檔案) (使用 `PEM` 格式) (或 `server-combined.cer` 合併憑證後的檔案)
3.  `server.pfx` (PFX 檔案) (使用 `PKCS#12` 格式)
4.  `server.csr` (憑證要求檔) (使用 `PKCS#10` 格式) (**這個檔案已經不需要了**)

以上就是申請正式 SSL/TLS 憑證的完整過程，非常簡單！ 👍

### TL;DR

最後來個懶人包，就算你不是工程師，開啟 Windows PowerShell 複製貼上總會吧？(請記得 `[dn]` 內的資訊要改過)

1.  快速建立**私密金鑰**(`server.key`)與**憑證要求檔**(`server.csr`)
    
    ```powershell
    @"
    [req]
    prompt = no
    default_md = sha256
    default_bits = 2048
    distinguished_name = dn
    x509_extensions = v3_req
    
    [dn]
    C = TW
    ST = Taiwan
    L = Taipei
    O = DUOTIFY INC.
    OU = IT
    CN = www.miniasp.com.tw
    
    [v3_req]
    "@ | Out-File -Encoding ascii -FilePath 'ssl.conf'
    
    openssl req -new -nodes -sha256 -utf8 -newkey rsa:2048 -keyout server.key -out server.csr -config ssl.conf
    ```
    
2.  寄出 `server.csr` 申請憑證
    
3.  收到 `cert.zip` 憑證清單壓縮檔
    
    基本上，目前目錄中應該有兩個重要檔案，一個是 `server.key` 金鑰檔，另一個是 `cert.zip` 憑證清單壓縮檔。
    
    先用 PowerShell 解壓縮 `cert.zip` 壓縮檔：
    
    ```powershell
    Expand-Archive -Path cert.zip -DestinationPath .
    ```
    
    合成一個 `server-combined.cer` 憑證檔
    
    ```powershell
    Get-Content server.cer, uca.cer, root.cer | Out-File -Encoding ascii -FilePath server-combined.cer
    ```
    
4.  產生 PFX 憑證檔 (`server.pfx`)
    
    ```bash
    openssl pkcs12 -export -in server-combined.cer -inkey server.key -out server.pfx -legacy -provider-path "C:\Program Files\OpenSSL\bin"
    ```
    
    > 請務必妥善保存 PFX 憑證密碼，匯入憑證時需要輸入。
    

### 相關連結

-   [OpenSSL Command-Line HOWTO](https://www.madboa.com/geek/openssl/)
-   [/docs/manmaster/man1/openssl-genpkey.html](https://www.openssl.org/docs/manmaster/man1/openssl-genpkey.html)
-   [/docs/manmaster/man1/openssl-genrsa.html](https://www.openssl.org/docs/manmaster/man1/openssl-genrsa.html)
-   [/docs/manmaster/man1/openssl-req.html](https://www.openssl.org/docs/manmaster/man1/openssl-req.html)
-   [/docs/manmaster/man1/openssl-rsa.html](https://www.openssl.org/docs/manmaster/man1/openssl-rsa.html)
-   [/docs/manmaster/man1/openssl-pkcs12.html](https://www.openssl.org/docs/manmaster/man1/openssl-pkcs12.html)
-   [How to generate an openSSL key using a passphrase from the command line? - Stack Overflow](https://stackoverflow.com/a/4300425/910074)
-   [PKCS 12 - 維基百科，自由的百科全書](https://zh.wikipedia.org/zh-tw/PKCS_12)
-   [RFC 2986 - PKCS #10: Certification Request Syntax Specification Version 1.7](https://datatracker.ietf.org/doc/html/rfc2986)
-   [Azure App Service unable to validate .pfx file: Certificate failed validation because it could not be loaded - Stack Overflow](https://stackoverflow.com/a/73001635/910074)
