Subject: [TLS] Record header size?

From: "Short, Todd" <[email-masked]>
Date: Tue, 17 Nov 2015 15:25:18 +0000

Apologies if this has been brought up before.

Has there been any consideration to changing the record header for encrypted traffic to be 4 bytes (i.e. 32-bits)? 5 bytes is a very awkward size, and some processors do not handle odd byte offsets well (it was a complaint I heard from Cisco router/switch engineers).

The latest TLS1.3 draft indicates that the record_version is deprecated and must be ignored. If TLSv1.3 is negotiated, then I propose that the record_version value must be { 4 } for encrypted records, making the version field is a single byte, such that the length of the record_header is reduced to 4 bytes.

Alternatively, a TLS extension could be added to negotiate the size of the record_header.

Yes, this creates a serious backwards compatibility issue, but if the record_version field is deprecated, then perhaps a change to the record_header could be made.

Thus:

   struct {
       uint8 major;
       uint8 minor;
   } ProtocolVersion;

   struct {
       ContentType type;
       ProtocolVersion record_version = { 3, 1 };    /* TLS v1.x */
       uint16 length;
       opaque fragment[TLSPlaintext.length];
   } TLSPlaintext;

   struct {
       ContentType opaque_type = application_data(23); /* see fragment.type */
       uint8 record_version = { 4 };    /* TLS v1.3 4-byte record header */
       uint16 length;
       aead-ciphered struct {
          opaque content[TLSPlaintext.length];
          ContentType type;
          uint8 zeros[length_of_padding];
       } fragment;
   } TLSCiphertext;

--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

---

From: Peter Gutmann <[email-masked]>
Date: Tue, 17 Nov 2015 15:40:56 +0000

Short, Todd <[email-masked]> writes:

>Has there been any consideration to changing the record header for encrypted
>traffic to be 4 bytes (i.e. 32-bits)? 5 bytes is a very awkward size, and
>some processors do not handle odd byte offsets well (it was a complaint I
>heard from Cisco router/switch engineers).

Not just Cisco, other hardware people have run into it as well.  You don't
need the version field at all because it's been negotiated in the handshake,
for the remainder of the session it's just wasted bytes.  So having a 1-byte
type and 3-byte length for a combined 32-bit field would work fine.

Peter.

---

From: "Short, Todd" <[email-masked]>
Date: Tue, 17 Nov 2015 16:35:50 +0000

Plaintext is still limited to 2^14 octets, so there is no need to have the length be 3 bytes. Having the version start with 4 will purposely indicate the size of the record header. One could go out on a limb and use it to actually indicate the length of the header (i.e. 5 bytes, 4 bytes, 8 bytes, etc.) with additional options thrown in, not that I am proposing that.
--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

On Nov 17, 2015, at 10:40 AM, Peter Gutmann <[email-masked]<mailto:[email-masked]>> wrote:

Short, Todd <[email-masked]<mailto:[email-masked]>> writes:

Peter.

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 17 Nov 2015 09:09:30 -0800

The concern here is backward compatibility with inspection middleboxes which
expect the length field to be in a particular place. We agreed in Seattle to
wait for early deployment experience before modifying the header to move
the length.

-Ekr

On Tue, Nov 17, 2015 at 7:25 AM, Short, Todd <[email-masked]> wrote:

> Has there been any consideration to changing the record header for
> encrypted traffic to be 4 bytes (i.e. 32-bits)? 5 bytes is a very awkward
> size, and some processors do not handle odd byte offsets well (it was a
> complaint I heard from Cisco router/switch engineers).
>
> The latest TLS1.3 draft indicates that the record_version is deprecated
> and must be ignored. If TLSv1.3 is negotiated, then I propose that the
> record_version value must be { 4 } for encrypted records, making the
> version field is a single byte, such that the length of the record_header
> is reduced to 4 bytes.
>
> Yes, this creates a serious backwards compatibility issue, but if the
> record_version field is deprecated, then perhaps a change to the
> record_header could be made.
>
> Thus:
>
>    struct {
>        uint8 major;
>        uint8 minor;
>    } ProtocolVersion;
>
>    struct {
>        ContentType type;
> // [email-masked]
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>
>

---

From: Daniel Kahn Gillmor <[email-masked]>
Date: Tue, 17 Nov 2015 15:45:53 -0500

> wait for early deployment experience before modifying the header to move

In particular, if we're going to make a change to the TLS record header,
the change would be to remove the version and the type entirely, leaving
only two octets of length on each record.  Is a two-octet offset going
to be problematic?

         --dkg

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 17 Nov 2015 12:50:28 -0800

Indeed. It doesn't seem useful to carry around two fixed bytes
for alignment reasons

-Ekr

On Tue, Nov 17, 2015 at 12:45 PM, Daniel Kahn Gillmor <[email-masked]
> wrote:

---

From: "Short, Todd" <[email-masked]>
Date: Tue, 17 Nov 2015 20:59:11 +0000

I would say that 32-bits would be optimal, since that is the typical word-size of processors that need alignment. 2-bytes isn’t much better than 5-bytes in this regard.
--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

On Nov 17, 2015, at 3:45 PM, Daniel Kahn Gillmor <[email-masked]<mailto:[email-masked]>> wrote:

        --dkg

---

From: Eric Rescorla <[email-masked]>
Date: Tue, 17 Nov 2015 13:09:39 -0800

Can you expand on the alignment issues some more?

Thinking through how typical software stacks work, you first read
the record header into some buffer to figure out how long the record
is and then you read the record payload into a buffer, which may
not even be the same buffer. For instance, in NSS, there are
two buffers, one for the header and one for the body:

https://dxr.mozilla.org/mozilla-central/source/security/nss/lib/ssl/ssl3gthr.c#53
https://dxr.mozilla.org/mozilla-central/source/security/nss/lib/ssl/sslimpl.h#377

In a system like this, there's nothing stopping the body from being 4-byte
aligned, whatever the alignment of the header is. I'd be interested in
hearing
about the design you have in mind.

-Ekr

On Tue, Nov 17, 2015 at 12:59 PM, Short, Todd <[email-masked]> wrote:

> I would say that 32-bits would be optimal, since that is the typical
> word-size of processors that need alignment. 2-bytes isn’t much better than
> 5-bytes in this regard.
> --
> -Todd Short
> // [email-masked]
> On Nov 17, 2015, at 3:45 PM, Daniel Kahn Gillmor <[email-masked]>
> wrote:
>

---

From: "Short, Todd" <[email-masked]>
Date: Tue, 17 Nov 2015 21:26:57 +0000

Eric,

To be honest, it’s always kinda bugged me that SSL/TLS uses a 5-byte header, coming from my embedded network system background.

I’ve had dealings with cryptographic hardware (SafeNet at Altiga, and Cavium Nitrox at Cisco), and they have to go through hoops to deal with unaligned access. The Cavium Nitrox chip is able to do TLS record processing on it’s own (it’s not just simple crypto), and network processors like aligned data.

Embedded systems don’t have the luxury of mbuf-type of buffer scheme (as you describe for NSS). Many have ethernet-frame sized buffers in locked/pinned memory that read in a whole ethernet frame, and then strip off headers by advancing pointers into the frame. This minimizes copies, and the goal is to have a zero-copy network stack. Once the 5-byte TLS header is reached, the data to be decrypted is no longer aligned, and this requires handling unaligned access, or copying the memory to an aligned buffer; both of which hurt performance. If the cryptography is to be offloaded to a co-processor, depending on the chip, the encrypted portion must be aligned, and thus must be copied.

This is a common architecture for Cisco IOS, Catalyst and other high-performance routers and VPN servers (e.g. Cisco ASA).

Other references regarding aligned vs. unaligned:

While this reference is old (~6 years), this guy tested aligned vs. unaligned access on Intel x86 architecture, and found that there was a difference in performance.

http://www.alexonlinux.com/aligned-vs-unaligned-memory-access

Intel recommends data alignment in structures (which is basically what a record_header is) for performance/cache reasons:

https://software.intel.com/en-us/articles/coding-for-performance-data-alignment-and-structures

Old Reference from IBM (2005) regarding aligned vs. unaligned access:

http://www.ibm.com/developerworks/library/pa-dalign/

So while RISC processors suffer the most from unaligned data, x86 processors can suffer from performance issues as well.

On Nov 17, 2015, at 4:09 PM, Eric Rescorla <[email-masked]<mailto:[email-masked]>> wrote:

https://dxr.mozilla.org/mozilla-central/source/security/nss/lib/ssl/ssl3gthr.c#53<https://urldefense.proofpoint.com/v2/url?u=https-3A__dxr.mozilla.org_mozilla-2Dcentral_source_security_nss_lib_ssl_ssl3gthr.c-2353&d=CwMFaQ&c=96ZbZZcaMF4w0F4jpN6LZg&r=QBEcQsqoUDdk1Q26CzlzNPPUkKYWIh1LYsiHAwmtRik&m=lkp-Abz8z3roFbGavfNCWmtzPXMDjErHNGNHTxYBzh4&s=p38_5XK14ePbhLx1x1rLlrxoFuOENyPWGV68GFYZgnY&e=>
https://dxr.mozilla.org/mozilla-central/source/security/nss/lib/ssl/sslimpl.h#377<https://urldefense.proofpoint.com/v2/url?u=https-3A__dxr.mozilla.org_mozilla-2Dcentral_source_security_nss_lib_ssl_sslimpl.h-23377&d=CwMFaQ&c=96ZbZZcaMF4w0F4jpN6LZg&r=QBEcQsqoUDdk1Q26CzlzNPPUkKYWIh1LYsiHAwmtRik&m=lkp-Abz8z3roFbGavfNCWmtzPXMDjErHNGNHTxYBzh4&s=sxL_eMfoN0otMi3nYvGkzcIdwM-orYF6xwF3POGP4DI&e=>

In a system like this, there's nothing stopping the body from being 4-byte aligned, whatever the alignment of the header is. I'd be interested in hearing
about the design you have in mind.

-Ekr

On Tue, Nov 17, 2015 at 12:59 PM, Short, Todd <[email-masked]<mailto:[email-masked]>> wrote:
I would say that 32-bits would be optimal, since that is the typical word-size of processors that need alignment. 2-bytes isn’t much better than 5-bytes in this regard.
--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

        --dkg

---

From: Viktor Dukhovni <[email-masked]>
Date: Tue, 17 Nov 2015 21:52:56 +0000

On Tue, Nov 17, 2015 at 09:26:57PM +0000, Short, Todd wrote:

> Embedded systems don�t have the luxury of mbuf-type of buffer scheme (as
> you describe for NSS). Many have ethernet-frame sized buffers in
> locked/pinned memory that read in a whole ethernet frame, and then strip
> off headers by advancing pointers into the frame. This minimizes copies,
> and the goal is to have a zero-copy network stack.

Right, both IP and TCP add padding after options to align the
payload on a 32-bit boundary.  So the TLS record layer always starts
at a 32-bit aligned address, which ensures that the record payload
is always misaligned.  Padding the record header with zeros to the
next multiple of 32-bits could plausibly improve the performance
of bare-metal zero-copy implementations.

-- 
	Viktor.

---

From: Peter Gutmann <[email-masked]>
Date: Wed, 18 Nov 2015 01:32:22 +0000

Eric Rescorla <[email-masked]> writes:

>expect the length field to be in a particular place.

Given that the rest of TLS 1.3 is going to break compatibility with pretty
much everything everywhere, I can't see this as a big concern, may as well fix
it at the same time as everything else is being changed.

Peter.

---

From: Peter Gutmann <[email-masked]>
Date: Wed, 18 Nov 2015 01:41:32 +0000

Short, Todd <[email-masked]> writes:

>To be honest, it’s always kinda bugged me that SSL/TLS uses a 5-byte header,
>coming from my embedded network system background.
>
>[...]

+1.  I wrote about this problem years ago in "Performance Characteristics of
Application-level Security Protocols",
https://www.cs.auckland.ac.nz/~pgut001/pubs/app_sec.pdf, see the section
"Interaction with Encryption Hardware" for more.  It doesn't name any names
since I could only use public sources, but was based on discussions with
hardware vendors.

Mind you, TLS is almost pleasant compared to the crazy calisthenics you have
to go through to deal with SSH data.  You basically can't do SSH's crypto
efficiently...

Peter.

---

From: Yoav Nir <[email-masked]>
Date: Wed, 18 Nov 2015 11:07:59 +0200

> On 18 Nov 2015, at 3:32 AM, Peter Gutmann <[email-masked]> wrote:
> 

Stateful firewalls tend to pass only what they understand. They use some measures to avoid tunneling and passing things that are not HTTPS over TCP port 443.

To achieve this, they run sanity checks on the traffic. They try to strike a balance between not getting circumvented and not dropping legitimate traffic. Sometimes they get it wrong. Sometimes they block legitimate but surprising stuff. As an example from 15 years ago, when Mac OS 9.2 came out, it sent data on the third packet of TCP (the ACK - last of the handshake packets). This is allowed by RFC, but was not done by any other platform. This failed the sanity checks of some firewalls, causing that traffic to be blocked. Two results of this event: we fixed our firewalls, but nobody (including Apple) does that anymore.

A sanity check on TLS might involve validating 5-byte record headers with sane length and version fields. A firewall might be out there that verifies this. This is the kind of thing that might be missed in testing, and we’ll only find out when some brave soul deploys TLS 1.3 in Chrome only to find out that it is blocked in 3% of the Internet.

Yoav

---

From: "Short, Todd" <[email-masked]>
Date: Wed, 18 Nov 2015 12:44:21 +0000

DPI, admittedly, is an expensive process that slows down traffic. DPI is even more expensive on a protocol such as TLS where the record headers aren't always in the same place in every packet. DPI is usually off by default on most firewalls. 

The problem you are more likely to encounter are TLS interception proxies that end up using only TLSv1.0 to authenticate a connection. 

Having this controlled by a TLS extension would at least give the client a modicum of control. (Oops, connection failed, let's try it again with a 3.1-compatible header.)

Also, having the "major" version number be 4, should indicate to these DPI engines that this is a new version of TLS, and should use new code or be ignored. Heck, the version in the handshake should be indicative of this.

I think the philosophy some people are going with, if we're going to break backwards compatibility, let's do it big time, so that we only have to do it once, and not make everyone play continuous catchup. 

> On Nov 18, 2015, at 4:09 AM, Yoav Nir <[email-masked]> wrote:
> 
>

---

From: Viktor Dukhovni <[email-masked]>
Date: Wed, 18 Nov 2015 15:24:22 +0000

> Stateful firewalls tend to pass only what they understand. They use some measures to avoid tunneling and passing things that are not HTTPS over TCP port 443.

If the record layer header for application-data (not the initial
handshak), is simply expanded by 3 bytes to 8 (zero padded), and
the padding is included in the record length, then to legacy parsers
it looks like a 5 byte header with payload that's 3 bytes longer.
While implementations aware of the change will treat this as a new
format in which the recorder header is 8 bytes and always overstates
the payload length by 3.

The real payload can then be properly aligned.

-- 
	Viktor.

---

From: "Short, Todd" <[email-masked]>
Date: Wed, 18 Nov 2015 15:30:04 +0000

Yes, that is true, and would accomplish the goals of backwards compatibility along with keeping (at least) 32-bit alignment.
Part of my non-stated goal was to also shrink the header, but *shrug*.

I still like the idea of marking it with a different version number (8.0)?
--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

On Nov 18, 2015, at 10:24 AM, Viktor Dukhovni <[email-masked]<mailto:[email-masked]>> wrote:

--
Viktor.

_______________________________________________
TLS mailing list
[email-masked]<mailto:[email-masked]>
https://www.ietf.org/mailman/listinfo/tls

---

From: [email-masked] (Martin Rex)
Date: Wed, 18 Nov 2015 21:52:29 +0100 (CET)

Yoav Nir wrote:
>> Peter Gutmann <[email-masked]> wrote:
>> 
>> much everything everywhere, I can't see this as a big concern, may
>> as well fix it at the same time as everything else is being changed.
> 
> A sanity check on TLS might involve validating 5-byte record headers
> with sane length and version fields. A firewall might be out there that
> verifies this.

The issue is much more about breaking _applications_ on top of TLS
by changing the existing 5-byte record header.  Padding the header
to 8 bytes (3 bytes into the original record body) would be OK, though.

With several TLS implementations it is possible to completely seperate
network communication (of the application) from the processing of
TLS records (performed by the TLS protocol stack).  For some TLS
implementations (e.g. Microsoft SChannel) this seems to be the only
possible mode of operation.

When I changed our (middlware SSL) application APIs from blocking to
non-blocking communication semantics a few years ago, I also moved the
entire network communication out to the middleware above the TLS protocol
stack, and only _full_ TLS records will ever get passed to the TLS library.
Everything that doesn't have the regular TLS record header will be
unconditionally rejected by the middleware above the TLS implementation.
I also use the content type to distinguish application data records from
handshake records to properly manage the half-duplex TLS handshake and the
resulting application-facing progress reporting.

Any changes to the TLS record layer will push support for TLSv1.3 easily
a decade into the future.  Padding the TLS record header to 8 bytes should
be OK and fully backwards compatible with such code, because the actual
processing of the TLS record body happens inside the TLS implementation only.

As far as alignment is concerned, some of the crypto hardware support
(such as Intels AESNI) might need 16-byte alignment.  Intel CPUs have
load instructions to load 16-bytes aligned (MOVDQA) or unaligned (MOVDQU)
into or between XMMx registers, and the amount of extra clock cycles
depends on the severity of the "misalignment".

https://software.intel.com/en-us/articles/reducing-the-impact-of-misaligned-memory-accesses

https://software.intel.com/en-us/forums/watercooler-catchall/topic/304126

-Martin

---

From: "Michael Gray" <[email-masked]>
Date: Thu, 19 Nov 2015 12:05:55 +1000

"TLS" <[email-masked]> wrote on 19/11/2015 06:52:29 AM:

> From: [email-masked] (Martin Rex)
> To: Yoav Nir <[email-masked]>
> Cc: "[email-masked]" <[email-masked]>
> Date: 19/11/2015 06:53 AM
> Subject: Re: [TLS] Record header size?
> Sent by: "TLS" <[email-masked]>
>
> Yoav Nir wrote:

We have the same kind of IO separation and I have observed a few times that
some products either interleave/multiplex TLS records with other
application data flow or route/buffer TLS traffic based on TLS record
header checking.  Padding the header to 8 bytes, as above, would probably
be OK.

-Mick

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 19 Nov 2015 02:17:25 +0000

> header checking.  Padding the header to 8 bytes, as above, would probably

Before we seriously consider going there, we should make sure that
this really addresses the problems that the hardware vendors
reputedly have.

Is it enough to pad just the application-data records (effectively
prepend 3-nul bytes to every application data record, and think of
it as either a longer record header, or initial data padding)?  Or
do the vendors in question need alignment of the handshake packets
too?  My guess is that changing the alignment of the handshake
packets would not be as useful, and would reduce interoperability
(confuse more middle-boxes).  But this guess could be wrong.

Can anyone definitively confirm the actual requirements?

-- 
	Viktor.

---

From: Peter Gutmann <[email-masked]>
Date: Thu, 19 Nov 2015 05:19:17 +0000

Short, Todd <[email-masked]> writes:

>I think the philosophy some people are going with, if we're going to break 
>backwards compatibility, let's do it big time, so that we only have to do 
>it once, and not make everyone play continuous catchup. 

Exactly.

I'm also not convinced by the middlebox argument, anything that does DPI is
going to be completely confused by the TLS 1.3 handshake which is nothing
like TLS 1.x, x < 3, so if middleboxes need to be upgraded to support the
1.3 handshake they can also support the 1.3 header format.

Peter.

---

From: [email-masked] (Martin Rex)
Date: Thu, 19 Nov 2015 10:38:16 +0100 (CET)

> Can anyone definitively confirm the actual requirements?

The padding issue was about inplace or hardware-based encryption/decryption
and would depends on whether the TLS record payload is encrypted (ciphertext)
or not (cleartext) -- the content type (handshake or app data) is irrelevant.
There is no need to pad cleartext TLS records (aka initial handshake
messages).

-Martin

---

From: "Short, Todd" <[email-masked]>
Date: Thu, 19 Nov 2015 12:08:06 +0000

Yes, this has to do with encrypted records. The non-encrypted handshake records are already hard enough to parse that the 5-byte header doesn’t mean much. I have worked on designs where the general-purpose processor handled the handshake and non-encrypted records, and a crypto co-processor handled the encryption.
--
-Todd Short
// [email-masked]<mailto:[email-masked]>
// "One if by land, two if by sea, three if by the Internet."

On Nov 19, 2015, at 4:38 AM, Martin Rex <[email-masked]<mailto:[email-masked]>> wrote:

Viktor Dukhovni wrote:

-Martin