Hi Jamil et al -
I think I finally understand the disconnect here - let me try and work
through an explanation from another direction.
The TLS 1.3 KDF is NOT HKDF-Expand, it is HKDF-Expand-Label.
HKDF-Expand has a calling sequence of HKDF-Expand (Secret, Label,
Length). That results in underlying calls to T(n) = PRF (Secret,
T(n-1) || label || n) for each block of key stream (RFC 5869 - page 3).
Two key things to understand here are: that the Length value in
HKDF-Expand is not passed in as a mixin, only as a value to determine
how much key stream to produce; that the "label" parameter is just
opaque data (remember this please - its important later).
HKDF-Expand-Label (Secret, Label, HashValue, Length) is defined as
HKDF-Expand (Secret, hkdfLabel, Length) where hkdfLabel is a structured
value (NON-Opaque) consisting of the Length, Label (from the top level
call) and Hash Value (also from the top level call) (TLS 1.3 section 7.1
Key Schedule). The hkdfLabel ultimately is the "label" part of the call
to the PRF.
A module creating a key from HKDF-Expand-Label knows that it MUST cut
off the key stream after Length bytes (and if a new length value is
provided, you get a whole different key stream). It can read the
hkdfLabel from the call and know this production is for a key or an iv
and set protections appropriately. HKDF-Expand-Label also knows that it
will only produce a single object from each call. In HDKF-Expand, the
Label value is opaque. It may contain the Length value, it may contain
key tagging information, it may contain your dog's name, but since it's
not structured in any way, an implementer of the HKDF-Expand calling
convention can't do anything useful with that data in figuring out the
assignment of the key stream to a key object.
I think what we have is a failure of language. HKDF (and for that
matter SP800-108) should be called key stream producers - not key
derivation functions. Mainly because they don't properly consider the
assignment of the key stream bytes to the keys and how that interacts
with the key stream production.
I need a way of making sure that 1) the key assignment/production
specifications can be included in the mixins, and 2) a way of letting
the module/provider be able to rely upon those specifications (e.g. by
changing the key stream if the specifications change). That means that
the KeyDerivation calling convention needs to let me provide all of this
data before the first call to derive a key.
This would have been more obvious had TLS1.3 kept the same multiple
production per KDF call as was in previous versions - the HkdfLabel
argument would have been an array of hkdfLabel structures. They opted
to clean it up slightly and limit it to a single production per KDF call.
Mike