5.11. handshake — Finished

在 ChangeCipherSpec 音讯之后,应该立刻发送 Finished 音讯,来确认密钥替换和认证过程曾经胜利了。ChangeCipherSpec 必须在其它握手音讯和 Finished 音讯之间。

Finished 音讯是第一条用刚刚协商进去的参数爱护的音讯。接管方必须确认Finished音讯的内容是正确的。一旦某一方发送了,并且确认了对端发来的Finished音讯,就能够开始在连贯上发送和接管利用数据了。

音讯构造:

struct {    opaque verify_data[verify_data_length];} Finished;verify_data   PRF(master_secret, finished_label,Hash(handshake_messages))      [0..verify_data_length-1];finished_label   对客户端发的Finished音讯来说,固定是字符串 "client finished".     对服务器发的Finished音讯来说,固定是字符串 "server finished".1.2.3.4.5.6.7.8.9.10.11.

Hash示意握手音讯的hash。hash函数是前文 PRF 的hash 函数。或者 CipherSuite 规定的用于 Finished 计算的hash函数。

在TLS的之前版本中,verify_data 总是 12 字节。在TLS 1.2中,这取决于CipherSuite。如果CipherSuite没有显式规定 verify_data_length ,就当成12字节解决。未来的CipherSuite可能会规定别的长度,然而不能小于12字节。

Finished 音讯必须跟在 ChangeCipherSpec 音讯之后,如果程序错乱,就是 fatal error.

handshake_message 的内容蕴含从 ClientHello开始,直到 本条Finished之前的所有音讯,只蕴含handshake层的音讯体,不蕴含record层的几个音讯头字段。包含CertificateVerify 音讯。同时,对客户端和服务器来说,handshake_message 的内容不同, 后发送者必须蕴含前发送者的 Finished 音讯。

留神:ChangeCipherSpec 音讯,alert,和其它的record 类型不是握手音讯,不蕴含在 hash计算中。同时,HelloRequest 音讯也不算在内。

5.12. handshake — NewSessionTicket

SessionTicket 定义在 RFC5077 规范外面,2008年公布。

SessionTicket是一种不须要服务器端状态的,复原TLS session的形式。
SessionTicket能够用于任何CipherSuite。 TLS 1.0, TLS 1.1, TLS 1.2 都实用。

在上面这些场景下,尤其有用:

用户量微小,session id的形式消耗服务器内存过多
服务器心愿长时间缓存session
服务器有多台,不心愿服务器间有共享状态
服务器内存不足
客户端在 ClientHello中设置一个 SessionTicket 扩大来标识本人反对 SessionTicket。如果客户端本地没有存之前收到的ticket,就把这个扩大设为空。

如果服务器心愿应用 SessionTicket 机制,服务器把本地的 session 状态存入一个ticket中,ticket会被加密,并被MAC爱护,无奈篡改,加密和算MAC用的key只有服务器晓得。
加密并MAC过的ticket用 NewSessionTicket 音讯分发给客户端,NewSessionTicket 音讯应该在 ChangeCipherSpec 音讯之前,在服务器验证通过客户端的Finished音讯之后发送。

Client                                               ServerClientHello(empty SessionTicket extension)------->                                                ServerHello                            (empty SessionTicket extension)                                               Certificate*                                         ServerKeyExchange*                                        CertificateRequest*                             <--------      ServerHelloDoneCertificate*ClientKeyExchangeCertificateVerify*[ChangeCipherSpec]Finished                     -------->                                           NewSessionTicket                                         [ChangeCipherSpec]                             <--------             FinishedApplication Data             <------->     Application DataFigure 1: Message flow for full handshake issuing new session ticket1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.

客户端把收到的ticket和master secret等其它与以后session无关的参数一起,缓存起来。
单客户端心愿复原会话时,就把ticket蕴含在 ClientHello 的 SessionTicket 扩大中发给服务器。
服务器收到后,解密ticket,算MAC确认ticket没有被篡改过,而后从解密的内容外面,获取session 状态,用来复原会话。如果服务器胜利地验证了ticket,能够在 ServerHello 之后返回一个 NewSessionTicket 音讯来更新ticket。

显然,这种状况下,相比残缺握手,能够省掉1个RTT。如下图:

Client                                                ServerClientHello(SessionTicket extension)      -------->                                                 ServerHello                             (empty SessionTicket extension)                                            NewSessionTicket                                          [ChangeCipherSpec]                              <--------             Finished[ChangeCipherSpec]Finished                      -------->Application Data              <------->     Application Data  Figure 2: Message flow for abbreviated handshake using new                        session ticket1.2.3.4.5.6.7.8.9.10.11.12.13.

如果服务器不能,或者不想应用客户端发来的ticket,那服务器能够疏忽ticket,启动一个残缺的握手流程。

如果服务器此时不心愿下发新的ticket,那就能够不回复 SessionTicket 扩大,或者不回复 NewSessionTicket 音讯。
此时除了 ClientHello外面的 SessionTicket扩大,就和个别的TLS流程一样了。

如果服务器回绝收到的ticket,服务器可能依然心愿在残缺的握手之后,下发新的ticket。
此时流程和全新 ticket 生成下发的区别,就是ClientHello的SessionTicket不是空的。

NewSessionTicket 音讯
服务器在握手过程中,发ChangeCipherSpec之前发送NewSessionTicket音讯。
如果服务器在ServerHello中蕴含了一个SessionTicket扩大,那就必须发送NewSessionTicket音讯。
如果服务器没有蕴含SessionTicket扩大,那相对不能发送NewSessionTicket音讯。
如果服务器在蕴含了SessionTicket扩大之后,不想发送ticket,那能够发送一个长度为0的NewSessionTicket音讯。

在残缺握手的状况下,客户端必须在确认服务器的Finished音讯正确之后,能力认为NewSessionTicket 外面的ticket非法。

服务器能够NewSessionTicket音讯中更新 ticket。

ticket_lifetime_hint 字段蕴含一个服务器的提醒,提醒客户端本ticket应该存多长时间就生效。单位是秒,网络字节序。当工夫到期时,客户端应该删掉ticket和关联的状态。客户端也能够提前删除。服务器端也能够提前认为ticket生效。

struct {    uint32 ticket_lifetime_hint;    opaque ticket<0..2^16-1>;} NewSessionTicket;1.2.3.4.

SessionTicket 和 Session ID 之间的关系比拟繁琐。感兴趣的自行去看RFC吧。

对于客户端来说,ticket就是一块二进制buffer,客户端并不论外面的内容。所以ticket具体怎么加密加MAC服务器能够随心所欲,无需顾及客户端的感触。

RFC5077中举荐了一种ticket的加密爱护办法:
服务器应用2个key,一个 aes-128-cbc的key,一个 HMAC-SHA-256 的key。

ticket的格局像这样:

struct {    opaque key_name[16];    opaque iv[16];    opaque encrypted_state<0..2^16-1>;    opaque mac[32];} ticket;1.2.3.4.5.6.

其中,key_name 用来标识一组key,这样服务器端就能够应用多组key。

加密过程,首先随机生成IV,而后用 aes-128-cbc 加密 session 的序列化后果,
而后用 HMAC-SHA-256 对 key_name,IV,encrypted_data 的长度(2字节),encrypted_data 计算MAC。
最好把各个字段填入下面ticket构造体。
显然,此处是 Encrypt-then-MAC的形式,是最平安的。

理论在openssl 中的session,用asn1格局序列化保留了上面这些字段:

typedef struct ssl_session_asn1_st {    ASN1_INTEGER version;    ASN1_INTEGER ssl_version;    ASN1_OCTET_STRING cipher;    ASN1_OCTET_STRING master_key;    ASN1_OCTET_STRING session_id;    ASN1_OCTET_STRING session_id_context;    ASN1_INTEGER time;    ASN1_INTEGER timeout;    ASN1_INTEGER verify_result;    ASN1_OCTET_STRING tlsext_hostname;    ASN1_INTEGER tlsext_tick_lifetime;    ASN1_OCTET_STRING tlsext_tick;} SSL_SESSION_ASN1;1.2.3.4.5.6.7.8.9.10.11.12.13.14.

6. ChangeCipherSpec 协定

ChangeCipherSpec用来告诉对端,开始启用协商好的Connection State做对称加密,内容只有1个字节。
这个协定是冗余的,在TLS 1.3外面间接被删除了。

changeCipherSpec协定抓包:

7. Alert 协定

一种返回码机制,简略

  enum { warning(1), fatal(2), (255) } AlertLevel;  struct {      AlertLevel level;      AlertDescription description;  } Alert;1.2.3.4.5.6.

其中level是等级,不同等级要求不同的解决。

其中有一种:close_notify,用来告诉对端,我不会再发送更多数据了。这个能够让对端被动close fd,这样能够缩小我方tcp timewait状态的socket 量。

alert协定:

8. application data协定

application data协定,就是把利用数据间接输出record层,做分段,算MAC,加密,传输。
抓包举例如下:

本文转自微信后盾团队,如有进犯,请分割咱们立刻删除

OpenIMgithub开源地址:

https://github.com/OpenIMSDK/...

OpenIM官网 : https://www.rentsoft.cn

OpenIM官方论坛: https://forum.rentsoft.cn/

更多技术文章:

开源OpenIM:高性能、可伸缩、易扩大的即时通讯架构
https://forum.rentsoft.cn/thr...

【OpenIM原创】简略轻松入门 一文解说WebRTC实现1对1音视频通信原理
https://forum.rentsoft.cn/thr...

【OpenIM原创】开源OpenIM:轻量、高效、实时、牢靠、低成本的音讯模型
https://forum.rentsoft.cn/thr...