Subject: [TLS] RFC 6066 - Max fragment length negotiation

From: Nitin Shrivastav <[email-masked]>
Date: Thu, 16 Mar 2017 15:12:20 -0400

Hello,

This is Nitin Shrivastav, Engineering Manager at Broadcom. I have a
question on RFC 6066 Maximum Fragment Length Negotiation section

The question i have is whether it is possible for a server to initiate the
Max fragment length negotiation. The RFC describes a scenario where a
constrained client can initiate this but in our product the server is very
tightly constrained on memory and we want to reduce the memory used for SSL
connections by forcing the clients to use reduce fragment length. We don't
have control over the clients in our scenario which are basically the
browsers like Chrome, IE etc.

Thanks,
Nitin

---

From: Yoav Nir <[email-masked]>
Date: Thu, 16 Mar 2017 22:48:58 +0200

Hi, Nitin.

In section 7.4.1.4 of RFC 5246 it says:

   An extension type MUST NOT appear in the ServerHello unless the same
   extension type appeared in the corresponding ClientHello.

So the answer is no. Only the client may request this.

Yoav

> On 16 Mar 2017, at 21:12, Nitin Shrivastav <[email-masked]> wrote:
> 
> Hello,
> 
> This is Nitin Shrivastav, Engineering Manager at Broadcom. I have a question on RFC 6066 Maximum Fragment Length Negotiation section
> 
> The question i have is whether it is possible for a server to initiate the Max fragment length negotiation. The RFC describes a scenario where a constrained client can initiate this but in our product the server is very tightly constrained on memory and we want to reduce the memory used for SSL connections by forcing the clients to use reduce fragment length. We don't have control over the clients in our scenario which are basically the browsers like Chrome, IE etc.
> 
> Thanks,
> Nitin
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

---

From: Yoav Nir <[email-masked]>
Date: Thu, 16 Mar 2017 22:59:54 +0200

> On 16 Mar 2017, at 22:52, Nitin Shrivastav <[email-masked]> wrote:
> 
> Thanks Yoav. I am assuming it is true for TLS1.2 also?

RFC 5246 *is* TLS 1.2.  But it’s true for previous versions and for 1.3 as well.
> 
> It would be nice to provide a mechanism for servers to do this as we are trying to run a web server in a constrained IoT end-points with only tens of KBytes of RAM and SSL/TLS based connection is important..

I don’t get if you mean that the constrained end-point is the client or the server. But either way, both sides can be configured to use small records. You only really need this extension when you both have large amounts of data (so large records would be used without this extension) and the server is a generic web server that responds to both constrained and non-constrained devices.

But even in that case, adding the extension to the ClientHello should not be infeasible.

Yoav

> On Thu, Mar 16, 2017 at 4:48 PM, Yoav Nir <[email-masked] <mailto:[email-masked]>> wrote:
> Hi, Nitin.
> 
>> On 16 Mar 2017, at 21:12, Nitin Shrivastav <[email-masked] <mailto:[email-masked]>> wrote:
>> 
>> Hello,
>> 
>> [email-masked] <mailto:[email-masked]>
>> https://www.ietf.org/mailman/listinfo/tls <https://www.ietf.org/mailman/listinfo/tls>
> 
>

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 16 Mar 2017 23:18:27 +0000

Nitin Shrivastav <[email-masked]> writes:

>We don't have control over the clients in our scenario which are basically
>the browsers like Chrome, IE etc.

I think a more important question would be "does any browser support this"?
Looking at:

https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations

it seems like the answer is mostly "no".

Peter.

---

From: Nitin Shrivastav <[email-masked]>
Date: Thu, 16 Mar 2017 19:35:31 -0400

Thanks Peter, seems like this extension is not an option.  I guess since our server is serving the web pages to browsers, we should be able to predict the max amount of data that will be pushed when user submits the data on the web page and tune the ssl buffer accordingly.

> On Mar 16, 2017, at 7:18 PM, Peter Gutmann <[email-masked]> wrote:
>

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 16 Mar 2017 23:45:42 +0000

Nitin Shrivastav <[email-masked]> writes:

>Thanks Peter, seems like this extension is not an option.  

In which case it might be time to update the RFC, since there's no obvious
reason why you can't send it from the server.  Can any of the original authors
provide a reason why it shouldn't be done by the server?

Peter.

---

From: Nitin Shrivastav <[email-masked]>
Date: Thu, 16 Mar 2017 20:00:01 -0400

Yoav

The constrained end point is server serving web pages to browsers. 

Nitin

> On Mar 16, 2017, at 4:59 PM, Yoav Nir <[email-masked]> wrote:
> 
> 
>>> On Thu, Mar 16, 2017 at 4:48 PM, Yoav Nir <[email-masked]> wrote:
>>> Hi, Nitin.
>>>

---

From: Martin Thomson <[email-masked]>
Date: Fri, 17 Mar 2017 11:05:42 +1100

> provide a reason why it shouldn't be done by the server?

Most clients will explode if the server sends an extension that the
client didn't offer.

You would have more luck getting clients to implement the extension.
I looked at this, and it's not impossible.  The spec contains some
frightening things in it though.

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 17 Mar 2017 00:22:30 +0000

Martin Thomson <[email-masked]> writes:
>Most clients will explode if the server sends an extension that the client
>didn't offer.

Is that from actually trying it with clients, or just assuming that
implementations will do what the spec says?  It's another one of those bits of
TLS 1.2 that make no sense, so I've ignored the requirement in my code, you
have to add a whole pile of code to perform the check (more attack surface)
and the best possible outcome is that it has no effect, while the worst is
that it breaks things if a buggy server drops in an extension the client
wasn't expecting.  In other words implementing it has negative utility.

There's also the escape hatch of "server-oriented extensions", all you'd need
to do is define one that tells the server that the client will accept any
extensions the server cares to send, thus negating the "no server extensions"
requirement.

Given that this looks like an embedded-only sort of thing, I could even add it
to -LTS, since a primary target of that is embdded/SCADA/etc.

Peter.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 17 Mar 2017 12:47:30 +1100

On 17 March 2017 at 11:22, Peter Gutmann <[email-masked]> wrote:
> implementations will do what the spec says?

I know for certain that NSS explodes.  Not from trying, but from
knowing that part of the code very well.  I'm fairly certain that
boringSSL does too, knowing David.

You say negative utility, but I've found that if you can get away with
stricter policing of these things, it helps prevent servers from
starting to do the wrong thing.  The odds that someone tests a new
server implementation against major browsers is fairly good.

In any case, what would you expect a client to do if they don't
advertise the extension?  In this case, max_fragment_length is so
badly designed that you can actually argue that it has utility, but I
don't consider that as a good argument for the general case.

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 16 Mar 2017 19:01:35 -0700

FWIW, this requirement is actually very old, dating back to RFC 3546. It's
not unique to TLS 1.2.

   Note that for all extension types (including those defined in
   future), the extension type MUST NOT appear in the extended server
   hello unless the same extension type appeared in the corresponding
   client hello.  Thus clients MUST abort the handshake if they receive
   an extension type in the extended server hello that they did not
   request in the associated (extended) client hello.

https://tools.ietf.org/html/rfc3546#section-2.3

-Ekr

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 17 Mar 2017 03:35:19 +0000

Martin Thomson <[email-masked]> writes:

>In this case, max_fragment_length is so badly designed that you can actually
>argue that it has utility, but I don't consider that as a good argument for
>the general case.

Why is it badly designed?  I can guess that some people would prefer to have a
mechanism for client and server to debate endlessly what the most cromulent
fragment size is, but that's about the only thing I can see.

As a slight aside, the client-only nature of the extension seems to be another
example of the all-the-world's-the-web view of TLS, that servers have infinite
resources and it's clients who may be constrained.  In the embedded world it's
far more likely to be the exact opposite, the server (e.g. a PLC) is very
resource-constrained and the client connecting to it (e.g. a PC controller)
has all the resources it needs.

Incidentally, here's a picture of a $25 million web server:

http://www.abb-conversations.com/wp-content/uploads/2013/09/ABB_Phaseshifter_transformer.jpg

It's resource-constrained.

(Actually that one doesn't do SSL as far as I know, and the server runs NT 4).

Peter.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 17 Mar 2017 14:49:39 +1100

> fragment size is, but that's about the only thing I can see.

I looked at implementing this for NSS with the idea that I would try
to be nice to embedded servers (because web servers are constrained
devices too).

I can't send a max_fragment_length extension that says I support
records of 2^14 octets in length.  Because I don't care and full-sized
fragments are valuable to me in some cases, but if a server is
constrained, it would be no trouble to send it smaller records.

And I can't fix that.  If I send a max_fragment_length extension with
a value other than the four values defined in RFC 6066, all I get for
my troubles is an "illegal_parameter" alert from any server that
implements the RFC correctly.

The design I would use is much simpler.  The extension would carry a
two octet value that is the maximum size of the plaintext that the
endpoint is willing to receive.  A client could say 2^14 and that
would allow the server to send that much if it were able.  The same
server could say 5 and the client would be forced to fragment like
crazy (ok, that last might be too far, we'd probably want to set a
lower bound on the value).

I'd happily implement and advertise that extension.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 17 Mar 2017 17:24:09 +1100

> I'd happily implement and advertise that extension.

I'd even go so far as to specify it:

https://martinthomson.github.io/tls-record-limit/

I'll submit an I-D once the blackout ends if people are interested in this.

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 17 Mar 2017 10:38:37 +0000

>https://martinthomson.github.io/tls-record-limit/

Some comments...

Firstly, do we have much real-world experience in using this extension?  From
the TLS-support matrix, it looks like very few implementations support this,
does this mean few people care about it or just that it's defined in a such a
manner that it's not practical to support it?  For anyone who does use it, how
do you use it, and what would you like to see changed?  If no fixed version of
max_fragment_length is defined, would anyone care?

(I've had support for max_fragment_length in my code since the extension was
defined but it's always been commented out, no-one has ever asked for it to be
supported).

If the draft is published, I'd like to have a boolean don't-fragment flag or
something similar available alongside RecordSizeLimit for implementations that
don't implement fragmentation (the implementation matrix doesn't record which
implementations support this, but I'd be pretty surprised if many embedded
stacks did, given the complexity and extra memory use that this adds).  

In other words a way to say "set RecordSizeLimit to 2048 bytes but don't
fragment messages", meaning the client or server holds back from sending 8,000
cipher suites and 500 extensions in the hello to keep each record below 2048
bytes.  Otherwise asking for a RecordSizeLimit of 2048 might produce
fragmentation, which leads to another fragment_length-induced handshake
failure if your guess at what to send is wrong.

Peter.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 17 Mar 2017 21:57:08 +1100

> max_fragment_length is defined, would anyone care?

This is apparently a big deal for people building little things with
TLS in them.  Hannes knows better than I do.  On the web, this
extension basically doesn't exist (for the aforementioned reasons, in
part, also because browsers historically didn't much for servers and
their resource constraints).

> stacks did, given the complexity and extra memory use that this adds).

TLS 1.3 has an issue here in that it encrypts handshake messages, and
that includes the worst offender (Certificate).  You might not care
about 1.3, but I think that handshake fragmentation is just something
implementations will need to deal with there.

Plaintext records don't have any such limits.  I explicitly excluded
them.  That means that TLS 1.2 implementations shouldn't be affected.
Well, unless they wanted to send massive messages after the handshake
completes.  Renegotiation would do that, of course, so don't do that.

---

From: Peter Gutmann <[email-masked]>
Date: Fri, 17 Mar 2017 11:21:12 +0000

Martin Thomson <[email-masked]> writes:

>Plaintext records don't have any such limits.  I explicitly excluded them.

Hmm, it's somewhat disguised in the text, technically all records are
"protected records" (if you use EMS, everything is at least integrity-
protected).  So if you mean "this only applies to application_data" then you
should probably say so (alerts and CCS are too short for it to matter, and I'm
assuming no rehandshake, so only application_data will be affected by the
length constraints).

However, this then leads to a problem where it doesn't actually solve the
constrained-client/server issue, if a client asks for 2K max record size and
the server responds with a 4K hello then it's going to break the client even
if later application_data records are only 2K.  So it would need to apply to
every record type, not just application_data.

Peter.

---

From: Thomas Pornin <[email-masked]>
Date: Fri, 17 Mar 2017 14:33:44 +0100

On Fri, Mar 17, 2017 at 11:21:12AM +0000, Peter Gutmann wrote:
> However, this then leads to a problem where it doesn't actually solve
> the constrained-client/server issue, if a client asks for 2K max
> record size and the server responds with a 4K hello then it's going to
> break the client even if later application_data records are only 2K.
> So it would need to apply to every record type, not just
> application_data.

Hello,

I had tried to raise the same issues here, a few months ago. The
max_frag_length extension, as currently defined in RFC 6066, has the
following issues:

  - It is client-driven:

    ** The server cannot send the extension unless the client has
       sent it first.

    ** Even if the client sent the extension, the only option for the
       server is to respond with an extension advertising the very
       same length. The server has no option to negotiate a smaller
       maximum fragment length.

  - "Big" clients (Web browsers) don't support it and have no incentive
    to do so, since they, as client, can totally use huge records,
    which are negligible with regards to the dozens of megabytes they
    eat up just for starting up.

  - The extension mandates the same size constraint on both directions.
    A constrained implementation may have two separate buffers for
    sending and receiving, and these buffers need not have the same size.
    In fact, in dedicated specific situations, records larger than the
    output buffer may be sent (the sender must know in advance how many
    bytes it will send, but it can encrypt and MAC "on the fly").

Fragmentation of messages is another issue, which is correlated but
still distinct. Note for instance that it is customary, in the case of
TLS 1.0 with a CBC-based cipher suite, to fragment _all_ records
(application data records, at least) as part of a protection against
BEAST-like attacks. Also, having very small buffers does not necessarily
prevent processing larger handshake messages, or even larger unencrypted
records. Here I may point at my own SSL implementation (www.bearssl.org)
that can do both: it supports unencrypted records that are larger than
its input buffer, and it supports huge handshake messages. It can
actually perform rudimentary X.509 path validation even with
multi-megabyte certificates, while keeping to a few kilobytes of RAM and
no dynamic allocation.

Now that does not mean that a "don't fragment" flag has no value.
Indeed, streamed processing of messages is not easy to implement (I
know, since I did it), and having some guarantees on non-fragmentations
may help some implementations that are very constrained in ROM size and
must stick to the simplest possible code. But it still is a distinct
thing. Moreover, maximum handshake message length needs not be the same
as the maximum record length. For instance, OpenSSL tends to enforce a
maximum 64 kB size on handshake messages. Maybe we need a "maximum
handshake message length" extension.

In order to "fix" RFC 6066, the following would be needed, in my opinion:

  - Allow the server to send the extension even if the client did not
    send it.

  - Allow the server to mandate fragment lengths smaller than the
    value sent by the client (a client not sending the extension would
    be assumed to have implicitly sent an extension with a 16384-byte
    max fragment length).

  - Preferably, change the encoding to allow for _two_ lengths, for
    both directions, negociated separately.

  - Preferably, write down in TLS 1.3 that supporting the extension is
    mandatory. Otherwise, chances are that Web browsers won't
    implement it anyway.

I can prototype things in BearSSL (both client and server).

	--Thomas Pornin

---

From: Ilari Liusvaara <[email-masked]>
Date: Fri, 17 Mar 2017 15:40:15 +0200

> assuming no rehandshake, so only application_data will be affected by the

I think Martin said the only case where this special case comes into play
is renegotiation?
 
> every record type, not just application_data.

I don't think responding with 2k ServerHello is even possible in TLS
1.3 as defined. Even group 260 would push the size slightly above 1k
And I don't think 1k is even reachable without that group.

In fact, in TLS 1.3, all messages except Certificate ones are likely to
be under 2k (or 1k). Of course, multiple can be combined into a record.

TLS 1.2 ServerHellos can be larger, but this is mostly connected with
certain extensions, like signed_certificate_timestamp. There are also
some messages that can be bit bigger, like certificate_status or
server_key_exchange.

-Ilari

---

From: Ilari Liusvaara <[email-masked]>
Date: Fri, 17 Mar 2017 16:44:48 +0200

> handshake message length" extension.

The TLS implementation I did has 128kB limit. Also, unfragmented
handshake messages are subject to zerocopy processing. No
streaming processing.

The mere thought of someone implementing streaming processing in
C scares me. I think BearSSL autogenerates that code.

Also, in TLS 1.3, certificate messages are considerably more
complicated. I don't think streaming processing of recommended-to-
support stuff is even possible.

My own implementation won't implement all of that, but the parts
it implements (still took a few security issues because of the
complexity beyond what TLS 1.2 REQUIRED) still require considerable
back and forth. Most of the memory is borrowed from the message, but
still not streamable.

>   - Allow the server to send the extension even if the client did not

TLS architecture does not allow this. Sending any extension in server
hello that wasn't in client hello causes loads of implementations to
just blow up (my implementation is certainly one of those). In fact,
clients are REQUIRED to.

>     be assumed to have implicitly sent an extension with a 16384-byte

I think allowing server to give lower limit for client records was
one of the key improvments over max_record_length.

I also think with the proposed extension, client could send 4096 and
server could send 16384. Meaning server->client only supports records
up to 4096, but client->server supports records of any size.

>     both directions, negociated separately.

You mean maximum handshake message size and maximum record size?

-Ilari

---

From: Hannes Tschofenig <[email-masked]>
Date: Fri, 17 Mar 2017 16:01:47 +0100

Here are my 5 cents: we implement this extension in our mbed TLS stack
and we consider it quite important for IoT devices that have limited
amount of RAM. The DTLS/TLS profiles for IoT RFC also recommends the use
of this extension and we discussed this in the DICE WG and there was no
objection against the recommendation.

We had also suggested to extend this functionality to make it symmetric
(i.e., both the client and the server can indicate that they are facing
memory restrictions). Currently, only the TLS client can indicate his
restrictions with the max fragment length extension.

We do, however, understand that this is not an extension that is very
useful for generic Internet devices since they are typically not
suffering from the same constraints.

Ciao
Hannes

---

From: Hannes Tschofenig <[email-masked]>
Date: Fri, 17 Mar 2017 16:04:14 +0100

Hi Martin,

we suggested it in Section 6 of
https://tools.ietf.org/html/draft-fossati-tls-iot-optimizations-00 and
Thomas also made a proposal in the same direction not too long ago as
well, see https://www.ietf.org/mail-archive/web/tls/current/msg22058.html

Ciao
Hannes

---

From: Hannes Tschofenig <[email-masked]>
Date: Fri, 17 Mar 2017 16:14:01 +0100

> their resource constraints).

In addition to us (mbedTLS) also WolfSSL implements the maximum fragment
length extension. According to their website their embedded TLS stack is
used in more than 2 billion devices.

MatrixSSL also supports this extension.

There may be other embedded TLS stacks supporting it but the complete
list of features is not always accessible on the websites of the vendors.

Ciao
Hannes

---

From: Thomas Pornin <[email-masked]>
Date: Fri, 17 Mar 2017 16:37:59 +0100

> C scares me. I think BearSSL autogenerates that code.

Yes, actual code is in a custom Forth dialect, which is compiled to
token-threaded code executed by a C interpreter. That's because if you
want to implement streamed processing sanely in an imperative language
(like C), then you basically need coroutines, i.e. the ability to
interrupt the processing, and later on jump back to the processing. You
cannot do that in plain C if you have function calls and thus a "call
stack" to save and recover (and if you do not, then the code becomes
insanely unreadable). You _could_ make a custom stack, but this is
expensive (since the C compiler tends to create local variables at will,
a custom stack would need at least 1 or 2 kB of extra RAM) and it is
awfully non-portable.

> support stuff is even possible.

Streaming processing is ill-supported and on the decline. E.g. even with
TLS 1.2, EdDSA-signed certificates cannot be processed with streaming,
because the hash function computation over the to-be-signed must begin
with hashing the 'R' element (which is part of the signature, and occurs
_after_ the TBS) and the 'A' value (the signer's public key, which is
found in the signer's certificate, that comes _after_ the current
certificate in TLS 1.2 Certificate message).

Since TLS 1.3 also mandates some options that may require considerable
buffering (e.g. the cookies and the session tickets, both ranging up to
64 kB), one might say that, as an evolving standard, TLS 1.3 is moving
away from the IoT/embedded world, and more toward a Web world. This is
not necessarily _bad_, but it is likely to leave some people unsatisfied
(and, in practice, people clinging to TLS 1.2).

> just blow up (my implementation is certainly one of those). In fact,

I know. BearSSL also rejects server extension that do not match client
extensions. It also rejects attempts by the server at trying to
negotiate a different maximum fragment length. It does so because the
RFC says so (even though I agree with Peter that the standard behaviour
is of questionable usefulness).

> You mean maximum handshake message size and maximum record size?

I mean a maximum record size for records sent by the client to the
server, _and_ a maximum record size for records sent by the server to
the client. Since any implementation may use distinct buffers for
sending and for receiving(*), the two sizes need not match.

(*) In particular, if you want to support HTTPS, where pipelining
requests is allowed, an HTTPS-aware server more or less needs to
have two distinct buffers for input and output.

	--Thomas

---

From: Ilari Liusvaara <[email-masked]>
Date: Fri, 17 Mar 2017 19:02:28 +0200

> (and, in practice, people clinging to TLS 1.2).

Cookies can indeed be quite large and are required. I don't think
session tickets are required (the implementation I did just throws
those to trash).

> sending and for receiving(*), the two sizes need not match.

Ah, I implemented version of record_size_limit extension (grabbing
codepoint 0x1053). The value sent is always 16384, but the value
received can be different.

-Ilari

---

From: Peter Gutmann <[email-masked]>
Date: Sat, 18 Mar 2017 07:35:42 +0000

Thomas Pornin <[email-masked]> writes:

>having some guarantees on non-fragmentations may help some implementations
>that are very constrained in ROM size and must stick to the simplest possible
>code.

It's not the code size, it's attack surface.  There have been endless attacks
on IP fragmentation and fragment reassembly, not to mention equally numerous
firewall/IDS bypasses by creative fragmentation.  So in my case not doing
fragmentation is a security thing, not a code-size thing (as was not doing
rehandshake, compression, and a pile of other things that have caused problems
in SSL/TLS in the past).

The fact that I've never encountered any embedded/SCADA device that handles or
requires fragmentation makes it ever easier.

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Sat, 18 Mar 2017 07:38:19 +0000

Ilari Liusvaara <[email-masked]> writes:

>In fact, in TLS 1.3, all messages except Certificate ones are likely to be
>under 2k (or 1k).

OK, in that case make the max message size 1K, or 512 bytes, or whatver you
need.

Also, TLS 1.3 as it currently stands, in a pre-standard draft, may have
messages under 2K or whatever, but so did SSL in its day.  Give it time and
it'll be bloated up with 200 extensions and 500 cipher suites just like TLS
is.

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Sat, 18 Mar 2017 07:40:19 +0000

Hannes Tschofenig <[email-masked]> writes:

>Here are my 5 cents: we implement this extension in our mbed TLS stack and we
>consider it quite important for IoT devices that have limited amount of RAM.
>The DTLS/TLS profiles for IoT RFC also recommends the use of this extension
>and we discussed this in the DICE WG and there was no objection against the
>recommendation.

Do you have a server that implements this online anywhere for interop
purposes?  I've had it implemented but commented out pretty much forever, it'd
be useful to have something to test against.

Peter.

---

From: Nitin Shrivastav <[email-masked]>
Date: Thu, 16 Mar 2017 16:52:47 -0400

It would be nice to provide a mechanism for servers to do this as we are
trying to run a web server in a constrained IoT end-points with only tens
of KBytes of RAM and SSL/TLS based connection is important..

---

From: "Sheehe, Charles J. (GRC-LCA0)" <[email-masked]>
Date: Mon, 20 Mar 2017 12:00:56 +0000

Hi

I agree that this would be a benefit to bandwidth restricted channels as well.

Thanks
Chuck  

Charles J. Sheehe III
Electronics Engineer
Glenn Research Center
21000 Brookpark Rd
Cleveland, OH 44135
[email-masked]
Office: 216-433-5179

"Science is the belief in the ignorance of the experts" – Richard Feynman
What you do makes a difference and you have to decide what kind of difference you want to make.

-----Original Message-----
From: TLS [mailto:[email-masked]] On Behalf Of Nitin Shrivastav
Sent: Thursday, March 16, 2017 4:53 PM
To: Yoav Nir <[email-masked]>
Cc: [email-masked]
Subject: Re: [TLS] RFC 6066 - Max fragment length negotiation

On Thu, Mar 16, 2017 at 4:48 PM, Yoav Nir <[email-masked] <mailto:[email-masked]> > wrote:

	Hi, Nitin.

	Yoav

		On 16 Mar 2017, at 21:12, Nitin Shrivastav <[email-masked] <mailto:[email-masked]> > wrote:

		Hello,

		Thanks,
		Nitin

---

From: Thomas Pornin <[email-masked]>
Date: Tue, 21 Mar 2017 14:15:14 +0100

> I'll submit an I-D once the blackout ends if people are interested in this.

I like this proposal. One comment, though: I think the wording in
section 4 should mandate that the value sent MUST NOT exceed the maximum
record size -- i.e. if an implementation supports records up to 16384
bytes, then it should put 16384 here, not a bigger value suc as 65535.

Rationale: last time this was discussed on this list, some people
expressed the wish to ultimately support records with more than 16384
bytes of plaintext. If such an extension ever comes to fruition (it is
certainly easy enough to do with CBC and GCM cipher suites), then
sending a record_size_limit with a limit of, say, 60000 bytes, would
serve as indication that the implementation indeed supports such larger
records. This holds only as long as no implementation sends a value
larger than 16384 if it does not really accept records of more than
16384 bytes.

Therefore, I propose to replace this paragraph:

    An endpoint that has no limit on the size of data they receive can
    set this value to any value equal to or greater than the maximum
    possible record size, such as 65535. A larger value does not allow
    the endpoint to send larger records than the protocol permits. An
    endpoint that receives a value larger than the maximum defined in
    the protocol MUST NOT exceed protocol-defined limits. For TLS 1.3
    and earlier, this limit is 2^14 octets.

with the following:

    An endpoint that supports all sizes that comply with the
    protocol-defined limits MUST send exactly that limit as value for
    maximum record size (or a lower value). For TLS 1.3 and earlier,
    that limit is 2^14 octets. Higher values are currently reserved for
    future versions of the protocol that may allow larger records; an
    endpoint MUST NOT send a value higher than 2^14 unless explicitly
    allowed by such a future version and supported by the endpoint.

    When an endpoint receives a maximum record size limit larger than
    the protocol-defined limit, that end point MUST NOT send records
    larger than the protocol-defined limit, unless explicitly allowed by
    a future TLS version.

Of course, larger-than-16384 records are not meant for constrained
systems, but for big systems. Overhead for 16384-byte records with
ChaCha20+Poly1305 is 21 bytes (for AES/GCM in TLS 1.2, this is 29
bytes), i.e. less than 0.2%, which seems small enough to me; but there
still is some demand for larger records, so it makes sense not to
prevent them from ever happening with tighter wording.

---------------

Another point which was made is that CBC cipher suites have a
variable-length padding, up to 256 bytes (length byte + padding), which
is not fully negligible: an endpoint with a 500-byte buffer would have
to send a "maximum record size" of 223 bytes only, in order to fully
support AES/CBC+HMAC/SHA-256 in all cases, while in practice most if not
all endpoints will stick to minimal-sized paddings. Maybe there should
be some extra wording saying that when a "maximum record size" was
received, with a value less than the protocol-defined limit, then an
endpoint SHOULD strive to use minimal-sized padding in cipher suites
that have a variable-sized padding. Or maybe something more convoluted
that says:

    An endpoint MUST NOT generate a protected record with plaintext
    larger than the RecordSizeLimit value received from its peer. An
    endpoint MUST NOT either generate a protected record such that the
    encrypted record length (TLSCipherText.length) exceeds the length of
    the smallest possible encrypted record that would contain exactly as
    many plaintext bytes as the received RecordSizeLimit value, in the
    currently active cipher suite.

This would be only for the benefit of CBC cipher suites with TLS 1.2 and
earlier, not for TLS 1.3, because recent AEAD cipher suites have
predictable (and small) overhead.

Arguably, pre-TLS-1.3 versions also have problem with compression, which
should be in all generality avoided, just like CBC cipher suites should
also be avoided. Maybe this is not a problem after all, and constrained
systems that are recent enough to implement this new extension will also
"naturally" avoid CBC cipher suites anyway. (In any case, if an endpoint
requires small records, then it cannot really talk with peers that don't
support the proposed maximum_record_size extension, so it needs recent
implementations that _should_ already implement at least TLS 1.2 and
some AEAD cipher suites.)

	--Thomas Pornin

---

From: Peter Gutmann <[email-masked]>
Date: Tue, 21 Mar 2017 13:32:06 +0000

Thomas Pornin <[email-masked]> writes:

>Maybe there should be some extra wording saying that when a "maximum record
>size" was received, with a value less than the protocol-defined limit, then
>an endpoint SHOULD strive to use minimal-sized padding in cipher suites that
>have a variable-sized padding.

I'd earlier thought of suggesting that the record length be the ciphertext
length, not the plaintext length, but wasn't sure if there'd be much support
for it.  It would however certainly make the required calculations easier,
since you no longer have to figure out what the potential size could be once
you've added the MAC size, padding, and anything else that needs to go in,
particularly since some of those factors are variable-length, leading to
guesswork as to what you need to specify since some of the parameters won't be
fixed at the time you ask for record size X.

Peter.

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Tue, 21 Mar 2017 14:50:33 +0100

>     larger than the protocol-defined limit, unless explicitly allowed

I support this proposal. It actually prevents re-introducing a
limitation which can hamper a future modification of the scope of this
extension.

regards,
Nikos

---

From: Martin Thomson <[email-masked]>
Date: Wed, 22 Mar 2017 10:51:20 +1100

Thanks Thomas, inline responses.

>     larger than the protocol-defined limit, unless explicitly allowed by

Added, tweaked a little:
https://github.com/martinthomson/tls-record-limit/commit/62a5ef2306c123394b4045913b81aee9f529dd90

(My original thought was that perhaps we could keep this orthogonal to
any potential extension that tweaked the maximum size, but this has
the same effect with less ugliness.)

> prevent them from ever happening with tighter wording.

Note that the main reason cited for having larger records is not the
size overhead (as you say, that's negligible), but the processing
overheads associated with processing each record.  Willy Tarreau gave
a great presentation at a workshop a while ago showing how moving
between different layers of his stack had a material effect on
performance.  Larger records means doing any per-record processing
less often.

> that have a variable-sized padding.

Yeah, the hazard there is that they don't minimally pad and then you
have no real recourse if you haven't reserved space for the extra
padding.  If you are going to do that, you need to make it a MUST I
think.

I didn't want to do this, because it's basically a prohibition on any
sort of padding-for-traffic-analysis-resistance (lame though it might
be).

So we have a trade-off.  I think that your suggestion is probably OK,
though that means making the limitation obvious.

> predictable (and small) overhead.

Well, in TLS 1.3 any padding is counted, so requiring minimal padding
at the cipher level would be possible even if the cipher required some
padding.

> some AEAD cipher suites.)

Yes, I think that I ultimately decided that I didn't care enough to
solve this problem for block ciphers and I would let someone who cared
about them propose the solution that best suits them.

---

From: Martin Thomson <[email-masked]>
Date: Wed, 22 Mar 2017 10:58:56 +1100

On 22 March 2017 at 00:32, Peter Gutmann <[email-masked]> wrote:
> for it.

Yep, you thought right.  I considered the same thing, investigated
what it would take to implement and found that it would be awful.  The
code that deals with record splitting doesn't know anything about the
specific cipher suite right now.  It would have to be taught about the
expansion, because without that information it would potentially send
a packet for encryption and then discover that it got too big in the
process and start over.  When compression is enabled, I can't imagine
what it would do.

Implementing a limit on pre-encryption data turns out to be pretty
trivial, because you change a constant (2^14) into a variable
(record_size_limit).

You are right that choosing the encrypted size makes setting the value
easier, but that moves the effort to the wrong place.  The constrained
device is the one that cares about this, so it can be the one to spend
the effort choosing the right value.  Move the effort somewhere else
and you will find that fewer non-constrained devices will bother
implementing the extension.

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 21 Mar 2017 17:09:29 -0700

On Tue, Mar 21, 2017 at 4:58 PM, Martin Thomson <[email-masked]>
wrote:

> what it would take to implement and found that it would be awful.

I don't feel strongly about this, but...

> The
> process and start over.

Couldn't you just use the maximum expansion you support (which
ought to be 16 for TLS 1.3).

> When compression is enabled, I can't imagine
>
what it would do.

I feel like we could ignore this, and just say "don't do compression"

 -Ekr

---

From: Martin Thomson <[email-masked]>
Date: Wed, 22 Mar 2017 11:44:03 +1100

> ought to be 16 for TLS 1.3).

That leads to the same problem that we're trying to avoid, namely that
your usable space goes through the floor.

> I feel like we could ignore this, and just say "don't do compression"

Already done, in the spec.  But not the code :(

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 21 Mar 2017 18:01:49 -0700

> your usable space goes through the floor.

I'm not quite sure I'm following. In the extension we say "You can send up
to X bytes"
and X can either be expressed in plaintext or ciphertext bytes. If we
express it
in ciphertext, then senders can totally safely marshall up to X - E_max
bytes of plaintext
where E_max is the maximum expansion of any cipher suite they support.

The maximum amount of wastage in this case is E_max - E_min where E_min is
the minimum amount of expansion of any cipher suite they support. If E_min
== E_max,
then this is fine (because you can just advertise X + E_max to hit a target
of X).

What am I missing?

-Ekr

---

From: Martin Thomson <[email-masked]>
Date: Wed, 22 Mar 2017 13:03:58 +1100

On 22 March 2017 at 12:01, Eric Rescorla <[email-masked]> wrote:
> the minimum amount of expansion of any cipher suite they support.

Right, I was concerned about the case where this difference is
(potentially) large.  That's all.

The main problem I see with a design that shifts complexity to the
sender is the economic one.  I want to provide as much incentive to
implement the sender side of this as possible, which means keeping it
simple.  If the cost of that is a little more complexity on receivers,
but only when using block ciphers, I think that I can live with that.
Given that the complexity is likely more in logic than it is code,
then I'm even more happy with what I've proposed.

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 21 Mar 2017 19:53:18 -0700

> then I'm even more happy with what I've proposed.

Sure, I don't think I really care, I just wanted to understand your
reasoning.

-Ekr

---

From: Peter Gutmann <[email-masked]>
Date: Wed, 22 Mar 2017 02:55:29 +0000

Thomas Pornin <[email-masked]> writes:

>TLS 1.3 is moving away from the IoT/embedded world, and more toward a Web
>world. This is not necessarily _bad_, but it is likely to leave some people
>unsatisfied (and, in practice, people clinging to TLS 1.2).

I would go slightly further and say that TLS 1.3 could end up forking TLS in
the same way that HTTP/2 has forked HTTP.  There's HTTP/2 for web content
providers and HTTP 1.1 for the rest of us/them (depending on your point of
view).  Similarly, there are sizeable groups of users who will take a decade
or more to get to TLS 1.3 (they're still years away from 1.2 at the moment),
or who may never move to TLS 1.3 because too much of their existing
infrastructure is dependent on how TLS 1.x, x = 0...2, works.  So as with
HTTP/2 we may end up with TLS 1.3 for web content providers and TLS 1.0/1.2
for everything else.

Peter.

---

From: [email-masked] (Martin Rex)
Date: Wed, 22 Mar 2017 22:06:06 +0100 (CET)

> HTTP/2 we may end up with TLS 1.3 for web content providers and TLS 1.0/1.2

I expect TLSv1.3 is going to be in a decade where IPv6 is today.

Not supporting IPv4 is a non-starter, because you can not reach
95% of the internet, and not even get internet connectivity in a
lot of places.

Not supporting IPv6 is paradise: less code, less headaches, less
interop problems, less security issues, and you will _not_ miss anything
at all, because everything that is at least remotely interesing,
is accessible via IPv4.

-Martin

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 23 Mar 2017 00:11:35 +0000

>I expect TLSv1.3 is going to be in a decade where IPv6 is today.

It'll be interesting to see.  This certainly seems to be true for HTTP/2
a.k.a. HTTP4Google, I was expecting usage to be mostly Google-only but from
the little data I could find it appears to be even worse than that:

https://trends.builtwith.com/docinfo/HTTP2

0.1% uptake is effectively zero adoption after two years, so this does seem to
parallel IPv6.

>Not supporting IPv4 is a non-starter, because you can not reach 95% of the
>internet, and not even get internet connectivity in a lot of places.

Yeah, good point (as an analogy for TLS).  It'll be interesting to see where
things are in a year or two.  Certainly 1.2 will be around forever, and by
that I don't mean "a while, until 1.3 gets deployed", but forever.  TLS 1.0 is
already proving scarily long-lived.

The one good thing about (almost) everyone fixating on TLS 1.3 is that it's
been possible to develop and in some cases already deploy LTS in peace, so
it's ended up doing what the target audience requires without lots of
unnecessary bells and whistles added.

Peter.