0%

TLS中ChangeCipherSpec为什么是个单独的协议类型

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中,另外,在ChangeCipherSpecFinished之间,也需要将连接状态从明文状态转换到加密状态,就需要停顿一下。

但是,并不一定每个实现都能很好的遵循”将Finished放入单独的record中发送”这个约定,这样就在协议设计的时候添加了这样的冗余,相当于使用ChangeCipherSpecClientKeyExchangeFinished强制分配到两个record中。

3. TLS1.3的ChangeCipherSpec

TLS1.3中并不需要该消息,因为协议本身保证了在状态转换前发送的消息都是确定的,比如握手消息在ClientHello, ServerHello之后都是加密的,应用消息在发送完Finished之后也都是加密的,而且TLS1.3的秘钥推导跟之前版本的也都不一样,不需要CCS这样的冗余设计。但为了兼容性,还是保留了一些。

4. 总结

ChangeCipherSpec是TLS1.2及之前的协议设计的冗余消息,目的是从协议上避免实现时的流水线停顿问题。

参考

  1. pipeling stall
  2. CCS pipeling stall
  3. OpenSSL再曝CCS注入漏洞