OpenSSL(2)创建私有证书颁发机构

  如果想要建立自己的CA, OpenSSL已经包含了所有你需要的东西。所有的操作都通过纯命令行执行,虽然不那么友好,整个过程也比较长,但是这可以让你去思考每个细节。

  我建议自己创建一套私有的 CA主要是出于教学的目的,不过还有一些别的原因。OpenSSL的CA天然满足个人或者小团体的需求,例如在开发环境使用一套CA比到处使用自签名的证书好得多。同时还可以通过客户端证书来提供双向验证,这可以极大地提高敏感Web应用的安全性。

  运行私有CA最大的挑战不是设置问题,而是如何保证基础结构的安全。例如根密钥必须离线保存,因为所有的安全都依赖它。另一方面, CRL和OCSP响应程序证书必须定期进行更新,而这会要求根密钥保持联机。

功能和限制

我们会创建一个与公共CA类似的私有CA架构。会先有一个根CA,然后创建其他的二级CA。接着我们会通过CRL和OCSP服务提供证书吊销信息。为了让根CA的私钥可以离线保存, OCSP响应程序需要使用它们自己的身份。这并非是最简单的CA,但是相对来说比较安全。另外二级CA会在技术上进行限制,只能给允许的主机名签发证书

完成设置之后,必须将根证书安全地分发给所有客户端。一旦根证书分发完毕,就可以开始签发客户端和服务器证书了。有一个限制是以这种方式设置的OCSP响应程序主要用来测试,因为只能承受比较小的负载。

创建根 CA 

创建全新的CA有几个步骤:配置、创建目录结构和初始化密钥文件,最后生成根密钥和证书。本节描述了整个过程和常见的CA操作。

1)根CA配置

创建CA之前,我们需要先准备一个配置文件告诉OpenSSL我们希望的配置。一般情况下并不需要配置文件,但是根CA的创建操作复杂,使用配置文件可以简便很多。 OpenSSL的配置文件很强大,在开始之前我建议你熟悉一下这些配置的功能(命令行上使用man config命令)。

配置文件第一部分包括了CA的名称、基础URL和CA可分辨名称等基本信息。因为这些配置都很灵活,只需配置一次即可。

[default]
name = root-ca
domain_suffix = example.com
aia_url = http://$name.$domain_suffix/$name.crt
crl_url = http://$name.$domain_suffix/$name.crl
ocsp_url = http://ocsp.$name.$domain_suffix:9080
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ca_dn]
countryName = "GB"
organizationName = "Example"
commonName = "Root CA"

第二部分直接控制了CA的操作。有关每个设置的完整信息,可以通过ca命令来获取它的文档(命令行上输入man ca)。大部分命令从字面意思就可以很容易理解,我们需要告诉OpenSSL存放文件的路径。因为根CA只用作二级CA的签发,所以我把有效期设置为10年。另外默认情况下使用SHA256作为签名算法。

默认策略( policy_c_o_match)限制了这张CA签发的证书的国家名和组织名会与CA本身一样。对于公共CA来说很少会有这样的设置,但对于私有CA来说这种方式比较合适:

[ca_default]
home = .
database = $home/db/index
serial = $home/db/serial
crlnumber = $home/db/crlnumber
certificate = $home/$name.crt
private_key = $home/private/$name.key
RANDFILE = $home/private/random
new_certs_dir = $home/certs
unique_subject = no
copy_extensions = none
default_days = 3650
default_crl_days = 365
default_md = sha256
policy = policy_c_o_match
[policy_c_o_match]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

第三部包含了req命令的配置, req命令只会在创建自签发根证书的时候用到一次。最重要的部分是扩展:基本限制( basicContraints)扩展表明这个证书是一张CA,密钥用法( keyUsage)扩展用来说明这个CA的用处:

[req]
default_bits = 4096
encrypt_key = yes
default_md = sha256
utf8 = yes
string_mask = utf8only
prompt = no
distinguished_name = ca_dn
req_extensions = ca_ext
[ca_ext]
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash

配置的第四部分包括了根CA创建证书所需要的信息。因为基本限制( basicContraints)扩展的设置,所有的证书都将成为CA,但是我们需要把pathlen设置为0,表示这些CA无法再签发新的CA了。

所有二级CA都会受到限制,也就是说他们签发的证书只能对一些域名的子集有效,并且会被限制使用场景。第一,扩展密钥用法( extendedKeyUsage)扩展限制了只能进行客户端验证( clientAuth)和服务器验证( serverAuth),也就是TLS的客户端和服务器验证。第二,名称限制( nameContraints)扩展限制了允许签发的域名只有example.com和example.org。理论上这样的设置让你可以签发二级CA给第三方,同时可以通过限制他们无法签发任意域名的主机名来保证安全。排除这两个IP段的要求来自CAB论坛的Baseline Requirements,该规范从技术上定义了对二级CA的限制。

实际上,名称限制( nameContraints)并不完美,因为当前还有很多主流的平台无法识别名称限制扩展。如果你将这个扩展标记为关键扩展,就会导致很多平台拒绝识别你的证书。如果将其标记为关键扩展,那么很多平台就不会识别这个扩展,导致名称限制实际没有任何效果。

[sub_ca_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:true,pathlen:0
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,keyCertSign,cRLSign
nameConstraints = @name_constraints
subjectKeyIdentifier = hash
[crl_info]
URI.0 = $crl_url
[issuer_info]
caIssuers;URI.0 = $aia_url
OCSP;URI.0 = $ocsp_url
[name_constraints]
permitted;DNS.0=example.com
permitted;DNS.1=example.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0

最后两部分的配置表示有了这个扩展的证书可以对OCSP响应进行签名。为了能够运行OCSP响应程序,我们生成一个特别的证书,并且将OCSP的签名能力赋予这张证书。从扩展可以看出这张证书不是一个CA:

[ocsp_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash

2)根CA的目录结构

下面我们会创建“根CA配置”中说到的目录结构,并且会初始化一些CA操作中会用到的文件。

$ mkdir root-ca
$ cd root-ca
$ mkdir certs db private
$ chmod 700 private
$ touch db/index
$ openssl rand -hex 16 > db/serial
$ echo 1001 > db/crlnumber
我们会用到以下这几个目录。
 certs/
存放证书的地方;证书在签名之后会放置到这个目录下。
 db/
这个目录用于证书数据库( index),一些包括下一张证书以及CRL数字的文件。 OpenSSL
会创建额外需要的一些文件。
 private/
这个目录会存放私钥,一个给CA使用,一个给OCSP响应程序使用。务必确保其他用户
都不能访问这个目录(事实上,如果你真的很在意这个CA,那么这台存放根证书和密钥
的服务器的用户账户必须尽可能少)。

3)CA生成

我们需要分两步来创建根CA。首先,我们生成密钥和CSR文件。当我们使用-config开关之后,所有需要的信息都会从配置文件中加载进来

$ openssl req -new \
-config root-ca.conf \
-out root-ca.csr \
-keyout private/root-ca.key

第二步我们会创建自签名证书。 -extension开关指向了配置文件的ca_ext部分,这样可以激活根CA所需的扩展。

$ openssl ca -selfsign \
-config root-ca.conf \
-in root-ca.csr \
-out root-ca.crt \
-extensions ca_ext

4)数据库文件结构 

db/index中的数据库是一个包含证书信息的明文文件,每行一个证书。我们刚刚创建根CA,现在这个文件只有一行信息

V 240706115345Z 1001 unknown /C=GB/O=Example/CN=Root CA

每一行包括以下6个以制表符分隔的值。

(1) 状态标记[ V表示有效( valid), R表示已吊销( revoked), E表示已过期( expired)]
(2) 过期时间(以YYMMDDHHMMSSZ格式表示)
(3) 吊销日期,如果没有被吊销则为空
(4) 序列号(十六进制)
(5) 文件路径(如果不知道就显示unknown)
(6) 可分辨名称

5)CA操作

使用ca命令的-gencrl开关给新CA生成CRL

$ openssl ca -gencrl \
-config root-ca.conf \
-out root-ca.crl

使用ca的的命令来签发证书。需要注意的是-extensions开关需要指向配置文件里面正确的部分(例如,你肯定不希望再生成另一个根CA)。

$ openssl ca \
-config root-ca.conf \
-in sub-ca.csr \
-out sub-ca.crt \
-extensions sub_ca_ext

  如果要吊销证书,可以使用ca命令的-revoke开关,不过需要有一份你想吊销的证书的副本。不过因为所有的证书都存在certs/目录下,所以只需要知道序列号即可。如果知道证书的可分辨名称,就可以在数据库里面查到它的序列号了。
  为-crl_reason开关中的值选择一个正确的理由。该值可以是以下这些值之一: unspecified、keyCompromise 、 CACompromise 、 affiliationChanged 、 superseded 、 cessationOfOperation 、certificateHold和removeFromCRL。

$ openssl ca \
-config root-ca.conf \
-revoke certs/1002.pem \
-crl_reason keyCompromise

6)创建用于OCSP签名的证书

首先我们需要给OCSP响应程序创建一个私钥和CSR。这两个操作对所有的非CA证书都适用,所以不需要指定配置文件:

$ openssl req -new \
-newkey rsa:2048 \
-subj "/C=GB/O=Example/CN=OCSP Root Responder" \
-keyout private/root-ocsp.key \
-out root-ocsp.csr

第二步需要使用根CA签发一张证书。 -extensions开关的值选择ocsp_ext,以确保设置了OCSP签名所需要的扩展。我将这个证书的生命周期减少为365天(原来默认是3650天)。这些OCSP证书是没有吊销信息的,所以无法吊销它们。因此你会希望尽可能减少它们的生命周期。 30天是一个比较好的选择,当然前提是你已经准备好频繁地创建新的OCSP证书。

$ openssl ca \
-config root-ca.conf \
-in root-ocsp.csr \
-out root-ocsp.crt \
-extensions ocsp_ext \
-days 30

现在你已经有了OCSP响应程序所需要的一切东西,可以直接在根CA所在的服务器上进行测试。当然,如果在生产环境中使用,就必须将OCSP响应程序的密钥和证书放到别的地方

$ openssl ocsp \
-port 9080
-index db/index \
-rsigner root-ocsp.crt \
-rkey private/root-ocsp.key \
-CA root-ca.crt \
-text

可以使用下面的命令来测试OCSP响应程序:

$ openssl ocsp \
-issuer root-ca.crt \
-CAfile root-ca.crt \
-cert root-ocsp.crt \
-url http://127.0.0.1:9080

输出结果中的verify OK表示已经成功验证签名,而good表示这张证书还没有被吊销。

Response verify OK
root-ocsp.crt: good
This Update: Jul 9 18:45:34 2014 GMT

创建二级 CA

创建二级CA的过程和根CA几乎完全一样。

1)二级CA配置

我们可以在前面根CA配置文件的基础上,进行一些适当的修改生成二级CA的配置。我们会把名称改为sub-ca并且使用另一个可分辨名称。我们将二级CA的OCSP响应程序放在另外一个端口,主要是因为ocsp命令不识别虚拟主机。如果为OCSP响应程序使用了适合的Web服务器,就可以完全避免使用特别的端口。该证书默认的生命周期是365天,我们会每隔30天生成全新的CRL。

将copy_extensions更改为copy意味着在生成新证书的时候,如果我们的配置文件里面没有设置某些扩展,那么就会使用CSR文件里面的扩展字段。进行此更改之后,在准备CSR文件的时候就可以加入别的一些需要的字段,这些信息会在生成证书的时候加入到证书里面。这个特性有几分危险(因为允许其他人可以在一定程度上直接控制证书里面的内容),不过我认为在较小的环境中这么做是可以的。

[default]
name = sub-ca
ocsp_url = http://ocsp.$name.$domain_suffix:9081
[ca_dn]
countryName = "GB"
organizationName = "Example"
commonName = "Sub CA"
[ca_default]
default_days = 365
default_crl_days = 30
copy_extensions = copy

在配置文件的最后面,我们会增加两个新的配置,分别用于服务器和客户端证书的生成。唯一的区别就是keyUsage和extendedKeyUsage扩展。注意到我们把basicContraints扩展的值设置为false。之所以这么做,原因在于我们会复制CSR文件里面的扩展。如果在配置文件中没有显示设置这个扩展,那么就可能会用到CSR文件中的basicContraints了。

[server_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,digitalSignature,keyEncipherment
subjectKeyIdentifier = hash
[client_ext]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
crlDistributionPoints = @crl_info
extendedKeyUsage = clientAuth
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash

改好配置文件之后,按照根CA的过程创建一个同样的目录结构,不过可以使用另外一个名称,比如sub-ca。

2)二级CA生成

与前面一样,创建二级CA需要两步。第一步生成密钥和CSR。当我们使用-config开关的时候,所有需要的信息都会从配置文件中加载进来。

$ openssl req -new \
-config sub-ca.conf \
-out sub-ca.csr \
-keyout private/sub-ca.key

第二步我们使用根CA来签发证书。 -extensions开关指向配置文件中的sub_ca_ext,从而使用二级CA所需要的扩展。

$ openssl ca \
-config root-ca.conf \
-in sub-ca.csr \
-out sub-ca.crt \
-extensions sub_ca_ext

3)二级CA操作

要签发服务器证书,可以在处理CSR文件的时候,在-extensions开关中指定server_ext

$ openssl ca \
-config sub-ca.conf \
-in server.csr \
-out server.crt \
-extensions server_ext

要签发客户端证书,可以在处理CSR文件的时候,在-extensions开关中指定client_ext

$ openssl ca \
-config sub-ca.conf \
-in client.csr \
-out client.crt \
-extensions client_ext
注意
当收到新证书申请请求的时候,你需要在对所有信息进行验证之后才能进行操作。你
需要确保所有资料符合规定,特别是当你处理的CSR文件是别人生成的时。特别要注
意证书的可分辨名称以及basicContraints和subjectAlternativeName扩展。

二级CA的CRL生成和证书的吊销过程与根CA是一样的。唯一不同的是OCSP响应程序所使用的端口;二级CA使用的是9081端口。推荐OCSP响应程序使用独立的证书,这样可以避免将二级CA部署到公开的服务器上.

 

本文摘自《OpenSSL攻略》 

详细操作扩展https://www.cnblogs.com/sparkdev/p/10369313.html

posted @ 2019-10-16 15:34  xdyixia  阅读(1599)  评论(0编辑  收藏  举报