yeziruo

利欲驱人万火牛 江湖浪迹一沙鸥

前言

接上一篇文章,本文章将讲述一个二/多级CA与OCSP服务器的搭建。

通常的CA架构

通常CA为多级架构,由根CA签署若干个不同用途的子CA,再由子CA签发给客户,以本站的证书为例,它是一个两级CA架构:

105252.png

二级从名字可以看出是专门于签署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代表私有的数字签名证书颁发策略。

CRLOCSP

为保证证书的有效性,引入了CRLOCSP
CRL证书吊销列表是一个由CA签名的结构化列表文件,包含CA信息,吊销的证书序列号和日期,和下一次更新时间,一般情况下这个文件通过http提供,由操作系统下载导入,并在到达更新时间时更新。
OCSP在线证书状态协议是继CRL后出现的证书状态检查协议,解决了要下载CRL和实时性问题,一般使用http协议承载,返回三个状态:GOOD,REVOKED,UNKNOWN
OCSP虽然解决了大部分CRL所带来的问题,但是OCSP会像DNS一样存在隐私问题,所以一般会让服务器缓存一个最近的OCSP响应来解决,此外,OCSP还容易遭到复读机攻击(重放),解决方法类似于解决CSRF问题一样,由客户端请求时附带一个nonce,让服务器原样返回。

根CA与子CA

构建CA的配置文件大部分均相同,只需要修改一些主题名称,扩展密钥用法和crlocsp地址即可:

[ 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

134000.png

用户

同上节所述,将上一节的emailca.crtemailca.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

135208.png

安全性说明:

在签发证书前,要仔细检查(扩展)主题信息,因为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

140846.png

开启服务器:

# 复制到新目录
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/

152122.png

(原本在Linux下测试的,后面为了补图又在Windows下测试)

结尾

使用OpenSSL命令行工具告一段落,上述可以用于学习,但不适合与应用集成,现在大多数语言的加密库附带x509功能,可以依托x509来实现颁发管理自动化。

已有 2 条评论

正在回复ID为 ??? 的评论

  1. name 2022-08-20 02:27

    It's been half a year, it's time to update

    1. yeziruo 2022-10-13 08:58

      So, I'm back. (Doge

© 2013-2022 yeziruo. All Rights Reserved. Start5 theme by yeziruo.

CC BY-NC-SA 3.0 CN