8. Design of the Block Cipher (AEAD) Component

This chapter specifies the cipher component: the dispatch table it exposes, the parameters it must answer, the lifecycle the record layer imposes, and the constraints inherited from §2.4. Requirements F1 and C2 are addressed here.

8.1 Why the AEAD interface and not a raw block cipher

TLS 1.3 protects records exclusively with AEAD. A raw block cipher is not directly usable: the protocol has no provision for a separate MAC, having removed the MAC-then-encrypt and encrypt-then-MAC constructions that TLS 1.2 supported. A block cipher therefore reaches TLS 1.3 only through an AEAD mode built on it — GCM and CCM being the standard constructions, with counter-mode-plus-polynomial-MAC the general pattern.

This is the first design decision and it is forced: the component this paper specifies is a mode over a block cipher, presenting an AEAD interface, not the block cipher in isolation. A provider offering only a block primitive would supply something TLS never fetches.

8.2 The dispatch table

The cipher operation's dispatch table for an AEAD comprises context management, the encrypt/decrypt lifecycle, and parameter access:

static const OSSL_DISPATCH tlsext_aead_functions[] = {
    { OSSL_FUNC_CIPHER_NEWCTX,          (void (*)(void))aead_newctx },
    { OSSL_FUNC_CIPHER_FREECTX,         (void (*)(void))aead_freectx },
    { OSSL_FUNC_CIPHER_DUPCTX,          (void (*)(void))aead_dupctx },
    { OSSL_FUNC_CIPHER_ENCRYPT_INIT,    (void (*)(void))aead_einit },
    { OSSL_FUNC_CIPHER_DECRYPT_INIT,    (void (*)(void))aead_dinit },
    { OSSL_FUNC_CIPHER_UPDATE,          (void (*)(void))aead_update },
    { OSSL_FUNC_CIPHER_FINAL,           (void (*)(void))aead_final },
    { OSSL_FUNC_CIPHER_CIPHER,          (void (*)(void))aead_oneshot },
    { OSSL_FUNC_CIPHER_GET_PARAMS,      (void (*)(void))aead_get_params },
    { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, (void (*)(void))aead_gettable_params },
    { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,  (void (*)(void))aead_get_ctx_params },
    { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,  (void (*)(void))aead_set_ctx_params },
    { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
                                        (void (*)(void))aead_gettable_ctx },
    { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
                                        (void (*)(void))aead_settable_ctx },
    { 0, NULL }
};

The distinction between algorithm parameters and context parameters is essential and is a common source of error. Algorithm parameters describe the algorithm itself — its key length, block size and mode — and are answerable without a context. Context parameters describe a particular operation in progress: the tag, the IV length in use, the AAD. The record layer queries the first to size its buffers before it has a context, and the second to retrieve the authentication tag after encrypting.

8.3 Algorithm parameters

The component answers at minimum:

ParameterTypeMeaning for TLS
keylensize_tBytes the key schedule must derive for the traffic key
ivlensize_tWidth of the static IV into which the sequence number is folded
taglensize_tCiphertext expansion; needed for record sizing
blocksizesize_t1 for a stream-like AEAD; used for buffer arithmetic
modeuintIdentifies the mode as AEAD to the consumer
aeadintFlag asserting AEAD semantics

Omitting any of the first three does not produce a clear error. It produces a consumer that computes a buffer size from a zero or a default and fails later, in the record layer, with a message about record length. This is the single most valuable debugging observation in the chapter: record-length errors in a custom AEAD are usually missing parameter answers, not arithmetic bugs.

8.4 Context parameters and the TLS-specific ones

Beyond the general AEAD context parameters — tag, AAD, IV length — the TLS record layer uses additional parameters to communicate its own framing. A cipher intended for TLS must accept the parameter by which the record layer supplies the fixed portion of the IV, and must answer the parameter reporting how much the ciphertext will expand.

Design. The component treats the IV as supplied, never generated. On einit it stores the static IV; for each record the caller supplies the constructed nonce, or the sequence number from which the component derives it, according to the parameter convention in use. Under no circumstances does the component choose a nonce itself (constraint C2). A nonce chosen by the algorithm would be catastrophic here: the AEAD constructions used by TLS lose all confidentiality guarantees on nonce reuse, and the protocol's whole nonce-management discipline assumes the algorithm is passive.

8.5 Lifecycle as the record layer drives it

The record layer's usage pattern is narrow and worth specifying, because a component that works under a test harness may still fail here:

  1. Fetch the cipher once per traffic-key epoch, not per record (N1).
  2. Create a context and initialise it for encryption or decryption with the traffic key and static IV.
  3. For each record: set the per-record nonce or sequence number, supply the record header as AAD, process the plaintext, and retrieve or verify the tag.
  4. On key update, initialise a fresh context with the new key; contexts are not re-keyed in place.

Step 3 repeats for the life of the connection with no intervening fetch, which is why per-call overhead rather than fetch overhead governs throughput (§5.4).

8.6 Decryption and the failure contract

Authenticated decryption must not release plaintext before the tag is verified, and must report verification failure as a distinguishable result rather than returning data. In the provider interface this means the final (or one-shot) entry point returns failure on tag mismatch and the caller must treat any output as invalid.

The TLS consequence is severe enough to state explicitly: a record whose tag does not verify must cause the connection to be torn down with a bad_record_mac alert. An AEAD component that returns success on a mismatched tag does not produce a subtly weaker connection; it produces one with no integrity protection at all, while appearing entirely normal in testing that never presents a corrupted record. Chapter 19 makes the corresponding negative test mandatory rather than optional.

8.7 Constant-time considerations

Requirement N2 applies with particular force to this component, because it processes attacker- influenced data continuously. Tag comparison must be constant-time; no branch may depend on plaintext or key material; and table lookups indexed by secret data — the classic weakness of naive block cipher implementations — must be avoided. Chapter 17 discusses the limits of what can be guaranteed at the C level.

8.8 Summary

The cipher component presents an AEAD interface over a block cipher, answers key, IV and tag lengths as algorithm parameters, accepts an externally supplied nonce and the record header as AAD, keeps plaintext unreleased until the tag verifies, and is fetched once per epoch. Its failure modes are concentrated in parameter reporting and in the tag-verification contract, and both are testable by deliberately violating them.