简介
前面介绍了使用 OpenSSL 创建和管理私钥的概念以及详细的实战操作,这篇文章继续这个话题,创建 OpenSSL 自签名的根证书。同样,提供全面的概念解析和详尽的实战操作案例。另外,这篇文章也为后续创建三级证书体系打下基础。
三级证书体系
我在 使用 OpenSSL 构建 X.509 三级证书体系 一文中详细介绍了三级证书的概念,按照这个体系,我们创建三个不同的目录来进行管理。如下:
这篇的重点就是创建顶层的根证书
RSA_VicSign_CA
假设我们根证书的属性如下:
- Self-signed (DV, OV, EV) 根证书都是自签名的
- Validity: 20 ~ 30 years 有效期都在 20 ~ 30 年左右 (7200 - 10800 天)
- x509 v3 extensions 包含的 v3 扩展字段有如下几个: [v3_ca]
- subjectKeyIdentifier = hash
- authorityKeyIdentifier = keyid:always,issuer:always
- basicConstraints = critical,CA:true,pathlen:3 # 多数没有 pathlen 限制
- keyUsage = critical, cRLSign,keyCertSign,digitalSignature # 多数没有 digitalSignature
- extendedKeyUsage
- subjectAltName
-
- Country: US
- State: TX
- Location: DAL
- Organization: DigiCert Inc (or Web Security)
- Organization Unit: www.digicert.com (or IT Department)
- CN: DigiCert Global Root CA
X509v3 extensions:
-
X509v3 Subject Key Identifier:
- 3E:01:1C:F3:88:81:25:F7:61:D6:2B:90:8A:41:63:C7:B8:39:8E:75
-
X509v3 Authority Key Identifier:
- 3E:01:1C:F3:88:81:25:F7:61:D6:2B:90:8A:41:63:C7:B8:39:8E:75
-
X509v3 Key Usage: critical
- Digital Signature, Certificate Sign, CRL Sign
-
X509v3 Basic Constraints: critical
- CA:TRUE, pathlen:3
解释:
主要分为三部分:
(1)签名算法:sha256WithRSAEncryption or ED25519
(2)Subject 信息:
- Subject, Issuer
- Validity
- Pub Key Algorithm: rsaEncryption or ED25519
(3)x509 V3 Extension 部分:
- 四项必须(subjectKeyIdentifier,authorityKeyIdentifier, basicConstraints, keyUsage)
- Key Usage: 里面,cRLSign 和 keyCertSign 这两项必须,digitalSignature 看情况
从 OU 那里,我们可以看到 digicert 有点像是其实是 OV 类型的证书,并且后面的 Key Usage 里面又有 Digital Signature 权限。
有些 Root CA 一般不会给这个权限。但是 SSL.com_Root_Certification_Authority_RSA.crt 也有这权限。
我们再看 Buypass_Class_3_Root_CA.crt 这个 Root CA 证书,它就没有 Digital Signature 权限。
操作要点:
- 配置文件
/opt/homebrew/etc/openssl@3/openssl.cnf或/usr/lib/ssl/openssl.cnf - 根据执行的命令去查找
openssl.cnf中对应的配置信息
比如 req 命令,那么就查找 [ req ] 部分对应的信息
第一步:私钥的创建与保管
一、创建私钥
按照我们在前面两篇文章中介绍的私钥加密的知识,我们可以自己的需要来选择不同的算法生成私钥。
OpenSSL 中,创建私钥的命令是 openssl genpkey。
这里实验为了方便,每次免去输入密码的麻烦,我们把密码文件来加密私钥。
(当然,如果你坚持暂时不加密码保护,你可以省去下面所有与使用 password.txt 相关的操作)
(1)RSA + 4096 bit (Key Size) + SHA256 (dgst algo)
openssl genpkey -algorithm RSA \
-aes256 -pkeyopt rsa_keygen_bits:4096 \
-pass file:password.txt \
-out rsa_private_encrypted.key
要点:
- 创建 RSA 私钥时,可以同时对其添加密码保护。
- 老版本的 OpenSSL 命令创建的 RSA 私钥是 PKCS#1 格式的,不支持
-pbkdf2,-iter和 -v2prf 选项,因为这些属性 PKCS#8 格式中的。 - 新版本的 OpenSSL (3.0+) 创建的私钥已经默认是 PKCS#8 格式了。(指定 -aes256 加密算法后,默认会使用 PBKDF2 函数,迭代次数为 2048次,伪随机算法为 hmacWithSHA256,并且 key size 默认为 2048 bit)
- 如果不是 PKCS#8 格式,则建议把私钥转换成 PKCS#8 格式,使用
openssl pkcs8命令,它支持手动指定上述选项。
查看 Key Size
openssl pkey -text -noout -passin file:password.txt -in rsa_private_encrypted.key
先创建密码文件:
openssl rand -base64 32 > password.txt
chmod 400 password.txt
(2)Ed25519 + SHA512 (dgst algo)
openssl genpkey -algorithm ed25519 \
-aes256 \
-out ed25519_private.key
要点:
- Ed25519 算法中的 Key Size 是固定大小的 256 bit(不可配置),它不像 RSA 中那样是可配置的。这是 Ed25519 优势的地方,它 256 bit 大小的 key size 的安全强度相当于 RSA 中 3072-bit,体积更小还意味着性能更好。
验证和检查私钥
有多个命令可以检查私钥相关的信息,比如:
openssl asn1parse -in rsa_private_encrypted.key
openssl pkey -in ed25519_private.key -text -noout
cat d25519_private.key -text -noout
可以看到,只要我们添加了 -aes256 选项对私钥进行密码保护,默认使用的就是 PBES2 密码标准,并且生成的密钥就是 PKCS#8 格式。openssl asn1parse 命令结果中显示的 :0800 是 16 进制的值,对应的是 2048,它表示的就是迭代次数。
下面分别是在不同的 Shell 中把这个值换算为十进制值的方式: Bash
echo $((0x0800))
Fish
math 0x0800
假如我们需要给私钥指定迭代次数的话,我们需要使用 openssl pkcs8 命令,前面的文章已经详细介绍过了,有兴趣的可以去查看。
如果想把私钥去掉密码保护,记得下面这个命令:
openssl pkcs8 -in ed25519_private_encrypted.key -out ed25519_private_decrypted.key -passin file:password.txt
二、保管私钥
限制访问权限
chmod 400 rsa_private_encrypted.key
移动到安全位置
mv rsa_private_encrypted.key ./private
有条件的,可以把私钥放到专门的存储硬件上去,并做好备份,这里就不详述了。
密码的话,当然是不建议使用上述的 password.txt 这种方式来保存的,安全风险较高,这里仅做实验用。
最佳实践是使用专门的密码管理工具(Password Manager),比如 1password, bitwarden 等。在 MacOS 中的话,推荐用 Keychain 来保管密码。
第二步:自签名证书
有了私钥,创建证书就简单了,我们有好几种方法,都是使用 openssl req -x509 命令,区别只在于是命令行传递配置信息还是通过配置文件传递。
方法一:配置文件
req.cnf
[ req ]
default_keyfile = ca_ed25519.key # Default private key filename
prompt = no # Disable prompt
distinguished_name = req_distinguished_name
x509_extensions = v3_ca # Extensions for self-signed root CA certificate
[ req_distinguished_name ]
C = US
ST = TX
L = DAL
O = Security Lab
OU = IT Department
CN = VicSign Root CA
[ v3_ca ]
# Extensions for a root CA certificate
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
For RSA Key
openssl req -new -x509 -days 7300 -sha256 \
-key rsa_private_encrypted.key \
-config rootca.cnf \
-passin file:password.txt \
-out rsa_ca.pem
For Ed25519 Key
openssl req -new -x509 -days 7300 \
-key ed25519_private_encrypted.key \
-config rootca.cnf \
-passin file:password.txt \
-out ed25519_ca.pem
注:
- 如果使用 RSA Key,那么需要通过 -sha256 指定哈希算法。而如果是 Ed25519 Key,则无需指定,默认就是 SHA256。
- -days 只能通过命令行传递,没法在配置文件中传递。
方法二:命令行参数
For RSA Key
openssl req -x509 -new -days 7300 -sha256 \
-key rsa_private_encrypted.key \
-subj "/C=US/ST=TX/L=DAL/O=Security Lab/OU=IT Department/CN=VicSign Root CA" \
-addext basicConstraints=critical,CA:true \
-addext keyUsage=critical,keyCertSign,cRLSign \
-addext subjectKeyIdentifier=hash \
-passin file:password.txt \
-out rsa_ca.pem
For Ed25519 Key
openssl req -x509 -new -days 7300 \
-key ed25519_private_encrypted.key \
-subj "/C=US/ST=TX/L=DAL/O=Security Lab/OU=IT Department/CN=VicSign Root CA" \
-addext basicConstraints=critical,CA:true \
-addext keyUsage=critical,keyCertSign,cRLSign \
-addext subjectKeyIdentifier=hash \
-passin file:password.txt \
-out ed25519_ca.pem
最后步骤
(1)访问权限
设置证书访问权限,所有人均可读但不可修改。
chmod 444 ed25519_ca.pem
(2)证书签发管理 由于是根证书,它需要记录和管理所有签发信息,所以务必创建下列文件和目录:
(i)ca.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
serial = $dir/serial
crlnumber = $dir/crlnumber
default_md = sha256
policy = policy_strict
default_days = 3650
default_crl_days = 30
[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
(ii)创建目录及文件
mkdir {certs,crl,newcerts,private}
touch index.txt
touch crlnumber
echo 1000 > serial
全文完!
如果你喜欢我的文章,欢迎关注我的微信公众号 deliverit。