Transcript

The Transcript Hash is a running sha2 of the handshake messages exchanged when establishing the secure connection. The digest is used many times, at various stages of the exchange, by TLSCipherSuite. The digest, together with the key exchanged via key_share or pre_shared_key, is used to generate the many secrets key used by the AEAD algorithms to encrypt exchanges.

There are shenanigans regarding ClientHello and HelloRetryRequest that make the implementation unfortunately not trivial.

About Client Hello

The client can offer multiple cipher suites in its first ClientHello, the different offered cipher suites can come with different hashing algorithm, e.g. TLS_AES_128_GCM_SHA256 vs TLS_AES_256_GCM_SHA384 (SHA256 vs SHA386). The actual hashing algorithm to use for this connection will only be known with the ServerHello / HelloRetryRequest hanshake of the server.

This means that either (1) we have to keep the ClientHello message around until we know what hash algorithm the server decides to use and only then compute the transcript hash, either (2) we save multiple hashes and then discard those we won’t use. The current implementation uses (2) as several passages of the TLS RFC hint at this choice and that it seems to be the common method used by many TLS implementations.

In cases multiple differents hashing algorithms are offered, that until receiving ServerHello / HelloRetryRequest we do not know which one will be used, it is forbidden to request a digest (via the digest() and hexdigest() methods) before calling post_init().

This has an important implication regarding TLSCipherSuite and Early Data: the transcript hash of ClientHello is used when generating the “early exported master” and “client early traffic” secrets. Those secrets are generated and used before receiving ServerHello / HelloRetryRequest. All the pre-shared-keys all must share the same hashing algorithm othersise it would be impossible to generate the secrets.

About Hello Retry Request

TLS 1.3 claims that it is possible to do a stateless HelloRetryRequest using a clever (but not smart) hack. We still don’t know how to do a stateless HelloRetryRequest but we still have to implement the hack otherwise the transcript wouldn’t be right.

class siotls.transcript.Transcript
__init__(digestmods)

Prepare a new empty transcript for a new connection.

Parameters:

digestmods (Iterable[siotls.crypto.HashFunction]) – the list of hash function that are supported for this connection, usually SHA256, SHA384, or both.

Raises:

ValueError – When digestmods is empty.

copy()

Create an independent copy of the current transcript hash.

digest()

Digest the current transcript hash.

Raises:

ValueError – When this method is called before post_init() was called to finilize the initialization.

Return type:

bytes

do_hrr_dance()

Implemented as follow:

Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
    Hash(message_hash ||        /* Handshake type */
         00 00 Hash.length  ||   /* Handshake message length (bytes) */
         Hash(ClientHello1) ||  /* Hash of ClientHello1 */
         HelloRetryRequest  || ... || Mn)
hexdigest()

Digest and hexlify the current transcript hash.

Raises:

ValueError – When this method is called before post_init() was called to finilize the initialization.

Return type:

str

post_init(digestmod)

Finilize the initialization with a definitive hash function.

Parameters:

digestmod (siotls.crypto.HashFunction) – The definite hash function.

Raises:

ValueError – When digestmod is not one of the hash functions this transcript was initialized with.

Return type:

None

update(handshake_data, side, handshake_type)

Update the underlying hash with new data.

The side and handshake type are used as sanity check, and also to save the ClientHello’s transcript digest for do_hrr_dance().

Parameters:
  • handshake_data (bytes) – The plain handshake, as extracted and decrypted from TLS record layer.

  • side ('client' | 'server') – The side of this connection.

  • handshake_type (HandshakeType | HandshakeType_) – The type of the handshake.