TLS建立在数字证书(digital certificates)之上。数字证书是一组经过精心格式化的信息,用于标识一个实体,并由证书颁发机构进行数字签名。服务器、服务和用户都可以拥有证书。
服务器证书(server certificate)用于应用程序服务器,用于权威地标识服务器。这是您将在web服务器中安装的证书。大多数系统管理员专注于服务器证书。
客户端证书(client certificate)或用户证书(user certificate)标识向服务器进行身份验证的某人或某物。一个人可能会使用客户端证书向VPN、邮件或web服务器进行身份验证,使用证书的密码短语,就像密码一样。内部邮件服务器可能有一个客户端证书,用于向其面向公众的出站邮件服务器进行身份验证——内部邮件服务器是出站服务器的客户端。
信任锚(trust anchor,有时称为根证书 —— root certificate)最终被信任来签署其他证书,如本章稍后所述。信任锚可能是全球受信任的公共CA,也可能是像Active Directory中使用的私有证书。
颁发证书(Issuing certificates)可以签署其他证书。颁发证书可能由证书颁发机构颁发,也可能是私有CA的一部分。第10章讨论了受名称约束的颁发证书。
本书中的大多数示例都使用服务器证书。我们还将讨论客户端证书,但适用于服务器证书的大部分内容都适用于用户证书。第10章介绍了创建CA证书、颁发证书等。如果你遇到一些特殊的东西,比如OCSP验证证书,你用来审查服务器证书的工具要么在它们上运行良好,要么你能够利用你的知识找到正确的命令来破解它。毕竟,所有这些证书都是建立在相同的标准之上的。
第三章:证书证书标准信任锚制作自己的信任包OpenSSL信任包证书组件扩展和约束验证级别信任和您的证书信任链中间CA信任树证书验证编码可分辨编码规则(DER)隐私增强邮件(PEM)编码之间的转换无输入文件的OpenSSLPKCS #12创建 PKCS#12 文件查看 PKCS#12 文件从PKCS#12文件导出证书内容证书扩展证书透明度数字签名无法理解的证书信息跳过密钥和签名多名称证书通配符证书查看远程证书选择CA
TLS在隐藏证书所基于的标准方面做得很好,但偶尔这些根会从森林中冒出来。如果你不认识他们,最终他们会绊倒你。
TLS证书信息是按照X.509组织的,X.509是国际电信联盟(International Telecommunications Union —— ITU)的数字证书标准。X.509用于许多需要精确格式化数据的应用程序。它定义了如何安排证书、使用哪些功能、如何验证和撤销证书等等。
X.509又建立在另一个ITU标准抽象语法表示法一(Abstract Syntax Notation One —— ASN.1)之上。ASN.1是一种用于定义跨平台数据结构并以全球公认的方式提供信息的方法。您将在LDAP和SNMP等协议中看到ASN.1。像OpenSSL这样的TLS工具会自动将这些数字转换为人类友好的单词。幸运的是,您不需要了解ASN.1的内部。接受他们被不止一个开发人员与疯狂悬崖进行了不利的比较,然后继续前进。
ASN.1是通过将对象排列成树来构建的。树上的每个分支和叶子都由一个数字对象标识符(Object Identifier —— OID)标识。X.509与SNMP等协议共享一个树,但位于不同的分支上。新对象缓慢但不断地添加到TLS证书中。每个CA都有自己的对象树块。您的软件可能没有证书中的所有OID。如果一个命令产生1.3.6.1.4.1.4447.1.1.1这样的输出,然后是一堆难以理解的胡言乱语,你应该想“啊哈!这是一个我的工具不知道如何处理的原始OID!”检查软件更新。CA还可以使用私有OID,例如1.3.9900到1.3.9999之间的OID。就像192.168.0.0/16 IP地址一样,这些地址不应该在组织之外可见,但偶尔会逃逸。
如果这还不够,X.509还掠夺了X.500目录标准。X.500为不同类型的信息定义了一个或两个字母的标签,如 OU =
、 O =
和 CN =
。O表示组织(Organization)名称,如公司或其他实体,而OU表示组织单位(Organizational Unit),即该实体的一个部门。
CN给出了 Common Name ,这在历史上是TLS中的主机名。自2000年以来,使用CN存储主机名已被弃用,因为CN不能支持长度超过63个字符的主机名。CN中主机名的替换称为服务器替代名称(Server Alternative Names —— SAN),本章稍后将讨论。许多CA透明地将主机名从CN复制到SAN。你偶尔会看到CA觉得有必要坚持的其他标签。
通用名可以是uid、电子邮件地址、名字和姓氏,或其组合。它甚至可能是一个序列号,用于识别设备。
每个目录项都有一个OID。如果你四处看看,你会发现无处不在的CN是2.5.4.3。你不需要知道这些数字,但当它们出现时不要感到困惑。
信任锚(trust anchor 通常称为根证书 —— root certificate)包含在最终受信任的证书列表中。这些证书没什么特别的。您的系统或应用程序已被告知要信任它们,所以它确实如此。是的,这是非常武断的。
许多信任锚是来自签署证书业务中的大型组织的自签名证书。如本章稍后所述,有些还带有其他信任锚点的签名。信任锚和任何其他自签名证书之间的唯一区别是,应用程序被告知要信任它。许多信任锚的寿命也很长,几十年或更长。
每个操作系统或应用程序平台都提供一个信任包(trust bundle),这是一组受信任的自签名证书,用于签署其他证书。它可能被称为信任锚包(trust anchor bundle)、根证书包(root certificate bundle),有时甚至被称为证书包(certificate bundle)或计划包(plan bundle)。微软、苹果和谷歌等供应商都有自己的捆绑包。Mozilla基金会维护Firefox中使用的捆绑包,但大多数版本的Unix也使用Mozilla捆绑包或其衍生物。Oracle和Adobe也有主要的信任包。
然而,并非所有这些组织都信任相同的信任锚。不同的CA适用于不同的束,并非所有CA都有资格在所有根中。像Trust Stores Observatory这样的项目会监控哪些信任锚点位于哪些包中。
组织可以运行自己的内部证书颁发机构,如第10章所述。此类CA在组织内部受到信任,但不受外部世界的信任。它很容易启动,维护起来很烦人。然而,对于许多组织来说,这是一个明智的解决方案。
许多专家和一大群业余爱好者反对在这些信任锚包中包含特定实体。政府和大公司需要我们自动信任他们,但我们需要扩大这种信任吗?这些根证书包是全局使用的。美国公民是否应该信任香港政府管理的CA?也许荷兰人民应该信任他们的政府,但他们应该信任美国政府吗?如果你今天信任他们,明天你应该信任他们吗?HARICA或上海电子认证机构到底是谁?你可以找到答案。你可以策划一系列你认为值得信赖的信任锚。不止一个人维护着“平民的信任锚包(trust anchor bundle for the commoners)”,但你如何决定信任策展人(curator)?当应用程序因无法验证证书而中断时,您会怎么做?你会处理不信任该证书的政治或技术后果吗?还是你会将信任锚重新添加到你的包中,然后回到看右手剑客用左手打架(right-handed swordsmen fight left-handed)?
这个问题是证书颁发机构所有讨论的基础。我不会再纠缠了。做出你的决定,并与之共存。
许多大型企业都有自己的信任包。该企业已决定不信任特定的政府或组织,和/或他们确实希望信任其仅限内部的证书颁发机构。诀窍在于他们在哪里部署这个包。
为网络浏览器维护自己的信任锚包是一个令人烦恼的爱好。你无法知道你的外部合作伙伴使用哪些CA,更不用说更广泛的互联网上的随机网站了。外部实体在更改CA时没有义务警告您。操作系统更新可能会覆盖您精心选择的捆绑包。精心策划的浏览器信任锚包是一种挫折感。
然而,其他应用程序绝对可以使用精心策划的信任锚包。
假设您的组织内部决定只从“Miracle Max的CA”获取证书。Max不仅会签署您的网站证书,还会签署您的邮件和LDAP服务器以及任何其他TLS应用程序。与其让这些客户端读取web浏览器的信任包,不如将它们配置为使用仅包含Miracle Max的CA证书的信任包。这使得入侵者更难劫持您的内部服务。也许入侵者可以欺骗Guilder为您的域颁发虚假证书,但如果您的应用程序不信任Guilder,证书错误将警告您的用户出了问题。
或者,您可以构建一个安装在所有办公室的嵌入式设备。此设备应仅与您自己的基础设施通信。其信任包应包括您的私有CA,但不包括其他证书。
OpenSSL必须有一个信任包(trust bundle)来验证证书。大多数OpenSSL安装都使用Mozilla信任包,该包作为包含所有CA证书的单个文件分发,但每种Unix都选择了自己的方式来管理这些证书。
大多数软件都希望在 /etc/ssl/certs 中找到证书。OpenSSL希望在系统OpenSSL目录的 certs 子目录中找到它们(可通过运行 openssl version -a
获得)。一些Unix将Mozilla的大文件分解为单独的证书。其他人没有。每个Unix都通过应用符号链接来解决这些冲突,直到投诉停止。
每个Unix都有自己的方式来管理这些证书。也许是 certctl
,或者 add-trusted-cert
,或者 update-ca-certificates
,或者一堆OpenSSL命令。如果您需要在OpenSSL信任存储中添加或删除证书,请查看操作系统文档以了解正确的方法。不要只是将文件扔进看起来正确的目录;系统更新很可能会覆盖它们。
如果你想在OpenSSL命令中使用特定的CA证书——比如,用于测试私有CA——你可以使用 -CAfile 选项指向证书文件。
证书包含两个主要部分:关于被认证实体的信息,以及该信息的数字签名。
关于被认证实体的信息是由请求证书的实体创建的。该实体可能是系统管理员,也可能是像ACME这样的自动化流程。它可能包括有关主机名、物理位置和负责组织的详细信息。它可能只是一个主机名。证书还包括公钥。此组织信息和公钥一起收集到一个X.509格式的文件中,称为证书签名请求(certificate signing request —— CSR)。您向证书颁发机构提交证书签名请求。你把私钥像宝藏一样藏起来。
CA验证证书签名请求中的信息,如本章后面的证书类型中所述。一些CA提供广泛的验证,确保请求来自正确的组织,并通过批准的渠道提交。其他一些,如免费的ACME CA,只验证提交请求的实体是否控制主机和/或其域。一旦CA对请求的合法性感到满意,它就会附加任何委托的权限,并对整个请求进行数字签名。这就是证书。
证书有有效日期,或者至少有到期日期。客户端可能会拒绝过期的证书。手动管理的CA通常提供一年期证书,而ACME CA通常使用三个月来鼓励自动化。证书安全性与证书寿命成反比。我见过多家金融机构使用24小时后到期的证书。通常,使用您可以可靠续订的最快到期的证书。此外,最新的浏览器会拒绝使用超过398天的证书。
使用证书需要CA返回的证书文件,以及您发出证书签名请求时创建的私钥。没有这两个组件,证书就毫无用处。
虽然证书的X.509格式严格定义了数据字段,但它也是可扩展的。证书颁发者可以将自己严格定义的数据字段添加到证书中。这些扩展大多用作约束或政策声明。
约束(constraint)规定了如何使用证书。一个常见的约束是名称约束,其中证书可以在特定域内对其他证书进行签名。我可能会在自己的中间CA上花一大笔钱,该CA可以签署证书,但仅限于我的域名 mwl.io
。我们将在第10章中讨论这些证书。某些证书可能有限制,只能对客户端证书或证书吊销列表进行签名,或者必须使用某些加密算法。
策略(policy)通常适用于TLS连接的各个方面。大多数策略都是使用X.509扩展构建的。证书可以有一个策略,即它只对某些域名有效,或者它只能用于客户端身份验证。
证书将每个扩展标记为关键(critical)或非关键(non-critical)。客户端必须处理和验证所有关键扩展。如果它无法验证关键扩展,则连接失败。客户端应尊重非关键扩展,但如果客户端软件无法识别该扩展,则有权跳过它们。然而,这并不能保证连接会正常工作。服务器替代名称(Server Alternative Names —— SAN)并不重要,但任何希望在现代互联网上运行的客户端都可以处理它们。
假设一个证书有一个约束,即它只能用于签署 mwl.io
域中的证书。名称约束始终是关键的扩展。我使用它为 microsoft.com
签署证书。该证书违反了关键约束。如果客户端不知道如何解释该约束,它将拒绝证书。如果客户端确实知道如何解释约束,它将意识到证书违反了约束并拒绝它。无论哪种方式,我的有限签名证书都无法在我的域外创建可用的证书。
对于大多数人来说,证书的全部目的是关闭程序对不安全应用程序的警告。证书为您的浏览器提供了一个小锁或保护。然而,某些环境可能需要比平时具有更高信任级别的服务器证书,这可以通过所有者的验证程度来表达。
域验证(domain validated —— DV)证书意味着CA验证了请求实体拥有并控制证书所针对的域。如果我想为我的域名 mwl.io
获得DV证书,我需要证明我拥有并控制着名称 mwl.io
指向的主机,或者我可以向DNS添加条目。所有免费的ACME和最便宜的证书都是DV。
组织验证(organization validated —— OV)证书包括DV证书中的所有内容,但也会检查请求组织是否存在以及是否位于所声称的地址。大多数商业CA都提供OV证书。
扩展验证(extended validated —— EV)证书深入请求证书的实体。它验证该组织的商业登记和管辖权。这种证书包括追踪组织所需的一切。这些证书可能价值数千美元。
每种证书类型都包含已验证的信息。DV证书仅包含域名。OV证书包括基本的组织信息,而EV证书则提供各种数据。
在大多数情况下,我们大多数人都希望我们的应用程序停止抱怨。DV证书就足够了。金融机构经常使用具有OV验证的证书。接收EV证书的应用程序可能会以某种方式标记用户;一些浏览器在使用EV证书的网站上将地址栏变为绿色。在现实世界中,用户几乎从未注意到这一点,当他们注意到时,他们会感到震惊。电动汽车证书完全与监管合规有关,因为它们没有技术优势。
证书的全部意义在于让实体证明其身份。当服务器或客户端从连接的另一端接收证书时,它必须验证该证书。从历史上看,证书是使用信任链(Chain of Trust)进行验证的。如今,它更像是一棵信任树(Tree of Trust)。
我们的示例假设TLS客户端(如web浏览器或电子邮件客户端)正在验证服务器的证书。客户端证书的工作方式相同。
在过去,系统管理员发出了一个包含其组织和服务器信息的证书签名请求。证书签名请求基本上是一个没有数字签名的证书。系统管理员将请求连同一叠现金一起发送给了证书颁发机构。CA对证书签名请求进行了签名,创建了一个完整的证书,并将其返回给系统管理员,系统管理员在其服务器上安装了证书文件。
在那些年里,信任链看起来像这样:
Guilder Root
CA
↓
Your Certificate
Figure 1: a primordial Chain of Trust
一个链接。易于验证。很简单。
当客户访问网站时,他们将首先验证证书。证书声称由特定的根CA签名。客户端信任该根CA。客户端将验证该签名并继续,或者拒绝签名并停止。
根CA在非常严格的要求下运行。私钥通常被严格锁定,只能由选定的公司官员访问。选定的公司官员不喜欢打断他们的乐趣来履行他们的公司职责,而他们应该正当地委派所有日常工作。这就是中间CA(intermediate CAs)发挥作用的地方。
中间CA有一个由受信任的CA签名的证书,因此客户端会反过来信任它。它的生命周期比信任锚点短——如果没有别的,您不希望受信任的CA证书在中间CA或其签名的任何证书仍在使用时过期。中间CA证书已被授予签署其他证书的特权。你现在有一个有多个链接的信任链,就像一个真正的链。
xxxxxxxxxx
Florin Root
CA
↓
Intermediate
CA
↓
Your
Cerificate
Figure 2: Chain of Trust with an intermediate CA
访问您网站的客户端通过评估您证书上的签名,然后评估用于签署您证书的证书签名,再评估CA的证书来验证您的证书。如果所有内容都匹配,则您的证书有效。
中间证书可以附加约束。Humperdinck Unlimited可能会购买自己的中间CA证书,可以签署其域中的任何证书。他们可能会为北美、欧洲和亚洲的子域创建更多的中间CA,并将签名权限委托给他们。
信任链的一个复杂之处是,客户端只有信任锚。它没有中间证书,也没有任何收集它们的方法。没有这些,验证就会失败。服务器必须向客户端提供证书链。链文件(chain file 有时称为CA包 —— CA bundle)包括任何和所有中间证书。它们有时包括信任锚,尽管这是不必要的。full chain 文件还包括最终主机的证书。使用中间证书的CA提供链文件。
如果您的CA有中间证书,而您的服务器没有向客户端提供链文件,则客户端无法验证您的证书。Period(就这么回事)。
在那些美好的旧时光里,客户可能需要验证七八个链接长的信任链。现在没那么容易了。
关于信任的事情?不是每个人都有。
虽然大多数用户满足于信任其软件附带的任何根CA,但一些组织不信任某些CA。政府实体可能拒绝信任其他国家的某些CA。一些公司可能不信任竞争对手的CA。
几年或几十年后,信任锚就会过期。SSL 1.0中包含的信任锚,使用1995年被认为牢不可破的算法,今天当然不应该被信任。定期更新的软件将获得更新的证书,但这并不总是现实的。即使是系统管理员也坚定地认为,所有用户软件都必须更新——通常对只能通过Internet Exploder 6访问的破旧关键任务系统负责。
但是,如果信任锚受到损害,会发生什么?信任锚不能被撤销,我们稍后会讨论。但是,该证书将从受信任证书列表中删除。更新后,客户端将不再信任该证书。
交叉签名(Cross-signing)允许证书带有多个签名。只要客户端能够找到一个有效的签名链,指向一个受信任的根,客户端就会信任证书。交叉签名创建了如图3所示的内容。
这样做的全部目标是确保您的证书有效,无论树上发生什么。如果Guilder的信任锚从受信任证书列表中删除,客户端可以根据Florin的信任锚验证证书。如果中间CA的证书被吊销,则另一个CA会提供到根CA的有效链接。您可能会在每个级别上失去所有受信任的实体,但仍会验证证书。
这是一个非常简单的交叉签名证书设置。几个根可能会对中间CA的组合中的任何一个进行签名,这些中间CA反过来都会对您的证书进行签名。你可能有无数的层次和无数的根,所有这些都将难以置信的信任洪流汇集到你不幸的证书上。您可能会在信任包中发现一个中间证书,但用于签名的证书已过期。信任之树有如此多奇怪的曲折和交叉连接,它更合理地被称为信任的扭曲缠结,但这会降低人们对所有现代工业和商业基础协议的信心,所以我们不会这样做。
虽然信任树在加密上是可靠的,但并非所有TLS客户端都能成功验证信任树。许多开发人员只关注第一条信任链的发现,忽视了整个树的其余部分。随着信任之树变得越来越复杂,这些应用程序表现不佳。一旦交叉签名证书中广泛使用的信任锚在2010年代末开始到期,应用程序开发人员就急于赶上。中间证书成为受信任的信任锚,但验证软件希望根位于树的顶部,而不是在中间。当原始信任锚过期时,由新根签名的证书验证失败。许多必要的软件改进仍在进行中,但信任之树不断向恐怖之谜(Tangle of Terror)演变。
这场比赛永远不会结束。
即使客户端软件可以验证复杂的信任树,它也不会有中间证书。您的应用程序必须提供完整的链。大多数服务器可以接受完整的链文件作为证书。
如果您的软件告诉您信任链不受信任,但证书检查显示有多个中介和根,则您的软件需要更新或修复。如果您的供应商没有更新,则您需要一个新的供应商。
客户端必须验证服务器证书。完整的证书验证过程是巴洛克式的,繁琐的,有一大堆异常、循环和死胡同。如果你需要细节,RFC 5280包含的细节足以摧毁真爱存在的任何希望。我们将讨论一般情况。
本讨论假设网站或邮件主机等应用程序服务器提供证书,浏览器或桌面邮件程序等客户端必须对其进行验证。某些应用程序要求客户端向服务器提供证书。也许客户端和服务器都提供证书。虽然协议内部不同,但双方遵循高度相似的程序。我们将“TLS客户端”和“TLS服务器”与应用程序客户端和服务器分开讨论。
每当TLS连接失败时,客户端都会向用户显示一条错误消息,说明原因。在大多数应用程序中,用户可以选择接受证书并继续。您已经在web浏览器中看到了这些消息,以及一些神秘的通知,声明您对TLS还有很多需要了解的地方。您的用户可能会覆盖错误并继续,或者致电帮助台并抱怨互联网中断。
在建立TLS连接后,服务器向客户端提供其证书和任何中间证书。客户端检查这些证书,检查有效日期和数字签名。如果签名无效,则证书在运输过程中被篡改或损坏。如果证书尚未生效或已过期,则无效。无论哪种方式,TLS连接都会失败。
如果证书完好无损并且日期正确,则客户端会尝试在服务器的证书和客户端的信任锚点之间找到一条路径。如果客户端找不到路径,如“信任和您的证书”中所述,证书将被拒绝,TLS连接将失败。
然后,客户端检查证书是否已被吊销。我们将在第4章讨论撤销及其所有变体,如OCSP。
如果证书到目前为止看起来不错,客户端就会检查证书中的约束和扩展。关键扩展必须验证,否则客户端将拒绝证书。
所有这些看起来都很简单。只要一切正常,它就是。如果证书吊销列表(如第4章所述)不可用,无论是由于停机、CA搞砸还是CA本周没有更新列表,您的特定客户会怎么做?每个应用程序开发人员都对如何处理失败做出了选择。如果一个网站在普通浏览器中抛出了一条令人困惑的错误消息,但另一个浏览器显示得很好,用户就不会关心真正的问题是OCSP主食已经过时,网站不值得信任。他们只关心他们的旧浏览器完全失败,而他们最喜欢的新浏览器正常工作。
虽然证书都使用X.509格式,但系统可以通过多种方式对这些证书进行编码(encode)和存储。某些软件只接受一种特定的编码。您必须能够识别不同的编码,并根据需要在它们之间进行转换。
编码(encoding)是一种排列数据的方法。它与加密(encryption)、密码(cipher)或密码(secret codes)无关,而与序列化对象以进行传输和存储有关。ASCII是一种编码。Microsoft Word文件具有编码。这本书的纸质版和电子版都有编码。我们中很少有人能用肉眼读取二进制或base64编码,但对于软件来说,它理解的所有编码都是可互换的。您没有PEM TLS证书,您有一个以PEM格式编码的TLS证书。如果编码不符合您的需求,请更改编码。
虽然Unix不认为文件扩展名有意义,但后缀对管理系统的人来说很有用。您将看到 .pem
、 .der
、 .crt
等扩展名。不幸的是,TLS似乎是系统管理员比平时更加蔑视此类扩展的领域。我不止一次被要求对服务器进行故障排除,在这些服务器中,系统管理员给出了所有以 .crt
结尾的TLS相关文件名,而不管文件的内容或使用的编码如何。您必须能够使用不仅仅是文件扩展名来区分编码。
可分辨编码规则(Distinguished Encoding Rules —— DER)是最古老的X.509证书编码方法之一。DER是ASN.1基本编码规则(Basic Encoding Rules for ASN.1 —— BER)的子集。DER为任何ASN.1对象提供唯一且明确的编码。支持DER的每个系统都将以完全相同的方式解释这些数据。
DER是一种二进制格式。一切都用标签、长度和数据编码。纯粹主义者可能会注意到,计算机中的所有内容都是零和一,但DER比大多数人更快地下降到这个水平。像 file(1)
这样的命令通常将DER编码的文件标识为“数据”。您不能复制和粘贴DER证书,也不能在电子邮件正文中发送它。要将证书视为文本,您必须将其转换为PEM。
以 .der 结尾的文件名提示内容应进行der编码。唯一确定的方法是使用OpenSSL的 x509
子命令查看证书。
$ openssl x509 -in file.der -inform der -text -noout
-in
选项允许您指定要读取的文件。我们正在阅读 file.der 。-inform
选项不会将你的颠覆活动发送给当局。它是“传入格式”的缩写。软件通常无法轻松识别像DER这样的纯数据格式,所以你必须告诉OpenSSL如何解释它。-text
标志告诉OpenSSL以可人工阅读的文本形式提供输出。可读性并不意味着理解。-noout
阻止显示编码的证书。DER编码的文件很小,通常用于对空间敏感的应用程序,如分发证书吊销列表(第10章)。
IETF早在1993年就创建了一个发送加密电子邮件的标准,即隐私增强邮件(Privacy-Enhanced Mail —— PEM)。PGP在电子邮件密码战中击败了PEM,但PEM编码被证明适用于密钥和证书,并幸存下来。
PEM主要是base64编码的DER,加上页眉和页脚,使其更人性化。您可能已经看到过以PEM格式编码的证书或密钥;它们以一行破折号和单词 BEGIN CERTIFICATE
或 BEGIN RSA PRIVATE KEY
开头。然后,您将看到一个充满字符和符号的屏幕,后面是一行声明END CERTIFICATE
或 KEY
的行。PEM编码允许在单个文件中包含多个项目。我偏向于PEM而不是DER,哪怕只是因为我可以看到内容并发现严重的错误,比如试图将密钥用作证书。
包含PEM编码项的文件通常以 .pem 结尾,但您也会看到 .crt 表示包含证书的文件, .key 表示公钥或私钥。PEM编码的好处是,您可以读取标头并查看其中的内容。
使用 openssl x509
查看PEM编码的证书:
$ openssl x509 -in file.crt -noout -text
-in
选项允许我们指定要读取的文件。 -noout
标志阻止显示证书,而 -text
表示生成人类可读的文本输出。OpenSSL默认为PEM,因此不需要手动设置 -inform
。
密钥文件大多是随机数据。如果你尝试使用 openssl x509
读取PEM编码的密钥,openssl会告诉你它不是证书。
有些软件只接受一种编码,有些CA只提供格式错误的证书。您必须能够在编码之间进行转换。
重新编码使用了我们用来查看证书的 -in
选项。它还需要给出一个目标文件名。我们还将使用 -intellite
和 -outform
来告诉OpenSSL如何读取DER文件以及使用什么编码。
在这里,我将DER编码的证书 www.der 转换为PEM编码的 www.pem 。 -notify
标志告诉 openssl x509
源文件是DER格式的。 -outform
标志允许我们为输出选择PEM。
xxxxxxxxxx
$ openssl x509 -in www.der -inform der -outform pem -out www.pem
将PEM证书转换为DER稍微简单一些。OpenSSL可以自动识别传入的PEM编码证书,因此我们不需要 -inform
选项。我们仍然需要 -outform der
来给出目标编码。
xxxxxxxxxx
$ openssl x509 -in www.crt -outform der -out www.der
现在,您可以为狭隘的软件提供所需的任何编码。
如果不使用 -in
或 |
指定输入源,OpenSSL将从标准输入中获取输入。您可以运行命令并将输入粘贴到其中。
假设我想将PEM证书转换为DER格式。我可以这样运行OpenSSL:
xxxxxxxxxx
$ openssl x509 -outform der -out cert.der
命令将挂起,等待输入。
然后,我转到另一个终端,复制我的PEM证书,包括 ---BEGIN CERTIFICATE--
页眉和页脚。我将其粘贴到我的命令窗口中,然后按 ENTER
键。该命令接收该输入并生成我的DER文件。
RSA实验室的公钥加密标准(Public Key Cryptography Standards —— PKCS)定义了存储、排列和使用加密信息的方法。这些标准最早是在20世纪90年代初创建的,其中大多数与公钥加密和密钥交换的内部工作有关。其中许多后来被重新发布为其他标准:PKCS#10定义了CSR,也作为RFC 2986提供。然而,PKCS#12定义了如何在单个存档文件中存储多个相关的加密文件。此存档可以加密和数字签名。它最常用于存储证书链及其私钥。每个文件都放在档案中的一个单独的容器中,称为 SafeBag 。您可以使用PKCS#12将私钥及其证书通过电子邮件发送给组织中的同事。只要你使用一个好的密码并将密码发送到带外(“Out of band” means “pick up the phone and call them.” Yes, the world contains worse things than OpenSSL.),它就相当安全。
Java大量使用PKCS#12。这是Java 8的默认密钥存储格式,它添加了几个功能,使其与其他PKCS软件不完全兼容。如果你需要一个程序与Java互操作,请仔细测试所有操作。
PKCS#12存档文件的文件后缀通常为 .p12 ,有时为 pfx 。(PFX文件格式是PKCS#12的前身。)
您需要能够将各种文件放入PKCS#12存档中,查看内容并提取这些相同的文件。所有这些功能都使用 openssl pkcs12
。
我想将私钥 privkey.pem 、证书 cert.pem 和链文件 chain.pem 存储在一个加密的PKCS#12存档中。使用 openssl pkcs12 -export
来完成此操作。-out 标志允许您设置PKCS#12存档文件的名称。使用 -inkey
提供私钥, -in
用于证书文件, -certfile
用于任何其他证书。
xxxxxxxxxx
$ openssl pkcs12 -export -out site.p12 -inkey privkey.pem -in cert.pem -certfile chain.pem
该文件需要密码。您必须输入两次以进行验证。
在将加密的PKCS#12文件发送给您的同事之前,请仔细检查它是否包含您的密钥。 -info
参数显示屏幕上的内容。
xxxxxxxxxx
$ openssl pkcs12 -info -in site.p12
Enter Import Password:
输入密码,你将看到每个SafeBag和它的内容:
xBag Attributes
localKeyID: 79 0D 40 5E A0 CC 45 DD D0 0E 03 C4 05 DC F9 FF 11 9E 4B 03
subject=CN = mwl.io
issuer=C = US, O = Let's Encrypt, CN = R3
-----BEGIN CERTIFICATE-----
MIIGwzCCBaugAwIBAgISBNkUzXsbmLOfPbh9m63mEqG6MA0GCSqGSIb3DQEBCwUA
…
此存档包含多个证书。每个人都放在自己的SafeBag里。您将看到每个SafeBag的元数据,然后是袋子里的证书。
当PKCS文件包含私钥时,OpenSSL默认以加密形式显示该密钥。在显示密钥之前,系统会要求您输入私钥加密密钥。如果你想看到密钥未加密,请在命令行中添加 -nodes
标志。
正如您对我们使用的所有其他OpenSSL命令所期望的那样,导出到文件的工作方式与在屏幕上查看非常相似。使用 -in
指定存档文件名,使用 -out
指定输出文件名。您需要PKCS密码才能打开存档。与查看文件一样, openssl pkcs
会要求您提供密码来加密私钥。添加 -nodes
以使私钥保持未加密状态。
xxxxxxxxxx
$ openssl pkcs12 -in site.p12 -out all.crt -nodes
all.crt 文件包含PKCS存档中所有内容的提取版本。
实际上,您不希望证书和密钥在一个文件中。您可能希望证书放在一个文件中,私钥放在另一个文件。此文件将包含每个证书的SafeBag元数据。在部署证书之前,您可能需要删除这些行。
xxxxxxxxxx
$ openssl pkcs12 -in site.p12 -out certs.crt -nokeys
使用 -nocerts
仅提取私钥,或使用 -nokeys
仅提取证书。再次,添加 -nodes
以保持私钥未加密。
xxxxxxxxxx
$ openssl pkcs12 -in site.p12 -nodes -out private.key -nocerts
查看导出的密钥,您将看到与导出证书非常相似的标识信息。但还有另一个更微妙的区别。
xxxxxxxxxx
Bag Attributes
localKeyID: 79 0D 40 5E A0 CC 45 DD D0 0E 03 C4 05 DC F9 FF 11 9E 4B 03
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDWbFJV+Z0wKngNOpenSSL …
乍一看,这看起来很好。你把包的细节剪掉,留下一个密钥档案。
此PEM编码证书以 BEGIN PRIVATE KEY
开头。这在技术上被称为PKCS#8格式。大多数私钥使用PKCS#1格式,其中PEM编码文件以标识加密算法的行开头,如 BEGIN RSA PRIVATE KEY
。上面的例子恰好是一个RSA密钥,但显式检查标头中“RSA”或“ECDSA”的软件会阻塞。您可以在导出过程中通过管道将密钥格式转换为 openssl rsa
(用于rsa密钥)或 openssl ec
(用于ECDSA密钥)。使用 -out
参数给出文件名。
xxxxxxxxxx
$ openssl pkcs12 -in site.p12 -nodes -nocerts | openssl rsa -out rsakey.pem
OpenSSL支持其他几个很少使用的PKCS选项。查看手册页了解详细信息。
使用 openssl x509
查看证书很容易,但证书中的所有污垢是什么?获取一个证书文件,并使用 -in
标志查看它,就像我在这里使用PEM证书 www.crt 一样。添加 -text
以文本形式显示输出,添加 -noout
以不显示编码证书。
xxxxxxxxxx
$ openssl x509 -in file.crt -text -noout
这会溢出证书内容。第一行总是说 Certificate :第二行是 Data 。
xxxxxxxxxx
Certificate:
Data:
接下来是有意义的东西:
xxxxxxxxxx
Version: 3 (0x2)
Serial Number:
03:c9:0d:76:bc:e1:a5:da:a4:70:3a:7d:ab:39:70:11:48:e0
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
Version 提供此证书的X.509证书版本。版本3是TLS证书最常见的版本,因为它支持许多互联网应用程序所依赖的扩展。很少使用的版本2用于“属性证书(attribute certificates)”,与TLS无关。如果证书没有版本字段,则它是版本1证书。版本1主要用于非TLS应用程序。
serial number 在此CA签名的所有证书中唯一标识此证书。您可以为同一主机购买多个证书,但如果它们都来自同一CA,则它们将具有不同的序列号。如果您需要吊销证书,您可能需要此编号。
Signature Algorithm 告诉CA是如何对此证书进行签名的。哈希和加密算法的每种合法组合都有自己的代码,但它们大多是不言而喻的。此证书是使用 sha256WithRSAEncryption 或受RSA加密保护的SHA256哈希签名的。
Issuer 标识CA。此处提供的信息采用X.509格式。C代表国家,O代表组织。CN标签给出了该实体的通用名称。该证书由总部位于美国的Let’s Encrypt公司签署,该公司运行CA“Let‘s Encrypt Authority X3”。
xxxxxxxxxx
Validity
Not Before: Jun 7 03:41:14 2020 GMT
Not After : Sep 5 03:41:14 2020 GMT
Subject: CN=mwl.io
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c8:88:be:30:04:f1:ad:3f:c3:5d:2e:fc:3b:c3:
…
Exponent: 65537 (0x10001)
Validity 提供了此证书生效和过期的时间戳。此证书有效期为90天。当某人或某事报告证书有效性问题时,请检查所有相关人员的时钟。
Subject 是被认证实体的主要身份。它通常被称为Distinguished Name 。OV和EV证书包括国家、城市和组织信息以及CN,而DV证书仅提供CN。此证书仍提供CN中的主机名,以支持较旧的客户端软件。此证书适用于我的网站 mwl.io
。请记住,证书的CN中不一定需要主机名;它可能是UID、电子邮件地址或其他东西。
Subject Public Key Info 提供了主机公钥的详细信息。这不是CA的密钥,而是我请求证书时在主机上生成的公钥。 Public Key Algorithm 标识所使用的算法和比特大小。modulus(模数) 和 exponent (指数)是公钥的数字分量。
证书的X509v3扩展(X509v3 extensions)列出了证书中包含的所有扩展。我们在本章前面的“扩展和约束”中讨论了扩展。未明确声明为关键的扩展是非关键的。请记住,软件必须符合关键扩展,否则将拒绝连接。程序应该符合他们理解的所有非关键扩展,但如果他们不理解非关键扩展的话,他们可以尝试继续。
并非所有证书都提供所有扩展,也不是所有证书都具有本例中显示的所有扩展。
xxxxxxxxxx
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
我们在本章前面的“扩展和约束”中讨论了扩展。X509v3扩展(X509v3 extensions)部分列出了这些扩展。
X509v3 Key Usage 扩展声明了如何将此证书用于低级TLS和加密选项。此证书可用于创建数字签名和交换短期加密密钥,这两个都是TLS的关键组件。
X509v3 Extended Key Usage 扩展提供了如何使用证书的更高层次视图。服务器可以使用此证书将自己标识为客户端或服务器。虽然描述声明它仅适用于web服务器,但此证书适用于SMTP或IMAP或您可能包装在TLS中的任何其他TCP/IP服务。请注意,这并没有标记为关键(critical),因此如果应用程序愿意,可以自由忽略它。
x509v3 Basic Constraints 扩展标识此证书是否是证书颁发机构根证书。如果CA为 FALSE
,则此证书无法签署其他证书。如果为 TRUE
,则为CA证书。CA证书还有一个 pathlen
参数,它显示了此证书签名的CA证书的数量,这些证书可能出现在链中的此证书下方。证书颁发机构使用 pathlen
创建其中间CA。这种扩展至关重要,必须遵守。
xxxxxxxxxx
X509v3 Subject Key Identifier:
A2:37:C8:8D:78:75…
X509v3 Authority Key Identifier:
keyid:A8:4A:6A:63…
X509v3密钥标识符是公钥。X509v3主题密钥标识符是此特定证书上的公钥。X509v3授权密钥标识符是签名者的公钥。虽然这些是非关键的扩展,但它们对于找到通往信任锚的路径至关重要。
xxxxxxxxxx
Authority Information Access:
OCSP - URI:http://ocsp.int-x3.letsencrypt.org
CA Issuers - URI:http://cert.int-x3.letsencrypt.org/
Authority Information 扩展声明了CA如何提供有关此证书的更多信息。该证书颁发机构提供OCSP(第4章)。CA Issuers字段指向所有CA颁发证书的集合。
xxxxxxxxxx
X509v3 Subject Alternative Name:
DNS:cdn.mwl.io, DNS:mwl.io, DNS:www.mwl.io
一个证书可以对多个主机有效。X509v3 Subject Alternative Name 字段列出了所有有效的主机名。这是获取证书名称的现代标准方法,取代了通用名称。请注意,此扩展未标记为关键;如果客户愿意,可以忽略它。此证书代表三个主机名: cdn.mwl.io
、 mwl.io
和 www.mwl.io
。
xxxxxxxxxx
X509v3 Certificate Policies:
Policy: 2.23.140.1.2.1
Policy: 1.3.6.1.4.1.44947.1.1.1
CPS: http://cps.letsencrypt.org
X509v3 Certificate Policies 扩展描述了CA的组织、操作控制和过程。您可以在所示的认证实践声明(Certification Practice Statement —— CPS)网站上获取更多信息。
如果您对特定的扩展感兴趣,可以使用 openssl x509
的 -ext
选项从证书中提取它。您必须在逗号分隔的列表中提供感兴趣的扩展名。
xxxxxxxxxx
$ openssl x509 -in mwlio.cer -noout -ext keyUsage,extendedKeyUsage
从 x509v3_config(5)
获取完整的扩展列表。
证书是公共信息。由于证书透明性(certificate transparency ,第9章),您可以查找为域颁发的所有证书。签名证书时间戳(Signed Certificate Timestamp —— SCT)提供了证书已提交到证书日志的加密证明。
xxxxxxxxxx
CT Precertificate SCTs:
Signed Certificate Timestamp:
Version : v1 (0x0)
Log ID : 07:B7:5C:1B:E5:7D:68:FF:F1:B0…
Timestamp : Aug 6 04:41:10.980 2020 GMT
Extensions: none
Signature : ecdsa-with-SHA256
30:44:02:20:5C:B4:6C:B9:1B:0E:77:80:12:D8:…
…
时间戳告诉您日志何时签名并将证书返回给CA。这是您对CA提供证书透明度的保证。
最终,TLS客户端将拒绝未提交到公共日志的证书。
在证书的末尾,您将看到数字签名。
xxxxxxxxxx
Signature Algorithm: sha256WithRSAEncryption
05:a1:e2:2b:49:44:af…
此证书使用SHA-256算法签名,并使用RSA加密。
如果你戳了足够多的证书,你最终会在证书中看到这样的东西。
xxxxxxxxxx
1.3.6.1.4.1.11129.2.4.2:
......v....Y....@.-/....K..G…
1.3.6.1.4.1.11129.2.4.2是原始ASN.1对象标识符。其次是它的价值。您的OpenSSL工具不知道如何解释此OID或其值。这可能是一个新的X.509v3扩展,或者是CA永远不会向您解释的私有扩展。
理想情况下,更新OpenSSL软件将为您提供此OID的解释。如果您无法更新,或者还没有可用的更新,或者您的软件还没有添加此OID,您可以在Internet上搜索此OID,以挖掘它所代表的内容。
很多时候,你想从证书中获取详细信息,但你不需要检查公钥或数字签名。没有必要展示它们。
-certopt
选项允许您指定如何显示证书。在这里,我告诉 openssl x509
在显示证书时跳过公钥和数字签名。
xxxxxxxxxx
$ openssl x509 -in mwlio.cer -text -noout -certopt no_pubkey,no_sigdump
x509手册页列出了使用 -certopt
定制输出的其他方法。是更容易键入这些额外的字符,还是向上滚动浏览签名?这取决于你。
许多网站使用多个主机名。我自己的网站位于 mwl.io
,但如果有人做出了完全可以理解的决定,在它前面放一个 www
,我希望他们能够访问我的网站,而不会出现任何可怕的TLS错误。我的证书声称对 mwl.io
和 www.mwl.io
都是合法的。这并不罕见,如果你检查大型网站上使用的证书的详细信息,你会看到。
现代TLS证书使用主题替代名称(Subject Alternative Names —— SAN)来标识证书适用的所有主机名。SAN是证书扩展,就像约束和策略一样。
要查看证书中的所有SAN,请使用 -ext
标志:
xxxxxxxxxx
$ openssl x509 -in mwlio.cer -noout -ext subjectAltName
X509v3 Subject Alternative Name:
DNS:cdn.mwl.io, DNS:mwl.io, DNS:www.mwl.io
有关扩展的完整详细信息,以及您可以使用SAN执行的所有操作,请阅读x509v3_config(5)
。
除非CA另有声明,否则请在初始证书签名请求中包含所有SAN(第6章)。
证书中不仅可以有多个主机名,还可以将其中一个主机名作为通配符。对于我的域名 mwl.io
,我可以获得一个证书,其中包括 *.mwl.io
作为主题替代名称。我可以在域中的每台主机上安装此证书及其私钥,证书就可以工作了。
乍一看,这似乎很棒。为什么我不在任何地方都这样做呢?
当一切正常时,这真是太好了。然而,如果我的一台主机被入侵,私钥被盗,我的整个组织都会面临风险。入侵者可以伪装成他们中的任何一个。如果入侵者想特别偷偷摸摸,他们会用我网络上不存在的主机名设置一台新机器。我的客户看到 www2.mwl.io
都不会有丝毫惊讶,但那不是一个真正的网站。
如果你使用商业证书并且有很多主机,你可能会考虑使用通配符证书来节省资金。许多大型企业都这样做。但是,在这样做之前要意识到风险。我看到许多公司限制通配符来选择其网络的部分。他们可能没有 *.company.com
证书,而是使用 *.api.company.com
和 *.images.company.com
来应对动态主机配置的流量。
通配符证书正走向淘汰。ACME提供了一个标准接口,用于在面向公众的主机上颁发和续订个人证书。私有CA可以对其主机使用相同的技术。然而,一些组织已经围绕他们的通配符证书建立了实质性的自动化,并且不希望将其全部删除。
我们所有的检查都是针对本地文件中的证书进行的,但有时您希望查看您可能控制或不控制的远程服务器上提供的证书。假设你的用户抱怨他们的浏览器在访问我的网站时发出警告,你决定看看。您可以打开Web浏览器并浏览菜单,直到找到“查看证书”,但当您有一个方便的命令提示符时,为什么要这样做呢?
从OpenSSL的 s_client
子命令开始,第2章对此进行了详细讨论。在这里,我运行 openssls s_client
来获取证书,并将该证书通过管道传输到 openssl x509
中进行解释。
xxxxxxxxxx
$ openssl s_client -connect www.mwl.io:443 < /dev/null | openssl x509 -text -noout -certopt no_pubkey,no_sigdump
这会将证书信息溢出到屏幕上。按 CTRL-C
中断网络连接。
如果要将证书信息写入文件,请添加 -out
选项和文件名。您将在屏幕上看到一些TLS调试,并且仍然需要按 CTRL-C
断开连接。现在,你可以随心所欲地学习证书。
要查看信任链中的所有证书,请使用 s_client
的 -showcerts
选项。 x509
子命令不会同时解析所有这些证书,因此您需要将其保存到文件中并单独分析它们。
xxxxxxxxxx
$ openssl s_client -showcerts -connect mwl.io:443 > mwl.chain
将证书剪切成单独的PEM编码文件,您就可以查看它们。
对于面向公众的证书,您必须使用主要信任包中包含的CA。许多公司提供免费和商业化的证书颁发机构服务。你应该使用哪一种?
你需要购买一张证书,还是免费一张就足够了?如果你买了一个,你是需要提高验证级别,还是仅仅因为公司不信任免费的东西而购买?我曾为那些真诚地相信1000美元的OV证书优于功能相同的100美元OV证书的组织工作过,特别是因为它的成本更高。
列出提供所需证书类型的候选CA。一旦你淘汰了完全不合适的公司,就会留下各种令人眼花缭乱的勉强合适的公司。通过提问来排除他们。
如果您需要ECDSA证书或通配符证书,请验证候选CA是否支持它们。
考虑位置。CA受其母国法律以及任何条约的约束。如果你正在为你的葡萄酒店建立一个电子商务网站,你可能不在乎。我知道从事敏感工作的人不能信任特定国家的任何组织,也不能信任签署了某些条约的任何国家。他们甚至想从这些国家以外的地方获得免费证书。你的组织信任谁?
您必须管理多少个证书?如果你需要一个证书,你可以忍受一个笨重的网络界面。需要数百个证书的组织必须有一个支持全自动证书管理的CA。当CA要求您手动将证书签名请求粘贴到浏览器窗口时,管理许多证书是一项全职工作,没有一个有资格管理证书的人愿意做这样乏味的工作。
您的CA应支持第4章中讨论的证书吊销列表(Certificate Revocation Lists —— CRL)和在线证书状态协议(Online Certificate Status Protocol —— OCSP)。理论上,所有CA都有CRL,但有些CA只提供空列表。CRL在网站上可用,在该CA签名的任何证书中都可用。请检查它是否存在。虽然你希望永远不需要撤销列表,但如果你需要它们,它们将是至关重要的。
我建议选择一个已经经营了很长时间的证书颁发机构,并将X.509证书视为其业务的主要组成部分。这些公司不太可能在您的证书到期之前蒸发。
一个好的CA还将支持第8章中讨论的证书颁发机构授权(Certification Authority Authorization —— CAA)记录。
最后,您的证书颁发机构必须解决其自身的安全问题。任何宣称从未有过问题的组织要么隐瞒了他们的事件,要么没有意识到这些事件。两者都不好。你希望一个组织承认其事件,迅速彻底地解决这些事件,并改变其流程以防止类似事件的发生。
当你有一个简短的候选人名单时,和你的系统管理员同事谈谈。如果有些CA很难使用,请将其从列表中删除。当一切正常时工作的CA很好,但真正有趣的是那些在事情出错时帮助你的同龄人的CA。能够解决实际问题的有效客户支持是选择任何商业供应商的最重要因素。
一旦你选择了CA,但在你告诉同事你已经做出了选择之前,请仔细阅读CA的程序。CA在程序上缺乏灵活性,一些CA有特殊的CSR要求。如果程序和要求不可接受,请选择另一个CA。
现在,您已经足够了解TLS是如何出错的。它确实如此。定期。接下来,我们将处理这个问题。