什么是SSL握手协议
SSL握手协议指在SSL协议中,客户端和服务器首先通过握手过程来获得密钥,此后在记录集协议中使用这个密钥来加密客户端和服务器间的通信信息。握手过程首先采用非对称加密的方法来交换信息,使得服务器获得客户端提供的对称加密的密钥(pre_master_secret),然后服务器和客户端使用这个pre_master_secret来产生会话密钥。
SSL握手协议的阶段
Handshake由一些客户与服务器交换的消息所构成,每一个消息都含有以下三个字段。
(1)类型(Type),1个字节:表示消息的类型,总共有十种。
(2)长度(Length),3个字节:消息的位组长度。
(3)内容(Content),大于或等于1个字节,与此消息有关的参数。
下图说明客户端与服务器要产生一条新连接时,所要进行的初始交换过程。这个交换过程可以视为四个阶段,即建立安全能力、服务器认证与密钥交换、客户端认证与密钥交换、完成。
1.建立安全能力
这个阶段的主要工作是要建立一条逻辑连接,以及与这个连接有关的安全功能。整个交换过程由客户端送出一个client_hello消息来开启,这个消息含有下面几个参数。
(1)Version(版本):客户端能够用的SSL最高版本。
(2)Random(随机值):一个由客户端产生的随机结构,包含一个32位长的时间戳,以及一个由随机数产生器所产生的28字节长的数字。
(3)Session ID(会话标识符):不定长度的session识别码。如果Session ID字段填上任何非零的数值,就表示客户端想继续使用上一个SSL连接,并且更新此连接的参数,或者在目前的session产生一个新的连接。如果此字段的值为零,则表示客户端希望重新建立一个新的session,并且产生一个新的连接。
(4)CipherSuit(密码套件):客户端能够支持的加密算法列表,这个列表会根据使用优先级由大到小排列。在这列表上的每一个密码套件都会定义其使用的密钥交换算法以及加密算法。
(5)Compression Methods(压缩算法):客户端能够支持的压缩算法列表。
当客户端送出client_hello消息后,会等待服务器响应一个server_hello消息。这个消息所包含的参数与client_hello消息夹带的参数相同。对于server_hello消息来说,每个字段用法如下。
(1)Version:服务器允许客户端使用的SSL版本。这个版本为客户端以及服务器双方都能支持的最高版本。
(2)Random:由服务器所产生的随机结构。与客户端所产生的随机结构类似,但彼此独立。
(3)Session ID:假如客户端传送过来的Session ID字段为非零的数值,那么服务器会将这个字段的值设定成客户端所指定的Session ID。否则服务器将会提供客户端新的会话,并为此字段填上代表这个新会话的标识符。
(4)CipherSuit:服务器从客户端所提供的密码套件列表中挑出的加密算法组合。
(5)Compression Method:服务器从客户端所提供的压缩方法列表中挑出的方法。密码套件参数所包含的第一个元素为密钥交换的算法(传统加密以及计算消息认证码时所会用到的密钥的交换方式)。有以下几种提供的密钥交换算法。
(1)RSA:由接收端的公开密钥来将密钥加密起来。为了事先得知接收端的公开密钥,其公开密钥的证书必须要能让发送端取得。
(2)Fixed Diffie-Hellman:Diffie-Hellman密钥交换法。服务器的证书中会包含经认证机构签署过的Diffie-Hellman公开密钥参数。假如需要对客户端做认证,则客户端会将Diffie-Hellman公开密钥参数包含在证书内,否则客户端会将这些参数放在密钥交换的消息中。由这个方法,使用固定的公开密钥经过Diffie-Hellman算法计算后,双方会建立起一个固定的密钥。
(3)Ephemeral Diffie-Hellman:这个方法是用来产生短暂的(Ephemeral)密钥。Diffie-Hellman公开密钥会利用传送者私人RSA密钥或者是DSS密钥来做签署,并且互相交换。而接收者随后便能使用对应的公开密钥来核对这个签名。除此之外,接收者也能利用证书来确认公开密钥的真实性,这将会是Diffie_Hellman三种选择方式中最安全的一种,因为它所产生的是一把短暂并且经过验证的密钥。
(4)Anonymous Diffie-Hellman:基本上使用Diffie-Hellman算法,但是不经过认证。也就是说,双方都会将自己的Diffie-Hellman公开参数在没有经过认证的程序下,直接传送给对方。这个方式很有可能受到中间人攻击(man-in-the-middle attack),攻击者可以向双方发起匿名的Diffie-Hellman交换攻击。
(5)Fortezza:在Fortezza架构中所定义的方法。
CipherSpec参数包含以下这些字段。
(1)CipherAlgorithm:加密算法。如RC4,RC2,DES,3DES,DES40,IDEA,Fortezza。
(2)MACAlgorithm:消息认证算法。MD5或是SHA-l。
(3)CipherType:加密类型。串流式或区块式。
(4)IsExportable:真或伪。
(5)HashSize:Hash值长度。16字节(使用MD5时)或20字节(使用SHA-1时)。
(6)KeyMaterial:用来产生写入密钥的数据。
(7)IVsize:CBC加密模式中,初始向量的长度。
2.服务器认证与密钥交换
当服务器送出server_hello消息后,或客户端需要验证服务器的身份时,服务器可以将其证书资料传送给客户端,它可能是单一(同一领域)或者是一连串的(跨领域)X.509证书。除了使用匿名Diffie-Hellman密钥交换算法,任何一种密钥交换程序都需要一个证书消息(Certificate Message)。请注意,假如使用fixed Diffie-Hellman法,则这个证书消息的功能就如同服务器的密钥交换消息,因为此消息包含了服务器的Diffie-Hellman公开参数值。
接着,假如有需要的话,服务器会送出server_key_exchange消息。在下面的两种情况下,服务器不需要送出这个消息:服务器已经送出包含fixed Diffie-Hellman参数的证书;使用RSA密钥交换算法。
3.客户端认证与密钥交换
当客户端收到服务器送出的server_done消息后,首先,假如有需要的话,客户端应该核对服务器提供的证书是否正确,接着再确认server_done消息中所携带的参数是否能够接受。如果这些都能满足的话,则客户端会响应一个或多个消息给服务器。如果之前服务器发出certificate_request消息,要求客户端送出自己的证书,那么客户端就得先响应一个certificate消息给服务器。如果客户端没有适当的证书可以提供,则会改送一个no_certificate消息给服务器。
接着,下一个交换的消息是client_key_exchange消息。在第三阶段中,一定要送出这个消息,至于其内容则要看客户端所选定的公开密钥算法类型而定,如:
(1)RSA:客户端先产生一个48B长的pre-mastersecret。然后,若服务器提供其他的证书,则利用此证书内的公开密钥将此密钥加密,不然就用server_key_exchange消息中携带的暂时性RSA密钥来加密。这个“预先的”密钥能够用来产生master secret。
(2)Ephemeral或Anonymous Diffie-Hellman:若使用这两种算法,则客户端传送自己的公开Diffie-Hellman参数。
(3)Fixed Diffie-Hellman:若使用这种算法,则之前客户端在传送证书消息时,就已经包含了自己的公开Diffie-Hellman参数。所以client_key_exchange消息这时内容就会是空的。
(4)Fortezza:客户端传送自己的Fortezza参数。若之前客户端需要传送自己的证书,则在这个阶段的最后,它也会连带送出一个certificate—verify消息给服务器,以便提供此证书的明确证明,而这个证明就是一个根据之前消息所计算出的Hash值。这个消息只有客户端证书拥有签名能力时(除了那些包含fixed Diffie-Hellman参数的证书以外的所有证书),才会跟着送出。因此消息会对此Hash值做签名,定义如下:
CertificateVerify.signature.md5_hash
MD5(master_secret||pad_2||MD5(handshake_messages || master-secret||pad_1));
Certificate.signature.sha+_hash
SHA(master_secret||pad_2||SHA(handshake_messages||master-secret||pad_1));
其中,pad_l与pad_2就是之前为MAC所定义的值。从client_hello消息开始后,所有通过Handshake协议所传送或接收的消息都属于handshake_messages。master_secret是一个经过计算的密钥。假如使用者的数字签名是DSS,则这个密钥将会被用来加密SHA-1 Hash值串接后的结果。不管哪一种情形,其目的都是希望利用客户端的证书来核对客户端是否拥有正确的私钥。就算有人滥用客户端的证书,因为他没有正确的客户端私钥,所以也没有办法送出这个certificate_verify消息。
4.完成
这个阶段完成了建立一条安全连接所应该做的设定工作。客户端会送出个change_cipher_spec消息,并且将目前的密码套件状态更新成即将要使用的密码套件状态。请注意,这个消息并不属于Handshake协议的一部分,而是利用加密算法修正协议所送出的消息。紧接着,客户端利用之前与服务器协议而得到的算法、密钥,来传送最后的finished消息。这个消息用来证明密钥交换以及认证的过程已经顺利完成,其内容包含两个Hash值:
MB5(master_secret||pad_2||MD5(handshake_messages||Sender||master-secret||pad1));
SHA(master_secret||pad_2||SHA(handshake_messages||Sender||master-secret||pad_1));
其中,Sender是一个代码,用来表示此消息为客户端所发出。除了这个finished消息以外,handshake_messages包含所有经由handshake消息所传送的数据。
为了响应这两个消息,服务器会传送自己的change_cipher_spec消息,并且将目前的密码套件状态更新为即将要使用密码套件状态,最后再送出finished消息。当这些handshake的步骤都完成后,客户端与服务器就能开始传送应用层的数据了。