SSL与CA
背景
无论是在使用docker过程中还是在接触gRPC的过程中,
如果想自己实现,都需要接触到SSL的问题,
因此想从理论到实践总结一下.
SSL/TLS
作用
- 加密信息,使无法窃听
- 校验内容,使篡改可发现
- 配备身份证书,防止冒充
历史
94年 网景设计了Secure Sockets Layer 1.0
95年 2.0
96年 3.0并推出
99年 ISOC接管兵重命名为TLS 1.0
06年 TLS 1.1 (戏称SSL 3.1)
08年 TLS 1.2 (戏称SSL 3.2)
11年 TLS 1.2+ (戏称SSL 3.3)
基本思路
- 客户端索要,并验证服务端的证书,从中取出服务器的公钥
- 客户端与服务端用密钥对密谋一个session key
- 正常对话使用session key加密以保证速度
注:前两步是握手阶段,客户端对服务器的证书要做验证:
- 是否可信的机构颁发的
- 证书中的域名是否与服务端的域名相符
- 证书是否过期
握手阶段具体过程
C: 随机数1
+自身情况(TLS版本,加密算法,压缩算法)
S: 随机数2
+自己的证书
+加密方法
C: 随机数3(用服务器公钥加密过)
+同意加密方法
+之前发送过的信息(供校验)
S: 同意加密方法
+算好的session key
+之前发送过的信息(供校验)
注:session key的计算中,服务器其实不信任客户端产生随机数的能力,
于是多用几个随机数,通过多几个自由度的方式让数字真的随机(伪随机数可能会被猜到)
CA
全称Certificate Authorities,证书颁发机构.
用于给网站,个人,设备等颁发数字证书以证明其真实可信的在线身份.
如果只有一个CA,那么它万一泄露私钥,波及范围极大.因此出现分级.
最上层的CA,证明一些二级CA,
各个网站和二级CA打交道,如果二级CA发生了私钥泄露,顶层CA及时吊销,可以保证受影响的范围小些.
PKI
PKI(Public Key Infrastructure,公钥基础设施)
主要由三部分构成
- 证书
- 证书颁发机构
- 证书库
就像电力基础设施包括
- 电本身
- 议价,统计用电量的电力公司
- 发电厂,电力线路,用电设施
X.509
证书的格式标准.
- 证书应该包含什么内容
- 证书使用什么扩展名
- 证书能够使用的加密/解密算法名单
证书的签名与验证
服务器证书的内容
- 证书版本号(Version)
- 证书序列号(Serial Number),当CA计划吊销该证书时,将该序列号加入到黑名单CRL中即可)
- 签名使用的算法(Signature algorithm),包含hash算法和非对称加密时的算法
- 证书的颁发机构(Issuer),国家,省市,地区,通用名,邮箱…
- 证书的有效期(Validity),开始日期,失效日期
- 证书的所有者(Subject),证书颁发给谁,国家,省市,地区,通用名,邮箱…
- 服务器的公钥(Subject Public key),值以外还有算法.
- 扩展信息
- 证书签名值
- 指纹
CA的签名过程
- 准备明文内容P(Issuer, Valid from/to, … Subject)
- 将明文hash后得到内容H
- 使用CA自己的私钥,利用指纹算法,对H进行RSA加密得到签名S(也叫指纹)
- P与S组合成一个文件,即网站的数字证书
验证方式
- 浏览器中已经安装证书颁发机构XXXCA的证书
- 从网站example.org得到一个证书后,发现颁发机构是XXXCA
- XXXCA的证书里有CA的公钥,用CA的公钥解密签名S,得到H1
- 自行对明文内容hash一次,得到H2
- 两个对比发现相同,则
要么服务器证书没有篡改,信息可信
要么有人偷了CA的私钥,用私钥伪造了假的服务器证书.
信任链体系
服务器证书的内容,用二级CA证书中的公钥验证.
二级CA证书的内容,要么用一级CA证书中的公钥验证.
一级CA证书的内容,使用明文中的公钥,能够解密指纹.这就是自签名.
一级CA证书也称根证书.通常会被浏览器默认信任.这就是大厂的地位.
openssl的特殊
理论上非对称加密的两个密钥,一个包含(n,e),一个包含(n,d),哪一个都可以作为公钥.
不过openssl为了一些工程上的考量,有一些明显的不同
-
私钥是私钥,包含(n, e, d, p, q, exponent1/2, coefficient,其中exponent1/2, coefficient等是用于加速运算的数据
使用openssl rsa -in xxx.key -text -noout
大概可以看到xxx.key
文件中包含的部分内容.
对应关系如下1
2
3
4
5
6
7
8modulus - n
privateExponent - d
publicExponent - e
prime1 - p
prime2 - q
exponent1 - d mod (p-1)
exponent2 - d mod (q-1)
coefficient - (q^-1) mod p私钥和公钥的文本中也直接包含
BEGIN RSA PRIVATE KEY
,BEGIN PUBLIC KEY
等字样 -
看起来一次只生成了"私钥"文件
1
openssl genrsa -out ca.key 2048
-
公钥可以使用"私钥"计算得出
1
openssl rsa -in ca.key -pubout > ca.pub
-
但文件的命名方式上却没有给出合理的默认值.甚至公钥和私钥可以用同样的扩展名
-
鉴于公钥可以计算得出,许多命令直接在最终产物中包含计算出的公钥,见不到显式计算公钥的命令
TODO 证据?
颁发自签名证书的大致过程
CA端
-
生成一对密钥,私钥
ca.key
, 公钥也隐含在这个文件中.1
2
3
4openssl genrsa -out ca.key 2048
genrsa 生成rsa密钥
-out 用于指定生成文件名
2048 算法允许的被加密内容的最大长度 -
自己使用快捷方式一步到位,申请得出同时直接签发csr证书文件
1
2
3
4
5
6openssl req -new -x509 -key ca.key -days 3650 -out ca.crt
req 生成签名请求
-new 新的请求
-x509 直接输出一个X509格式的证书
-days 证书的有效时间
-key 签名用的私钥 -
查看自签名证书的解析后数据
1
2openssl x509 -in ca.crt -noout -text
x509 证书操作,这里用来查看
服务器端
-
服务端S生成一对密钥,明面上认为只有私钥文件
example.org.key
1
openssl genrsa -out example.org.key 2048
-
服务器端S填写申请信息并最终生成申请文件
example.org.csr
1
2
3
4
5
6key中包含的自己的公钥信息,因此用key文件来制作申请文件
openssl req -new -key example.org.key -days 3650 -out example.org.csr
注意common name一定要和自己的网站名写得相同
查看一下申请时用的文件
openssl req -in example.org.csr -noout -text -
将文件提交给CA
-
CA机构B,使用自己的私钥
ca.key
来对a.pub
施加数字签名并生成一个证书a.crt
-
客户端C,使用CA公开的证书
ca.crt
里的公钥(明文),验证服务端的证书a.crt
. -
验证成功,则C信任
a.crt
中的公钥,并用该公钥加密消息以和S握手通信
再次CA端
-
使用自己的
ca.key
文件,对提交来的example.org.csr
文件中的内容进行签名.-
提取信息
-
使用自己的
ca.crt
帮助填写一部分信息 -
hash
-
签名该hash
1
2
3
4
5
6
7openssl x509 -req -in example.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out example.org.x1.crt
-req 表明输入文件是csr文件
-in 输入文件是xxx
-CA 用于指定签发该csr请求时所用的CA证书,或许是用来填写服务器证书中CA的国家地区等信息
-CAkey 用于签发请求时数组签名的CA私钥
-CAcreateserial 如果序列号文件不存在,则创建它.
CA本身需要一系列文件夹和文件结果,专门用于保存一些已经发行过的服务器证书的序列号.
注意
-
Common Name
一定要与自己的域名完全相同,不要带通配符 -
openssl命令查看证书时通常
Common Name
简写作CN
-
firefox只检查
Common Name
, 但Chromium/Chrome会额外验证Subject Alternative Name
.
此时需要借助配置文件来签名.1
openssl x509 -req -in example.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out example.org.crt -extfile example.extensions.cnf
其中配置文件
1
2
3
4
5
6
7basicConstraints=CA:FALSE
subjectAltName=@my_subject_alt_names
subjectKeyIdentifier = hash
[ my_subject_alt_names ]
DNS.1 = *.example.org
DNS.2 = example.org
-
-
查看和验证是否成功
1
2
3
4
5
6正常查看一下
openssl x509 -in example.org.x1.crt -noout -text
验证是否成功
openssl verify -CAfile ca.crt example.org.x1.crt
verify 验证动作
nginx配置
1 | http { |
- 如果在server下配置ssl,则有可能在nginx语法检查时报错说还没有配置ssl,需要提前到http中
- example.org.bundle.crt靠
cat example.org.crt ca.crt > example.org.bundle.crt
形成
在浏览器中表现则是,有bundle则证书有2个tab页可以查看(一个网站的,一个CA的),无bundle则只有1个tab(网站的)
浏览器添加证书
需要添加的是CA的证书 ca.crt
firfox
firefox有自己独有的数据库来保存所有可信任的CA证书.
设置->隐私与安全->查看证书->证书颁发机构->导入证书
chromium
在linux系统上,chromium和其他自带软件(比如用来校验发邮件的人)依靠的是名为 nssdb
的数据库.
该数据库由系统拥有,可以使用CLI来交互
1 | 查看目前系统中的证书列表 |
当然,chromium等也可以使用GUI配置
设置->隐私设置和安全性->安全->管理证书->授权机构->导入
访问
- 访问需要完整的URL,比如
https://example.org//
- 如果还没有host可以在
/etc/hosts
中添加,也可以- 在
/etc/resolv.conf
中设置DNS服务器地址,包含路由器 - 更改路由器的
/etc/hosts
文件 - 使用
killall dnsmasq; dnsmasq
的方法重启DNS服务 - 使用
dig <hostname>
的方式验证DNS是否起效
- 在