前言
接上一篇文章,本文章将讲述一个二/多级CA与OCSP服务器的搭建。
通常的CA架构
通常CA为多级架构,由根CA签署若干个不同用途的子CA,再由子CA签发给客户,以本站的证书为例,它是一个两级CA架构:
二级从名字可以看出是专门于签署DV SSL证书的。一般CA机构会颁发三种用途的CA,分别是用于SSL,邮件/文件签名和代码签名。
要实现上面三种CA,首先了解一下扩展密钥用法,扩展密钥用法指定了CA及其所颁发证书的用途,在OpenSSL中有如下用法:
serverAuth SSL服务器验证
clientAuth SSL客户端验证
codeSigning 代码签名
emailProtection 邮件加密
timeStamping 可信时间戳
OCSPSigning OCSP签名
ipsecIKE 密钥交换协议
msCodeInd Microsoft 个人代码签名
msCodeCom Microsoft 商业代码签名
msCTLSign Microsoft 信任列表签名
msEFS Microsoft Windows文件系统加密
(RFC 5280)(https://www.openssl.org/docs/manmaster/man5/x509v3_config.html)
题外话:在Windows中,内核驱动必须被微软交叉签名的CA所签署的证书所签署,在早期有被泄露出来的代码签名证书,可以通过个人搭建时间戳服务器来绕过签名的时间戳认证,即让系统认为签署的时间在证书的有效期中,从而实现加载未正儿八经签名的内核驱动。(HT Srl)
在OpenSSL配置文件中指定extendedKeyUsage
即可为证书赋予不同的用途。其实这些属性代表的是oid
,即对象标识符,除了通用的oid
外,还用于证书私有策略。
比方说本站证书中的1.3.6.1.4.1.6449.1.2.2.64
,前缀1.3.6.1.4.1.
为命名空间,6449
代表私营企业编号(PEN,由IANA分配,http://www.iana.org/assignments/enterprise-numbers),这里是查询到的是Sectigo Limited
,.1.2.2.64
代表私有的数字签名证书颁发策略。
CRL
与OCSP
为保证证书的有效性,引入了CRL
和OCSP
。
CRL
证书吊销列表是一个由CA签名的结构化列表文件,包含CA信息,吊销的证书序列号和日期,和下一次更新时间,一般情况下这个文件通过http
提供,由操作系统下载导入,并在到达更新时间时更新。
OCSP
在线证书状态协议是继CRL
后出现的证书状态检查协议,解决了要下载CRL
和实时性问题,一般使用http
协议承载,返回三个状态:GOOD,REVOKED,UNKNOWN
。
OCSP
虽然解决了大部分CRL
所带来的问题,但是OCSP
会像DNS
一样存在隐私问题,所以一般会让服务器缓存一个最近的OCSP
响应来解决,此外,OCSP
还容易遭到复读机攻击(重放),解决方法类似于解决CSRF
问题一样,由客户端请求时附带一个nonce
,让服务器原样返回。
根CA与子CA
构建CA的配置文件大部分均相同,只需要修改一些主题名称,扩展密钥用法和crl
和ocsp
地址即可:
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/cacert.crt
serial = $dir/serial
crlnumber = $dir/crlnumber
crl = $dir/crl.crl
private_key = $dir/cakey.key
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = 730
default_crl_days= 30
default_md = default
preserve = no
policy = policy_match
copy_extensions = none
#[ crl_info ]
#URI.0 = http://127.0.0.1/root/ca.crl
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
[ req ]
utf8 = yes
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
string_mask = utf8only
[ req_distinguished_name ]
# 默认主题信息
countryName = Country Name (2 letter code)
countryName_default = CN
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Beijing
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Strategic Fooyou Agency
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Strategic Fooyou Agency Root CA
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ usr_cert ]
basicConstraints=CA:FALSE
extendedKeyUsage = emailProtection,clientAuth
crlDistributionPoints = URI:http://127.0.0.1/root/ca.crl
authorityInfoAccess = OCSP;URI:http://127.0.0.1/root/ocsp
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# Email CA
[ email_ca ]
basicConstraints= critical,CA:true
# 扩展密钥用法
extendedKeyUsage = emailProtection,clientAuth
# CRL
crlDistributionPoints = URI:http://127.0.0.1/root/ca.crl
# OCSP
authorityInfoAccess = OCSP;URI:http://127.0.0.1/root/ocsp
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage = cRLSign, keyCertSign
# OCSP证书
[ v3_ocsp ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = OCSPSigning
crlDistributionPoints = URI:http://127.0.0.1/root/ca.crl
authorityInfoAccess = OCSP;URI:http://127.0.0.1/root/ocsp
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# Root CA
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = cRLSign, keyCertSign
crlDistributionPoints = URI:http://127.0.0.1/root/ca.crl #@crl_info
authorityInfoAccess = OCSP;URI:http://127.0.0.1/root/ocsp
CA目录配置:
mkdir rootCA && cd rootCA
mkdir certs
mkdir crl
mkdir newcerts
echo "01" > serial
echo "01" > crlnumber
touch index.txt
自签根CA:
openssl req -new -config rootca.cnf -out ca.csr -keyout cakey.key
openssl ca -selfsign -config rootca.cnf -in ca.csr -out cacert.crt -extensions v3_ca
生成子CA请求:
# 建议新建目录复制和修改配置文件再生成
openssl req -new -config rootca.cnf -out emailca.csr -keyout emailcakey.key -extensions email_ca
签署子CA:
openssl ca -config rootca.cnf -in emailca.csr -out emailca.crt -extensions email_ca
用户
同上节所述,将上一节的emailca.crt
和emailca.key
移动到新的子CA目录,按上述步骤配置,以及修改配置文件。
请求文件配置:
[ req ]
default_bits = 2048
encrypt_key = no
utf8 = yes
string_mask = utf8only
req_extensions = v3_req
prompt = yes
distinguished_name = distinguished_name
# SSL SAN
#req_extensions = server_reqext
#[ server_reqext ]
#subjectAltName = @domain_san
#
#[ domain_san ]
#DNS.1 = sfa.org.cn
[distinguished_name]
# 准确来说这里CN应该等于Email,作为友好名称,但我好像没办法让它自动复制
#commonName = Main Domain
#commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ v3_req ]
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
生成签发请求:
openssl req -new -config email.cnf -out certs/email.csr -keyout certs/email.key
由子CA签发证书:
openssl ca -config emailca.cnf -in certs/email.csr -out certs/email.crt -extensions usr_cert -days 365
安全性说明:
在签发证书前,要仔细检查(扩展)主题信息,因为OpenSSL
没有提供(没查到)编辑主题信息的有效方法。
管理CA
以下提供了简单管理CA的方法。
吊销
openssl ca -config emailca.cnf -revoke certs/email.crt
生成CRL
与发布
openssl ca -config emailca.cnf -gencrl -out email.crl [-crldays 1]
之后将这个crl
文件放入证书中指定的路径即可,更新时间在配置文件的default_crl_days
中已经指定。
响应OCSP
OpenSSL
可以作为OCSP
服务器使用,在此之前,我们需要签署一个扩展密钥用法为OCSPSigning
的证书:
openssl req -new -config rootca.cnf -out ocsp.csr -keyout ocsp.key -extensions v3_ocsp
openssl ca -config rootca.cnf -in ocsp.csr -out ocsp.crt -extensions v3_ocsp
开启服务器:
# 复制到新目录
mkdir ocsp && cd ocsp
cp ../emailCA/emailca.crt .
cp ../emailCA/index.txt .
cp ../rootCA/ocsp.crt .
cp ../rootCA/ocsp.key .
# 启动
openssl ocsp -index index.txt -port 80 -rsigner ocsp.crt -rkey ocsp.key -CA emailca.crt -text
验证:
openssl ocsp -issuer chain.crt -cert email.crt -url http://127.0.0.1/
(原本在Linux下测试的,后面为了补图又在Windows下测试)
结尾
使用OpenSSL
命令行工具告一段落,上述可以用于学习,但不适合与应用集成,现在大多数语言的加密库附带x509
功能,可以依托x509
来实现颁发管理自动化。