论坛首页 Java企业应用论坛

深入研究SSL【第二章 part-2】-SSL握手协议的研究

浏览 9256 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-02-26   最后修改:2011-01-06

第一章. 对SSL的基本概念和框架的介绍
第二章.对SSL握手协议的研究(part-1 )
第三章.对SSL握手协议的研究(part-2)
第四章.对SSL握手协议细节和实现的介绍
第五章.对SSL记录协议细节和实现的介绍
第六章.对SSL的安全性分析
第七章.举例一种将usbkey融入java JSSE框架的解决方案
 

· Client 处理和回应 Server Hello 阶段

客户端收到服务器发过来的那些消息,要做的是验证服务器证书,发送自己的证书(如果双向认证),发送计算出的预主密码,发送证书验证消息。

 

 

收到 Server Hello

server hello 阶段连续的发了多个消息,最先发出的是 server hello client 收到后将 SSL 会话 ID ,服务器端的一个随机数,协商出的 SSL 协议版本号以及密钥套件放到会话缓存中。

 

收到 Server Certificates

接下来收到的应该是 server 端的证书消息了,取出所有的消息,最头上的是 server 证书,最末端的 CA 根证书。在 SUN JDK JSSE 中实现的 SSL 是这样处理的:

SSLContex 中取出 trust manager ,如果用过 java SSL 编程的同学应该知道,可以自己实现 X509TrustManager X509KeyManager 两个接口来定制对证书的验证, sun jdk 中就是调用这个 trust manager 的验证方法来验证证书(在解决浏览器检测到证书是自签名的时候跳出警告框的问题就是可以自己实现这个 trust manager 来让浏览器不跳出警告框)。

 

JDK 当然也有默认的证书验证实现,就是验证签名有效性,验证证书是否过期等。证书签名的有效性验证是在取证书链中某证书中的公钥验证前一个证书的签名,这样第一个证书就是用第二个证书的公钥来验证,那有人可能会问最后的根 CA 的证书谁来验证?根 CA 的证书是自签名的,就是自己给自己签名,没人管的了, JDK 中某个文件中有存储一堆可信任的证书发行机构的证书列表,如果你的根 CA 在那个列表中并对比后确实是那个根 CA 的证书那就 OK ,验证通过,这个可信任的机构也可以自己实现那个 trust manager 来添加设置。

 

收到 Server Key Exchange 消息

RSA 方式密钥交换消息则把消息中的加密用公钥放入会话缓存中,作为客户端这边握手阶段的写密钥而不是用服务器证书中的公钥。

DH 方式的消息就把消息中的 p,g,Ys 三个参数记录下来,有这些 client 端就可以计算出 pre-master 了,只要回头再把自己这边的 Yc 参数发过去, server 端就也能计算出相同的 pre-maseter 了。

 

收到 server Certtificats Request 消息

将消息中的证书类型列表和可信任证书发行机构列表保存下来,可在后面发送客户端证书时候拿来筛选证书用。

 

收到 Server Hello Done 消息

收到这个消息后 client 端开始向 server 发消息了

 

发送 Client Certificates 消息

如果是 server 端要求客户端认证就会发这个消息,否则不发。客户端可能会有多个证书,在 JSSE 里头多个客户端证书存储在 keystore 里头,选哪个发过去呢?这时候要用到 server 端之前发的 cert request 消息中的支持的证书类型列表和信任的根 CA 列表,满足这个两个条件的第一个证书链就会被选中作为客户端证书。

 

发送 Client Key Exchange 消息

若是 RSA 方式密钥交换,则产生一个 48 位随机数作为 pre-master 并用服务器公钥加密后发出去

若是 DH 方式的密钥交换,则根据 sever g,p,Ys ,产生 Xa Yc Xa Ys 能计算出 pre-master ,把产生的 Yc 放入消息中发给 server ,这样 server 用它的 Xb Yc 也能计算出 pre-master 了。计算出预主密码后就顺便把主密码 (master secret) 给算出来了。算出主密码就把对称密钥产生出来了。

 

发送 Certificate verify 消息

这个消息是可选的,只有在客户端发送了自己证书到服务器端,这个消息才需要发送。发这个消息的目的是让服务器验证发消息的客户端和客户端证书的真实所有者。这个消息中要包含一个签名,签名里头内容就是从 client hello 开始到目前为止所有握手消息(不包括本消息)的摘要,主密码,若是 RSA 方式则要把这些内容分别用 MD5 SHA1 计算一遍,两种摘要算法算得的摘要拼接起来用客户端证书中公钥对应的私钥加密就获得了签名。到时候服务器端会用收到的证书中的公钥来验证签名。

 

发送 change cipher spec 消息

发送这个消息,然后把 session 的写密钥设置成计算得到得对称密钥,从此消息之后再发送消息就会用这个写密钥来加密消息。

 

发送 client Finished 消息

Client 端的 Finished 消息一般都是紧随 change cipher spec 消息发送出去,标志着本方的 SSL 协商成功结束。消息中包含两个个摘要,是分别用 MD5 SHA 算法计算当前收到所有握手消息和主密码的摘要,不包括本消息和 change cipher spec( 因为不属于握手消息 )

 

该消息是SSL握手中的最后要互传的消息,包含一个所有握手消息的摘要值,这是为了防止中间人将强度较大的CipherSuite在client hello消息中删除,使得server不得不选择强度较小的CipherSuite,然而这非client所愿。问题是这个摘要不可以被中间人更改吗?想象一下这时共享对称密钥已经协商好了,ChangeCipherSpec已经经过,所以这些消息本身是加过密的。

·        Server 处理和回应 cleint Finished 阶段

Server 收到 client 的证书链后验证证书,并验证 certificatie verify 中的签名,验证通过了也就确认了 client 的身份,如假包换。收到 client key exchange 消息从中拿出 Pre-master 计算出 master ,生成对称密钥。收到 client change cert spec 后将会话的读密钥设置为刚产生的对称密钥。


处理完这些 server 会发送自己的 change cipher spec 消息并把会话的写密钥设置为生成的对称密钥,最后发送 server Finished 消息, client 端收到 server 端的 change cipher spec 消息将会话的读密钥设置为生成的对称密钥。到此握手过程圆满结束,接下来的应用消息将使用设置好的读写密钥对数据加解密。

 

   发表时间:2011-01-30  
我觉得写的不错,为什么不接着出了?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics