浅谈SSL和GPG

本文最后更新于:3 天前

去年的这个时候因为想用GPG签名git提交学习了一下GPG的工作原理,还写了一篇博客简单记录。今年又是这个时候偶然看到了CloudFlare Blog 的一篇2015年的文章How to build your own public key infrastructure在讲如何构建自己的自签名SSL证书用于加密后端服务内部的相互通信,文章讲的炒鸡简洁清晰,感觉一下子对之前一直迷迷糊糊的SSL证书签署过程有了比较清晰的理解,和GPG密钥两相对照之下也加深了对GPG的理解,所以写下此文简要记录一下。

GPG和SSL的区别

Public key cryptography provides many mechanisms for trust, including PGP’s “web of trust” and HTTPS’s public key infrastructure (PKI) model.

——CloudFlare Blog

这两个背后对应的是两种不同的信任机制模型,一句话来说GPG的背后PGP模型是”信任你信任的人所信任的人”,而HTTPS背后的PKI模型则是”信任权威机构信任的人”。

这两种方式都可以简单可靠的建立直接信任,所谓直接信任是指使用者因为知道一把密钥从哪里来而信任它是有效的。简单的例子比如你和我当面交换公钥,然后之后我们在网络上使用自己私钥对内容进行签名,那么我们互相都可以证明对方收到的信息真的是由自己发出的并且没有被篡改。再比如软件仓库的维护者将公钥发布在使用了HTTPS的网站上,当我们下载了软件后就可以通过验证签名确认软件没有被篡改。

但是我们在生活中往往遇到的都是需要向完全陌生人证明自己是自己这样的情况,在这种情况下两者各有优缺点:

PGP把信任机制的建立诉诸于社交网络式的结构而不是权威机构,带来的直观好处就是省下了权威机构认证的钱。坏处就是信任机制较弱,PGP可以帮助轻松的证明秘文没有被修改也可帮你完成信息的加密和解密,但是很难帮你向陌生人证明你(uid)就是你,虽然可以通过密钥被接收者也信任的人签名过来间接确认,但是信任机制的建立需要长时间慢慢积累来建立。

随着时间过去,你累积到许多人的密钥,其中有些人你也许愿意签署信赖他们,别人也会签署一些他们自己信赖的他人密钥。每个人都逐渐累积到一些他人已签署信赖的密钥,然后自己再签署并散发出去。那么便能期待,下一个拿到这把密钥的人在签署名单上总有一两个是自己信赖的。这最终能形成所有公钥的分布式防弊的信赖网络。

——PGP的发明者 菲利普·齐默曼

和PGP相反,PKI模型则是把信任的建立诉诸权威机构,通过权威机构逐级签署密钥的方式来建立信任,HTTPS正是采用这种方式。这样建立信任比较简单,只要将几个知名CA的证书在操作系统中就预先标记为受信任,那么由他们的私钥直接签署的证书或者由他们签署的中间级证书对应的私钥签署的证书都可以被标记为受到信任,这样的签署机制逐层传递下去就可以很轻松的使得证书的拥有者证明自己就是自己。但是正是因为信任的建立和身份的真实性的鉴别都依赖权威机构,所以证书的申请者需要为此付费,这也导致HTTPS最初推广进展缓慢,直到Let’s Encrypt 之类的免费证书签发机构的出现才改善了状况。

SSL证书是如何被签署的?

要想清楚了解SSL证书的签署过程,首先要先搞清楚过程中需要的几个文件:

  • 证书:所谓证书就是一个包含拥有者信息、公钥、CA签名的一个文件
  • 私钥:每个证书都对应一个私钥可以用来签名或者加密
  • CSR(certificate signing request):包含CA签名证书所需信息的文件,我们需要把这个提交给CA来签名我们的证书,主要包括几部分
    • 申请者的信息
    • 待签名证书的公钥
    • 用自己的私钥产生的签名

在得到CSR后CA就可以开始签署过程:

  1. 首先使用公钥验证CSR的签名,确保请求没有被篡改
  2. 按照审核规则检查申请者的信息,审核信息是否真实并判断是不是可以通过(典型的手段包括验证DNS记录和HTTP验证等方式)
  3. 使用CA自己的私钥创建并签名证书,并把证书发回申请者,整个过程结束

需要注意的是因为对于CA来说被预先内置在操作系统中分发的证书(根证书)极为重要,相应的私钥一旦丢失就意味着信任机制的完全破坏几乎无法恢复,所以在操作中并不使用”根证书”的私钥签署,而是先用其签署一份”中级证书”之后就离线保存起来,之后使用Intermediate 证书来进行签署,这样万一真的发生泄漏只要将中级证书吊销,根证书的信任仍然可以不受破坏。

此外对于Let’s Encrypt 这样的较新的颁发机构来说,为了确保自己的证书可以被更多的浏览器信任,会使用多个已被广受信任的根证书来进行交叉签名。关于这一点的详细的描述见 Let’s Encrypt: Chain of Trust

CA是如何建立的?

建立CA并不难,主要包括三步:

  1. 创建根证书
  2. 创建中间证书并使用根证书签名,完成后将根证书离线安全保存
  3. 按照一定规则审核申请并使用中间证书签发证书

但是要想让自己的证书广受信任就得把自己的根证书在操作系统中标记为信任,在不打扰用户的情况下这对我们来说是不可能完成的任务,所以使用自签发证书让用户的浏览器自动显示小绿锁是没有办法做到的。但是像文章开头说的那样建立自己的CA用于加密后端服务内部的相互通信是简单可行的,参照How to build your own public key infrastructure就可以了。

GnuPG使用备忘

-s, --sign                  生成一份签名
    --clear-sign            生成一份明文签名
-b, --detach-sign           生成一份分离的签名
-e, --encrypt               加密数据
-d, --decrypt               解密数据(默认)
    --verify                验证签名

其它使用见之前的文章浅谈GPG

工具网站:

  1. crt.sh 用来查询证书状态
  2. certbot 用来申请证书的客户端工具

参考资料:

  1. How to build your own public key infrastructure
  2. 信任网络,PGP,GPG

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!