导航
本文通过开源软件 Dogtag 描述 PKI 的基础功能和安装实践,分为上下 2 篇:
- 上篇,即本篇,描述 PKI 的基础知识。
 - 下篇,实践篇,描述如何使用 Dogtag 搭建 PKI 系统,点击链接即可访问:PKI 公钥系统 – 基于 Dogtag 实践
 
本文基于以下软件进行描述
| 序号 | 软件 | 版本 | 描述 | 
| 01 | Rocky Linux | 9.6 | 操作系统 | 
| 02 | Dogtag | 11.6.0 | PKI 基础架构(idm-pki-ca) | 
| 03 | Nginx | 1.22.1 | WEB 服务 | 
| 04 | Firefox | 143.0.4 | 浏览器 | 
术语
- PKI: Public Key Infrastructure, 即公钥基础架构。
 - CA: Certificate Authority, 即证书中心。
 
前言
PKI 的背后是一套非常复杂的数学和密码学的混合实现,再加上其发展过程中的历史纠葛,以至于很多人对理解 PKI 的知识感到畏惧,在相当长的一段时间里都刻意避开它。
本文通过开源软件 Dogtag 来实现 PKI 的基础功能,以企业内部自建 CA 的流程进行相关描述,这与互联网的 CA 有些许差异,但是原理基本都是一致的。
下图是整篇文章使用的例子,我们以一张数字证书的全生命周期进行说明:
- 创建一个 2 层的 CA 架构用于证书的管理,描述 CA 的基础知识;
 - 给 Nginx 服务器签发证书以提供身份验证和加密通讯,描述证书的作用;
 - 用户通过 HTTPS 访问网站并向 CA 验证服务器的证书,描述浏览器和 CA 的交互知识。
 
如何被信任
我们都知道,当 PC 需要访问某个网站时,HTTP 的流量是通过明文传输的,在仅仅只是浏览网站时当然没有任何问题,如下图:
但是当涉及到敏感数据的传输,比如输入账号和密码时,这些隐私数据如果没有得到有效的保护直接使用 HTTP 传输,那么就有被窃取的风险,以下的中间人攻击仅是”数据诈骗”的其中一种方式:
由于传统 IP 网络的实现是完全开放性的,要实现安全通讯的功能,就需要通讯的双方必须是可被信任的实体,只有当双方的身份都被确认后,安全的通讯才能被建立,这也就引申出了 PKI 帮助我们解决的安全问题:
- 如何在网络中证明自己
 - 如何保证数据在传输过程中没有被篡改
 
PKI 的基础知识
HASH
中文名是哈希,也叫数字摘要(digest), 功能是通过特定的算法,将任意长度的数据(文件)转换为固定长度的唯一标识符,这一串标识符就是哈希值。以中文环境来说,将 hash 的输出描述为数字摘要似乎更为贴切。
无论是一小段消息还是巨大的镜像文件,hash 的输出都是单向的,并且具有唯一性,在任何设备上,只要输入的数据完全一致,那么输出都是完全相同的。反之如果数据有任何修改,哪怕一个标点符号的改变,hash 输出都是完全不一样的。
Hash 在互联网下载的应用中非常常见,软件公司通常会将软件产品通过官方的下载地址提供,并且附上相应 hash 值文件,这样用户在下载软件后可以自己再次生成 hash 值,然后与下载页面提供的 hash 值做对比,从而确认数据的完整性。
以 Rocky Linux 的下载页面为例,可以看到在每个镜像文件(iso)的下载地址内都会包含相应的校验文件:
这个文件就是 iso 镜像文件的官方 hash 输出:
作为例子说明,我们对下载的镜像文件再做一次 hash, 可以看到 2 个 hash 值是一致的,这就说明下载的镜像文件是完整的,和官网提供的镜像文件一致,没有任何修改。
由于 hash 的单向特性,任何人都无法从 hash 的输出反推输入(原始数据),这一点至关重要。
MAC
Message Authentication Code, 即消息认证码,在双方的通信中,网络 2 端的实体提前沟通好通讯密码,即共享同一个密钥(密码),发送方首先将共享的密钥和需要发送的消息组合在一起,然后做 hash,这个 hash 的输出就是 MAC, 发送方把 MAC 和原始消息一起发送给对方。
接收方收到 MAC 和原始消息后,使用共享密钥和原始消息再做一次 hash, 只要密钥正确并且消息没有被修改,那么新生成的 MAC 和收到的 MAC 肯定是一致的,通过对比 2 个 hash 的输出结果,接收方可以清楚地了解到:
- MAC 一致,说明数据来源可靠并且数据在传输过程中没有被修改;
 - MAC 不一致,则说明数据曾被修改过,对方身份可疑,任何对方发来的数据都应拒绝。
 
相对于 hash 使用单一的输入,MAC 使用 2 个输入(即共享密钥和消息)来产生 hash 输出,这样确保只有知道密码的接收者才能正确地识别消息,从而保证数据的完整性。
需要强调的是 MAC 的生成过程是依赖共享密钥的,这种使用共享密钥进行数据完整性验证的方法也被称为对称加密技术,使用这种加密技术的前提是参与通信的任何一方都需要知道共享密钥,任何人都可以使用共享密钥来进行加密或解密。
在密码被妥善保护的情况下,对称加密技术可以安全地验证通讯 2 端的身份和数据完整性,但是共享密钥也同样带来了安全挑战:
- 在多人参与通信的条件下,需要频繁地更新共享密钥以防止密钥泄漏的风险;
 - 共享密钥如何安全地分发。
 
数字签名
为解决对称加密带来的安全挑战,我们使用数字签名(即公钥系统)来进行进一步的改善。
数字签名的概念和 MAC 相似,相对于 MAC 使用共享密钥来进行数据加解密,数字签名使用一对相互关联的密钥对,即公钥和私钥对数据进行加密和解密:
- MAC 方式中,参与通讯的前提条件是需要知道共享的密钥,参与的人越多,密码泄露的风险越大,而参与数字签名活动的公钥和私钥是不对称的,公钥可以自由分发,没有安全风险,只需要对私钥进行妥善保护即可。任何公钥加密的数据都能被私钥解密。
 - 私钥加密的数据一般被称为数字签名,并且只能被它所关联的公钥进行验证(解密)。因此对于接收方来说,能够使用对方的公钥来验证签名是否合法,一旦验证(解密)通过就可以确认对方的身份。
 
让我们再次回到上面的例子,这次我们使用公钥系统进行验证:
发送方生成一对相互关联的密钥,即公钥和私钥,其中的公钥可以自由地分发到网络中,私钥必须严格保密。
当发生通讯时,发送方首先对需要发送的消息做 hash,然后将 hash 后的输出(数字摘要)使用私钥进行加密,这个加密后的输出就是数字签名。发送方将签名和消息一起发送给接收方。
接收方收到数字签名和消息后,首先将消息再做一次 hash 得到本地的数字摘要,然后使用发送方的公钥对数字签名进行解密,解密后得到原始的数字摘要,接收方对比 2 份数字摘要,如果比对结果一致,则可以确定:
- 发送方的身份是合法的,因为只有发送方的公钥才能正确验证数字签名的合法性(解密成功)。
 - 数据是完整的,因为 2 份数字摘要的对比结果一致。
 
最后当接收方需要响应时,直接使用发送方的公钥进行数据加密并将加密后信息发给对方,由于公钥加密的数据只能被对应的私钥解密,双方得以建立安全的沟通机制。
由于公钥和私钥的不对称特性,这同时也引申出了一个关于数据签名的”不可否认性”的结论,因为仅且只有发送方拥有私钥,并且只有对应的公钥才能验证(解密)私钥加密的数据,那么一旦公钥成功解密数据,持有私钥的人就无法否认数据是由他签名的这一事实,这样也就验证了发送方的身份。我们可以代入到现实世界中的签名,因为每个人的笔迹都是不一样的,所以任何手写的签名都能被识别出签名者的身份并且具有法律效应(无法否认)。
公钥加密的实现
公钥加密技术是构成 PKI 架构的基础,背后的逻辑是基于数学的魔法实现,这种不对称的加密和解密方式也被称为非对称加密技术。
任何实体(比如服务器)只要生成一对相互关联的公钥和私钥,公钥可以自由地在网络中分发,私钥进行安全地保护。任何拥有公钥的用户,就可以在网络中对该实体的签名进行验证,验证一旦通过就可以明确对方的身份并安全地与之通讯。
更通俗一些的说法就是:只要拥有某个实体的公钥,我们就可以在开放式的网络中正确地识别它。
再次重申公钥加密技术的实现原理:
- 公钥可以自由地分发,任何公钥加密的数据仅能被对应的私钥进行解密。
 - 私钥加密的数据一般被称为数字签名,只能被对应的公钥进行验证(解密成功)。
 
代入到我们的示例中,PC 在没有证书介入的情况下可以这样验证服务器的身份(https 前段交互):
- 服务器生成一对公钥和私钥,并把公钥发布到网络中;
 - PC 通过网络得到服务器的公钥,然后发起通讯,首先随机生成一长串数字,然后发送给服务器;
 - 服务器使用私钥将这一串数字进行签名(加密),然后将签名发回给 PC;
 - PC 使用服务器的公钥对签名进行解密,只要解密后的数字和发送的数字一致,那么 PC 就可以确认与之通讯的服务器的身份。
 
证书
回到 PC 验证服务器身份的例子,PC 是如何得到服务器的公钥的呢?答案就是数字证书。
数字证书本身是一个很简单的数据结构,主要内容就是服务器的公钥和名字,最重要的是这个数据结构是被签名的,签名后就实现了公钥和名字的绑定,这个绑定在证书中以主题(subject)的形式展示。
由于签名后的证书中绑定了公钥,而公钥的作用是身份验证和加密数据,这也决定了证书可以自由分发。
如下是一张 Web 证书(www.thelearningbook.online.crt)的例子:
数字证书必须被私钥签名后才能生效,使用私钥进行签发的实体就是证书颁发者(issuer),根据私钥的拥有者可以分为:
- 如果用于签名的私钥是 web 服务器自己生成的,那么这就是一张自签名的证书。
 - 如果用于签名的私钥是由一个权威机构生成的,那么这就是一张具有公信力的权威证书。
 
自签名证书
如下图,如果在 Web 服务器内部生成密钥对,然后使用私钥给自己签发证书,那么这个证书就是一张自签名证书。
自签名证书通常应用在企业内部或测试环境中,并且不具有权威性,自签名证书的 issuer 和 subject 将是同一个名字。
下图是一张 Nginx 服务器自签名证书的样本,可以看到证书绑定的名称和证书颁发者都是相同的。
任何不具有权威性的证书都会被浏览器标记为不信任网站,并且给出告警提示,如下:

权威证书
在自签名架构中,web 服务器通过证书向 PC 证明了自己的身份,但是这张证书由于是自己签发的,通常不被浏览器认可。
为了让证书能被浏览器信任,服务器的证书需要由权威机构的私钥进行签名,也就是说需要找到一个通讯双方都信任的权威机构,然后使用它的私钥来签发服务器证书,这个权威机构就是 CA(Certification Authority)。
信任仓库
权威 CA 是一个完全被信任的第三方公信机构,网络中所有的设备都信任该 CA 签发的证书,权威 CA 的公钥证书都会随操作系统或者浏览器一起安装,存储这些证书的地方就是证书仓库,也叫信任仓库(Trust Stores), 如下图,这是火狐浏览器的默认证书仓库,预装了大量的权威 CA 证书:
在我们日常访问各个网站时,浏览器都会收到服务器发来的证书,浏览器首先查看证书的颁发者(Issuer), 然后到信任仓库中选择对应的 CA 公钥证书对服务器证书的签名进行验证,验证成功后再到 CA 查询该服务器证书的状态,只要成功命中就可以完成对服务器的身份验证。
信任关系的建立
回到我们的例子,我们的目标是创建一个仅供企业内部使用的 CA 架构, 然后通过它来完成内部 web 服务器证书的签发和验证,同时也需要应用程序(如浏览器)能够信任自建 CA 的证书。
如下图,我们创建了一个新 CA, 同时服务器的证书也经过了 CA 的签名,但是由于 CA 是自建的, 在 PC 的信任仓库中并没有这个 CA 的公钥证书,所以当我们访问 web 服务器时,浏览器同样会给出安全风险的提示。
要解决这个办法也很简单,只要把我们自建 CA 的公钥证书加入到证书仓库中就可以了。当自建 CA 的公钥证书被添加到信任仓库后,就可以对所有经过该 CA 签名的证书进行验证,只要你信任它, 就可以信任它所签发的所有证书。
PKI 架构
至此,我们已经触碰到了 CA 对于数字证书的一些基本功能,更进一步,我们需要一个对证书进行全生命周期管理的系统,它就是 PKI(Public Key Infrastructure).
PKI 由多个功能模块组成,在当下有很多软件都可以实现 PKI 的功能,我们使用开源软件 Dogtag 来构建一个内部的 PKI 系统(本文中仅用于数字证书) ,以一张证书的全生命流程进行描述,如下图:
Entity
即申请证书的实体,可以是硬件,也可以是软件,任何你在网络中想定义的东西都可以称作实体,这是一个很宽泛的名词。
当实体作为证书的发起者时,它将收集自己的相关属性信息,然后使用工具软件(如 openssl)生成证书请求(Certificate Signing Request, CSR),然后发送给 RA 进行审核。
CSR 数据结构通常包括请求者的公钥和名字等细节,向 CA 表明自己的属性信息,以下是一张 CSR 的部分截图:

RA
Registration Authority, 即注册中心,作为证书处理的第一个入口,主要功能有 2 点:
- 接受证书申请,不但需要确认实体的身份和权限,而且 CSR 的内容也必须进行合规检查,检查完成以后再将请求送入 CA.
 - 撤回证书申请,负责处理证书的撤回请求操作。
 
需要注意的是,RA 不但能接受实体发来的 CSR, 自己本身也能生成证书申请,然后直接发送给 CA.
如果由 RA 生成 CSR 就需要考虑在完成证书申请后,如何安全地将证书和申请者的私钥一起发回给申请者。
CA
Certification Authority, 是构建 PKI 最核心的子系统,负责对证书进行最基础的管理:
- 签名,最核心的功能,对某个实体的公钥和名字的绑定进行担保,确保拥有 CA 公钥证书的用户可以验证所有此 CA 签发的证书,从而确定对方的身份。Dogtag 可以通过网页的方式来签发证书。
 - 更新,证书是有使用寿命的,当证书有效期到达,如果需要继续使用此证书,那么就需要更新它,即延长证书的有效期。
 - 撤回,当证书由于某些原因需要停止服务时,可以撤回此证书。证书一旦被撤回,则不再起作用。
 - 存储,Dogtag 将所有签发的证书的相关信息写入目录服务器(389ds),最终形成证书信息数据库。
 - 分发,Dogtag 可以通过 web 来分发证书,证书生成后,用户可以访问网页来下载相关的证书。
 - 验证,验证证书的有效性,比如检查名字和公钥的绑定,证书的有效期等。
 
CA 层级
CA 通常采用分层设计的架构,顶层的 CA 叫做根 CA, 下层的 CA 不管分几层一律称为中间层 CA, 之所以设计为层级结构主要是考虑到安全和性能。
- 安全性方面,在大型企业中,成千上万的软硬件都需要使用证书来进行安全通讯,根 CA 的私钥安全问题就显得尤其重要,一旦根 CA 的私钥发生安全事故将直接影响所有的设备,所以有必要设计中间层 CA 来代替根 CA 的工作,一旦真的发生重大安全问题,甚至可以直接注销整个中间 CA 从而避免造成更大的损失。
 - 性能方面,大量证书的并发访问和分类管理也需要中间层 CA 进行负载分担。
 
在我们的例子中,我们创建了一个双层架构的 CA 系统,由一个根 CA 和两个子 CA 组成,子 CA 分别用于负载不同的业务:subCA01 负责 web 服务器证书管理,subCA02 负责硬件设备的证书管理:
根 CA
即 root CA, 作为皇冠般的存在,它只负责对中间层 CA 证书的签发, 不会参与到端点层设备的证书签发工作,所有端点设备的证书都由最底层 CA 的私钥签发。
需要注意的是,由于根 CA 处于顶点位置,它的证书只能由自己的私钥进行签发,也就是说根 CA 的证书是自签名的。根 CA 的公钥证书是整个 CA 域的证明,此证书将分发到网络中,我们只需要将自建根 CA 的证书加入到浏览器的信任仓库中,那么整个 CA 域中所有签发的证书都能被信任。
它的 issuer 和 subject 的名字是一样的。

中间层 CA
也叫 intermedia CA 或 subordinate CA, 即可以根据用途或者地理位置创建不同的子 CA,也可以根据规模划分更多层次的子 CA, 创建方式非常灵活。每一个子 CA 的证书都由上层 CA 的私钥签发,每一张子 CA 的证书都可以通过其上层 CA 的公钥进行验证,即每一张子 CA 证书都包含上层 CA 的名字(Issuer), 如些层层递进的信任关系,最终到达 root CA.

底层 CA
也叫 leaf CA, 位于架构中的最底层,负责具体的证书管理工作,这里是实体证书在整个生命周期中打交道的最多的地方。
本文中,由于我们只在根 CA 下创建了一层 CA,所以底层 CA 也是中间层 CA.
证书链 certificate chain
对于浏览器来说,它只拥有根 CA 的公钥证书,中间层 CA 的公钥证书并不会发布到网络中,那么浏览器是如何验证服务器的证书呢,答案就是证书链。
从顶层的根证书到最底层的实体证书,形成了一个不断向下签发证书的链路,这也就是证书链。
如下图,rootca 证书 –> subca01 证书 –> www 证书,就是一个完整的证书链。
通过证书链,中间层 CA 签发的证书能被浏览器正确地层层验证,所以在配置服务器证书时,一般都需要把整个链路上的所有 CA 证书都添加到服务器的证书中,形成一个新的服务器证书(全链证书)。
当 PC 访问 web 服务器时,服务器会将全链证书发送给用户的浏览器,浏览器通过证书链不断回溯, 最终找到根 CA, 然后通过存储在信任仓库中的根 CA 的公钥证书不断向下验证,直到服务器的证书:
- 浏览器查看证书链文件,从中找到该证书的签发者,即 subCA01.
 - 浏览器继续查看 subCA01 的证书,从中找到该证书的签发者,即 rootCA.
 - 浏览器检查信息仓库,rootCA 的证书存在,即该证书是可信的。
 - 浏览器使用根证书的公钥来验证 subCA01 的数字签名, 验证通过。
 - 浏览器使用 subCA01 的公钥来验证 Nginx 服务器数字签名,验证通过。
 - 全部验证通过后,浏览器即可信任 Nginx 的服务器证书。
 
OCSP Responder
Online Certificate Status Protocol,即在线证书检查协议,这是一个轻量级的在线验证证书的实现。
当一张证书被 CA 签发后,会生成一个唯一的序列号(serial number )和证书进行绑定,OCSP 服务允许客户端通过证书的序列号来查询这个证书的状态。
在多层 CA 架构中,由最底层的 CA 负责 OSCP 的响应,在我们的例子中,是由 subca01 负责响应 OSCP 的查询。
OCSP 的验证地址通常附加在证书内,默认就是 CA 的地址,任何支持 OCSP 功能的应用程序(浏览器)都可以通过这个地址对证书进行验证。

在 Dogtag 的环境中,当浏览器使用 Nginx 服务器证书的序列号和 OCSP responder 进行验证时,会生成一条查询日志:
证书的终结
在传闻中,时间是拥有剧毒的东西,没有任何东西可以抵挡时间的剧毒侵蚀。一张电子证书的生命同样也是有时间限制的,当证书的终止时间临近时,需要在 CA 内对证书进行干预:
* 更新证书,把证书的生命周期继续延长,证书对应的实体将继续被信任。
* 终止证书,证书对应的实体将不再被 CA 所信任。
当一张证书的生命终结后,在 CA 内将被标记为失效,OCSP 的查询将返回不可用的结果,证书对应的实体将被标记为不可信任。失效的证书是不可复用的,如果实体后续需要证书服务,只能使用私钥创建新的证书申请。
总结
公钥加密系统的核心作用是让通讯的双方在开放式的网络中可以清楚地看到彼此:
- 我拥有你的公钥,那么我就可以用它来加密数据,只有你的私钥可以解密这些数据,安全通道打开。
 - 我只能通过证书来获取你的公钥,你的证书是被第三方权威部门签发的,我信任它所以我也信任你。
 
本文完