yokila
yokila
Published on 2022-09-18 / 34 Visits
0
0

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

零、序章

前情提要:OpenSSL命令行实例

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

来自官网的警告提示:

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

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

注:正常情况下,我一般只会使用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 安装目录的 bin/cnf文件夹 里面

注意:复制的 openssl.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

下图为默认的 OpenSSL 对与 CSR 的 Subject 信息要求:

openssl.cnf原始配置

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

其中:

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

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

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

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

注意:不知道为什么,默认的 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 指定CA签发末端证书

执行命令:openssl ca -in test.csr -cert subCA.crt -keyfile subCA.key -config openssl.cnf

不指定的话,就是使用前面我们在 openssl.cnf 里配置的默认的CA和私钥进行证书颁发。

7.4 批量签发证书

执行命令:openssl ca -config openssl.cnf -infiles testa.csr testb.csr testc.csr

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

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

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

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

7.5 签发证书时手动设置证书有效期

执行命令: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官网:openssl-ca

  2. 人文章指路:openssl ca(签署和自建CA)

  3. 一些补充:

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


Comment