RFC5246中说:
Note: To help avoid pipeline stalls, ChangeCipherSpec is an independent TLS Protocol content type, and is not actually a TLS handshake message.
为了避免pipeline stall,ChangeCipherSpec
是个单独的协议类型,不属于握手协议。这里什么是pipeline stall?
1. pipeline stall
通俗点的理解是,在CPU流水线设计中,有些指令必须在某些指令之后执行,中间需要停顿一下,等待前一个指令执行完,才能开始后一个指令;或者逻辑分支时,需要控制程序指令转移,导致流水线停顿。如果这样的stall过多,就会影响的性能。可以采取一些办法减少或避免停顿。
2. TLS1.2及之前的ChangeCipherSpec
为什么ChangeCipherSpec
需要是单独的类型呢?如果是握手协议类型,TLS协议规定相同协议类型的数据可以集中到一个record中发送,也就是说,一个record中可以同时存放ClientKeyExchange,ChangeCipherSpec,Finished
这三个消息,其中ClientKeyExchange,ChangeCipherSpec
这两个是不加密的,Finished
是需要加密的。但TLS的加密是以record为单位的,一个record只能加密或不加密,不能其中一部分数据加密,另一部分不加密。所以在实现的时候,必须将Finished
放入一个单独的record中,另外,在ChangeCipherSpec
和Finished
之间,也需要将连接状态从明文状态转换到加密状态,就需要停顿一下。
但是,并不一定每个实现都能很好的遵循”将Finished
放入单独的record中发送”这个约定,这样就在协议设计的时候添加了这样的冗余,相当于使用ChangeCipherSpec
将ClientKeyExchange
和Finished
强制分配到两个record中。
3. TLS1.3的ChangeCipherSpec
TLS1.3中并不需要该消息,因为协议本身保证了在状态转换前发送的消息都是确定的,比如握手消息在ClientHello, ServerHello
之后都是加密的,应用消息在发送完Finished
之后也都是加密的,而且TLS1.3的秘钥推导跟之前版本的也都不一样,不需要CCS这样的冗余设计。但为了兼容性,还是保留了一些。
4. 总结
ChangeCipherSpec
是TLS1.2及之前的协议设计的冗余消息,目的是从协议上避免实现时的流水线停顿问题。
参考