Subject: [TLS] Labels in the TLS 1.3 key schedule

From: Andrei Popov <[email-masked]>
Date: Tue, 10 Oct 2017 01:22:11 +0000

Sorry if I missed some text in the TLS 1.3 spec, but are the various labels used in the key schedule ASCII and nul-terminated?

Thanks,

Andrei

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 10 Oct 2017 11:21:33 +0300

On Tue, Oct 10, 2017 at 01:22:11AM +0000, Andrei Popov wrote:
> Sorry if I missed some text in the TLS 1.3 spec, but are the various
> labels used in the key schedule ASCII and nul-terminated?

The labels _are_ ASCII, but _not_ NUL-terminated. Instead, the labels
have explicit length field.

Constructing some examples of raw HKDF info blocks (for draft-21), I
hope these are correct:

Example 1) SHA-256, server handshake traffic secret:

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 20|12|ASCII(tls13 s hs traffic)             |
+--+--+--+     +--+--+--+--+--+--+--+--+--+--+--+
|              |20| Handshake hash up to and    |
+--+--+--+--+--+--+                             +
| including ServerHello                         |
+                 +--+--+--+--+--+--+--+--+--+--+
|                 |
+--+--+--+--+--+--+

Total 54 bytes, exactly fills one SHA-256 block after HKDF to HMAC
lowering and SHA-256 padding (not a coincidence). The byte immediately
before the boxed 0x20 contains ASCII 'c'.

Example 2) SHA-384 client application traffic secret:

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 30|12|ASCII(tls13 c ap traffic)             |
+--+--+--+     +--+--+--+--+--+--+--+--+--+--+--+
|              |30| Handshake hash up to and    |
+--+--+--+--+--+--+                             +
| including ServerFinished                      |
+                                               +
|                                               |
+                 +--+--+--+--+--+--+--+--+--+--+
|                 |
+--+--+--+--+--+--+

Total 70 bytes, fits into one SHA-384 compression, even after lowering
to HMAC and SHA-384 padding. The byte immediately before the boxed 0x30
contains ASCII 'c'.

Example 3) SHA-256, the "derived" stages (which are just before
injecting raw DHE result and just before injecting block of zeroes):

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 20|0d|ASCII(tls13 derived)                  |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|20|e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9|
+--+                                            +
|24 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8|
+  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|55|
+--+

Total of 49 bytes. Note e3...55 is SHA-256 of empty input. Another
place that uses similar construction is the per-exporter key
derivation. Byte 15, immedately before boxed 20 contains ASCII 'd'.

Example 4) SHA-384, traffic key update:

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 30|11|ASCII("tls13 traffic upd")            |
+--+--+--+  +--+--+--+--+--+--+--+--+--+--+--+--+
|           |00|
+--+--+--+--+--+

Total of 21 bytes. Note, no hash of empty input, as this uses
hkdf-expand-label as opposed to derive-secret. The byte immediately
before boxed 0x20 contains ASCII 'd'.

Example 5) SHA-256, inner exporter derivation for label
"EXPORTER: teap session key seed":

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 20|25|ASCII(tls13 EXPORTER: teap session key|
+--+--+--+                                      +
| seed)                                         |
+                       +--+--+--+--+--+--+--+--+
|                       |20|e3 b0 c4 42 98 fc 1c|
+--+--+--+--+--+--+--+--+--+                    +
|14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4 64 9b 93|
+                          +--+--+--+--+--+--+--+
|4c a4 95 99 1b 78 52 b8 55|
+--+--+--+--+--+--+--+--+--+

Total of 73 bytes. Note, this blows SHA-256 block (this exporter inner
hash is the only place in current spec that might blow out SHA-256
block, However, if another hash function is defined, that might have
its block blown in other places too). The byte immedately before the
boxed 0x20 contains ASCII 'd'. Also note that the way the label is
split, there is a space between words "key" and "seed".

Without the empty hash, this would blow blocks less (e.g., would not
blow with this example label), but still could blow them, as the
maximum label is 249 bytes, giving 259+<hashoutputlen> byte raw info
block, which exceeds the blocksize of any known hash function).

Example 6) SHA-384, deriving IV for Chacha20-Poly1305:

+--+--+--+--+--+--+--+--+--+--+--+--+
|00 0c|08|ASCII(tls13 iv)        |00|
+--+--+--+--+--+--+--+--+--+--+--+--+

Total of 12 bytes (this is the shortest of these blocks). The output is
truncated to 12 bytes. The byte immedately before the boxed 0x00
contains ASCII 'v'.

Example 7) SHA-256, final exporter derivation step for 64-byte output
(exporter label is not material):

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 40|0E|ASCII(tls13 exporter)                 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|  |00|
+--+--+

Note that HKDF lowers into HMAC two times here, since there is 33 to 64
bytes of output, but SHA-256 only produces 32 bytes of output. The
empty box in the last row contains ASCI 'r', as the label overflows to
byte 16.

-Ilari

---

From: Martin Thomson <[email-masked]>
Date: Tue, 10 Oct 2017 20:00:46 +1100

> Constructing some examples of raw HKDF info blocks (for draft-21), I

You can see other examples at
https://tools.ietf.org/html/draft-ietf-tls-tls13-vectors-02

e.g.

      info (54 octets):  002012746c733133 2073206873207472
         6166666963208ac5 1822361c59632de3 c6b259e5808ce52b
         8278a6493de2a976 f441abbadc8c

Which matches the length of your example.

---

From: Andrei Popov <[email-masked]>
Date: Tue, 10 Oct 2017 16:57:31 +0000

> The labels _are_ ASCII, but _not_ NUL-terminated.

Thanks; I can't find any mention of character set or nul-termination in draft-21. Perhaps it would be a good idea to clarify.

Cheers,

Andrei