Subject: Re: [TLS] rfc7366: is encrypt-then-mac implemented?

From: Peter Gutmann <[email-masked]>
Date: Thu, 30 Oct 2014 12:24:47 +0000

Manuel Pégourié-Gonnard <[email-masked]> writes:
>On 30/10/2014 11:44, Peter Gutmann wrote:
>> Oh, so the issue isn't that you're MAC'ing extra stuff that isn't there, but
>> that you're using a length value that includes stuff that isn't MAC'd?  In
>> other words in the above 'length' isn't 'length of encrypted_stuff that
>> follows the length value' but 'length of encrypted_stuff that follows the
>> length value + length of MAC'?
>Precisely. It looks like we're making progress in undertanding each other.

OK, so I'll try and summarise this, for:

struct {
       ContentType type;
       ProtocolVersion version;
       uint16 length;
       GenericBlockCipher fragment;
       opaque MAC;
       } TLSCiphertext;

what goes on the wire for the 'length' field is the overall length of
everything that follows, i.e. the ciphertext fragment length plus MAC length.

What gets MAC'd is something like:

    MAC(MAC_write_key, seq_num +
                       TLSCompressed.type +
                       TLSCompressed.version +
                       TLSCompressed.length +
                       GenericBlockCipher.fragment);

(I say "something like" because RFC 5246 doesn't make this explicit, it refers
back to section 6.2.3.1 which is for null or generic stream ciphers and uses
TLSCompressed.fragment when it should be TLSCiphertext.fragment).

Since the MAC value isn't part of the data that's MAC'd, its length isn't
included in the MAC calculation.

Now the other interpretation, that more recent implementations are using, is
that what gets MAC'd is the length of GenericBlockCipher.fragment plus the
length of MAC[SecurityParameters.mac_length], which is the length value that
goes on the wire.

Arguments could be made that either interpretation is valid... it could be
just a case of saying "who will be least inconvenienced by switching over?".
In any case it points to what's required for issuing a clarification to the
text.

Peter.

---

From: Manuel Pégourié-Gonnard <[email-masked]>
Date: Thu, 30 Oct 2014 13:56:23 +0100

> everything that follows, i.e. the ciphertext fragment length plus MAC length.
Ok. I think all implementations so far agree on this point.

> TLSCompressed.fragment when it should be TLSCiphertext.fragment).
Are you refering the "normal" (MtE) case or the EtM case here? I'm confused. in
the MtE case, what's MAC'ed is indeed TLSCompressed.fragment. Anyways, what
matters is the text in RFC 7366 about MAC computation, which uses
TLSCiphertext.length.

> included in the MAC calculation.
I understand this reasoning and it certainly makes sense, I'm not discussing
that. But that means that when you write TLSCiphertext.length at the beginning
of page 3 in:

   MAC(MAC_write_key, seq_num +
       TLSCipherText.type +
       TLSCipherText.version +
       TLSCipherText.length +
       IV +
       ENC(content + padding + padding_length));

you mean something different from the length field of the TLSCiphertext
structure just two paragraphs below. Which I find rather confusing.

> length of MAC[SecurityParameters.mac_length], which is the length value that
Right. This is supported by the fact that both (what get's MAC'd and what goes
in the wire) are written as TLSCiphertext.length in the RFC.

> In any case it points to what's required for issuing a clarification to the
Again, I have no preference on which interpretation is chosen, as long as there
remains only one arguably valid way to interpret the text.

If you want to go the same way as the eid server (which is reasonnable IMO as it
is deployed) I'd suggest changing from

   MAC(MAC_write_key, seq_num +
       TLSCipherText.type +
       TLSCipherText.version +
       TLSCipherText.length +
       IV +
       ENC(content + padding + padding_length));

to

   MAC(MAC_write_key, seq_num +
       TLSCipherText.type +
       TLSCipherText.version +
       length of ENC(content + padding + padding_length) +
       IV +
       ENC(content + padding + padding_length));

    where the length is encoded as two bytes in the usual way.

This avoids any ambiguity related to TLSCiphertext.xxx and how its definition
should or should not be adapted from the one in RFC 5246.

To be extra sure that people don't get confused about what goes on the wire
(even though all implementations so far agreed on this point), you could also change

   This is identical to the existing TLS/DTLS layout, with the only
   difference being that the MAC value is moved outside the encrypted
   data.

to add:

   This is identical to the existing TLS/DTLS layout, with the only
   differences being that the MAC value is moved outside the encrypted
   data and length is now sum of the length of fragment and the length
   of the MAC.

(or something to that effect).

Manuel.