使用 OpenSSL 建立私有 CA:1 根證書

sparkdev發表於2019-02-14

OpenSSL 建立私有 CA 三部曲:
使用 OpenSSL 建立私有 CA:1 根證照
使用 OpenSSL 建立私有 CA:2 中間證照
使用 OpenSSL 建立私有 CA:3 使用者證照

OpenSSL 是一個免費開源的庫,它提供了一些處理數字證照的命令列工具。其中一些工具可以用作證照頒發機構(Certificate Authority 即 CA)。
證照頒發機構(CA)是簽署數字證照的實體。許多網站需要讓他們的客戶知道連線是安全的,所以需要從一個被廣泛信任的CA(例如VeriSign, DigiCert)來為他們的域名簽署證照,也就是我們常說的 HTTPS 證照。
本系列文章的目的不是讓你建立像 VeriSign 那樣的 CA 機構。在很多情況下,我們需要在公司區域網內的網站中啟用 HTTPS,比如測試環境,或者是公司內網中的管理系統(現在主流的瀏覽器都把 HTTP 站點標記為不安全)。此時通過 OpenSSL 建立私有 CA 並頒發證照就是很好的選擇了。
本系列分為三篇文章,即本文《使用 OpenSSL 建立私有 CA:1 根證照》後續的《使用 OpenSSL 建立私有 CA:2 中間證照》和《使用 OpenSSL 建立私有 CA:3 使用者證照》。
說明:本系列文章的演示環境為 Ubuntu 18.04,OpenSSL 的版本為 1.1.0g。

基本目錄結構

建立 myca 目錄儲存 CA 相關的所有內容,然後建立 myca/rootca 目錄用來儲存根證照相關的內容:

至於上圖中的 myca/powerca 和 myca/usercert 則存放後面要介紹的中間證照和使用者證照的內容。

準備根證照的配置檔案

OpenSSL 程式提供了一個預設的配置檔案:/etc/ssl/openssl.cnf,但是由於我們自定義的內容比較多,所以乾脆建立一個套單獨的配置檔案。建立檔案 rootca/rootca.cnf,編輯其內容如下:

# OpenSSL root CA configuration file.
# v1
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = /home/nick/projects/myca/rootca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/db/index
serial = $dir/db/serial
RANDFILE = $dir/private/random
# The root key and root certificate.
private_key = $dir/private/rootca.key.pem
certificate = $dir/certs/rootca.cert.pem
# For certificate revocation lists.
crlnumber = $dir/db/crlnumber
crl = $dir/crl/rootca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 3750
preserve = no
policy = policy_strict
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
# Optionally, specify some defaults.
prompt = no
input_password = 123456

default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
# make sure use x509_extensions, do not use req_extensions.
x509_extensions = v3_ca
# use the req_extensions not work.
#req_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = CN
stateOrProvinceName = ShaanXi
localityName = Xian
organizationName = NickLi Ltd
organizationalUnitName = NickLi Ltd CA
commonName = NickLi Root CA
emailAddress = ljfpower@163.com
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

這是一個非常重要的配置檔案,指定了很多配置的目錄,其中最重要的一個已經被抽取成了變數 dir。我們要做的就是指定 dir 的路徑,並且根據下面的步驟來建立其餘的目錄和檔案。
為了把建立證照的過程也自動化掉,筆者在 req 段新增了下面的配置:

[ req ]
prompt = no
input_password = 123456

其中的 123456 就是後面建立的祕鑰的密碼,這樣在建立 Certificate Signing Requests(csr) 時就不需要以互動的方式輸入密碼了。
下面的內容是預設的 CA 資訊:

[ req_distinguished_name ]
countryName = CN
stateOrProvinceName = ShaanXi
localityName = Xian
organizationName = NickLi Ltd
organizationalUnitName = NickLi Ltd CA
commonName = NickLi Root CA
emailAddress = ljfpower@163.com

準備目錄和檔案

在 rootca 目錄下建立下面的目錄和檔案:

rootca/certs/           # 存放新建的證照
rootca/db/              # spenssl 用來存放資訊的目錄
rootca/private/         # 存放私鑰
rootca/crl/                                 
rootca/newcerts/

rootca/db/index
rootca/db/serial
rootca/db/crlnumber

其中的 rootca/private 目錄需要 700 的許可權,主要是為了既保證私鑰的安全有能夠建立私鑰檔案。rootca/db/serial 和 rootca/db/crlnumber 則需要被初始化為特定的值。簡單起見我們可以使用下面的指令碼來建立這些目錄和檔案:

#!/bin/bash

# create dir certs db private crl newcerts under rootca dir.
if [ ! -d rootca/certs ]; then
    mkdir -p rootca/certs
fi

if [ ! -d rootca/db ]; then
    mkdir -p rootca/db
    touch rootca/db/index
    openssl rand -hex 16 > rootca/db/serial
    echo 1001 > rootca/db/crlnumber
fi

if [ ! -d rootca/private ]; then
    mkdir -p rootca/private
    chmod 700 rootca/private
fi

if [ ! -d rootca/crl ]; then
    mkdir -p rootca/crl
fi

if [ ! -d rootca/newcerts ]; then
    mkdir -p rootca/newcerts
fi

把上面的程式碼儲存到 myca/roothelpler.sh 檔案中,然後 cd 到 myca 目錄下執行:

$ ./roothelpler.sh

此時當前目錄為 myca,rootca 下的子目錄和檔案都已經建立成功。

建立 root 祕鑰

進入 rootca 目錄:

$ cd rootca

執行下面的命令建立私鑰:

$ openssl genrsa -aes256 -out private/rootca.key.pem 4096

這裡筆者設定的密碼為:123456,記住這個密碼,後面還會用到。然後為了確保安全,把祕鑰的訪問許可權設定為 400:

$ chmod 400 private/rootca.key.pem

此時當前目錄為 myca/rootca。

建立 Certificate Signing Requests(csr)

執行下面的命令建立 csr:

$ openssl req -new \
    -config rootca.cnf \
    -sha256 \
    -key private/rootca.key.pem \
    -out csr/rootca.csr.pem

下面的命令可以檢查生成的 csr:

$ openssl req -text -noout -in csr/rootca.csr.pem

注意,csr 中包含了 CA 的基本資訊,和公鑰資訊。

建立 CA 的根證照

有了前一步中生成的 csr,我們就可以通過下面的命令生成 CA 的根證照了:

$ openssl ca -selfsign \
    -config rootca.cnf \
    -in csr/rootca.csr.pem \
    -extensions v3_ca \
    -days 7300 \
    -out certs/rootca.cert.pem

在互動式的提示中輸入私鑰的密碼 123456,並同意其它的確認提示,就完成了根證照的生成操作。注意,上面命令中的 -selfsing 選項,它說明所有的根證照都是自簽名的。同樣,我們也可以通過命令來檢視證照的詳細資訊:

$ openssl x509 -noout -text -in certs/rootca.cert.pem

其中的 Signature Algorithm 為簽名演算法;Issurer 是簽發方,即簽署證照的實體;Validity 指明證照的有效期為 2018-11-26 號至 2038-11-21 號;然後是公鑰資訊;Subject 指明證照自身的資訊,這裡 Issurer 和 Subject 的資訊是一樣的;下面還有 X509 協議相關的資訊,這部分資訊由配置檔案 rootca.cnf 中的 [ v3_ca ] 段控制:

紅框中的資訊表明這個證照被用作 CA。

總結

至此我們已經為私有的 CA 建立了根證照,在接下來的《使用 OpenSSL 建立私有 CA:中間證照》一文中我們將詳細的介紹如何建立 CA 的中間證照。

參考:
OpenSSL Certificate Authority
《openssl-cookbook》

相關文章