证书颁发机构由人管理。不,不是像你和我这样的人。经营CA需要自律和对细节的细致关注,这是我们大多数人认为自己拥有的品质。当在使用外部证书颁发机构和运行自己的证书颁发机构之间做出选择时,对于面向公众的系统,您几乎肯定应该使用外部证书机构。
然而,有时你别无选择,只能自己经营。
许多应用程序和设备,如VPN和无线接入点,都使用客户端证书进行身份验证。它们附带了用于生成这些证书的CA。这些CA旨在让您快速启动和运行,这很好。然而,他们很少记录长期运营,这并不好。其中一些快速启动的CA包括破坏长期运营的脚本。如果你正在使用CA,了解它的工作原理以及如何长期运营CA是非常宝贵的。这些“包含”的CA大多基于OpenSSL构建。
在小型组织或家庭实验室中,您可能会运行一个私有CA,并将根证书部署到您的系统中。较大的组织可能会发现部署完整的证书颁发机构软件套件并向商业CA支付名称受限的签名证书是值得的。你们中的一些人可能想加入进来,建立自己的商业证书颁发机构。
我们将依次讨论每一个。
第十章:成为CA私人信任锚CA软件OpenSSL CAs创建一个 OpenSSL CA根CA组织和默认值配置CA策略配置请求创建根证书配置中间CA创建中间CA证书证书数据库链文件准备OCSP响应程序网站证书撤销证书生成CRL客户端证书专用OCSP响应程序名称约束 CA成为全球根
私有信任锚(private trust anchor)CA创建自己的自签名证书,并使用它们对其他证书进行签名。在您在这些证书上安装私有根证书之前,客户端不信任这些证书。像Ansible或Active Directory这样的自动化系统可以为您配置客户端。如果你只有几个客户端,你可以到处跑,手动安装证书。
运行证书颁发机构的工作量与需要证书的客户端、服务器和应用程序的数量成正比。经营私人CA的全球公司都有专门的工作人员。你不应该轻易开始这项工作。如果安装和运行私有CA是一项繁重的工作,那么在任何地方删除该CA以支持自签名证书可能会更加繁重。
第一个关键问题是,你将在哪里管理你的CA?如果这是你的测试实验室,你正在为自己的启发构建一个CA,那么虚拟机是可以的。由真实组织使用的真实CA应该受到更严格的保护。如果您正在构建一个公共CA并希望向全世界提供证书签名,则持有根证书的系统可能会与互联网断开连接并锁定在保险库中。扩展需求以保护您的CA和您的环境。
在证书颁发机构软件套件之间迁移具有挑战性。选择一些适合你长期需求的东西。如果你的组织规模超过少数人,可以考虑使用easy-rsa、XCA或Dogtag等工具作为全面的内部CA,并支持CRL和OCSP响应器。大型组织可能会考虑FreeIPA或EJBCA。任何一种都可以填满一本这么大的书,所以我们不会详细介绍,但使用任何一种,都需要这本书中的所有内容。
小型组织可以使用纯OpenSSL命令构建自己的私有CA。我们将为您的测试实验室考虑这样做。但是,在生产中使用这样的CA之前,请查看您组织中已经部署的CA。你有Active Directory,或者像FreeNAS或Puppet这样的开源工具吗?您是否使用Hashicorp Vault存储证书?所有这些,以及更多,都可以签署web服务器证书。云服务通常向客户提供其内部CA或CA工具包。Java包含一个CA。你有很多选择。
如果您的组织足够大,管理证书需要付出努力,请考虑在内部部署ACME。Let's Encrypt的ACME服务器Boulder是开源的。然而,Boulder会提交证书透明度日志,这会向公众泄露有关服务器的信息。像step这样的CA软件也支持ACME。您可以在ACME服务器中使用中间证书,从而可以灵活地通过ACME或其他工具颁发证书。
您可以使用OpenSSL构建自己的CA。甚至还有一个命令, openssl-ca(1)
。该手册页说:“ca实用程序最初是作为如何在ca中做事的示例。它本身不应该被用作一个完整的ca:尽管有些人正在为此目的使用它。”仔细阅读BUGS和RESTRICTIONS部分进一步说明,OpenSSL的内置ca工具适合您的测试实验室,但不适合大型组织。特别是,openssl-ca不适合多用户使用。CA数据库没有锁定。CSR签名无法过滤X.509扩展。然而,使用OpenSSL构建CA将教会你CA是如何工作的。
TLS在过去的四分之一个世纪里发展迅速。通往我们目前协议的旅程可能看起来像一条直线,但它走过了无数死胡同,又折返了一段。OpenSSL对其中许多死胡同都有挥之不去的支持。OpenSSL的部署非常广泛,更改配置语法和默认值,就像更改命令行一样,会对许多人产生不利影响。这意味着您的配置将包括看起来应该是默认值的语句。在21世纪20年代,你将有一些必须设置为一定值的选项,因为它们从20世纪90年代就开始了。我不会解释为什么某个特定值在2003年被标准化的历史琐事。该手册适用于希望支持20世纪90年代PKI的人。
OpenSSL包含一个OCSP响应程序 openssl-ocsp(1)
。不要把它暴露在互联网上。在过去的几年里,OpenSSL经历了相当繁重的代码审计,但编写面向互联网的服务器并不是他们的首要任务。如果此约束与您的需求冲突,请利用旨在充当CA的工具。
当你的OpenSSL CA开始变得复杂时,不要编写冗长的脚本来自动化它。我认识许多这样做的系统管理员,他们每个人都对此感到后悔。(偶尔编写简单通用命令的脚本是可以的。)切换到CA工具包,如easy rsa、dogtag或step-CA。但是,如果你必须调试其中之一,了解CA的工作方式和底层OpenSSL操作将对你大有裨益。
此外,OpenSSL也在不断发展。Bug得到修复。添加、删除和调整功能。当你更新OpenSSL时,你的CA可能会崩溃。对于某些用户来说,任何关于如何运行CA的教程都会中断。您需要完全掌握调试、搜索答案和研究手册页中的细则。
经过这一切,如果你决心用OpenSSL运行一个最小的CA,这里有一种方法。
一个真正的证书颁发机构有几个强制性组件。你的测试实验室可能不需要所有这些,但如果你跳过关键组件,你不妨忘记整件事,到处接受自签名证书。
您的CA文件应该只能由 root
访问。鉴于当今大多数Unix系统,将学习CA放在 /root/CA 中并非不合理。
您必须对证书和密钥进行严格的组织。我们将在 openssl.cnf 中部分地执行这一点,部分地通过我们惊人的纪律的力量来执行,尽管你也可以使用shell脚本。
现代CA既有根证书,也有中间证书。供应商在其信任包中包含根证书。中间证书在日常操作中用于颁发证书。
X.509扩展的策略和控制将CA证书与随机自签名证书区分开来。您将在 openssl.cnf 中设置两者。根证书和中间证书需要稍微不同的策略,不同类型的证书需要不同的扩展名。我们将在本节中逐步构建它们,但完整的示例可在 https://cdn.mwl.io
。
每个签名证书,无论是根证书还是中间证书,都维护着已颁发和已吊销证书的数据库。我们将使用 openssl ca
来实现这一点,即使它缺少锁定。
每个签名证书还需要一个证书吊销列表。您需要在某个web服务器上提供CRL。由于这是一个私有CA,因此该web服务器可能也应该是私有的。
同样,您需要一个OCSP响应器,它需要访问证书数据库。对于测试实验室,您可以在CA机器本身上运行它。在真实环境中,您不会让密钥签名基础设施靠近公共响应者。
用于随机OpenSSL客户端的设置不适用于根CA。此外,中间证书使用的策略与根策略略有不同。为根证书提供自己的私有 openssl.cnf 。由于根证书位于 /root/CA/root 中,请将其放在 /root/CA/root/openssl.cnf 中。我的示例文件可以从以下网址下载 https://cdn.mwl.io
。
适用于 openssl ca
的配置部分出现在 [ ca ]
部分。
[ ca ]
default_ca = CA_default
default_ca
选项告诉OpenSSL在哪里查找有关默认CA的信息。是的,你可以在一个 openssl.cnf 文件中有多个CA,但这类事情会让你的系统管理员同事进行多年的复仇任务。不要这样做。在这里,我们告诉 openssl ca
默认ca是在名为 CA_default
的部分中定义的:
xxxxxxxxxx
[ CA_default ]
# Directory and file locations.
dir = /root/CA/root
…
CA配置的第一个关键部分是放置CA的位置。一旦定义了 dir
,就可以使用该变量分配其他选项。这里有几个重要的目录。
xxxxxxxxxx
…
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
…
certs
选项设置此CA存储关键证书(如根证书)的目录。这设置为 $dir/certs 或 /root/CA/root/certs 。
new_certs_dir
选项告诉OpenSSL将新证书放在何处。我们已将其设置为 /root/CA/root/newerts 。
您的CA需要一个目录来存储其证书吊销列表。用 crl_dir
设置它。在这里,它是 $dir/crl 。
在创建证书之前,所有这些目录都必须存在。
xxxxxxxxxx
…
database = $dir/index.txt
serial = $dir/serial
…
database
和 serial
选项设置OpenSSL在其中存储已签名证书的数据库和证书序列号列表。
xxxxxxxxxx
…
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
…
使用 certificate
和 private_key
设置签名证书及其私钥的位置将为您节省大量打字时间。在运行任何命令之前,private 目录必须存在,但只能让 root
访问。
xxxxxxxxxx
…
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
…
希望您的根证书不需要撤销任何中间证书,但始终做好最坏的打算。每个新的CRL都被分配了一个递增的数字。值 crlnumber
指向包含要使用的下一个CRL编号的文件。当前PEM编码的CRL存储在 crl
中。CRLs使用特定的X.509扩展, crl_ext
部分将枚举我们需要的扩展。最后,default_crl_days
选项表示crl的有效期。您必须在旧CRL过期之前生成并发布新的CRL。
xxxxxxxxxx
…
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict
name_opt
和 cert_opt
选项控制OpenSSL在签名命令中显示信息的方式。将这些设置为 ca_default
,会告诉 openssl
使用现代设置。让它们不被设置会引发过时的、不受欢迎的行为。
default_days
选项给出证书的标准到期日期。在这里,我们签署的证书有效期为375天。
preserve
选项可以处理某些长期过时的系统中的错误。将其设置为 no
。
policy
是事情变得有趣的地方。CA策略规定了CA可以签署的证书类型。根证书和中间证书之间的巨大差异出现在策略中。我们的根CA从名为 policy_strict
的部分获取其策略。
policy 告诉OpenSSL应该签署哪些证书。它通过比较签名证书和CSR中的变量来完成。受信任捆绑包中包含的根证书应仅对中间证书进行签名。这意味着它签名的证书必须与根证书属于同一组织。我们需要一个相当严格的政策。
xxxxxxxxxx
[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
match 设置意味着CSR中的设置必须与签名证书中的设置相同。在我的组织中, countryName
设置为US。如果我尝试使用此证书对Florin或Guilder的内容进行签名,OpenSSL将拒绝它。
optional 设置意味着该值不是必需的。如果CSR包含电子邮件地址或部门,则政策不在乎。
如果设置为 supplied ,则策略要求CSR中存在该值。它接受任何值,只要它存在。
私有CA根必须至少生成一个自己的CSR。我们想设置一些基本值,比如哈希算法。配置需要一个 req
部分:
xxxxxxxxxx
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
default_md = sha256
x509_extensions = v3_ca
prompt = no
default_bits
、 distinguished_name
和 default_md
设置应该在第6章的CSR讨论中熟悉。将 string_mask
设置为 utf8only 限制变量中可以显示的字符类型。UTF-8自2003年以来一直是标准。最后,x509_extensions
设置将我们指向 v3_ca
部分,其中包含对CA有意义的扩展。
如果使用 default_keyfile
设置默认私钥位置,请不要将其指向包含CA私钥的文件。不完整的命令可能会覆盖CA的私钥。这太糟糕了。
req_distinguised_name
部分直接来自请求CSR。
xxxxxxxxxx
[ req_distinguished_name ]
C = US
ST = Michigan
L = Detroit
O = Inconceivable Incorporated
OU = IT
CN = My CA Root Certificate
主要的补充是 v3_ca
部分中CA的扩展列表。这些扩展应用于使用此配置请求的证书。 x509v3_config(5)
手册页包含更多选项,但这些是CA最常见的选项。
xxxxxxxxxx
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Subject Key Identifier 包含标识特定证书的唯一代码。自2002年以来,将 subjectKeyIdentifier
设置为 hash 一直是标准设置。
Authority Key Identifier 有助于识别用于创建这些证书的公钥。当有人从一对密钥迁移到另一对密钥时,它很有用。将 authorityKeyIdentifier
设置为 keyid:always 选项告诉OpenSSL不仅要将此信息添加到证书中,而且如果不能遵守,则会失败。将签名证书中的 issuer 副本标识信息添加到此证书中,以进一步帮助区分正确的密钥,但它并没有设置为always ,因此如果OpenSSL无法确定颁发者,它可以继续。
basic constrains 约束规定了创建的证书是否可以对其他证书进行签名,也就是说,如果它是一个签名证书。这被标记为关键扩展,因此客户端必须尊重它。进一步的基本约束被设置为变量、冒号和值。在这里,我们使用 basicConstraints
将 CA
设置为 true 。此配置创建CA证书。
通过 keyUsage
设置,我们规定了在此策略下创建的证书可以做什么。您可以创建用途非常狭窄的证书,例如只能加密的证书和只能解密的证书,或者只提供不可否认性的证书。CA的重要值是 digitalSignature 、cRLSign 和 keyCertSign 。这授予CA签署证书及其自己的CRL的权利。许多客户端无法验证 keyUsage
。 extendedKeyUsage
选项包含其他用途,我们将在本章后面的“用户证书”中看到。
中间证书应该能够签署证书,但它签署的证书不应该能够签署其他证书。这需要将X.509基本扩展 pathlen
设置为零。设置此附加约束的唯一方法是创建一个新的扩展列表并告诉 req
部分使用它。我们必须在根CA的 openssl.cnf 中创建它,因为根CA对中间CA施加了此限制。
xxxxxxxxxx
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
v3_intermediate_ca extensions
列表与 [v3_ca]
中的扩展列表相同,除了在 basicConstraints
末尾添加 pathlen:0
。
您已经在 openssl.cnf 中定义了目录结构。在继续之前,请确保所有这些目录都存在。除了 certs 、 crl 、 newcerts 和 private 目录外,还创建了一个用于存储CSRs的 csr 目录。在存储所有东西时要非常有纪律,否则几个月后,你会迷失在一片外观相似的文件沼泽中。
此外,签名证书为每个证书分配连续的十六进制序列号。序列号文件在启动之前必须存在,并且需要一个初始种子值。对于一个真正的CA,你会使用一个随机数,但为了便于阅读,我从1000开始。同样,您需要一个CRL序列号。您还需要一个空的证书索引文件,该文件将成为已签名证书的数据库。
xxxxxxxxxx
# cd /root/CA/root
# echo 1000 > serial
# echo 1000 > crlnumber
# touch index.txt
至此,您的CA支持文件已准备就绪。您可以使用 openssl req
创建根证书。转到 /root/CA/root 。我们所有的根CA操作都使用 -config
标志来拉取CA的私有 openssl.cnf 。 -newkey
和 -keyout
选项告诉OpenSSL创建一个新密钥并将其放在哪里,而 -out
告诉它将完成的证书放在哪里。 -x509
指示OpenSSL创建自签名证书。我们希望此证书的有效期为7300天,即20年,并使用我们在 v3_ca
部分中描述的X.509v3扩展。
xxxxxxxxxx
# openssl req -config openssl.cnf -newkey rsa -keyout private/ca.key.pem -x509 -days 7300 -extensions v3_ca -out certs/ca.cert.pem
系统将提示您输入密码。根证书需要密码。如果这是一个大型的商业CA,而不是用于测试的东西,你可以利用硬件安全模块来存储私钥。
请查看使用 openssl x509
的证书。
xxxxxxxxxx
$ openssl x509 -in certs/ca.cert.pem -noout -text
验证它是否是X.509版本3证书,颁发者和使用者是否正确,以及它是否包含 openssl.cnf 中设置的扩展。如果您以某种方式创建了X.509版本1证书,请在尝试创建中间CA之前停止并找出原因。
ca.cert.pem 文件是您的私有根证书。将其分发给您的客户端,并让他们将其安装在受信任的证书存储中。
现在我们有了根CA,我们可以创建一个从属的中间CA。将其放在 /root/CA/intermediate 中,并复制根证书所需的所有子目录。
xxxxxxxxxx
# mkdir intermediate
# cd intermediate
# mkdir certs crl csr newcerts private
# touch index.txt
# echo 1000 > serial
# echo 1000 > crlnumber
我们不会创建一个全新的 openssl.cnf ,而是将其复制到根证书中。
xxxxxxxxxx
# cp ../root/openssl.cnf .
根据需要编辑中间CA的 openssl.cnf 。首先,更改文件和目录位置。目录和路径都是根据变量 dir
配置的。将 dir
更改为 /root/CA/intermediate 会使中间CA中的所有内容都有自己的位置。
xxxxxxxxxx
[ CA_default ]
dir = /root/CA/intermediate
certs = $dir/certs
…
由您的中间CA签署的证书应该有一年的有效期,就像真正的中间CA一样。我打算再增加几天,以防我需要冲进城堡或其他什么地方。我还需要设置一个默认算法。
xxxxxxxxxx
default_md = sha256
default_days = 375
在 CA_default
中,证书和密钥文件应该有自己的名称,以及CRL。
xxxxxxxxxx
private_key = $dir/private/intermediate.key.pem
certificate = $dir/certs/intermediate.cert.pem
…
crl = $dir/crl/intermediate.crl.pem
演示OpenSSL的 ca
子命令如何不用于实际使用的一点是,它如何处理客户端请求的X.509扩展。人们期望能够过滤客户端被允许请求的扩展。相反,OpenSSL有 copy_extensions
选项。如果设置为 copy ,则复制CSR中设置的但不是CA设置的任何扩展。如果设置为 copyall ,则CSR中的设置将覆盖CA的默认值。将 copy_extensions
设置为 copy 是OpenSSL CA支持多个主机名证书的唯一方法。如果您试图将OpenSSL用作CA,则必须仔细检查所有传入CSR上的扩展。
xxxxxxxxxx
copy_extensions = copy
在 CA_default
部分的最后,设置策略。中间证书需要能够签署比根证书更广泛的证书。
xxxxxxxxxx
policy = policy_loose
现在描述一下这种宽松的政策:
xxxxxxxxxx
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
这项政策只要求一个通用名称。与其说它是“松散的(loose)”,不如说是“漠不关心的(indifferent)”。你可以随意收紧它以反映你的需求。
最后,更改可分辨名称。组织信息应保持不变,但通用名称应反映这不是根证书。我称此为 Intermediate Certificate 1 (中级证书1),因为稍后我可能需要第二或第三个证书。
xxxxxxxxxx
[ req_distinguished_name ]
C = US
ST = Michigan
L = Detroit
O = Inconceivable Incorporated
OU = IT
CN = My CA Intermediate Certificate 1
根CA有一个策略,要求这些字段中的大多数与其声明相匹配,因此除了通用名之外,其他所有字段都与根CA相同。
我们将为要签名的每种不同类型的证书向中间CA配置添加扩展列表,但这足以创建中间CA证书。
在继续之前,请仔细检查中间CA目录中是否存在所有必要的目录和文件。中间CA将对您的大部分证书进行签名,因此它比根CA需要更多的文件存储规则。
进入 /root/CA/intermediate 创建您的CSR。该命令看起来几乎与创建根证书CSR的命令完全相同。只有创建的文件的名称会更改。
xxxxxxxxxx
# openssl req -config openssl.cnf -newkey rsa -keyout private/intermediate.key.pem -out csr/intermediate.cert.csr
出现提示时输入密码。它应该不同于用于根证书的证书。
现在使用根证书对中间CA的CSR进行签名。您需要同时引用 root 目录和 intermediate 目录下的文件,因此最简单的方法是直接在 /root/CA 下执行。我们将使用 openssl ca
命令。创建根证书时应该熟悉许多选项。 -batch
选项跳过各种“点击是继续”提示。我们使用 -days
使中间证书的有效期仅为10年,而不是根证书的20年。替换中间证书比在供应商信任包中获取新证书要简单得多。
xxxxxxxxxx
# openssl ca -batch -config root/openssl.cnf -extensions v3_intermediate_ca -days 3600 -notext -in intermediate/csr/intermediate.cert.csr -out intermediate/certs/intermediate.cert.pem
Using configuration from root/openssl.cnf
Enter pass phrase for /root/CA/root/private/ca.key.pem:
您必须使用根证书的私钥密码才能继续。
xxxxxxxxxx
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 4096 (0x1000)
Validity
Not Before: Jan 20 15:57:55 2021 GMT
Not After : Nov 29 15:57:55 2030 GMT
…
这是我们CA签署的第一个证书,所以它有一个很好的偶数序列号。接下来,我们将了解证书的详细信息。验证一切看起来都是你想要的,或者和它一起生活十年。最后,在最后,我们有数据库信息。
xxxxxxxxxx
…
Write out database with 1 new entries
Data Base Updated
这个“database”到底是什么?
关键(critical)CA数据库是序列号和索引。档案(archive)也很有用。
serial 文件包含CA颁发的 next 证书的序列号。一旦将该编号分配给证书,serial 文件将移动到 serial.old ,并创建具有下一个序列号的新序列文件。虽然我用1000来让它更容易阅读,但请记住这些是十六进制数字。
index.txt 文件描述了CA颁发的每个证书。OCSP响应程序使用此数据库来验证请求。它有六个字段,尽管其中一个字段通常是空的。让我们看看我们的。
xxxxxxxxxx
V 301129155755Z 1000 unknown /C=US/ST=Michigan/O=Inconceivable Incorporated/OU=IT/CN=My CA Intermediate Certificate 1
第一个字段是一个字母,表示此证书的状态。V 表示有效(Valid),R 表示撤销(Revoked),E 表示到期(Expired)。我们的根证书仍然有效。
第二个字段是证书的到期日期,格式为YYMMDDHHMMSS。最后面的Z表示此时间戳是UTC。此证书将于2030年11月29日下午4点前到期。
第三个字段是证书的吊销日期。它在我们的数据库中是空白的。当我们撤销证书时,我们会看到这一点。
证书的序列号位于第四个字段中。
第五个字段是包含证书的文件名。对于我们的CA来说,这将永远是未知的。
最后,第六个字段是证书的可分辨名称(Distinguished Name)。
每当您使用 openssl ca
命令对证书进行签名时,它都会更新数据库。它还将证书的副本保存在以序列号命名的 newerts 目录中。
无论何时签署证书,都要备份数据库文件。文本数据库很容易损坏,损坏的数据库文件很难修复。恢复备份要容易得多。真正的CA软件用实际的数据库替换文本文件。OpenSSL人员不想将sqlite添加为依赖项(相当合理),因此我们得到了文本文件和大量警告。
就像任何使用中间签名证书的可信CA一样,我们的CA也需要一个链文件——chain file。这是一个包含任何中间证书的单个文件。是的,你可能有多个中间人。它也可以包含根证书,但这是不必要的。
xxxxxxxxxx
# cat intermediate/certs/intermediate.cert.pem > chain.pem
我们将使用它来完成单个证书全链文件。
您的OCSP响应程序需要一个证书,以便客户端可以验证其合法性。中间CA将对其进行签名,并添加正确的X.509v3扩展名。您每年都会重新生成此证书,因此请为其创建一个配置文件。此证书是CA操作不可或缺的一部分,将由中间CA操作员创建,因此可以将OCSP配置与其余中间CA文件一起存储。
这是OCSP证书的OpenSSL配置文件示例 ocsp.conf :
xxxxxxxxxx
[ req ]
prompt =no
default_bits = 4096
distinguished_name = req_distinguished_name
default_md = sha256
default_keyfile = ocsp.privkey.pem
[ req_distinguished_name ]
C = US
ST = Michigan
L = Detroit
O = Inconceivable Incorporated
OU = OCSP
CN = OCSP Responder
# openssl req -config ocsp.conf -newkey rsa -out ocsp.cert.csr
请注意配置的最后一行。我每年只使用此文件一次,因此我将创建新CSR的命令作为注释放入文件中。运行该命令。
xxxxxxxxxx
$ openssl req -config ocsp.conf -newkey rsa -out ocsp.cert.csr
给它一个密码,你就有了OCSP CSR。将其拖动到中间CA的 csr 目录中。
OCSP证书需要特定的X.509扩展名。在中间CA的 openssl.cnf 中定义这些扩展。这是一份 ocsp
政策。
xxxxxxxxxx
[ ocsp ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
我们以前见过这些 basicConstraints
、 subjectKeyIdentifier
、 authorityKeyIdentifier
和 keyUsage
设置。最后一行 extendedKeyUsage
用于其他角色。虽然标准中设置了密钥使用的可接受值,但扩展密钥使用可以包括任何有效的OID。如果您可以在ASN.1中定义一个角色并为其分配一个OID,则可以将其绑定到证书。您将看到许多标准的扩展密钥使用值,包括用于签名OCSP证书的值。此扩展标记为关键。不理解扩展的客户端必须拒绝整个证书。
通过策略和CSR,我们可以对OCSP证书进行签名。我从 intermediate 目录运行这个。
xxxxxxxxxx
# openssl ca -batch -config openssl.cnf -extensions ocsp -notext -in csr/ocsp.cert.csr -out certs/ocsp.cert.pem
系统将提示您输入中间CA的密码,然后显示证书。CA将证书保存在 -out
后指定的文件中,但也会在其主存储库的 newcerts 目录下保留一份副本。
您必须为OCSP响应者做出一个最终决定:它应该在哪里监听网络。如果您正在构建CA作为教育练习,请将响应者限制在localhost。如果您的环境不允许传入Internet连接,您可以允许它监听您的本地网络。如果您在公共Internet上,您可以使用此证书并公开响应程序,但不要使用OpenSSL响应程序。使用专为互联网曝光而设计的第三方响应器,并将其连接到使用真实数据库的CA软件。OCSP响应程序通常在端口80上监听。
我使用主机名 ocsp.mwl.io
作为ocsp响应程序。它指向测试IP 203.0.113.207
。通过在未来的证书中使用该主机名,我可以根据需要移动IP。
一旦我们撤销了响应者抱怨的证书,我们就会对其进行配置。
CA应该对其签署的证书应用合理的扩展。这需要中间CA的 openssl.cnf 中的策略。这里有一个适用于典型网站的策略,称为 server_cert
:
xxxxxxxxxx
[ server_cert ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
authorityInfoAccess = OCSP;URI:http://ocsp.mwl.io:80
crlDistributionPoints = URI:http://crl.mwl.io/intermediate.crl
basicConstraints
、 subjectKeyIdentifier
和 keyUsage
现在应该都很熟悉,所以我们将看看新字段。
authorityKeyIdentifier
具有常用的 keyid 和 issuer 关键字,但这次 issuer 设置为 always 。如果OpenSSL无法确定如何设置 issuer ,则操作失败。我们的CA正在颁发此证书,它最好知道它是什么。
serverAuth 的 extendedKeyUsage
是一个标准OID,这意味着此证书仅适用于服务器。如果您将这样的证书放入web或电子邮件服务器中,它将标识服务器。例如,您不能将其用于OCSP服务器。
证书可以使用 authorityInfoAccess
关键字包含有关其证书颁发机构的信息。在这里,CA将其OCSP响应器的位置添加到它签名的每个服务器证书中。同样, crlDistributionPoints
将中间CA的CRL放入证书中。
现在,转到您的服务器并为服务器创建CSR,与第6章中讨论的完全相同。CA不需要服务器的私钥信息,只需要CSR。如果你在测试实验室创建证书,你可能会使用与托管CA相同的主机进行创建,但至少要创建一个新目录,防止它们弄乱你的根CA和中间CA。
下面是一个典型服务器证书的配置,可能会要求我的CA对其进行签名。
xxxxxxxxxx
[ req ]
prompt = no
default_bits = 2048
default_md = sha256
default_keyfile = server-private.key
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
CN = blackhelicopters.org
[ v3_req ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = blackhelicopters.org
DNS.2 = www.blackhelicopters.org
DNS.3 = freebsd.blackhelicopters.org
DNS.4 = centos.blackhelicopters.org
DNS.0 = debian.blackhelicopters.org
请注意,这不是针对CA的域 mwl.io
。我正在为一个完全不同的域颁发证书。这是普通CA需要验证请求者身份的地方,但我控制着这两个域,所以我将跳过这一步。创建CSR并将其复制到中间CA的CSR目录中,转到中间目录并签署证书。
xxxxxxxxxx
# openssl ca -batch -config openssl.cnf -extensions server_cert -notext -in csr/server.csr
Using configuration from openssl.cnf
Enter pass phrase for /root/CA/intermediate/private/intermediate.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 4097 (0x1001)
…
您可能会注意到,我没有告诉OpenSSL将创建的证书放在哪里。它没有丢失。OpenSSL的 ca
子命令按序列号保存newerts下所有已签名证书的副本。这是证书1001,所以是 newerts/1001.pem 。如果检查证书,您将看到服务器扩展。
将该文件返回给您的客户。如果你很友好,你可以将它与现有的链文件结合起来,发送一个完整的链文件。
xxxxxxxxxx
$ cat chain.pem intermediate/newcerts/1001.pem >> server.fullchain.pem
您现在拥有真正的服务器证书。
除非学习经历涵盖了失败,否则它就是不完整的。像这样配置证书。
xxxxxxxxxx
[ req ]
prompt = no
default_bits = 2048
default_keyfile = revoked-private.key
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
CN = microsoft.com
[ v3_req ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = microsoft.com
DNS.2 = google.com
DNS.3 = whitehouse.gov
是的,是的,你是一个淘气的系统管理员,CA应该拒绝它。但假装他们错过了。继续签署它,就像签署任何其他网站的证书一样。现在,您可以为微软、谷歌和白宫设置一个web服务器,任何信任您的证书的主机都会相信您。你需要一个主机条目,但值得做一次才能把课程带回家。
此证书需要吊销。
OpenSSL的 ca
子命令具有 revoke
功能。它只需要一个参数,即要吊销的证书。此特定证书的序列号为1003。我将使用中间CA存档中的副本来撤销它。
xxxxxxxxxx
# openssl ca -config openssl.cnf -revoke newcerts/1003.pem
Using configuration from openssl.cnf
Enter pass phrase for /root/CA/intermediate/private/intermediate.key.pem:
Revoking Certificate 1003.
Data Base Updated
数据库现在将此证书列为已吊销。请注意,第三个字段现在已填充。
xxxxxxxxxx
R 220131162148Z 210122132923Z 1003 unknown /CN=microsoft.com
OpenSSL的OCSP响应程序使用此条目通知客户端证书已被吊销。
当OCSP响应程序读取证书数据库时,证书吊销列表是客户端下载的文档。定期重新生成CRL,无论是按计划还是在吊销证书时。
CRL是一个由CA签名和编码的项目列表。它本质上是一个专用证书,就像我们的OCSP响应器一样。它需要特定的X.509扩展。当我们设置CA的 openssl.cnf 时,我们将CRL扩展指向 crl_ext
部分。是时候定义该部分了。
xxxxxxxxxx
[ crl_ext ]
authorityKeyIdentifier=keyid:always
CRL只需要授权密钥标识符(Authority Key Identifier)扩展。关键字 always 告诉我们,如果密钥ID不存在,则CRL无法签名。
您现在可以创建CRL。
xxxxxxxxxx
# openssl ca -config openssl.cnf -gencrl -out crl/2020-01-22.crl.pem
OpenSSL读取索引并输出CRL。以创建CRL的日期(可能还有时间)命名CRL。虽然您必须将此文件复制到CA的 crlDistributionPoint
中给出的URL,但了解文件的创建时间对于故障排除非常有价值。
使用 openssl crl
查看新CRL的内容。
xxxxxxxxxx
$ openssl crl -text -noout -in crl/2020-01-22.crl.pem
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
…
在查看吊销证书列表之前,您将看到有关颁发者和包含的X.509扩展的信息。
xxxxxxxxxx
Revoked Certificates:
Serial Number: 1003
Revocation Date: Jan 22 13:29:23 2021 GMT
…
客户端可以将证书序列号与CRL进行比较并采取相应行动。
设置web服务器以向客户端提供CRL是留给系统管理员的练习。
虽然签署客户端证书的命令与签署服务器证书的命令非常相似,但客户端证书需要不同的X.509扩展。这是 openssl.cnf 中的中间CA客户端配置:
xxxxxxxxxx
[ user_cert ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
authorityInfoAccess = OCSP;URI:http://ocsp.mwl.io:2560
crlDistributionPoints = URI:http://crl.mwl.io/intermediate.crl
此策略与服务器证书策略之间的区别在于 extendedKeyUsage
的值。此证书可用于客户端身份验证和电子邮件保护。在签署证书时将此策略应用于证书。
xxxxxxxxxx
$ openssl ca -batch -config openssl.cnf -extensions user_cert -notext -in csr/client.csr
Using configuration from openssl.cnf
Enter pass phrase for /root/CA/intermediate/private/intermediate.key.pem:
输入密码,您将获得证书。
xxxxxxxxxx
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 4101 (0x1005)
…
这是证书0x1005。将 newerts/1005.pem 退还给客户。
再说一次,不要在开放的互联网上运行OpenSSL的OCSP响应程序。这是为了教育,不是为了生产。只能在私人实验室玩,或者更好的是在本地主机上玩。如果您的CA必须为互联网上的主机提供吊销通知,并且您不想运行更大的CA软件,请跳过OCSP,只提供CRL。
使用 openssl ocsp
命令运行OCSP响应程序。 -port
标志允许您设置它绑定到的端口。 -text
标志告诉命令以纯文本打印其响应,这样您就可以检查正在运行的终端并查看发生了什么。使用 -indexfile
指定索引文件的位置,使用 -CA
指向私有CA的链文件。最后,使用 -rkey
指向OCSP响应者证书的私钥文件,使用 -rsinger
给出实际的OCSP证书。(如果你运行的是LibreTLS,你可以指定校验和算法、IP和端口等细节。)
# openssl ocsp -port port -text -index indexfile -CA chain.pem -rkey private-key -rsigner cert.pem
在这里,我将所有需要的证书、链文件和密钥从中间CA复制到一个目录中,并在端口80上运行OCSP响应器。
xxxxxxxxxx
# openssl ocsp -port 80 -text -index ../index.txt -CA chain.pem -rkey ocsp.privkey.pem -rsigner ocsp.cert.pem
Enter pass phrase for ocsp.privkey.pem:
给出OCSP密钥的密码,响应者将准备就绪。
xxxxxxxxxx
ocsp: waiting for OCSP client connections...
运行是一个开始,但它不能代替工作。让我们按照第4章进行OCSP查询。打开另一个终端,选择一个新颁发的证书进行验证。我们将从客户端证书开始。
xxxxxxxxxx
$ openssl ocsp -issuer chain.pem -cert client.cert.pem -text -url http://localhost
响应者和客户端都会发出响应。浏览所有关于哈希和非数的东西,你会发现这种乐趣。
xxxxxxxxxx
…
Cert Status: good
…
验证应该验证的东西是很好的,但请仔细检查OCSP是否也可以拒绝证书。本章早些时候,我们撤销了一份证书。让我们检查一下。
xxxxxxxxxx
$ openssl ocsp -issuer ../chain.pem -cert revoked.cert.pem -text -url http://localhost
…
Cert Status: revoked
…
它奏效了。
您现在有了一个功能测试CA。您可以随意使用它,尝试证书,并深入了解X.509、公钥加密和TLS的内部。请记住,OpenSSL CA仅用于测试和教育,不适用于重型使用。
如第4章所述,证书撤销是可疑的。一些行业必须能够有效地消除对证书的信任。与CA的OCSP响应者联系的浏览器可能会认为证书是正确的。OCSP订书钉有效地创建了七天后到期的证书,但一周的时间足以对选定的目标进行银行账户盗窃。
考虑到TLS的功能,我们低端用户提高协议健壮性的最佳方式是缩短证书寿命。如果您的公共证书是真实的,并且必须由公众广泛认可的CA验证,并且您想缩短证书寿命,则可以考虑使用具有名称约束的签名证书。
受名称约束的签名证书(name-constrained signing certificate)允许组织在“使用者备选名称”中的有限DNS名称列表内对证书进行签名。这是一个dNSName约束(dNSName Constrained)证书。您还可以获得对可分辨名称、IP地址、电子邮件地址和其他证书标识符具有名称约束的证书。如果我为我的域名 mwl.io
购买了一个名称受限的证书,我就可以为该域名和该域名中的任何主机签署证书。我可以根据我喜欢的任何条件和用途颁发这些证书。如果我想让我的服务器证书在24小时内过期,我可以这样做。部署和启用这些证书的自动化将留给系统管理员进行练习,同时安排替换时间以在证书到期前解决任何问题。
名称受限证书(Name constrained certificates)适用于有员工和资金的组织。适用于运行私有信任锚的所有内容都适用于管理受名称约束的证书。任何获得您组织私钥的人都可以为您网络中的任何主机创建证书。
允许您为域名内的任何主机或客户端签署证书的证书可能需要数万美元。然而,尽管DV服务器证书的成本大幅下降,但许多人预计受名称限制的签名证书的价格会下降。对于有实际风险的组织,特别是过去因TLS故障而遭受损失的组织,这笔费用可能被认为是值得的。
使用这样的证书需要真正的PKI软件,而不是上一节中演示的笨拙的OpenSSL CA。如果你缺乏人员来正确部署和管理像Dogtag这样的东西,那么名称受限的证书不适合你。
这是一个非常边缘的案例,我不会深入探讨。不过,你们中的一些人在职业生涯中会需要这个,意识到它的存在会让你成为英雄。或者对雇主的崩溃负责。其中之一。
本章早些时候,您没有从运行测试CA中学到什么,您认为您可能希望构建一个全球认可的证书颁发机构。从技术上讲,这是一个众所周知的问题。你构建服务器。您可以在某种硬件安全模块(Hardware Security Module —— HSM)上保护您的私钥。您找到一个现有的根CA,并向他们支付一大笔钱来交叉签署您的证书,同时完成要求,使您的根证书在所有主要的信任包中被接受。
这是你的第一个问题:所有主要的信任包(all major trust bundles)。
目前,这是微软、Mozilla、谷歌、苹果、甲骨文和Adobe。
每个供应商都有一个评估、接受和在其集合中包含组织根证书的流程。他们每个人都有自己的标准。一般来说,潜在的根证书组织需要通过几次不同的审核,并同意接受未来的定期审核。收集和维护这类数据需要大量的时间、对细节的关注和大量的双重检查。
要摆脱成为公共CA的恼人的冲动,请查阅CA/浏览器论坛文件“公共可信证书颁发和管理的基线要求”(Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates)的最新版本。这将治愈大多数读者。不过,如果阅读这份文件能让你的灵魂感到温暖,你可能只是大自然的CA操作员之一。
成为全球公认的根CA听起来可能很好,但这是一种花哨的方式,表明你厌倦了做系统管理员,你的真爱是复杂、挑剔的文书工作。成功意味着世界各地的人都会试图欺骗你,欺骗你,假装成别人。(Success means that people all across the world will try to scam you, rip you off, and fake being someone else.)
Sysadmin现在看起来没那么糟糕,是吗?
通过对TLS的一些理解,您可以使您的系统表现得更好。或者更糟。如你所愿。