目录
TLS相关知识
加密技术
TLS依赖两种加密技术
-
对称加密(symmetric encryption)
-
非对称加密(asymmetric encryption)
对称加密
对称加密的一方用秘钥 K 给文本 M 加密;另一方用同一个秘钥K对密文C进行解密:
C = E(M, K)
M = D(C, K)
痛点: 很有可能有人窃听到密钥 K,窃听者就可以假扮双方中的任何一 方与另一方通信。这叫中间人攻击。
非对称加密
非对称加密利用成对的两个秘钥:K1 和 K2。
其中一个加密文本,另一个解密文本:
C = E(M, K1)
M = D(C, K2)
双方中的一方可以生成 K1和K2,然后把其中一个秘钥 (比如K1)私藏,称为私钥 ;另一个(比如K2)公开,称为公钥。
另一 方得到公钥之后,双方就可以通信。
痛点:中间人还是可能截获公钥 K2,然后自己弄一对秘钥(K1', K2')。这样中间人每次可以用截获的 K2 解密发送文本得到明文(甚至可能修改文本),再用 K1' 加密了发出去;接收方用 K2' 解密接收得到的是被中间人篡改后的文档。
//OpenSSL的genrsa命令生成一个2048 bit的公钥私钥对,输出到文件server.key里:
openssl genrsa -out server.key 2048
//server.key是PEM格式的:
数字签名和CA
为了确定得到的公钥不是中间人伪造的 K2',*数字签名(digital signature)*技术应运而生。
数字签名的做法是:
-
发送方把自己的公钥和ID(身份证号码,或者域名)合为身份证申请(certificate signing request,CSR),
-
把CSR发给权威机构CA(被称为 certificate authority,CA),
-
CA用自己的私钥加密 CSR,得到的密文被称为数字签名(digital signature),
-
CA把 数据签名 和 CSR 的明文合在一起称为 CA签署的身份证(CA signed certificate,CRT),发给发送方,
发送方:CSR = 公钥 + 域名
signature = E(CSR, CA的私钥)
CRT = CSR + signature
//以下OpenSSL的req命令, 以上文中的 server.key 为输 入,生成一个身份证申请(CSR)文件 server.csr
openssl req -nodes -new -key server.key -subj "/CN=localhost" -out server.csr
//这个 CSR 里的公钥是从 server.key 里提取出来的,域名是 localhost。
//以下OpenSSL的x509命令用指定的私钥 server.key 签署 server.csr,输出身份证 server.crt:
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
//server.crt也是PEM格式的
当接收方和发送发通信时(建立HTTPS连接),发送发出示CA签署的身份证。 接收方是在自己机器上安装了CA的身份证的,
-
从CA的身份证中的CSR里提取出CA的公钥;
-
然后用CA的公钥解密发送方身份证中的signature,得到发送方的CSR';
-
如果这个CSR'和发送方身份证中的CSR明文一致,则说明发送方是CA权威认证的。
接收方:CA的公钥 = CA的CRT.CSR.CA的公钥
CSR' = D(CRT.signature, CA的公钥)
if CSR' == CRT.CSR then OK
信任链
CA如果担心没有人信任自己是个好 CA,可以找一个大家都信的 CA',用CA'的私钥在CA的身份证上签名:
CA:CSR = CA的公钥+CA域名
signature = E(CSR, CA'的私钥)
CRT = CSR + signature
如果浏览器或者操作系统里安装了CA'的公钥则可以验证"CA的身份证是CA'确认并且签名过的。
这样,CA在签署发送方的身份证的时候,可以在发送方身份证后面附上自己的身份 证。
当接收方和发送方通信的时候:
- 接收方会先要求发送方出示自己的身份证;
- 接收方虽然不信任CA,但是信任CA',所以接收方可以用CA'的身份证里的CA'的公钥来验证CA的身份证,于是就可以信任CA了;
- 然后接收方用CA身份证里的公钥验证发送方的身份证。
从而形成了一条信任链(trust of chain)chain。
根身份证和自签名
信任链总会有个顶端,被称为根身份证(root CA) 。那么根身份证是谁签名 的呢?答案是:自己签名。实际上,我们每个人都可以自己签名认证自己的身份 证,得到自签名的身份证(self-signed certificate)。具体过程是:
- 生成一对秘钥:公钥 K2 和私钥 K1,
- 创建自己的 CSR,
- 用自己的秘钥加密CSR得到signature,然后把CSR明文和signature一起发布。
任何人只要信任我们自签名的身份证 CRT,也就可以用 CRT.CSR.K2 作为公钥加 密要传递给我们的文本。我们可以用自己的私钥 K1 来解密文本。
双方TLS认证
上述解释了通信的一方如何验证另一方的身份。这种情况的一个常见应用是: 我们通过浏览器访问银行的网页。这里的关键是,我们要能验证银行的身份证, 然后才敢于在网页里输入账号和密码。浏览器验证银行的身份证的过程如下:
- 在浏览器和银行的HTTPS服务建立安全连接的过程中,银行的HTTPS服务会把 它的身份证发给浏览器showcerts;
- 浏览器使用内置的CA的身份证来验证银行的身份证。
浏览器验证了银行的HTTPS服务的身份之后,就轮到银行验证浏览器的用户的身份了:
- 浏览器展示银行HTTPS服务发来的登陆页面;
- 用户在这个页面里输入账号和密码,银行的HTTPS服务由此验证用户的身份。
在这个过程中,银行HTTPS服务器的身份是通过TLS身份证来验证的。而我们(用 户)的身份是通过我们输入的账号和密码来验证的。
有时通信的双方都是程序(而不是人)。此时,让一方输入账号和密码,不如让 双方都通过TLS身份证来互相验证方便。尤其是在很多分布式系统里,有多种类 型的程序互相通信,而不只是两方通信。
比如在 Kubernetes 机群里,不光操作机群的客户端程序 kubectl 要能验证 Kubernetes master node(具体的说是 apiserver)的身份,才能放心地把包括 敏感信息(比如数据库密码)的计算作业提交给 apiserver。类似的, apiserver也要能验证 kubectl 的身份,以确认提交作业的是公司的合法雇员, 而不是外贼sign。
为此,通信各方都需要有各自的身份证。一个公司可以自签名一个CA身份证,并 且用它来给每个雇员以及每个程序签署身份证。这样,只要每台电脑上都预先安 装好公司自己的CA身份证,就可以用这个身份证验证每个雇员和程序的身份了。 这是目前很多公司的常用做法。
加密和解密的性能
因为TLS模式下所有传输的数据都是加密的,大家会关注加密和解密的性能。客观的说,非对称加密技术的加密和解密比较慢,相对来说,对称加密技术的加密 解密过程更快。所以实际的连接和握手过程中,通信双方会协商一个对称加密秘钥,之后的数据通信过程中的加密都是利用对称加密技术来实现的。
具体的做法是:握手的时候,双方各自生成一个随机数,并且以非对称加密的方式 分享给对方。然后每一方都把自己的随机数和对方的随机数拼起来,就是接下来 通信时候使用的对称加密方法的秘钥了。