本文中所用主要方法,取自https://jamielinux.com/docs/openssl-certificate-authority/ 但有所修改.
用于管理CA的系统安装于虚拟机,配置如下:
- Ubuntu 16.04.3 LTS(Server)
- 要启用OpenSSH-Server,即
sshd
,以在主机上透过SSH访问- 需要OpenSSL,可以使用自带的1.0.2g版本,我使用的是自行编译的1.1.0f版本,故下文所涉及的椭圆曲线列表可能有差异
- 本文中一切在用于CA主机上的操作均使用
root
用户- 单核心处理器
- 256MiB内存
- 8GiB硬盘
- 直连模式的虚拟网卡
- 必须将虚拟网卡的模式由"NAT"改为"直接连接",以保证能从主机上透过SSH访问该虚拟机)
建立CA
1.建立根证书目录
$ cd ~
$ mkdir EC_CA
$ cd EC_CA
$ mkdir crl newcerts
$ touch index.txt
$ echo "0000" > serial
2.在~/EC_CA/
目录下建立OpenSSL配置文件,命名为openssl.cnf
,内容如下
[ ca ]
default_ca = CA_default
[ CA_default ]
# 路径根据实际情况修改
dir = /root/EC_CA
crl_dir = $dir/crl
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/.rand
new_certs_dir = $dir/newcerts
private_key = $dir/ca.key
certificate = $dir/ca.cer
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl
crl_extensions = crl_ext
default_crl_days = 10
default_md = sha384
name_opt = ca_default
cert_opt = ca_default
default_days = 365
preserve = no
policy = policy_loose
[ policy_strict ]
# 严格政策,在为中级CA签名时使用
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# 宽松政策,在为用户/服务器证书签名时使用
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
distinguished_name = req_distinguished_name
string_mask = utf8only
[ req_distinguished_name ]
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
default_md = sha256
x509_extensions = v3_ca
[ v3_ca ]
# CA证书配置
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# 用户证书配置
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "Hardrain Users' Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# 服务器证书配置
basicConstraints = CA:FALSE
nsCertType = server
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
#keyUsage = critical, digitalSignature, keyEncipherment
keyUsage = keyEncipherment
extendedKeyUsage = serverAuth
# 添加SAN支持
subjectAltName = @alt_names
[ crl_ext ]
authorityKeyIdentifier=keyid:always
[ ocsp ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
# SubjectAlterName,可追加更多
[ alt_names ]
DNS.1 = domain.tld
DNS.2 = *.domain.tld
3.建立私钥
首先使用openssl ecparam -list_curves
查看可用的Named curves列表
得到类似如下输出:
secp112r1 : SECG/WTLS curve over a 112 bit prime field
secp112r2 : SECG curve over a 112 bit prime field
secp128r1 : SECG curve over a 128 bit prime field
secp128r2 : SECG curve over a 128 bit prime field
secp160k1 : SECG curve over a 160 bit prime field
secp160r1 : SECG curve over a 160 bit prime field
secp160r2 : SECG/WTLS curve over a 160 bit prime field
secp192k1 : SECG curve over a 192 bit prime field
secp224k1 : SECG curve over a 224 bit prime field
secp224r1 : NIST/SECG curve over a 224 bit prime field
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field
prime192v2: X9.62 curve over a 192 bit prime field
prime192v3: X9.62 curve over a 192 bit prime field
prime239v1: X9.62 curve over a 239 bit prime field
prime239v2: X9.62 curve over a 239 bit prime field
prime239v3: X9.62 curve over a 239 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
sect113r1 : SECG curve over a 113 bit binary field
sect113r2 : SECG curve over a 113 bit binary field
sect131r1 : SECG/WTLS curve over a 131 bit binary field
sect131r2 : SECG curve over a 131 bit binary field
sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field
sect163r1 : SECG curve over a 163 bit binary field
sect163r2 : NIST/SECG curve over a 163 bit binary field
sect193r1 : SECG curve over a 193 bit binary field
sect193r2 : SECG curve over a 193 bit binary field
sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field
sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field
sect239k1 : SECG curve over a 239 bit binary field
sect283k1 : NIST/SECG curve over a 283 bit binary field
sect283r1 : NIST/SECG curve over a 283 bit binary field
sect409k1 : NIST/SECG curve over a 409 bit binary field
sect409r1 : NIST/SECG curve over a 409 bit binary field
sect571k1 : NIST/SECG curve over a 571 bit binary field
sect571r1 : NIST/SECG curve over a 571 bit binary field
c2pnb163v1: X9.62 curve over a 163 bit binary field
c2pnb163v2: X9.62 curve over a 163 bit binary field
c2pnb163v3: X9.62 curve over a 163 bit binary field
c2pnb176v1: X9.62 curve over a 176 bit binary field
c2tnb191v1: X9.62 curve over a 191 bit binary field
c2tnb191v2: X9.62 curve over a 191 bit binary field
c2tnb191v3: X9.62 curve over a 191 bit binary field
c2pnb208w1: X9.62 curve over a 208 bit binary field
c2tnb239v1: X9.62 curve over a 239 bit binary field
c2tnb239v2: X9.62 curve over a 239 bit binary field
c2tnb239v3: X9.62 curve over a 239 bit binary field
c2pnb272w1: X9.62 curve over a 272 bit binary field
c2pnb304w1: X9.62 curve over a 304 bit binary field
c2tnb359v1: X9.62 curve over a 359 bit binary field
c2pnb368w1: X9.62 curve over a 368 bit binary field
c2tnb431r1: X9.62 curve over a 431 bit binary field
wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls12: WTLS curve over a 224 bit prime field
Oakley-EC2N-3:
IPSec/IKE/Oakley curve #3 over a 155 bit binary field.
Not suitable for ECDSA.
Questionable extension field!
Oakley-EC2N-4:
IPSec/IKE/Oakley curve #4 over a 185 bit binary field.
Not suitable for ECDSA.
Questionable extension field!
brainpoolP160r1: RFC 5639 curve over a 160 bit prime field
brainpoolP160t1: RFC 5639 curve over a 160 bit prime field
brainpoolP192r1: RFC 5639 curve over a 192 bit prime field
brainpoolP192t1: RFC 5639 curve over a 192 bit prime field
brainpoolP224r1: RFC 5639 curve over a 224 bit prime field
brainpoolP224t1: RFC 5639 curve over a 224 bit prime field
brainpoolP256r1: RFC 5639 curve over a 256 bit prime field
brainpoolP256t1: RFC 5639 curve over a 256 bit prime field
brainpoolP320r1: RFC 5639 curve over a 320 bit prime field
brainpoolP320t1: RFC 5639 curve over a 320 bit prime field
brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
brainpoolP384t1: RFC 5639 curve over a 384 bit prime field
brainpoolP512r1: RFC 5639 curve over a 512 bit prime field
brainpoolP512t1: RFC 5639 curve over a 512 bit prime field
从中选择一种,如384位(等效于3072位RSA)的NIST P-384(secp384r1
),来生成私钥并使用AES-256-CBC加密
# 这一步会要求输入加密密码.
$ openssl ecparam -name P-384 -genkey|openssl ec -aes256 -out ca.key
$ chmod 400 ca.key
4.生成CA证书
# 这一步需要输入证书相关信息(国家/地区/机构/部门/通用名/电邮)和上一步所设置的密码
# 有效期和摘要算法(此例为sha256)可酌情更改,根CA证书可以使用不安全的摘要算法,如SHA1/MD5.
$ openssl req -config openssl.cnf -key ca.key -new -x509 -days 3650 -sha256 -extensions v3_ca -out ca.crt
$ chmod 444 ca.crt
至此,这个CA已经建立完成了,在使用前须将ca.crt拷贝至所需设备上并添加至信任的CA.
使用CA来签名证书
以下步骤在用户一侧完成:
5.建立OpenSSL配置文件,命名为openssl_usr.cnf
,内容如下:
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
req_extensions = req_ext
# 必须使用安全的摘要算法(sha256|sha384|sha512)
default_md = sha384
[ req_distinguished_name ]
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
[ req_ext ]
# 若生成(用于SSL客户端认证/电子邮件加密的)用户证书,注释掉以下一行
subjectAltName = @alt_names
[ alt_names ]
# 服务器证书的SubjectAlterName,可追加
DNS.1 = domain.tld
DNS.2 = *.domain.tld
6.生成私钥,以2048位的RSA为例
$ openssl genrsa -out domain.tld.key 2048
7.生成CSR(Certificate Signing Request,证书签名请求)文件
// 必须使用安全的摘要算法
// 要填写证书相关信息(国家/地区/机构/部门/通用名/电邮)
// 如果私钥被加密,这一步需要输入密码
$ openssl req -config openssl_usr.cnf -key domain.tld.key -new -sha384 -out domain.tld.csr
// 检查CSR的信息是否正确
$ openssl req -in domain.tld.csr -noout -text
将生成的.csr
文件提交给CA.
以下步骤在CA一侧完成
8.查看CSR信息,如为服务器证书,找到其所有SAN,填入CA的openssl.cnf
中(重要,如忽略此步骤,签名的服务器证书将因为没有任何SAN而无法使用)
然后对证书进行签名
$ cd ~/EC_CA/
// 此步骤将确认证书信息,并将签名事件写入日志(index.txt),由于使用到私钥,需输入第3步所设置的密码
$ openssl ca -config openssl.cnf -extensions server_cert -days 365 -notext -in ./domain.tld.csr -out ./newcerts/domain.tld.cer
// 验证证书信息
$ openssl x509 -in ./newcerts/domain.tld.cer -noout -text
将domain.tld.cer交给用户,即完成.