上一篇TLS简介
本文中假定C需要验证S的身份。
上一篇中提到了C和S如何互相证明我是我
的问题,并且提到了非对称密钥算法。我们提到,在S与C的发起通信时,S要向C证明自己是自己,需要先给C一份公钥,并且C已经相信这是S的公钥
。C发送给S的凭证称为公钥证书
。
在内部网络中,C已经相信这是S的公钥
可以通过网络管理员预先将S的证书放置到C的基础信任集合里来保证。但实际上互联网公开网络中,比如普通用户通过浏览器使用https访问某家公司的网站时,证书会在通信过程中由服务端发送给客户端,此时客户端C如何判断这个证书是否可信呢?
如何信任一个未知的东西?人不可能凭空去信任一个不认识的人,通常需要有另一个已经熟知的人做介绍。计算机领域也一样。信任需要首先有一个基础的信任集合,然后这个集合可以告诉客户端哪些人可以信任。这个集合被称为信任根
。比如在通过浏览器访问https网站的过程中,系统中已经内置了包含了一些CA(Certificate authority)的证书,这些证书已经被假定为可信。CA是指颁发证书的机构,在这里不做过多介绍。
有了信任根之后就可以建立信任链。其基础想法是:如果客户端已经相信了A,A向客户端承诺B可信,那么客户端也就可以相信B。通过这种链条机制,客户端可以判断一个新的陌生的通信方是否可信。
A如何承诺B可信?A需要传达出的信息A信任B
,且客户端能验证这段信息确实由A传达。密码学通过签名
来实现这个目标。
通常意义上的签名
过程是人在一份文件上写上自己的名字,然后验证方看看签名的笔迹是否是本人亲笔书写。在密码学领域,签名
的概念与此类似,它表示用自己的私钥对一段内容的哈希码加密,用于承诺内容经过了自己的认证。客户端接受到内容和签名后,算出内容的哈希码,用公钥解密出签名对应的哈希码,比对两个哈希码是否相同,从而判断出签名的内容是否可信。
内容本身不需要加密。比如在上面的场景中,A信任B
本身就是一个需要公开的内容,需要验证的是A信任B这个内容确实是A承诺的。因此,签名算法只需要对内容生成的哈希码加密。
上文讲述了信任链
的基础思路,客户端信任A, A信任B,则客户端可以信任B。
如果这个时候B承诺信任C,客户端A是否可以信任C?
在链条式信任下,回答是肯定的。但在实际使用场景中,A承诺相信B既可能是A相信B和所有B相信的对象,或者A承诺相信B,但不一定相信其相信的对象。因此,信任链上存在终端节点,终端节点不能再继续延长信任链。
对应到证书上,需要对证书进行分类:根证书,中间证书,终端实体证书。 根证书和中间证书可以用来传递信任链,终端实体证书不能传递信任链。
根证书是内置在客户端的证书,是客户端的基础信任集合,证书验证的过程中,最终都会对应到对根证书的验证。
比如chrome浏览器有内置的证书管理,通过页面chrome://settings/certificates可以查看和管理证书。
证书支持撤销机制,如果所有的终端实体证书都直接由根证书来直接认证,那么任意一个实体变得不可信都需要直接更改根证书;因此,采用分而治之的策略:根证书签名中间证书,中间证书签名中间证书(多级管理),最终签名终端实体的方式来管理证书。
终端实体证书就是被证明可信任的实体,其中包含了实体的身份信息。终端实体证书不能用于签名其他证书。
因此,对于上面的问题,回答是:只有当B拥有的是中间证书的时候,他才能使客户端去信任其他实体。
通过上面的描述,我们知道
公钥证书
中主要的信息是:
- 公钥
- 公钥持有人信息
- ( 信任链的上端)对证书内容的签名。
TLS协议使用X509规范
定义的公钥证书的格式。
X509证书包含了以下内容:
1、X.509版本号。
2、证书持有人的公钥。
3、证书的序列号:由CA给予每一个证书分配的唯一的数字型编号。
4、主题信息:证书持有人唯一的标识符(或称DN-distinguished name)这个名字在 Internet上应该是唯一的。这个信息在申请证书时需要填写
5、证书的有效期:证书起始日期和时间以及终止日期和时间;指明证书在这两个时间内有效。
6、认证机构:证书发布者,是签发该证书的实体唯一的CA的X.509名字。使用该证书意味着信任签发证书的实体。(注意:在某些情况下,比如根或顶级CA证书,发布者自己签发证书)
7、发布者的数字签名:这是使用发布者私钥生成的签名,以确保这个证书在发放之后没有被撰改过。
8、签名算法标识符。
X509证书中使用扩展字段‵CA:false‵来禁止信任链继续传递。
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
openssl 生成证书
上文中讲述了证书的信任链机制和证书中应当包含的内容,本节中说明如何通过openssl来生成证书和查看证书。
所有的证书都起源是被预先置于客户端的根证书,根证书中包含的公钥可以直接验证其签名。我们通过openssl来生成一个根证书。
前文已经提到证书基于非对称密钥机制,因此首先需要生成一对非对称密钥:
$ openssl genrsa -out rsa_private.key 2048
genrsa
指非对称算法的类型,2048
表示密钥的长度。
尽管这里的名字是 rsa_private.key ,但实际上这个key里也包含可以推导出了公钥和用于加密流程的私钥信息,算法,位数等基本信息。
可以通过以下信息查看生成的密钥信息:
openssl rsa -in rsa_private.key -noout -text
从私钥信息中提取出公钥
$ openssl rsa -in rsa_private.key -pubout -out rsa_public.key
获得了公钥。
前文中已经提到,根证书是可以自验证的证书,因此,生成证书只需要输入所有者信息(在X509中用DN, Distinguished Name) 标志,并用私钥对其签名
$ openssl req -new -x509 -days 365 -key rsa_private.key -out cert.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CH
State or Province Name (full name) [Some-State]:test
Locality Name (eg, city) []:test
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []:test
Email Address []:[email protected]
-new 指生成证书请求,-x509 指定证书格式,-key 指定私钥文件,-days365 为有效期
自此,我们已经生成了私钥,公钥及根证书。