EMZETT.
Login

Change Cipher Spec Protocol

In short: A short TLS sub-protocol that signals: “From now on, we continue encrypted with the keys just negotiated.”

In more detail: The change cipher spec message consists of just a single byte and marks the transition from the unencrypted handshake to encrypted communication. Both client and server each send this message once, as soon as they’re ready to encrypt with the newly negotiated session key. In TLS 1.3 this step was removed for the sake of simplicity (it only remains for compatibility reasons).

In Depth

In TLS 1.2 (where change cipher spec is still actively used), the sequence looks like this in simplified form:

Client                                          Server
  |-- ClientHello ------------------------------>|
  |<------------------------------ ServerHello --|
  |<----------------------- certificate, key exchange --|
  |-- key exchange data ------------------------>|
  |-- [Change Cipher Spec] ---------------------->|   from here: client encrypts
  |-- Finished (encrypted) ---------------------->|
  |<--------------------------- [Change Cipher Spec] --|  from here: server encrypts
  |<---------------------------- Finished (encrypted) --|

Important: change cipher spec isn’t part of the actual handshake protocol, but a separate, third TLS sub-protocol (alongside handshake and application data) — it simply tells the record layer: “the next record I send already uses the newly negotiated encryption.” Because client and server make this switch independently of each other (each as soon as it’s ready itself), it can briefly be asymmetric: one side is already encrypting while the other is still sending in plain text.

In TLS 1.3, this explicit signalling step was removed completely — there, the switch to encryption is implicitly fixed by the position in the handshake, which simplifies the protocol and eliminates a potential source of errors. The (empty) change cipher spec message only still exists in TLS 1.3 for compatibility reasons, so that middleboxes (e.g. older firewalls) that “wait” for this byte pattern aren’t confused — TLS 1.3 implementations simply send an empty, functionless change cipher spec byte along without it having any effect, purely so that network middleboxes still recognise the traffic as “normal TLS”.

Why this step was simplified at all

The historical reason for its removal in TLS 1.3 lies in a series of real security problems with the old, explicit signalling: in 2014 the so-called “change cipher spec injection” vulnerability became known (CVE-2014-0224 in OpenSSL), in which an attacker, by cleverly injecting a premature change cipher spec message, could get vulnerable clients to encrypt with a predictable, weak key — practically a downgrade to an easily decrypted connection, even though the connection looked like normal TLS from the outside. Incidents like this strengthened the TLS 1.3 designers’ resolve to simplify the protocol drastically overall and to drop explicit, separately processed signalling steps such as change cipher spec completely.

Relationship to the other handshake messages

Within the TLS 1.2 handshake, change cipher spec marks the only moment at which the encryption state changes IN THE MIDDLE of the protocol sequence — all messages before it (ClientHello, ServerHello, certificate exchange) run unencrypted, all after it (the respective Finished message) already encrypted. The handshake protocol itself contains the actual negotiation logic (which cipher suite, which keys); change cipher spec is just the pure switching trigger for it.

Structure of the message

Technically, the change cipher spec message is as simple as it gets: the TLS record has its own content type value (20) and a single payload byte value (0x01) — there are no further fields, no parameters, nothing to negotiate. This minimalism is intentional: the actual cryptographic negotiation (which algorithm, which key length, which session key) has already been completed entirely in the preceding handshake protocol — change cipher spec is purely a synchronisation signal between the two already fully negotiated states “old (unencrypted)” and “new (encrypted)”.

See also: Handshake Protocol, TLS