Subject: [Emu] Processing of TEWAP erratum 5127

From: Eliot Lear <[email-masked]>
Date: Fri, 22 Nov 2019 17:21:10 +0800

I have been reviewing this erratum, and I think it is correct, but I have a question:

> Section 5.2. says:
> 
> IMSK = First 32 octets of TLS-PRF(EMSK, "[email-masked]" |
>      "\0" | 64)
> It should say:
> 
> IMSK = First 32 octets of TLS-PRF(EMSK, "[email-masked]" |
>      "\0", 64)

Is that last parameter “seed” or “seed size”?  Confusedly yours.

Eliot
> Notes:
> 
> According to
> 
> RFC5246 The Transport Layer Security (TLS) Protocol Version 1.2
> 
> 5. HMAC and the Pseudorandom Function
> 
> "TLS's PRF is created by applying P_hash to the secret as:
> 
> PRF(secret, label, seed) = P_<hash>(secret, label + seed)"

---

From: Jouni Malinen <[email-masked]>
Date: Sun, 24 Nov 2019 13:31:42 +0200

> Is that last parameter “seed” or “seed size”?  Confusedly yours.

It's neither.. The main problem here is in RFC 7170 not defining
TLS-PRF() properly. All it says is "TLS-PRF is the PRF negotiated as
part of TLS handshake" while RFC 5246 does not define PRF as a function
with arguments that would be compatible with even a single instance of
TLS-PRF() use in RFC 7170.. And the RFC 7170 uses are inconsistent with
themselves like this erratum show, but this instance is not the only
issue: TLS-PRF() is used with two, three, and even four arguments. This
leaves the implementer guessing what exactly these maps to..

> > PRF(secret, label, seed) = P_<hash>(secret, label + seed)" 

So this PRF(secret, label, seed) is what is available and RFC 5246 does
not define that 64 part in the example above as an argument. That 64 is
the number of octets of output that is fetched from the PRF.

In other words, RFC 7170 should have defined TLS-PRF(secret, label,
seed, output-len-in-octets) as taking output-len-in-octets of octets
from the output of RFC 5246 PRF(secret, label, seed). With this,
following fixes would be needed for the users for TLS-PRF() in RFC 7170:

IMSK:
This could be one of following (last two having identical outcome):
TLS-PRF(EMSK, "[email-masked]", "", 64)
TLS-PRF(EMSK, "[email-masked]", "\0", 64)
TLS-PRF(EMSK, "[email-masked]", "\0" | 0x00 | 0x40, 64)
TLS-PRF(EMSK, "[email-masked]", 0x00 | 0x00 | 0x40, 64)

However, this TLS-PRF() instance is more strange.. The "Optional data
parameter is not used in the derivation" part does not make any sense
since I think "optional data parameter" is a reference to the seed value
going into PRF. The following description is then clearly indicating
that "\0" is 0x00 and length (that | 64) is "2-octet unsigned integer in
network byte order".  That seems to be talking about some binary data
and the seed is the only place where such byte order and field size
discussion would apply. I'm actually implementing that last one because
of that discussion in the RFC.

It should also be noted that the "First 32 octets of TLS-PRF(..., 64)"
does not make much sense since "TLS-PRF(..., 32)" would cover same. This
would seem to imply that "First 32 octets of TLS-PRF" could actually be
trying to address that PRF argument mismatch. Anyway, maybe this should
simply say:

IMSK = TLS-PRF(EMSK, "[email-masked]", 0x00 | 0x00 | 0x40, 32)
(or with empty seed "" instead of that 3 octet seed)

The "and the length is 64 octets" part just above this is a bit
confusing with this, though.

IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", IMSK[j], 60)
   (this is actually unchanged)

MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", "", 64)
   (i.e., add the missing empty seed)

EMSK = TLS-PRF(S-IMCK[j],
           "Extended Session Key Generating Function", "", 64)
   (i.e., add the missing empty seed)

-- 
Jouni Malinen                                            PGP id EFC895FA

---

From: Eliot Lear <[email-masked]>
Date: Mon, 25 Nov 2019 14:41:10 +0100

Hi Juoni,

Thanks for taking the time.  I suspect this will take a few iterations to get the actual text right, as I am drinking water from a fire hose here.  Please bear with me.

> On 24 Nov 2019, at 12:31, Jouni Malinen <[email-masked]> wrote:
> 
> TLS-PRF() use in RFC 7170..

> And the RFC 7170 uses are inconsistent with
> issue: TLS-PRF() is used with two, three, and even four arguments.

Indeed.  So that we’re clear, here they are:

Section 5.2:

2 args.

Later, same section:

IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
                IMSK[j], 60)

4 args.

And then further down:

 MSK  = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
 EMSK = TLS-PRF(S-IMCK[j],
           "Extended Session Key Generating Function", 64)

3 args.

And 5246 says:

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

And so I agree with you that nowhere is there a length field for the return value in RFC 5246.

> This
> TLS-PRF(EMSK, "[email-masked] <mailto:[email-masked]>", "", 64)
> TLS-PRF(EMSK, "[email-masked] <mailto:[email-masked]>", "\0", 64)
> TLS-PRF(EMSK, "[email-masked] <mailto:[email-masked]>", "\0" | 0x00 | 0x40, 64)
> TLS-PRF(EMSK, "[email-masked] <mailto:[email-masked]>", 0x00 | 0x00 | 0x40, 64)
> 
> going into PRF.

Could it be that this text refers to RFC 5295:

>  If an inner method supports export of an Extended Master Session Key
>  (EMSK), then the IMSK SHOULD be derived from the EMSK as defined in
>  [RFC5295].  The usage label used is "[email-masked]", and the
>  length is 64 octets.  Optional data parameter is not used in the
>  derivation.

USRK = KDF(EMSK, key label | "\0" | optional data | length)

Which perhaps is meant to translate to:

IMSK = KDF(EMSK, “[email-masked] <mailto:[email-masked]>”, 64)

But again, only when the inner method supports export of the EMSK.  Note the text below, by the way:

> USRKs MUST be at least 64 octets in length.

However we interpret the text, it seems that either the argument count is wrong or the function is wrong.

> The following description is then clearly indicating
> IMSK = TLS-PRF(EMSK, "[email-masked] <mailto:[email-masked]>", 0x00 | 0x00 | 0x40, 32)

I’m really not sure what adding a known seed gets us at this point.

>   (i.e., add the missing empty seed)

On the last two, entropy is thus borrowed from S-IMCK[j].  Correct?  I don’t have the full flow in my head, but are these indepedently generated on both sides, right?  If so, I don’t see any other alternative to what you are suggesting.

Eliot