Subject: [TLS] Issue #964: Shortened HKDF labels

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 05:56:58 -0700

https://github.com/tlswg/tls13-spec/issues/964

Hi folks,

It was raised during the WG meeting in Chicago that some of the labels have
gotten a bit long and after checking it seems like many of them push us into
two hash blocks, which seems silly.

Here is a proposed set of new labels, which, while slightly less clear, all
fit
into the 18 byte limit which Ilari (and I agree) says is what we have.

external binder # was external psk binder key
resumption binder # was resumption psk binder key
client e. traffic # was client early traffic
e. exporter master # was early exporter master secret
client hs traffic # was client handshake traffic secret
server hs traffic # was server handshake traffic secret
client app traffic # was client application traffic secret
server app traffic # was server application traffic secret
exporter master # was exporter master secret
resumption # was resumption master secret
key # was key
iv # was iv
finished # was finished
traffic key update  # was application traffic secret
exporter # was exporter

Note that this actually pushes us into multiple hash blocks anyway if we
compute > 1 output block, but I don't believe that ever happens except
for very silly uses of exporters. I would appreciate a double check that
haven't accidentally made one >18 or duplicated or something.

If anyone has strong opinions about these, please let me know by Wednesday.
Otherwise, I'll merge them into the draft.

-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 24 Apr 2017 18:24:22 +0300

> into the 18 byte limit which Ilari (and I agree) says is what we have.

Doing a santiy check...
 
> client e. traffic # was client early traffic

Isn't the previous label "client early traffic secret"?

> traffic key update  # was application traffic secret

Seems to be missing:

derived secret # was derived secret

All look to fit into 18 bytes and none seem to be duplicated.

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 08:28:33 -0700

> Isn't the previous label "client early traffic secret"?

Oops. Yeah, search and replace fail.

> derived secret # was derived secret

Yep. This one we can keep.

Thans,
-Ekr

---

From: Ilari Liusvaara <[email-masked]>
Date: Mon, 24 Apr 2017 19:16:19 +0300

> > > into the 18 byte limit which Ilari (and I agree) says is what we have.

Aargh, turns out that Merke-Damgård strengthening probably affects
things...

For SHA-256, MD strengthening consists of padding bit and 64-bit
message bit count, for total of 65-512 bits of padding.

Trying to construct the raw SHA-256 message words for inner hash with
9 byte label (K is key, L is label, H is hash).

KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK 
36363636 36363636 36363636 36363636 36363636 36363636 36363636 36363636 
00201254 4C532031 2E332C20 LLLLLLLL LLLLLLLL LL20HHHH HHHHHHHH HHHHHHHH
HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH HHHH0180 00000000 000003B8

Adding 10th byte to label seems to blow the block (0x3C0=1*512+448):

KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK KKKKKKKK 
36363636 36363636 36363636 36363636 36363636 36363636 36363636 36363636 
00201354 4C532031 2E332C20 LLLLLLLL LLLLLLLL LLLL20HH HHHHHHHH HHHHHHHH
HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH HHHHHHHH HHHHHH01 80000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000 00000000 00000000 00000000 00000000 000003C0 

For comparision, with SHA-384, the blocks for 9-byte label seem to be:

KKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKK
KKKKKKKKKKKKKKKK KKKKKKKKKKKKKKKK 3636363636363636 3636363636363636
3636363636363636 3636363636363636 3636363636363636 3636363636363636
3636363636363636 3636363636363636 3636363636363636 3636363636363636
003012544C532031 2E332C20LLLLLLLL LLLLLLLLLL30HHHH HHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHH HHHHHHHHHHHHHHHH 
HHHHHHHHHHHH0180 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000638

(Which has 327 hash block padding bits).

-Ilari

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 09:39:32 -0700

Nice catch.

9 bytes seems a bit cramped. What I suggest here is that we remove the "TLS
1.3, ", as it was just there by analogy to the handshake context and then
we are back to having 18 bytes.

If people feel like we should have some "TLS" prefix, I think "TLS " would
be enough, giving us 1 bytes.

-Ekr

On Mon, Apr 24, 2017 at 9:16 AM, Ilari Liusvaara <[email-masked]>
wrote:

> > > > Here is a proposed set of new labels, which, while slightly less
> clear,
> > > all
> > > > fit

---

From: Dave Garrett <[email-masked]>
Date: Mon, 24 Apr 2017 16:57:30 -0400

> be enough, giving us 1 bytes.

(assuming you mean 14 bytes here)

If I remember correctly, in some discussion quite a while back, we decided we wanted to bake the version number into the labels. This could be done more compactly by adding a ProtocolVersion value (2 bytes) to the HkdfLabel struct. "TLS" could be stuck in there as a static 3 byte opaque string, with no length or space. (yeah, the combined plaintext will go "TLSclient hs traffic", but nobody needs to care)

Also, why is HkdfLabel.length 16 bits instead of 8? Is there any conceivable scenario where we'd need to HKDF-Expand to more than 256 bytes, in our uses here? Unless I'm missing something, our values for this field range from 12-32 normally (or up to 64 with 512 bit). Ditching the extra byte here would salvage another byte for labels. (just an aside: HkdfLabel.length would be a lot more clear as to its meaning if it were named HkdfLabel.output_length, instead; too many length values here)

With ProtocolVersion + "TLS" + dropped length byte, that results in a label space of 14 bytes, whilst still keeping the version number baked into the label directly.

An extra couple of bytes could even be salvaged out of the HkdfLabel struct by ditching the lengths of the 'label' and 'hash_value' fields, though going this far may be overkill.

Dave

---

From: Benjamin Kaduk <[email-masked]>
Date: Mon, 24 Apr 2017 16:13:33 -0500

On 04/24/2017 03:57 PM, Dave Garrett wrote:
> If I remember correctly, in some discussion quite a while back, we decided we wanted to bake the version number into the labels. This could be done more compactly by adding a ProtocolVersion value (2 bytes) to the HkdfLabel struct. 

I would prefer to keep both "TLS" and the version number involved.  I
generally don't mind having a non-ASCII encoding for the version number,
but then we have to pay attention to avoid putting a NULL byte in it by
accident.

-Ben

> "TLS" could be stuck in there as a static 3 byte opaque string, with no length or space. (yeah, the combined plaintext will go "TLSclient hs traffic", but nobody needs to care)

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 15:04:39 -0700

On Mon, Apr 24, 2017 at 1:57 PM, Dave Garrett <[email-masked]>
wrote:

> If I remember correctly, in some discussion quite a while back, we decided
> we wanted to bake the version number into the labels.

I don't remember there really being a reason for that...

This could be done more compactly by adding a ProtocolVersion value (2
> bytes) to the HkdfLabel struct. "TLS" could be stuck in there as a static 3
> byte opaque string, with no length or space. (yeah, the combined plaintext
> will go "TLSclient hs traffic", but nobody needs to care)
>

How is this better than "TLS13client hs traffic" in the label?

Note that we could do "T13"...

With ProtocolVersion + "TLS" + dropped length byte, that results in a label
> space of 14 bytes, whilst still keeping the version number baked into the
> label directly.
>
> An extra couple of bytes could even be salvaged out of the HkdfLabel
> struct by ditching the lengths of the 'label' and 'hash_value' fields,
> though going this far may be overkill.

That seems very dangerous.

-Ekr

---

From: Benjamin Kaduk <[email-masked]>
Date: Mon, 24 Apr 2017 17:09:01 -0500

On 04/24/2017 05:04 PM, Eric Rescorla wrote:
>
>
> On Mon, Apr 24, 2017 at 1:57 PM, Dave Garrett <[email-masked]
> <mailto:[email-masked]>> wrote:
>
>     If I remember correctly, in some discussion quite a while back, we
>     decided we wanted to bake the version number into the labels. 
>
>

Double-plus extra surefire way to avoid cross-version badness.

>
>     This could be done more compactly by adding a ProtocolVersion
>     value (2 bytes) to the HkdfLabel struct. "TLS" could be stuck in
>     there as a static 3 byte opaque string, with no length or space.
>     (yeah, the combined plaintext will go "TLSclient hs traffic", but
>     nobody needs to care)
>
>  

Probably fine.

>
>     With ProtocolVersion + "TLS" + dropped length byte, that results
>     in a label space of 14 bytes, whilst still keeping the version
>     number baked into the label directly.
>
>     An extra couple of bytes could even be salvaged out of the
>     HkdfLabel struct by ditching the lengths of the 'label' and
>     'hash_value' fields, though going this far may be overkill.
>
>

It seems not worth doing, yes.

-Ben

---

From: "Salz, Rich" <[email-masked]>
Date: Mon, 24 Apr 2017 22:17:22 +0000

Using a registry also prevents conflicts.

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 16:21:13 -0700

Based on Ilari's comments, it seems like we just lost 9 bytes, and the TLS
1.3, label was 9 bytes, so these cancel each other out and we have a total
of 18 bytes to work with, including the label.

Hence, the following proposal for the complete label, where the longest
string is 18 bytes.

16 tls13 ext binder    #  was external psk binder key
16 tls13 res binder    #  was resumption psk binder key
17 tls13 c e traffic    #  was client early traffic secret
18 tls13 e exp master    #  was early exporter master secret
18 tls13 c hs traffic    #  was client handshake traffic secret
18 tls13 s hs traffic    #  was server handshake traffic secret
18 tls13 c ap traffic    #  was client application traffic secret
18 tls13 s ap traffic    #  was server application traffic secret
16 tls13 exp master    #  was exporter master secret
16 tls13 res master    #  was resumption master secret
9 tls13 key    #  was key
8 tls13 iv    #  was iv
14 tls13 finished    #  was finished
17 tls13 traffic upd    #  was application traffic secret
14 tls13 exporter    #  was exporter
13 tls13 derived    #  was derived

Further bikeshedding?

-Ekr

On Mon, Apr 24, 2017 at 9:39 AM, Eric Rescorla <[email-masked]> wrote:

> Nice catch.
>
> 9 bytes seems a bit cramped. What I suggest here is that we remove the
> "TLS 1.3, ", as it was just there by analogy to the handshake context and
> then we are back to having 18 bytes.
>
> On Mon, Apr 24, 2017 at 9:16 AM, Ilari Liusvaara <[email-masked]
> > wrote:
>

---

From: Benjamin Kaduk <[email-masked]>
Date: Mon, 24 Apr 2017 18:29:12 -0500

On 04/24/2017 06:21 PM, Eric Rescorla wrote:
> Based on Ilari's comments, it seems like we just lost 9 bytes, and the
> TLS 1.3, label was 9 bytes, so these cancel each other out and we have
> a total of 18 bytes to work with, including the label.
>
> Hence, the following proposal for the complete label, where the
> longest string is 18 bytes.
>

I had something more olive-ish puce in mind ... but this is fine; ship it.

-Ben

---

From: Dave Garrett <[email-masked]>
Date: Mon, 24 Apr 2017 21:08:53 -0400

> 13 tls13 derived    #  was derived

I think "tls13 c e traffic" is the only one that could be tweaked to be a little more obvious. Abbreviating "early data" as "ed", instead of just "early" as "e", would still fit and follow the same pattern as the other traffic labels.

Other than that, this sounds fine.

Dave

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 24 Apr 2017 20:12:31 -0700

On Mon, Apr 24, 2017 at 6:08 PM, Dave Garrett <[email-masked]>
wrote:

> I think "tls13 c e traffic" is the only one that could be tweaked to be a
> little more obvious. Abbreviating "early data" as "ed", instead of just
> "early" as "e", would still fit and follow the same pattern as the other
> traffic labels.
>

Unfortunately this woud explode tls13 e exp master.

-Ekr

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 25 Apr 2017 14:50:01 -0700

PR here:
https://github.com/tlswg/tls13-spec/pull/977

---

From: Martin Thomson <[email-masked]>
Date: Wed, 26 Apr 2017 16:51:01 +1000

Unsurprisingly, this was easy to implement.  If anyone else is
tracking this closely, I can share a version of NSS that includes this
change (and pretends to be an implementation of -20).

On 26 April 2017 at 07:50, Eric Rescorla <[email-masked]> wrote:
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Ilari Liusvaara <[email-masked]>
Date: Wed, 26 Apr 2017 10:21:48 +0300

> change (and pretends to be an implementation of -20).

Not very hard, altough I had to do some refactoring in order to semi-
cleanly support multiple versions at once (I have a branch that does
-17 to -20, with "-20" being -19 + this label change.

-Ilari