欢迎光临散文网 会员登陆 & 注册

OpenSSL命令行:自建CA&操作CRL

2022-09-18 12:20 作者:寂风也过路  | 我要投稿

零、序章

前情提要:OpenSSL命令行实例

:本文均以RSA密钥为例,整太多就复杂化了

来自官网的警告提示:

此命令最初用作如何在 CA 中执行操作的示例。它的代码没有生产质量。它本身不应该被用作一个完整的CA,但是有些人至少在内部使用它来达到这个目的。执行此操作时,应特别注意正确保护用于签名证书的私钥。建议将它们保存在安全的硬件存储(如智能卡或HSM)中,并通过合适的引擎或加密提供程序访问它们。

此命令命令实际上是单个用户命令:不对各种文件执行锁定,并且尝试在同一数据库上运行多个 openssl ca 命令可能会产生不可预知的结果。

UP注:

正常情况下,我一般只会使用openssl来进行不需要安全保障的一些测试和测试数据生成,不会用于生产实际。需要安全保障的情况下,一般也不会使用简单的命令行工具,而是使用真正的安全设备(如加密机)来保障安全。

本文编写环境:OpenSSL 3.0

本文内容二次验证环境:OpenSSL 1.1.1h

一、创建一些文件夹

命名最好用英文

结果如图

我创建的主文件夹(CA工作目录)名称:myCA

CA文件夹:个人喜好,用于单独存放根CA的证书、csr、私钥

certs文件夹:已签发证书的保存位置,主要是自己归类。openssl似乎不会对这个文件夹进行操作。

newcerts文件夹:新签发证书的保存位置,必定输出到该位置。即便你指定了输出路径,这个文件夹还是会生成一份证书文件(此时输出了两本一样的证书)。

index.txt文件:数据库索引文件,即会记录CA颁发的证书的信息

serial文件:颁发出来的证书的serial number(序列号)。创建时需要往里面输入初始值“01”(也可以填入其他十六进制值表示)(印象中这个序列号长度是有上限的,所以不要随便弄一个很长的数值进来),则颁发证书时会依据这个值开始自动递增

serial文件初始内容如图

二、复制一份openssl.cnf文件到主文件夹内

openssl.cnf通常是在OpenSSL安装目录的bin/cnf文件夹里面


三、编辑openssl.cnf文件

注意,是刚刚复制过来的这个文件,本文修改的都是这个文件

修改图中所示的[CA_default]里的内容

dir:主文件夹路径,我这里用“点”表示“当前文件夹”,因为正常都是进入到主文件夹里去执行操作。当然,你这里也可以写刚刚创建的主文件夹的绝对路径,如:F:/myCA

certs、database、new_certs_dir、serial:都是和刚刚创建的文件/文件夹的路径对应

注意:$dir/certs之类的表示,意思是查找的是dir路径下certs文件/文件夹

四、生成CA证书

4.1 生成密钥对

openssl genrsa -out ca.key 2048

详见“前情提要”内容

(我是把ca.key放入CA文件夹中进行了归类,实际看自己喜好)

修改openssl.cnf里关于CA私钥路径的配置

注意:这里路径以你实际的为准即可,不绝对。

4.2 生成CSR

openssl req -new -key ca.key -out ca.csr

详见“前情提要”内容

4.3 生成自签名证书CA 途径一:

使用X509命令生成V1自签名证书

openssl x509 -req -days 3650 -sha256 -in ca.csr -signkey ca.key -out ca.crt

使用X509命令生成V3自签名证书(推荐)

openssl x509 -req -days 3650 -sha256 -extfile openssl.cnf -extensions v3_ca -in test.csr -signkey test.key -out test.crt

详见“前情提要”内容

4.4 生成自签名证书CA 途径二:

使用本方式前,请先看“七、签发子证书”开头关于policy_match的相关描述,避免根证书出问题。

4.4.1 修改openssl.cnf配置:

修改后的配置文件内容

解释:原配置是usr_cert,使得颁发出来的证书的扩展字段用的是末端证书的配置。而如果要颁发CA证书,则应该使用CA证书的配置,所以我这里是将其配置成V3版本的CA证书配置。否则等下颁发出来的自签名CA证书,用的是V3的版本,却缺少必要的扩展字段,在证书链校验时会失败。

注意:颁发CA时,临时使用v3_ca的配置;颁发末端证书时,要记得改回成usr_cert

有效期配置:原文件默认有效时间长度是365天,可以将其修改成你希望的有效时间长度,如:3650天。

4.4.2 自签名颁证

openssl ca -selfsign -in ./CA/ca.csr -config openssl.cnf -out ./CA/ca.crt -keyfile ./CA/ca.key

示例是在主文件夹目录底下运行的

注意1:此处使用“-config openssl.cnf”指定使用刚刚我们修改过的配置文件

注意2:此处使用“-out ./CA/ca.crt”指定结果文件的额外输出位置。不指定,就只是会输出到刚刚openssl.cnf里配置的new_certs_dir对应路径中,指定后,new_certs_dir对应路径依旧会有一本以序列号命名的证书文件。

注意3:此处使用“-keyfile ./CA/ca.key”指定本次签发证书使用的私钥,如果不指定,那么就会使用配置文件里配置的私钥,即:

默认的签发证书使用的私钥

注意4:每次证书签发过程会有两次提示,第一次是让你确认以下是否真的要签发证书,第二次是让你确认是否要向数据库(就是那个index.txt文件)中添加本次颁发证书的信息。

五、第一次签发完证书

你会发现,出现了三个新的文件

index.txt.attr:签发证书时的属性

index.txt.old:上一版本的index.txt文件内容

serial.old:  上一版本的serial文件内容

5.1 index.txt

当前index.txt中的内容

内容解析:

[证书状态] [证书生效时间] [证书到期时间] [证书吊销时间] [证书序列号] [证书存放路径] [特征名称(DN)值]

证书状态可选值

V(Vaild),有效

R(Rovoked),吊销

E(Expire),过期

证书生效时间:UTC时间(网友说有,但是该字段我在1.1.1h和3.0版本没见过)

证书到期时间:UTC时间,如图是:23年9月15日14:02:15过期

证书吊销时间:UTC时间,在证书吊销后出现。如果有设置吊销原因,则后面会跟着显示吊销原因

证书序列号:十六进制格式(依据serial文件得来)

证书存放路径:生成证书存储的具体位置,若标记为unknown(ca指令指定了证书输出文件)不影响证书库的正常使用

特征名称(DN)值:证书主题名(Subject)

对于过期的证书,文本数据库并不会自动更新,需要使用ca指令的-updatedb选项进行更新,一般来说,在生成CRL之前,都应该使用-updatedb进行更新

时间都是零时区时间

5.2 index.txt.attr

当前index.txt.attr中的内容

该文件内容为第一次颁证时自动生成,生成的依据来源是配置的openssl.cnf(默认是yes)

openssl.cnf的配置

当为yes时,严格要求所有签发的csr的subject不重复,最直观的就是同一本csr不能重复签发

报错举例

当为no时,允许签发的csr的subject重复,最直观的就是同一本csr可以重复签发

重复签名举例:对ca.csr重复签名

如果要调整配置,直接在index.txt.attr中修改yes/no即可。(如果一开始就准备允许subject重复,则可以在第一次颁证前就在openssl.cnf里将该属性设置为no)

官方文档描述:

如果给定值 yes,则数据库中的有效证书条目必须具有唯一的使用者。如果给出值 no,则几个有效的证书条目可能具有完全相同的主题。默认值为 yes,以便与较旧(0.9.8 之前)版本的 OpenSSL 兼容。但是,为了使 CA 证书滚动更新更容易,建议使用值 no,尤其是在与 -selfsign 命令行选项结合使用时。

请注意,在某些情况下,创建没有任何主题的证书是有效的。如果有多个证书没有主题,则不算作重复。

注:

当第二次颁发证书时,又会多出一个文件。这个文件即颁发证书前的index.txt.attr的文件内容备份。

5.3 serial

当前serial中的内容

序列号从我们一开始填入的初始值01,变成了02

六、配置CA证书路径

将刚刚生成的自签名的CA证书存在路径配置进openssl.cnf中,这样,当我们没有手动指定使用哪本CA时,openssl就会默认使用这个路径对应的CA证书来签发子证书。

注:路径要依据实际情况配置

七、签发子证书

注:请颁发子证书前,先查看openssl.cnf的配置是否正确。通常情况下,扩展应该配置成usr_cert。

注:默认情况下,配置要求根证书CA和要颁发的子证书的CSR的国家、城市、组织相同,不然不允许颁发子证书。但是实际两者不一定会相同。所以,可以依据实际情况进行匹配策略的设置。

其中:

match: 该变量在证书请求中的值必须和CA的subject中的对应项完全相同,否则拒签。

supplied: 该变量在证书请求中必须提供(值可以不同),否则拒签。

optional: 该变量在证书请求中可以存在也可以不存在(相当于没有要求)。 

除非preserve=yes或者在ca命令中使用了-preserveDN,否则在签发证书时将删除匹配策略中未提及的对象。

openssl.cnf原始配置

注意:不知道为什么,默认的policy_match里没有配置localityName这个字段,这会导致即便csr里有这个字段,也会因为策略未提及而忽略,这很不正常,所以,一定要先补充这个字段

拒签报错举例
修改后的配置

7.1 颁发子CA

openssl ca -in test.csr -extensions v3_ca -config openssl.cnf

注:请自行生成test.csr,然后在开头创建的主文件夹内执行命令,并指定csr的路径

注:其中,-extensions v3_ca的作用同刚刚的在openssl.cnf中对扩展字段的配置,即指定扩展字段要用哪个配置。如果是颁发末端证书,则可以使用-extensions usr_cert。默认情况下,csr里附带的所有扩展字段都将被忽略,生成的证书的扩展字段全是配置提供。

操作举例


7.2 颁发末端证书

openssl ca -in test.csr -config openssl.cnf

注:请自行生成test.csr,然后在开头创建的主文件夹内执行命令,并指定csr的路径

操作举例

注:默认情况下,颁发出来的这本末端证书的扩展字段,用的是usr_cert里的配置,原csr中的扩展字段全部被忽略了。

openssl.cnf的usr_cert的配置

7.3 批量签发证书

openssl ca -config openssl.cnf -infiles testa.csr testb.csr testc.csr

使用命令:-infiles

执行命令过程中,会一一列举出证书细节让你确认是否要签发证书。

(内容过长,这里就不截图举例了,本质上和普通的证书签发没啥区别)

注意:-infiles必须放在最后,所有后续参数都被视为包含证书请求的文件的名称。

另外建议:可以创建一个叫csrs的文件夹,专门用来放待签发的或者签发过的csr文件。

7.4 签发证书时手动设置证书有效期范围

openssl ca -in testd.csr -startdate 220917111120Z  -enddate 20220918114020Z  -config openssl.cnf

使用命令:

-startdate: 设置证书有效起始时间(实测时间比当前早也行)。我这里设置的是2022年9月17日11点11分20秒。

-enddate: 设置证书有效结束时间。我这里这里设置的是2022年9月18日11点40分20秒。

输入事件的格式有两种,都支持:

YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure)

YYYYMMDDHHMMSSZ (the same as an ASN1 GeneralizedTime structure)

最后的“Z”必须附带。

注意:这里设置的时间,是零时区的时间。如果你要生成马上过期的证书,则要注意进行时区的转换。

八、让CSR中的扩展字段起效

来自官网的警告提示:

应谨慎使用copy_extensions选项。如果不小心,则可能存在安全风险。例如,如果证书请求包含具有 CA:TRUE 的基本约束扩展,并且copy_extensions值设置为 copyall,并且用户在显示证书时未发现此扩展,则这将向请求者提供有效的 CA 证书。通过将copy_extensions设置为要复制并在配置文件中包含 CA:FALSE 的基本约束,可以避免这种情况。然后,如果请求包含基本约束扩展,则将被忽略。

建议还包括其他扩展(如 keyUsage)的值,以防止请求提供自己的值。

可以对 CA 证书本身施加其他限制。例如,如果 CA 证书具有:

basicConstraints = CA:TRUE, pathlen:0

那么即使证书是用CA:TRUE颁发的,它也是无效的。

开启copy_extensions(默认是注释掉)

字段解释:是否将证书请求中的扩展项信息加入到证书扩展项中去。

取值范围以及解释: 

none: 忽略所有证书请求中的扩展项 (默认)

copy: 将证书扩展项中没有的项目复制到证书中 

copyall: 将所有证书请求中的扩展项都复制过去,并且覆盖证书扩展项中原来已经存在的值。

在copy_extensions = copy的前提下

usr_cert模块的配置修改为以下样子:

当前openssl.cnf中的配置

再生成一本带有扩展字段的CSR

注意图中的扩展字段

使用上面介绍的命令,颁发末端证书

openssl ca -in test.csr -config openssl.cnf

颁发证书

可见,当使用copy_extensions = copy时,ca颁证使用的配置模块若有相应字段的描述,则会直接覆盖csr中的对应字段;若没有相应字段描述,则会使用csr中对应字段内容放入到最终的证书中。

九、创建crlnumber文件

先新建文件夹“crl”,然后创建“crlnumber”文件,往crlnumber里预置初始值“01”(或者是其他你喜欢的起始数字,这个数字将会作为被吊销的证书记录的编号,更新吊销证书列表时会自增)。

修改openssl.cnf配置文件,使得路径对应上

十、生成/更新吊销证书列表(CRL)

10.1 更新文本数据库 

还记得上文中生成第一本证书后的介绍说明文字吗?有一处有提及,因为index.txt不会自动将过期证书设置为过期,所以在生成/更新crl前,需要先updatedb,更新数据库索引以清除过期的证书

openssl ca -updatedb -config openssl.cnf

没有证书过期时的示例

当真的有证书过期时,会多出现一行,提示哪个编号的证书过期了。

有证书过期时的示例

与此同时,index.txt中对应行也发生了变化,原本valid状态的证书变成了expire状态

index.txt文件

10.2 生成/更新CRL

openssl ca -gencrl -out ./crl/crl.pem -config openssl.cnf

示例

注:我发现,即便我还没有开始吊销任何一本证书,但是我执行了这个命令,crlnumber就会产生crlnumber.old文件,然后crlnumber里的编号就会开始自增(但是是虚的,等吊销证书真有变化后再生成,就恢复正常了)。

注:这里不能不写“-out crl.pem”,不写的话实测没输出内容

十一、吊销证书

注:吊销完证书,需要更新CRL,crl.pem里的数据才会是新的数据。

11.1 普通吊销(不标注原因):

openssl ca -revoke ./newcerts/03.pem -config openssl.cnf

示例,吊销03.pem证书

执行成功后,会提示你刚刚吊销的证书的序列号。

index.txt里的对应行变化

注:有没有注意到,相当于上文中颁发完证书生成的字段,开头的“V”变成了“R”,然后多了一个时间字段,这个时间,即为“证书吊销的时间”,但是看样子是零时区的时间。

11.2 标注原因的吊销:

openssl ca -revoke ./newcerts/04.pem -crl_reason cessationOfOperation -config openssl.cnf

openssl ca -revoke ./newcerts/05.pem -crl_reason superseded -config openssl.cnf

可以看到,相对于不标注原因的写法,index.txt里在吊销证书的时间后面会附带上我们指定的吊销原因。

index.txt里的对应行变化

-crl_reason可选项:

unspecified

keyCompromise

CACompromise

affiliationChanged

superseded

cessationOfOperation

certificateHold

removeFromCRL

说明:

原因的匹配不区分大小写。设置任何吊销原因都会使 CRL v2。

在实践中,“removeFromCRL”并不是特别有用,因为它仅用于当前未实现的增量 CRL。

十二、 查看crl文件内容

openssl crl -in ./crl/crl.pem -noout -text

没有吊销证书时的内容

可见,内容中有CA信息,有被吊销的证书信息(证书序列号,吊销时间,吊销原因)

有吊销证书时的内容

附加

1、OpenSSL官网对应地址

https://www.openssl.org/docs/man3.0/man1/openssl-ca.html

2、他人文章指路

https://www.cnblogs.com/f-ck-need-u/p/7115871.html

3、一些补充

上文中很多地方都有出现的配置[CA_default]的内容,实际上都可以像设置有效期一样,在操作的时候使用命令进行手动指定。这些内容可以参考上面提供的两个链接,篇幅有限,这边不过多举例说明。

OpenSSL命令行:自建CA&操作CRL的评论 (共 条)

分享到微博请遵守国家法律