握手消息 | 动作描述 | 消息内容 |
---|---|---|
1. Client —> ClientHello —> Server | 客户端(浏览器)发送一个hello消息给服务端,发起建立SSL会话的请求。并告诉服务端,自己支持哪些加密算法(Cipher Suite List)。除此之外,还需要产生一个随机数(第一个随机数,用于以后生成对称密钥),发送给服务端。 | 1)支持的协议版本,如TLS 1.0版<br/>2)由客户端生成的随机数,用于生成后面的“对称密钥”<br/>3)支持的加密方法,比如RSA公钥加密<br/>4)支持的压缩方法<br/>5)请求的域名<br/> |
2. Server —> ServerHello —> Client | 服务端的首次响应,会确定加密协议版本,以及加密的算法,也会生成一个随机数(第二个随机数)给客户端。 | 1)协议的版本<br/>2)加密的算法<br/>3)服务端生成的随机数<br/> |
3. Server —> Certificate —> Client | 还会把自己的证书发送给客户端,让客户端进行校验。服务端证书中的公钥也可被用于加密后面握手过程中生成的对称密钥。 | 1)服务端证书<br/> 证书颁发机构的名称<br/> 证书本身的数字签名<br/> 证书持有者公钥<br/> 证书签名用到的Hash算法<br/> |
4. Server --> ServerKeyExchange —> Client | 指定使用哪种密钥协商协议。服务端可以在ServerKeyExchange之后立即发送CertificateRequest消息,要求校验客户端的证书。 | 1)使用哪种密钥协商方式<br/>2)密钥协商时客户端需要的信息 |
5. Server —> ServerHelloDone —> Client | 服务器发送ServerHelloDone消息,告知客户端服务器这边握手相关的消息发送完毕。 | |
6. Client —> ClientKeyExchange —> Server | 消息中包含客户端这边的EC Diffie-Hellman算法相关参数,然后服务器和客户端都可根据接收到的对方参数和自身参数运算出对称密钥。 | 1)密钥协商时服务端需要的信息 |
7. Client —> ChangeCipherSpec —> Server | ChangeCipherSpec消息,通知服务器此消息以后客户端会以加密方式发送数据。 | 准备好了做加密传输的通知 |
8. Client —> Finished —> Server | 客户端计算生成对称密钥,然后使用该对称密钥加密之前所有收发握手消息的Hash值,发送给服务器,服务器将相同的会话密钥(使用相同方法生成)解密此消息,校验其中的Hash值。 | |
9. Server —> ChangeCipherSpec —> Client | ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据。 | 准备好了做加密传输的通知 |
10. Server — > Finished —> Client | 服务器使用对称密钥加密(生成方式与客户端相同)之前所发送的所有握手消息的hash值,发送给客户端去校验。 | |
11. Application Data | 真正的数据传输(使用对称加密) |
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
RSA
AEAD_AES_128_GCM
SHA256
ECDHE
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
公钥
和私钥
,公钥会做到证书里面,私钥则会给到网站方。网站方的信息
和网站方的公钥
、签名算法
等信息(就是Wireshark Packet 20中的数据,除了“签名值”),计算一个hash值(图中hash算法是SHA256),然后CA再用自己私钥做加密(图中公开密钥算法是RSA),最后的这个密文就是“数字签名”(也就是我们在图中看到“encrypted”签名值)。* 浏览器通常也会内置大多数主流权威CA的根证书。
* 如果查找不到对应的可信CA,则判断这个证书是伪造的,不可信的。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
CA机构证书
里面的公钥
信息,将网站方证书
中的签名值
(也就是数字签名)做解密,得到网站证书
信息的hash摘要A。网站证书
中的信息,做hash得到摘要B,比对摘要A和摘要B是否一致。如果不一致,说明网站证书
中的信息被修改了。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)公钥
,用于后面的握手签名。证书
公钥对签名值解密,获得摘要A。并将这次数据明文做SHA512的hash,获得摘要B,做比对。(这里对协商算法做签名校验,目的可能是防止中间人对协商算法方式做篡改,虽然DH算法不担心公钥在不安全的网络中传输,但是其他算法可能需要考虑被篡改的情况。所以猜测服务端密钥协商时做签名是这个目的,因为服务端这时已经确定是DH算法了,所以客户端协商时就不需要做签名了,DH算法不需要考虑这个安全问题)服务端密钥协商的公钥以及自己的公钥
EC Diffie-Hellman
密钥协商协议为例,来看看客户端、服务端是怎么协商出相同的密钥的(这里协商出来的是PreMasterSecret,不是最终的对称加密用到的密钥)。struct {
opaque verify_data[verify_data_length];
} Finished;
verify_data
PRF(master_secret, finished_label,Hash(handshake_messages))
[0..verify_data_length-1];
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
select (HandshakeType) {
case hello_request: HelloRequest; //HelloRequest是服务端在任何时候都可以发出的,告诉客户端需要重新进行握手协议,客户端随即发送新的ClientHello
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;//服务端或客户端发送自己证书给客户端。
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;//服务端请求,客户端发送自己的客户端证书,给服务端做校验。这个步骤在博文中没有提到,看以后有需要再了解。
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;//客户端发出,从client hello开始,一直到CertificateVerify之前的所有消息的hash加上客户端证书对应私钥的加密结果。
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
struct {
ProtocolVersion protocol_version; //协议版本
CipherSuite cipher_suite; //加密套件类型
CompressionMethod compression_method; //压缩方法
opaque master_secret[48]; //对称密钥
ClientIdentity client_identity; //客户端ID
uint32 timestamp;//ticket有效期
} StatePlaintext;