
HTTPS | Cross Signing
一般来说,我们现在搭建站点都要开启HTTPS协议。HTTPS中的S指的是Secure,安全的HTTP协议。
为了达到安全的目的,我们在HTTP上套了一根管子,叫TLS管道,是通过双方证书和密钥协商生成一个临时密钥,加密传输信息,形成可信信道。这个过程中需要TLS证书和密码,而证书需要可信机构签名,每年你都需要重新续签一次证书。问题就来了,可信机构本身也会过期,如果可信机构过期时间恰好在我们证书有效期中间,那该怎么办呢?这个证书废掉了吗?
TL;DR:
Cross Signing是一种通过签发一个过期时间更晚但是公私钥和以前一样的中间CA证书,让两个密钥一样的证书同时生效,以解决CA过期、过渡到新CA时,域名证书的有效性的问题
TLS怎么工作的
要讨论这个问题,我们要了解TLS是怎么工作的。
前提条件
今天讨论的只是浏览器访问网站时,所使用的TLS。服务器配置了TLS证书和对应的私钥。
发起请求:浏览器的ClientHello
当你开始访问一个HTTPS链接时,浏览器会通过TCP请求请求服务的TLS端口,默认是443。连接上去以后,浏览器会发送一个ClientHello信息,其中包含一个session id,包含客户端支持的密码学参数,比如说支持什么算法?使用什么参数?交换密钥用什么算法?用椭圆曲线的话用什么曲线?
有的时候还会带上额外的一些拓展,比如说我ecdsa可以用什么曲线啊,我希望访问哪个域名啊什么的。类似于打游戏告诉你的队友,我会什么,我擅长跟什么英雄打配合。
尤其是最后这个访问哪个域名,这个叫Server Name Indication,认识这个拓展(额外信息)的服务器,如果配置了正确的virtual host,virtual host配置了证书,就会返回对应的这个vhost的证书。
新的HTTP3使用了UDP,但是本质上也是建立了一根有状态的链接。
HTTP2中如果之前访问过这个域名的这个端口,可能会复用之前的连接,如果复用的话这一整套握手的过程都不会再次发生。
服务器回复
服务器看客户端很友善,看了一遍客户端写的信息,也回复了一句Hello。服务器端Hello都包含了什么信息呢?
服务器Hello首先要说明,我和你是一个通话频道上的,我们的session id一样。还说了我选择了什么版本和密码学参数,这里的版本和参数一般是服务器和客户端共同支持的部分中最高和最复杂的。
除此之外很重要的一个地方就是发送了服务器证书(有可能是证书链)和一个用来交换的密钥信息。
发送完这些信息以后,服务器会告诉客户端,我说完了,该你了。
最后客户端检查证书并且交换密钥
客户端看到服务器的信息以后,会检查(服务器证书或者证书链)+本地可信CA能不能推导出信任链,在本地CA这里检查CA给证书的签名是不是有效的,去CA服务器上检查证书链上有没有证书被吊销了。还可能会检查一些别的问题,比如说域名和证书能不能对的上。
检查过后客户端会把自己这侧生成的交换密钥发给服务器。
完成密钥交换,建立信道
最后服务器和客户端会根据一种交换密钥的方法,计算出一个只有服务器和客户端知道的共享密钥,由此建立一个可信的信道,之后的密文都会用这个共享密钥来加密解密。密钥在整个Session中都有效,而Session和密钥在一段时间后会过期,过期后会再交换一次密钥,生成共享密钥。
CA本身续签的问题
如果CA证书本身要续签,也就意味着除非你能很精确的在CA过期的那一刻在服务器上换上新的网站TLS证书,你的网站很有可能会在更换证书前遭遇到客户端无法验证证书链的情况。
客户端会在验证证书链的时候发现:
- 构建出了一条有根证书的信任链 Trust Path
- 那证书链有没有可信上级CA和根CA呢?有,但是过期了 于是无法建立连接。
有没有办法解决呢?有。
Cross Signing
刚才提到服务器可以配置也可以返回一个证书链,客户端只要能在本地验证证书链就可以。那么我们构建两条信任链,一条是老的,一条是新的。问题就解决啦。
这种方法就叫做Cross Signing。一般是CA机构完成。
一个CA机构会管理多个根证书,多个根证书签发中间证书,最后中间证书签发你的证书。当有CA过期时,CA机构给你的CA证书链一般会包含两个中间CA,两个中间CA会用一样的密钥,所以给你的证书签发的还是一个签名,只有一个你的证书。
配置到证书链以后,客户端会拿到你的一个证书和新老两个中间CA证书,验证证书链的时候就会
- 构建出两个证书链:
- 老的CA的证书链
- 在过期之前这个证书链都有效,总是通过验证
- 新CA的证书链
- 在过期之后这个证书链有效 于是解决问题。
- 老的CA的证书链
引出一个问题
这个问题是在老东家坚果云遇到的,用到的证书是Sectigo在2020年5月30号过期的,我们遇到一些系统或者一些实现对Cross Signing支持的不好的情况,大部分情况是系统比较老或者SSL实现比较老。当时正好在周末,出了问题以后电话被打爆的感觉很酸爽。
就有一些个人的猜测。当然我积累比较浅,大部分都是瞎猜。
证书链的顺序问题
以前我们总是不理解为什么证书一定要从自己的证书开始。一方面是规格一般是这么要求,另一方面现在我自己有这么个瞎猜的部分:很有可能老版本的SSL实现很可能就是从第一个证书开始逐个检查当前证书有没有通不过验证的,所以我们配置带有两个IntermediateCA证书的证书链后,这部分实现仍然会验证到老证书过期,于是建立信道失败。
所以老证书一定要放在前面
新系统大概率有新的SSL实现,新的CA证书放在后面大概率没问题。老系统大概率会依次验证,老证书放前面就会先完成验证,短路导致后面的证书无所谓。
至于新系统有老的SSL实现这种情况,比如说编译Electron用了超老的openssl版本,只能祈祷不会有这种情况了。