### 简介
OpenSSL 是一款自由开源的加密库, 提供了一些命令行工具来处理数字证书. 其中的一些工
具可以作为证书权威机构来使用.
证书权威(CA)是一个认证证书实体的证书机构. 许多 Web 站点需要让他们的客户清楚他们
的连接是安全的, 他们通过向一些国际性的可信 CA(eg. VeriSign, DigiCert)为他们的站
点去购买一个证书.
在一些时候, 相比于去购买一个证书,更需要去实现一自己的 CA. 通常是需要内部网络使用
的安全连接, 或者是需要向客户发布一个证书来让他们通过服务器的认证(eg, Apache,
OpenVPN)
### 创建 root pair
成为一个 CA 意味着需要处理加密密钥对, 私钥和证书. 首先需要第一步创建的是 root
pair. 它包含 root key(ca.key.pem)和 root certificate(ca.cert.pem). 这对迷药就是
CA 的身份认证.
通常, root CA 不会给任何服务器或客户端签名. root CA 只被用来创建更多的二级 CA,
二级 CA 被 root CA 签名, 作为 root CA 的代表. 这是最佳实践, 可以让 root key 保持
离线和尽量少的被使用, 以保证 root key 有最小的泄漏风险.
```
⚠️注意
最佳实践是在一个安全的环境里创建root pair. 理想情况下, 在一个完全保密的环境, 并且和互联网完全隔离, 并拔除无线和有线网卡.
```
#### 准备目录
选择目录来保存所有的 keys 和 certificates
```
# mkdir /root/ca
```
创建目录结构. 其中 `index.txt` 和 `serial` 文件是用来保存已经签名证书的记录的文
件数据库.
```
# cd /root/ca
# mkdir certs crl newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial
```
#### 准备配置文件
我们需要创建一个 OpenSSL 配置文件来使用. 复制 root CA 的配置文件到
`/root/ca/openssl.cnf`.
root CA 配置文件
```
# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = /root/ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.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 = 375
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
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
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.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = GB
stateOrProvinceName_default = England
localityName_default =
0.organizationName_default = Alice Ltd
organizationalUnitName_default =
emailAddress_default =
[ 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
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ 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
```
其中 `[ca]` 部分是必须的. 这里我们告诉 OpenSSL 使用选项 `[CA_default]` 部分
```
[ ca ]
# `man ca`
default_ca = CA_default
```
而 `[CA_default]` 部分包含一类设置配置. 确保之前配置的目录 `/root/ca` 有效
```
[ CA_default ]
# Directory and file locations.
dir = /root/ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.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 = 375
preserve = no
policy = policy_strict
```
我们应用 `policy_strict` 到所有的 root CA 签名, 使 root CA 仅被用来创建二级 CA.
```
[ 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
```
我们应用 `policy_loose` 到所有二级 CA 签名, 二级 CA 会给所有的 Server 和 Client
签名, 它们会有很多的种类变化.
```
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
```
`[req]` 部分会被使用到所有的证书请求和证书创建
```
[ req ]
# Options for the `req` tool (`man req`).
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.
x509_extensions = v3_ca
```
`[req_distinguished_name]` 部分包含了一般证书请求签名信息. 可以手动添加一些默认
值来配置.
```
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = GB
stateOrProvinceName_default = England
localityName_default =
0.organizationName_default = Alice Ltd
#organizationalUnitName_default =
#emailAddress_default =
```
之后的几个部分是一些扩展, 这些扩展可以在证书签名的时候使用. 例如: 使用
`-extensions v3_ca` 命令行参数会应用在 `[v3_ca]` 下的选项.
在创建根证书的时候, 我们使用 `v3_ca`
```
[ 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
```
在创建二级 CA 时, 使用 `v3_intermediate_ca`, 其中额外增加了 `pathlen:0` 来确保二
级 CA 下可以再创建 CA
```
[ 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
```
在签发客户端证书时, 我们使用 `usr_cert`, 这些被使用做远程用户认证.
```
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
```
在创建服务器证书时, 使用 `server_cert` 选项, 这些被用于 Web 服务器.
```
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
```
在创建证书废除列表时, `crl_ext` 选项会被自动应用
```
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always
```
在签名在线证书状态协议(Online Certificate Status Protocol (OCSP))证书时, 使用选
项 `ocsp`
```
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
```
#### 创建 root key
创建 root key( `ca.key.pem` )并保证它的绝对安全. 任何拥有 root key 的人都可以创
建受信任的证书. 使用 AES 256-bit 来加密 root key, 并创建一个健壮的密码.
```
⚠️注意
使用4096位创建所有的根CA和二级CA的keys.
你仍然可以使用更短的长度来创建服务器和客户端证书.
```
```
# cd /root/ca
# openssl genrsa -aes256 -out private/ca.key.pem 4096
Enter pass phrase for ca.key.pem: secretpassword
Verifying - Enter pass phrase for ca.key.pem: secretpassword
# chmod 400 private/ca.key.pem
```
#### 创建根证书(Root certificate)
使用 root key(ca.key.pem)来创建根证书(ca.cert.pem). 给根证书设置一个比较长的有效
期, 比如 20 年. 一旦根证书失效, 所有被根证书签名的证书都会失效.
```
⚠️警告
当使用`req`工具时, 必须使用`-config`选项来指定一个配置文件, 否则OpenSSL会默认使用`/etc/pki/tls/openssl.cnf`
```
```
# cd /root/ca
# openssl req -config openssl.cnf \
-key private/ca.key.pem \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out certs/ca.cert.pem
Enter pass phrase for ca.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:GB
State or Province Name []:England
Locality Name []:
Organization Name []:Alice Ltd
Organizational Unit Name []:Alice Ltd Certificate Authority
Common Name []:Alice Ltd Root CA
Email Address []:
# chmod 444 certs/ca.cert.pem
```
#### 验证根证书
```
# openssl x509 -noout -text -in certs/ca.cert.pem
```
输出会显示
- `Signature Algorithm` 签名算法
- `Validity` 证书的有效期
- `Public-Key` 公钥长度
- `Issuer`, 签发证书的实体
- `Subject`, 指向证书自己
当 `Issuer` 和 `Subject` 相同时, 说明证书是自签名的. 明确所有根证书都是自签名的.
```
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=GB, ST=England,
O=Alice Ltd, OU=Alice Ltd Certificate Authority,
CN=Alice Ltd Root CA
Validity
Not Before: Apr 11 12:22:58 2015 GMT
Not After : Apr 6 12:22:58 2035 GMT
Subject: C=GB, ST=England,
O=Alice Ltd, OU=Alice Ltd Certificate Authority,
CN=Alice Ltd Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
```
输出还会显示 _X509v3 extensions_. 我们创建证书时应用的选项 `v3_ca`, 所以
`[v3_ca]` 下的配置项会被反映出来.
```
X509v3 extensions:
X509v3 Subject Key Identifier:
38:58:29:2F:6B:57:79:4F:39:FD:32:35:60:74:92:60:6E:E8:2A:31
X509v3 Authority Key Identifier:
keyid:38:58:29:2F:6B:57:79:4F:39:FD:32:35:60:74:92:60:6E:E8:2A:31
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
```
### 创建二级 CA, intermediate pair
二级 CA 作为 Root CA 代表的实体. Root CA 签署中间证书, 来达成一个信任链.
使用二级 CA 的主要目的是为了安全. 这样 root key 可以被保存在一个离线环境, 并尽可
能少的被使用. 如果二级 CA 的 key 泄漏, root CA 可以废弃二级 CA 证书并创建一个新
的二级密钥对.
#### 准备目录
Root CA 文件保存在目录 `/root/ca` 下. 选择一个不同的目录(
`/root/ca/intermediate` )来保存二级 CA 文件
```
# mkdir /root/ca/intermediate
```
创建和 root CA 相同的目录结构来保存文件. 增加了一个新的目录 `csr` 来保存证书签名
请求
```
# cd /root/ca/intermediate
# mkdir certs crl csr newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial
```
添加一个 `crlnumber` 文件到二级 CA 目录树. 使用 `crlnumber` 来对证书废除列表
(certificate revocation lists)进行追踪.
```
# echo 1000 > /root/ca/intermediate/crlnumber
```
复制二级 CA 配置文件到 `/root/ca/intermediate/openssl.cnf` 文件.
二级 CA 配置文件内容:
```
# OpenSSL intermediate CA configuration file.
# Copy to `/root/ca/intermediate/openssl.cnf`.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = /root/ca/intermediate
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/intermediate.key.pem
certificate = $dir/certs/intermediate.cert.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/intermediate.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 = 375
preserve = no
policy = policy_loose
[ 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
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
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.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = GB
stateOrProvinceName_default = England
localityName_default =
0.organizationName_default = Alice Ltd
organizationalUnitName_default =
emailAddress_default =
[ 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
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ 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
```
相对于 root CA, 有 5 个选项发生了变化
```
[ CA_default ]
dir = /root/ca/intermediate
private_key = $dir/private/intermediate.key.pem
certificate = $dir/certs/intermediate.cert.pem
crl = $dir/crl/intermediate.crl.pem
policy = policy_loose
```
#### 创建二级 CA 的 Key
创建二级 CA 的 key( `intermediate.key.pem` ) 使用 AES 256-bit 来加密并设置强密码
.
```
# cd /root/ca
# openssl genrsa -aes256 \
-out intermediate/private/intermediate.key.pem 4096
Enter pass phrase for intermediate.key.pem: secretpassword
Verifying - Enter pass phrase for intermediate.key.pem: secretpassword
# chmod 400 intermediate/private/intermediate.key.pem
```
### 创建二级 CA 证书
使用二级 CA 的 key 来创建证书签名请求(CSR). 详细信息和 CA 大致相同. 尽管如此,
Common Name 选项必须不同.
```
⚠️警告
确保你指定的配置文件是`intermediate/openssl.cnf`
```
```
# cd /root/ca
# openssl req -config intermediate/openssl.cnf -new -sha256 \
-key intermediate/private/intermediate.key.pem \
-out intermediate/csr/intermediate.csr.pem
Enter pass phrase for intermediate.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:GB
State or Province Name []:England
Locality Name []:
Organization Name []:Alice Ltd
Organizational Unit Name []:Alice Ltd Certificate Authority
Common Name []:Alice Ltd Intermediate CA
Email Address []:
```
创建二级 CA 证书, 使用 root CA 签名 CSR 并使用选项 `v3_intermediate_ca`. 二级证
书需要设置一个比 root CA 证书更短的有效期. 10 年是一个比较好的选项.
```
⚠️警告
这次, 指定root CA配置文件`/root/ca/openssl.cnf`
```
```
# cd /root/ca
# openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in intermediate/csr/intermediate.csr.pem \
-out intermediate/certs/intermediate.cert.pem
Enter pass phrase for ca.key.pem: secretpassword
Sign the certificate? [y/n]: y
# chmod 444 intermediate/certs/intermediate.cert.pem
```
`index.txt` 文件是 OpenSSL `ca` 工具用来保存证书的数据库. 不要删除或手动修改这个
文件. 现在它应该包含了二级 CA 证书的信息
```
V 250408122707Z 1000 unknown ... /CN=Alice Ltd Intermediate CA
```
#### 验证二级 CA 证书
和验证根证书一样, 使用相同的方式来验证二级 Ca 证书的有效性.
```
# openssl x509 -noout -text \
-in intermediate/certs/intermediate.cert.pem
```
验证二级 CA 证书紧靠着根证书. 返回 `OK` 指示这个信任链是正确的.
```
# openssl verify -CAfile certs/ca.cert.pem \
intermediate/certs/intermediate.cert.pem
intermediate.cert.pem: OK
```
#### 创建证书链文件
当应用(比如, web 浏览器)尝试去对二级 CA 签名的证书做验证, 它必须也验证根证书和二
级 CA 的信任链. 完成信任链, 就需要创建一个证书链来给应用.
创建证书链, 把二级 CA 证书和根证书连接起来, 我们随后会使用这个文件来演正被二级
CA 证书的签名.
```
# cat intermediate/certs/intermediate.cert.pem \
certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
# chmod 444 intermediate/certs/ca-chain.cert.pem
```
```
⚠️提示
我们的证书链文件必须包含根证书, 因为当前所有的客户端应用都没雨配置这个根证书. 更好的选项是, 比如你是一个内网的管理者, 可以把根证书安装到所有需要验证的客户端. 用这种方式, 证书链文件只需要包含你的二级CA证书
```
### 签名 Server 和 Client 证书
我们接下来使用我们的二级 CA 来签名. 你可以在多种情况时使用这些签名证书, 比如创建
安全的浏览器连接, 或者客户端到 server 的认证.
```
⚠️注意
接下来的步骤揭示你作为certificate authority(CA). 第三方, 尽管可以自己创建自己的私钥和证书请求(CSR), 不需要把它们的私钥(private key)显示给你. 他们只想你提供CSR, 然后你签署一个签名的证书给他们. 在这种情况下, 忽略`genrsa`和`req`命令.
```
#### 创建 key
我们的根 CA 和二级 CA 都是 4096bit 的. Server 和 Client 证书通常在一年内失效, 所
以我们安全的使用 2048 位密钥对.
```
⚠️注意
尽管4096bits略微安全于2048bits, 它会减慢TLS握手并且显著的增加握手时的处理器负载. 基于这个原因, 大多数websites都适用2048bit密钥对
```
如果你为一个 web 服务器(如: Apache)创建密钥对, 你需要在每次重启服务时都输入密码.
可以删除掉 `-aes256` 选项来创建一个没有密码的 key.
```
# cd /root/ca
# openssl genrsa -aes256 \
-out intermediate/private/www.example.com.key.pem 2048
# chmod 400 intermediate/private/www.example.com.key.pem
```
#### 创建证书 certificate
使用私钥(private key)来创建证书请求(CSR). CSR 详情不需要匹配到二级 CA. 对 Server
证书, 配置的 Common Name 必须是一个 FQDN(full qualified domain name,
如www.example.com), 然而对 Client 证书它可以是任何唯一的识别码(如, 一个邮件地址
). 记住 Comman Name 不能和你的根证书或二级 CA 证书相同.
```
# cd /root/ca
# openssl req -config intermediate/openssl.cnf \
-key intermediate/private/www.example.com.key.pem \
-new -sha256 -out intermediate/csr/www.example.com.csr.pem
Enter pass phrase for www.example.com.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:US
State or Province Name []:California
Locality Name []:Mountain View
Organization Name []:Alice Ltd
Organizational Unit Name []:Alice Ltd Web Services
Common Name []:www.example.com
Email Address []:
```
使用二级 CA 去签名 CSR 来创建一个证书. 如果证书是被用于一个 server, 那么使用
`server_cert` 扩展. 如果证书时给用户做用户认证, 使用 `user_cert` 扩展. 证书通常
给予指定一年的有效期, 尽管通常 CA 会额外给于几天时间方便.
```
# cd /root/ca
# openssl ca -config intermediate/openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in intermediate/csr/www.example.com.csr.pem \
-out intermediate/certs/www.example.com.cert.pem
# chmod 444 intermediate/certs/www.example.com.cert.pem
```
`intermediate/index.txt` 文件应该会包含一行内容指向新的证书
```
V 160420124233Z 1000 unknown ... /CN=www.example.com
```
#### 验证证书
```
# openssl x509 -noout -text \
-in intermediate/certs/www.example.com.cert.pem
```
_Issuer_ 就是二级 CA. _Subject_ 就是证书自己
```
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=GB, ST=England,
O=Alice Ltd, OU=Alice Ltd Certificate Authority,
CN=Alice Ltd Intermediate CA
Validity
Not Before: Apr 11 12:42:33 2015 GMT
Not After : Apr 20 12:42:33 2016 GMT
Subject: C=US, ST=California, L=Mountain View,
O=Alice Ltd, OU=Alice Ltd Web Services,
CN=www.example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
```
输出会显示 _X509v3 extensions_. 当创建证书, 选择的是 `server_cert` 或者
`usr_cert`. 这个选项的内容就会在这里被反射出来
```
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
OpenSSL Generated Server Certificate
X509v3 Subject Key Identifier:
B1:B8:88:48:64:B7:45:52:21:CC:35:37:9E:24:50:EE:AD:58:02:B5
X509v3 Authority Key Identifier:
keyid:69:E8:EC:54:7F:25:23:60:E5:B6:E7:72:61:F1:D4:B9:21:D4:45:E9
DirName:/C=GB/ST=England/O=Alice Ltd/OU=Alice Ltd Certificate Authority/CN=Alice Ltd Root CA
serial:10:00
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
```
使用之前创建的 CA 证书链文件(ca-chain.cert.pem), 我们可以验证新的证书在被信任链
上是正确的
```
# openssl verify -CAfile intermediate/certs/ca-chain.cert.pem \
intermediate/certs/www.example.com.cert.pem
www.example.com.cert.pem: OK
```
#### 部署证书
现在可以讲证书部署到 server, 或者发布证书给客户. 当部署到服务器应用(如, Apache)
时, 你需要确保下边的文件可用:
- `ca-chain.cert.pem`
- `www.example.com.key.pem`
- `www.example.com.cert.perm`
如果你是给第三方的证书请求(CSR)做签名, 你不需要获取他们的私钥(private key), 所以
你需要返回给他们证书链文件( `ca-chain.cert.pem` )和证书文件(
`www.example.com.cert.pem` )
#### 证书废除列表(Certificate revocation lists)
证书废除列表(Certificate revocation lists(CRL))提供了一个证书的列表, 表明其中的
证书都是被废除的. 客户端应用, 比如 web 浏览器, 可以使用 CRL 去检查服务器真实性.
服务器应用, 比如 Apache 和 OpenVPN, 可以使用 CRL 来禁止不被信任的客户端的访问.
发布 CRL 到一个可以公开访问的地方(如: http://example.com/intermediate.crl.pem).
第三方可以根据地址获取到 CRL, 他们可以根据这个来检测他们依赖的证书是否被废除.
```
⚠️注意
一些应用废除了CRLs, 他们使用在线证书状态协议(Online Certificate Status Protocol (OCSP))来代替.
```
#### 准备配置文件
当一个 CA 签名证书, 他们通常会写入 CRL 地址到证书里. 添加
`crlDistributionPoints` 到对应的部分. 在这里, 我们添加到 `[server_cert]` 部分中
```
[ server_cert ]
# ... snipped ...
crlDistributionPoints = URI:http://example.com/intermediate.crl.pem
```
#### 创建 CRL
```
# cd /root/ca
# openssl ca -config intermediate/openssl.cnf \
-gencrl -out intermediate/crl/intermediate.crl.pem
```
```
⚠️注意
在ca man page中的`CRL OPTIONS`部分包含了更多关于如何创建CRLs的信息
```
可以使用 `crl` 工具来检查 CRL 的内容
```
# openssl crl -in intermediate/crl/intermediate.crl.pem -noout -text
```
现在没有被吊销的证书, 所以输出是 `No Revoked Certificates`.
你应该定期的重新创建 CRL. 在默认情况下, CRL 在 30 天后失效. 这个值由
`[CA_default]` 部分中的 `default_crl_days` 选项控制.
#### 吊销证书
通过一个例子来看看这个过程. Alice 有一个 web 服务器和一个私有的目录存放一些暖心
的可爱小猫图片. Alice 想授权她的朋友 Bob 来访问这个集合.
Bob 创建了一个私钥和证书请求文件 CSR
```
$ cd /home/bob
$ openssl genrsa -out bob@example.com.key.pem 2048
$ openssl req -new -key bob@example.com.key.pem \
-out bob@example.com.csr.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name [XX]:US
State or Province Name []:California
Locality Name []:San Francisco
Organization Name []:Bob Ltd
Organizational Unit Name []:
Common Name []:bob@example.com
Email Address []:
```
Bob 发送他的 CSR 给 Alice, Alice 给他签名.
```
# cd /root/ca
# openssl ca -config intermediate/openssl.cnf \
-extensions usr_cert -notext -md sha256 \
-in intermediate/csr/bob@example.com.csr.pem \
-out intermediate/certs/bob@example.com.cert.pem
Sign the certificate? [y/n]: y
1 out of 1 certificate requests certified, commit? [y/n]: y
```
Alice 验证证书有效
```
# openssl verify -CAfile intermediate/certs/ca-chain.cert.pem \
intermediate/certs/bob@example.com.cert.pem
bob@example.com.cert.pem: OK
```
`index.txt` 文件包含一个新的连接
```
V 160420124740Z 1001 unknown ... /CN=bob@example.com
```
Alice 发送证书给 Bob. Bob 安装证书到浏览器, 现在可以访问到 Alice 的小猫图片.
坏事, 随着 Bob 的不端行为而来. Bob 把 Alice 的小猫图片发送到了 Hack News, 说了他
是这些的拥有者, 并获得了大量的赞. Alice 发现了这事摒弃要立即吊销他的访问权限.
```
# cd /root/ca
# openssl ca -config intermediate/openssl.cnf \
-revoke intermediate/certs/bob@example.com.cert.pem
Enter pass phrase for intermediate.key.pem: secretpassword
Revoking Certificate 1001.
Data Base Updated
```
`index.txt` 中 Bob 的证书这行开始现在使用字符 `R` 标示, 这表示证书已经被吊销
(Revoked).
```
R 160420124740Z 150411125310Z 1001 unknown ... /CN=bob@example.com
```
在吊销了 Bob 的证书后, Alice 必须重新创建 CRL
#### 服务端使用 CRL
对于客户端证书, 一般时候服务器应用(如, Apache)来进行验证. 服务应用需要可以访问
CRL.
在 Alice 的例子中, 他可以添加 `SSLCARevocationPath` 直接到她的 Apache 配置文件中
并复制 CRL 到她的 web 服务器. 下次 Bob 再进行访问时, Apache 会检查他的证书存在于
CRL 中并禁止访问.
相似的, OpenVPN 也使用 `crl-verify` 指向了被禁用的客户端证书.
#### 客户端使用 CRL
对于服务器证书, 一般是由客户端应用(如,浏览器)来进行验证. 这时, 应用必须可以远程
访问 CRL.
如果证书被签名的扩展中包含了 `crlDistributionPoints`, 客户端应用能够根据地址读取
到 CRL 信息.
CRL 地址信息可以在证书的 x509v3 详情中看到.
```
# openssl x509 -in cute-kitten-pictures.example.com.cert.pem -noout -text
X509v3 CRL Distribution Points:
Full Name:
URI:http://example.com/intermediate.crl.pem
```
### 在线证书状态协议 (Online Certificate Status Protocol)
在线证书状态协议 (Online Certificate Status Protocol)(OCSP) 被创建用于替代证书吊
销列表(CRL). 和 CRLs 相似, OCSP 运行访问查询出证书的吊销状态.
当服务器签名证书时, 他们一般会包含一个 OSCP 服务器地址(如,
http://ocsp.example.com)在证书中. 这个功能和 CRL 的 `crlDistributionPoints` 功能
作用相似.
示例, 当 web 浏览器接受到一个服务器证书, 它立即想请求证书中的 OSCP 服务器地址.
在这个地址中, OCSP 响应程序监听请求和响应证书的吊销状态.
```
⚠️注意
虽然推荐尽可能的使用OCSP, 尽管实际上你应该趋向于只需要OCSP来给web站点证书. 一些web浏览器已经废弃或移除了对CRL的支持.
```
#### 准备配置文件
要使用 OCSP, CA 必须要编码 OCSP 服务器地址到签名的证书中. 使用
`authorityInfoAccess` 选项到合适的部分, 在这里应该是 `[server_cert]` 部分
```
[ server_cert ]
# ... snipped ...
authorityInfoAccess = OCSP;URI:http://ocsp.example.com
```
#### 创建 OCSP 密钥对
OCSP 响应程序必须要一个加密密钥对来签名发送给请求的响应内容. OSCP 密钥对必须由和
证书签名相同的 CA 签名.
创建私钥并使用 AES-256 加密
```
# cd /root/ca
# openssl genrsa -aes256 \
-out intermediate/private/ocsp.example.com.key.pem 4096
```
创建证书签名请求 CSR. 详细信息默认需要和签名 CA 相同. Common Name, 需要是 FQDN.
```
# cd /root/ca
# openssl req -config intermediate/openssl.cnf -new -sha256 \
-key intermediate/private/ocsp.example.com.key.pem \
-out intermediate/csr/ocsp.example.com.csr.pem
Enter pass phrase for intermediate.key.pem: secretpassword
You are about to be asked to enter information that will be incorporated
into your certificate request.
-----
Country Name (2 letter code) [XX]:GB
State or Province Name []:England
Locality Name []:
Organization Name []:Alice Ltd
Organizational Unit Name []:Alice Ltd Certificate Authority
Common Name []:ocsp.example.com
Email Address []:
```
使用 CA 签署 CSR
```
# openssl ca -config intermediate/openssl.cnf \
-extensions ocsp -days 375 -notext -md sha256 \
-in intermediate/csr/ocsp.example.com.csr.pem \
-out intermediate/certs/ocsp.example.com.cert.pem
```
验证证书的 _x509v3 extensions_ 正确性
```
# openssl x509 -noout -text \
-in intermediate/certs/ocsp.example.com.cert.pem
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage: critical
OCSP Signing
```
#### 吊销证书
OpenSSL 的 `ocsp` 工具实现了一个 OCSP responder, 但只为了做测试使用. 生产级别的
OCSP responder 也有, 但是超越了这个指引的范围.
创建一个 server 证书测试.
```
# cd /root/ca
# openssl genrsa -out intermediate/private/test.example.com.key.pem 2048
# openssl req -config intermediate/openssl.cnf \
-key intermediate/private/test.example.com.key.pem \
-new -sha256 -out intermediate/csr/test.example.com.csr.pem
# openssl ca -config intermediate/openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in intermediate/csr/test.example.com.csr.pem \
-out intermediate/certs/test.example.com.cert.pem
```
在 `localhost` 上运行 OCSP responder . 有别于 CRL 保存吊销状态于各个文件中, OCSP
responder 直接读取 `index.txt` . 响应被 OCSP 密钥对签名(使用 `-rkey` 和
`-rsigner` 选项)
```
# openssl ocsp -port 127.0.0.1:2560 -text -sha256 \
-index intermediate/index.txt \
-CA intermediate/certs/ca-chain.cert.pem \
-rkey intermediate/private/ocsp.example.com.key.pem \
-rsigner intermediate/certs/ocsp.example.com.cert.pem \
-nrequest 1
Enter pass phrase for ocsp.example.com.key.pem: secretpassword
```
在另一个终端中, 发送一个请求给 OCSP responder. 指定的 `-cert` 选项指定了请求的证
书.
```
# openssl ocsp -CAfile intermediate/certs/ca-chain.cert.pem \
-url http://127.0.0.1:2560 -resp_text \
-issuer intermediate/certs/intermediate.cert.pem \
-cert intermediate/certs/test.example.com.cert.pem
```
开始的输出显示如下:
- 是否接收到成功的响应 (OCSP Response Status)
- responder 的身份 (Responder Id)
- 证书的吊销状态 (Cert Status)
```
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: ... CN = ocsp.example.com
Produced At: Apr 11 12:59:51 2015 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: E35979B6D0A973EBE8AEDED75D8C27D67D2A0334
Issuer Key Hash: 69E8EC547F252360E5B6E77261F1D4B921D445E9
Serial Number: 1003
Cert Status: good
This Update: Apr 11 12:59:51 2015 GMT
```
吊销证书
```
# openssl ca -config intermediate/openssl.cnf \
-revoke intermediate/certs/test.example.com.cert.pem
Enter pass phrase for intermediate.key.pem: secretpassword
Revoking Certificate 1003.
Data Base Updated
```
之后, 运行 OCSP responder 并在另一个终端中发请求. 这次, 输出会显示
`Cert Status: revoked` 和 `Revocation Time` .
```
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: ... CN = ocsp.example.com
Produced At: Apr 11 13:03:00 2015 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: E35979B6D0A973EBE8AEDED75D8C27D67D2A0334
Issuer Key Hash: 69E8EC547F252360E5B6E77261F1D4B921D445E9
Serial Number: 1003
Cert Status: revoked
Revocation Time: Apr 11 13:01:09 2015 GMT
This Update: Apr 11 13:03:00 2015 GMT
```