Subject: Re: [Emu] Processing of TEWAP erratum 5127

From: Joseph Salowey <[email-masked]>
Date: Thu, 23 Jan 2020 21:05:19 -0800

On Mon, Nov 25, 2019 at 5:43 AM Eliot Lear <[email-masked]> wrote:

> 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:
>
> On Fri, Nov 22, 2019 at 05:21:10PM +0800, Eliot Lear wrote:
>
> 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.
>
>
> 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..
>
>
>
[Joe] Looking at this again I do not think the errata is correct, but the
text is this section is confusing.

"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 <https://www.rfc-editor.org/rfc/rfc5295>]. "

RFC5295 specifies the KDF signature

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

The IMSK adds confusion by substituting the TLS 1.2 PRF for the KDF. I
believe the intent here is to map this to the following in RFC5246

IMSK = First 32 octets of P_<hash>(EMSK, "[email-masked]"| "\0"   |   64)

I don't think the errata text is correct.   It should either use the
existing text or the clarification using P_<hash> form 5246 above.

The other key derivation in the spec are ambiguous as Jouni indicates,
but I need to give my brain a rest before I tackle those.

>
> 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.
>
>
>
> Indeed.  So that we’re clear, here they are:
>
> Section 5.2:
>  IMSK = First 32 octets of TLS-PRF(EMSK, "[email-masked]" |
>      "\0" | 64)
>
>
> 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
> leaves the implementer guessing what exactly these maps 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)"
>
>
> 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.
>
>
>
> 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]”, 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
> 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)
>
>
> I’m really not sure what adding a known seed gets us at this point.
>
>
> 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)
>
>
>
> 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
> _______________________________________________
> Emu mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/emu
>

---

From: Joseph Salowey <[email-masked]>
Date: Sun, 26 Jan 2020 20:46:18 -0800

> I’m really not sure what adding a known seed gets us at this point.
[Joe] The intent is that the IMSK derivation uses the USRK derivation of
RFC 5295.  The label, null and 2-byte length are defined in that
specification.  (P_<hash> is defined in RFC 5246)

IMSK = P_<hash> (EMSK, "[email-masked]" | 0x00 | 0x00 | 0x40)

P_<hash> is iterated to generate 64 bytes, the output is truncated to 32.
If we add a parameter to the P_<hash>  to define the length, this would be

IMSK = Truncate(P_<hash>(EMSK, "[email-masked]" | 0x00 | 0x00 | 0x40,
64), 32)

>> [Joe]  In particular its not clear If the same construction should be
used for the other derivations. For example, whether to include the output
length into the data fed into the PRF or not or if there is a null between
the label and the seed.  I believe the intent was the following:
>> IMCK[j] =  P_<hash>(S-IMCK[j-1], "Inner Methods Compound Keys", | 0x00 |
IMSK[j] | 0x00 | 0x3C, 60)

>>   (i.e., add the missing empty seed)
MSK = P_<hash>(S-IMCK[j], "Session Key Generating Function" | 0x00 | 0x00 |
0x40, 64)

>>   (i.e., add the missing empty seed)
EMSK = P_<hash>(S-IMCK[j], ""Extended Session Key Generating Function" |
0x00 | 0x00 | 0x40, 64)

>> on both sides, right?  If so, I don’t see any other alternative to what you
[Joe]  THis is not the only the derivation could be interpreted.  The null
after the label and the inclusion of the length are part of RFC 8295 and
not the TLS PRF.   To fix this errata I think we should define the TLS-PRF
to be P_<hash> with a length parameter for TLS 1.2  and then use the
definitions above that explicitly define the 3 inputs.   TLS 1.3 defines
the PRF in terms of HKDF extract and expand functions from RFC 5869 so
there would need to be some mapping to 1.3 as well.

---

From: Eliot Lear <[email-masked]>
Date: Tue, 28 Jan 2020 16:28:45 +0100

> On 27 Jan 2020, at 05:46, Joseph Salowey <[email-masked]> wrote:
> 
> [Joe]  THis is not the only the derivation could be interpreted.  The null after the label and the inclusion of the length are part of RFC 8295 and not the TLS PRF.   To fix this errata I think we should define the TLS-PRF to be P_<hash> with a length parameter for TLS 1.2  and then use the definitions above that explicitly define the 3 inputs.   TLS 1.3 defines the PRF in terms of HKDF extract and expand functions from RFC 5869 so there would need to be some mapping to 1.3 as well.

So… I’m not sure we can deal with 1.3 in an erratum, but we sure as heck shouldn’t make it harder later.  I think what you are suggesting matches the OpenSSL call as well, which is where much of this derives from.