标题也正是本人一直想问的一个问题。时至今日,感觉也该对其做一个总结了。
最近查找了不少资料,发现不少资料都很不错,特列写如下:
- PKI/CA 技术的介绍
- 数字证书原理
- 数字证书
- 数字证书以及12306的证书问题
- Digital Certificates
- 数字证书及 CA 的扫盲介绍
- What are digital signatures?
- 扫盲 HTTPS 和 SSL/TLS 协议(1):背景知识、协议的需求、设计的难点
- 扫盲 HTTPS 和 SSL/TLS 协议(2):可靠密钥交换的原理
- An Introduction to Mutual SSL Authentication
- 使用wireshark观察SSL/TLS握手过程–双向认证/单向认证
另外,有几篇文章是写如何搭建自己的 CA 的,也很不错:
基本概念
关于基本概念,博文数字证书原理已经讲得没谁的了,太赞了,一定要看!
这里要特别提一下的是 PKI 的概念。对其解释采用博文 PKI/CA 技术的介绍中的说法:
- PKI 就是 Public Key Infrastructure 的缩写,翻译过来就是公开密钥基础设施。它是利用公开密钥技术所构建的,解决网络安全问题的,普遍适用的一种基础设施。美国政府的一个报告中把 PKI 定义为全面解决安全问题的基础结构,从而大大扩展了 PKI 的概念。而我们认为,
采用了公开密钥技术的基础设施就可以称为 PKI 。
公开密钥技术也就是利用非对称算法的技术。说 PKI 是基础设施,就意味着它对信息网络的重要。将 PKI 在网络信息空间的地位与电力基础设施在工业生活中的地位进行类比非常确切。电力系统,通过伸到用户的标准插座为用户提供能源。 PKI 通过延伸到用户本地的接口,为各种应用提供安全的服务,如认证、身份识别、数字签名、加密等。从概念上讲,如果离开使用 PKI 的应用系统, PKI 本身没有任何实际的用处,正如电力系统离开电器设备也没有用一样。有了 PKI ,安全应用程序的开发者不用再关心那些复杂的数学运算和模型,而直接按照标准使用一种插座(接口)。用户也不用关心如何进行对方的身份鉴别而可以直接使用标准的插座,正如在电力基础设施上使用电吹风一样。PKI 中最基本的元素就是数字证书。
所有安全的操作主要通过证书来实现。 PKI 的硬设备还包括签置这些证书的证书机构 (CA) ,登记和批准证书签置的登记机构 (RA) ,以及存储和发布这些证书的电子目录。 PKI 中还包括证书策略,证书路径以及证书的使用者。所有这些都是 PKI 的基本元素。许多这样的基本元素有机地结合在一起就构成了 PKI 。
为什么我们需要数字证书
注:假设本部分采用的密码算法和密钥都极难破解(没有百分之百的安全)。
我们先来看一下通信可采用的一些方案:
方案一:对称加密
在互联网上,我们可以直接采用对称加密的方法进行通信。只要我们采用的密码算法破解难度足够大,通信的安全就有保证。但问题就来了,我们如何分发对称加密密钥而保证不被他人嗅探?
这是一个难点。方案二:非对称加密
既然直接采用对称加密的方法存在密钥分发的难点,那采用非对称加密(如 RSA)呢?例如,我们利用服务器公开的公钥对我们要发送给它的消息进行加密,然后再将密文发送给它。因为只有服务器有私钥,所以只有服务器才能够正确解密密文。这样看起来好像是安全的。但是,如果服务器要给我们发消息呢?它用自己的私钥加密消息后再发送给我们,不过所有有公钥的人都可以解密该消息,这样就不安全了。所以直接利用非对称加密的方法进行通信是不行的。
方案三:对称与非对称加密相结合
但如果我们把上述两者相结合起来呢?例如,我们选择一个对称加密算法和生成一个密钥,利用服务器公布的公钥对它们进行加密后发送给服务器。因为只有服务器能解密,所以通信是安全的。服务器解密后得知对称加密算法和密钥,就可以愉快地跟我们进行通信了。这样看起来貌似可行。但我们怎么确定服务器公布的密钥就是真的呢?
这个缺陷所导致的攻击就是大名鼎鼎的中间人攻击(Man-In-The-Middle Attack, MITM),即有攻击者同时冒充服务器和用户,让用户和服务器都相信攻击者就是它们要通信的一方。方案四:对称与非对称加密相结合,同时利用数字证书保证公钥的可靠性
数字证书是由数字证书认证机构(Certificate Authority, CA)颁发的用于确保通信双方身份的证书。只要通过数字证书确认了双方的身份(确认了公钥的可靠性),那利用方案三的通信方案就是可靠的。这里的关键是认证机构。只有认证机构是可信的,那它颁发的数字证书才是可信的。
但,我们怎么相信认证机构就是可信的呢?这时候就需要根证书(Root Certificate)出场了。根证书是认证机构颁发给自己的数字证书,只要该证书是可信的,那该机构颁发的证书就都是可信的。这就是所谓的证书信任链
,即只要 A 信任 B,B 信任 C,而 A 是可信,那 B、C 就都是可信的,以此类推。因此,我们也可以看出,根证书是整个证书体系的根本。
一旦根证书不可信,那它信任的所有证书都是不可信的。
爱深究的你肯定又会想,我们怎么保证根证书是可信的?(认证机构还能够给自己颁发证书?)(感觉这是个无底洞啊…)这时候该操作系统出来终结这个无休无止的连环问题了。在我们安装好操作系统时,那些经过权威认证的根证书就已经被安装到操作系统中。终于可以松一口气了…
到这里,我们应该知道,网络通信的安全性非常依赖于认证机构所颁发的数字证书(包括根证书)。这也是我们为什么需要数字证书的原因。
注:这里我没有说网络通信安全完全依赖于数字证书主要是因为安全还依赖于其他原因,如密码算法、攻击手法。
消息摘要和数字签名
消息摘要(Message Digest)
主要用来保证消息的完整性。它利用 Hash 函数对一段消息(数据)进行运算,得到一个固定长度的值。所采用的 Hash 函数要具有单向性,即不能由 Hash 值推算得到原始消息。而且,对消息的改变都会导致最终求得的 Hash 值不同,所以可以用消息摘要来保证消息在传输过程中的完整性。
这里又存在一个问题,即如果攻击者知道消息的 Hash 值,那攻击者可以在修改完消息后,同时更新消息的 Hash 值,这样接受者就不会知道消息原来已经遭到攻击。所以,我们需要对消息的 Hash 值进行加密(非对称),也即数字签名(Digital Signature)
。要提醒一下的是,数字签名跟数字证书完全是两回事。
博文 What are digital signatures?画了一个非常形象的图来说明什么是消息摘要和数字签名:
上图中,签名者对原始数据进行 Hash 运算,得到一个 Hash 值,然后将该值用自己的私钥加密,和原始数据一起发送给另一方。另一方在收到数据后,对原始数据(用同样 Hash 算法)求 Hash 值,并利用签名者的公钥解密加密的 Hash 值,最终对这两个值进行比较,以确认原始数据是否被篡改。
消息摘要和数字签名除了可以用来保证消息的完整性,也可以用来保证数字证书的完整性。
数字证书
X.509
是被广泛使用的数字证书标准。摘录维基英文解释如下:
In cryptography, X.509 is an important standard for a public key infrastructure (PKI) to manage
digital certificates
andpublic-key encryption
and a key part of the Transport Layer Security protocol used to secure web and email communication. An ITU-T standard,X.509 specifies formats for public key certificates, certificate revocation lists, attribute certificates, and a certification path validation algorithm.
关于 X.509 的详细,官方 RFC 文档有特别详细的解释。
数字证书长啥样
数字证书格式
现在我们使用的证书标准主要是 X.509 的第 3 个版本。可见于下图:
图片来源
微软官方对其有一个较为简要的英文解释。但博文 OpenSSL 与 SSL 数字证书概念贴讲的更为详细(SSL 公钥证书格式):
1 | 1. 证书版本号(Version) |
还有样例(作者太好了!):
1 | Certificate: |
查看一个证书(如WoSign.pem)的内容可以如下命令:
1 | openssl x509 -in WoSign.pem -inform pem -noout -text |
看了这一大串,让我们来看看 Windows 中的证书。
Windows 中的数字证书
Windows 中的数字证书长这样:
其中跟本文相关较大的都用红色或绿色方框表示出来。公钥是经过数字证书认证过的可信的。不过这建立在数字证书是可信和完整
的基础上。数字证书的可靠性建立在认证机构的根证书上,这个我们在前文已经讨论过。但数字证书也是在网络上分发的,我们如何保证我们收到的证书是完整没有被修改过的?
这就涉及到证书的签名了。
认证机构在给个人或机构颁发证书的时候,会分成两步来对证书进行签名
:
- 利用指纹算法(实际就是哈希算法,上图中是 sha1)计算证书的 Hash 值,得到一个指纹
- 将该指纹用自己的私钥(注意是认证机构的)加密,得到一个数字签名
接收到证书后,我们分三步对该证书的完整性进行验证
:
- 由证书上的签名算法,得知签名所用算法(上图中是 RSA,去掉 sha256)
- 因为我们的电脑上都已经安装了认证机构的根证书,那我们就可以用该根证书所提供的公钥对证书签名进行解密,得到一个指纹
- 另外,我们利用证书提供的指纹算法计算该证书的 Hash 值(即指纹),将其与解密得到的指纹进行比较,就可以知道证书是否是完整的了
上述过程可用图表示如下:
图片来源
图中有几个地方有点疑惑
,有待后续解决:
- 签名哈希算法实际只是指用于计算消息摘要的哈希算法,不包括签名算法。感觉应该要跟指纹算法一样才对,但图片中显示的是不一样的。
- 签名算法的值前边加了哈希算法的名字(sha256),感觉没这个必要啊
数字证书在 SSL/TLS 中的应用
不了解证书跟 SSL(Secure Socket Layer) 之间的历史,应该说,SSL 就是建立在数字证书的基础之上的。TLS(Transport Layer Security)是 SSL 的升级版本,不过也常称为 SSL。
博文 An Introduction to Mutual SSL Authentication 对 SSL 的两种认证方式有一个比较简要清晰的阐述。特摘译如下:
翻译:导论
(省略部分)从高层次的角度来看,基于数字证书的 SSL 双向身份验证,身份验证和加密信道建立涉及到了以下步骤:
- 客户端向服务器请求受保护的资源
- 服务器向客户端发送它的数字证书
- 客户端验证服务器的证书
- 如果验证成功,客户端发送自己的证书给服务器
- 服务器验证客户端的证书
- 如果成功,服务器就允许客户端访问受保护的资源
翻译:背景
SSL 双向身份认证类似于 SSL 单向身份验证,比后者多了一步对客户端数字证书的验证。因此,SSL 单向身份验证和 SSL 双向身份验证也分别被非正式地称为单向 SSL 身份验证和双向 SSL 身份验证。作为一个开发者,如果你对开发或者能够调试 SSL 双向身份认证感兴趣,理解验证背后的的握手细节将会有很大帮助。
SSL 单向身份认证(服务器–>客户端)
在 SSL 单向身份验证中,客户端接受来自服务器的数字证书,然后将服务器 CA 与客户端信任的 CA 列表进行匹配。如果匹配成功,客户端会验证证书是否可信、是否被篡改过。在单向身份验证过程中,客户端和服务器采用 9 个握手消息,在开始消息交换前建立一个加密通道。
- 客户端向服务器发送一个 ClientHello 消息,提议可采用的 SSL 选项
- 服务器回应一个 ServerHello 消息,选择(即将采用的) SSL 选项
- 服务器发送一个 Certificate 消息,该消息包含了服务器的证书
- 服务器发送一个 ServerHelloDone 消息,结束服务器端发送
- 客户端发送一个包含会话密钥信息(用服务器公钥加密)的 ClientKeyExchange 消息
- 客户端发送一个 ChangeCipherSpec 消息,激活与服务器协商好的在接下来所有消息中即将采用的 SSL 选项
- 客户端发送一个 Finished 消息,以让服务器检查激活的 SSL 选项
- 服务器发送一个 ChangeCipherSpec 消息,激活协商好的在接下来所有消息中即将采用的 SSL 选项
- 服务器发送一个 Finished 消息,以让客户端检查激活的 SSL 选项
译注:这样的描述其实还是非常简单的,更详细可参考博文 SSL/TLS原理详解。
SSL 双向身份认证(服务器<–>客户端)
然而,在 SSL 双向身份验证中,客户端和服务器都需要通过数字证书来验证对方的真实性,以确保对方的身份是可信的。在双向身份验证过程中,客户端和服务器采用 12 个握手消息,在开始消息交换前建立一个加密通道。
- 客户端向服务器发送一个 ClientHello 消息,提议可采用的 SSL 选项
- 服务器回应一个 ServerHello 消息,选择(即将采用的) SSL 选项
- 服务器发送一个 Certificate 消息,该消息包含了服务器的证书
- 服务器发送一个 CertificateRequest 消息,请求客户端的证书,以进行双向验证
- 服务器发送一个 ServerHelloDone 消息,结束服务器端发送
- 客户端回应一个 Certificate 消息,包含了客户端证书
- 客户端发送一个包含会话密钥信息(用服务器公钥加密)的 ClientKeyExchange 消息
- 客户端发送一个 CertificateVerify 消息,向服务器证明它拥有已发送的证书
- 客户端发送一个 ChangeCipherSpec 消息,激活与服务器协商好的在接下来所有消息中即将采用的 SSL 选项
- 客户端发送一个 Finished 消息,以让服务器检查激活的 SSL 选项
- 服务器发送一个 ChangeCipherSpec 消息,激活协商好的在接下来所有消息中即将采用的 SSL 选项
- 服务器发送一个 Finished 消息,以让客户端检查激活的 SSL 选项