Subject: [TLS] Application data during renegotiation handshake

From: Mike Bishop <[email-masked]>
Date: Wed, 11 Nov 2015 18:39:51 +0000

A question for TLS implementation owners:  During the discussion of the TLS 1.2 portion of https://tools.ietf.org/html/draft-thomson-http2-client-certs-00, it was pointed out that HTTP/2 breaks a simplification of the HTTP-TLS interface that some implementations may have assumed.

Since HTTP/1.1 only has one request per connection and that request is waiting on the client certificate to be retrieved via renegotiation, you can assume that the client will not send any application data between the new ClientHello and sending the Finished message.  ("...it is expected that the negotiation will begin before no more than a few records are received from the client.")  Likewise, the server will not emit any application data between sending the HelloRequest and sending its own Finished message.  Since HTTP/2 will have other requests being generated and served in parallel, this is no longer the case.  Per the TLS 1.2 spec, that's permitted, but if it's not been done before, I'm afraid we may be hitting less-tested code paths.

I know that BoringSSL<https://www.imperialviolet.org/2015/10/17/boringssl.html> explicitly requires that application data flow be stopped during renegotiation.  If the HTTP working group adopts this draft, do the owners of other TLS implementations expect this to require changes in their TLS 1.2 implementations?

---

From: Adam Langley <[email-masked]>
Date: Wed, 11 Nov 2015 17:32:09 -0800

On Wed, Nov 11, 2015 at 10:39 AM, Mike Bishop
<[email-masked]> wrote:
> Since HTTP/1.1 only has one request per connection and that request is
> waiting on the client certificate to be retrieved via renegotiation, you can
> assume that the client will not send any application data between the new
> ClientHello and sending the Finished message.  (“…it is expected that the
> negotiation will begin before no more than a few records are received from
> the client.”)  Likewise, the server will not emit any application data
> between sending the HelloRequest and sending its own Finished message.
> Since HTTP/2 will have other requests being generated and served in
> parallel, this is no longer the case.  Per the TLS 1.2 spec, that’s
> permitted, but if it’s not been done before, I’m afraid we may be hitting
> less-tested code paths.
>
> I know that BoringSSL explicitly requires that application data flow be
> stopped during renegotiation.  If the HTTP working group adopts this draft,
> do the owners of other TLS implementations expect this to require changes in
> their TLS 1.2 implementations?

Chrome, Android WebView etc treat a HelloRequest when HTTP/2 has been
negotiated as a fatal error. We do not expect to change this.

The TLS 1.3 post-handshake client-auth was intended, as I recall, to
support HTTP/1.1 over TLS 1.3.

With HTTP/2 isn't it cleaner to do client-auth at the HTTP layer (i.e.
by signing exporter values)? SPDY, at one point of development,
supported this via the CREDENTIAL frame. That also avoided a confused
deputy problem: with connection pooling over HTTP/2, there seems to be
a risk of confusion about which requests are authenticated with which
client certificate.

Cheers

AGL

-- 
Adam Langley [email-masked] https://www.imperialviolet.org

---

From: Yoav Nir <[email-masked]>
Date: Thu, 12 Nov 2015 08:43:21 +0200

> On 12 Nov 2015, at 3:32 AM, Adam Langley <[email-masked]> wrote:
> 

No, it was (and is) presented as a way to do client certificate authentication with HTTP/2 not at the initial handshake.

> by signing exporter values)?

It is. I thought that an HTTP authentication method based on certificates could be a drop-in replacement for TLS layer authentication, but someone (I think it was Mike) pointed out that with TLS-layer certificate authentication the stream continues after the authentication, while with HTTP-layer authentication, the stream ends with a 401 status code, and the client has to start a new stream with the Authorization header. So applications would need to be changed for this to work.

> SPDY, at one point of development,

I agree that is a good idea. We have to be mindful of how this interacts with multiple concurrent streams requiring authentication, and whether we can avoid race conditions where the server sends a different response for the same resource depending on authentication without actually requiring it (“Hello, guest” vs “Hello, Adam”)

Yoav

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Thu, 12 Nov 2015 09:23:41 +0100

On Wed, 2015-11-11 at 18:39 +0000, Mike Bishop wrote:

> I know that BoringSSL explicitly requires that application data flow
> be stopped during renegotiation.  If the HTTP working group adopts
> this draft, do the owners of other TLS implementations expect this to
> require changes in their TLS 1.2 implementations?

GnuTLS also has this requirement.

regards,
Nikos

---

From: Matt Caswell <[email-masked]>
Date: Thu, 12 Nov 2015 09:09:03 +0000

> GnuTLS also has this requirement.
OpenSSL also does not allow application data during renegotiation.

Matt

---

From: Hubert Kario <[email-masked]>
Date: Thu, 12 Nov 2015 13:37:02 +0100

On Wednesday 11 November 2015 18:39:51 Mike Bishop wrote:
> Per the TLS 1.2 spec, that's permitted, but if
> it's not been done before, I'm afraid we may be hitting less-tested
> code paths.

It's also something that Java does and what NSS supports.

But indeed it is problematic:
https://rt.openssl.org/Ticket/Display.html?id=3712&user=guest&pass=guest

-- 
Regards,
Hubert Kario
Senior Quality Engineer, QE BaseOS Security team
Web: www.cz.redhat.com
Red Hat Czech s.r.o., Purkyňova 99/71, 612 45, Brno, Czech Republic

---

From: [email-masked] (Martin Rex)
Date: Thu, 12 Nov 2015 15:51:56 +0100 (CET)

> OpenSSL also does not allow application data during renegotiation.

Our implementation also does not allow application data during renegotiation.
(But it also has server-side renegotiation completely disabled.)

-Martin

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Thu, 12 Nov 2015 16:32:41 +0100

On Wed, 2015-11-11 at 18:39 +0000, Mike Bishop wrote:
> A question for TLS implementation owners:  During the discussion of
> the TLS 1.2 portion of https://tools.ietf.org/html/draft-thomson-http
> 2-client-certs-00, it was pointed out that HTTP/2 breaks a
> simplification of the HTTP-TLS interface that some implementations
> may have assumed.
>  
> Since HTTP/1.1 only has one request per connection and that request
> is waiting on the client certificate to be retrieved via
> renegotiation, you can assume that the client will not send any
> application data between the new ClientHello and sending the Finished
> message.  (“…it is expected that the negotiation will begin before no
> more than a few records are received from the client.”)  Likewise,
> the server will not emit any application data between sending the
> HelloRequest and sending its own Finished message.  Since HTTP/2 will
> have other requests being generated and served in parallel, this is
> no longer the case.  Per the TLS 1.2 spec, that’s permitted, but if
> it’s not been done before, I’m afraid we may be hitting less-tested
> code paths.

We may are also introducing a new attack surface by allowing
application data during rehandshake and implementations cache the
messages until the handshake is complete.

There is an interesting part of the triple handshake attack which can
take advantage of applications which cache application data during
rehandshake.

Quoting: https://www.secure-resumption.com/
"... Consequently, A cannot read or send messages on these connections
any more. However, its prior [to rehandshake] messages on both
connections may well be prefixed to the messages sent after
renegotiation."

So an attacker could ensure that his messages are prefixed to the next
session if he simply sends his application data during rehandshake.
That was not possible with most implementations until now.

So we are hitting less-tested protocol paths as well, not only code
paths.

regards,
Nikos

---

From: David Benjamin <[email-masked]>
Date: Thu, 12 Nov 2015 20:43:15 +0000

On Wed, Nov 11, 2015 at 10:43 PM Yoav Nir <[email-masked]> wrote:

> No, it was (and is) presented as a way to do client certificate
> authentication with HTTP/2 not at the initial handshake.
>
> It is. I thought that an HTTP authentication method based on certificates
> could be a drop-in replacement for TLS layer authentication, but someone (I
> think it was Mike) pointed out that with TLS-layer certificate
> authentication the stream continues after the authentication, while with
> HTTP-layer authentication, the stream ends with a 401 status code, and the
> client has to start a new stream with the Authorization header. So
> applications would need to be changed for this to work.
>

Using existing HTTP semantics would certainly be cleaner in a vacuum, but
one could still do it in HTTP/2 layer without creating a new stream.
Perhaps adapt SPDY's CREDENTIAL frame and add a new SWITCH_CREDENTIAL frame
to swap a stream's credential slot mid-stream?

Alternatively, HTTP/2 frontend could make the application think there were
two independent requests. Am I misunderstanding the objection? What about
this:
1. Client hits HTTP/2 frontend. Frontend talks to application which decides
it needs client auth, expecting it on the same stream.
2. Frontend immediately aborts that request and returns a 401 to the
client. Application thinks the client just gave up.
3. Client makes a new stream, now authenticated. The frontend hits the
application fresh. Application requests client auth as before and frontend
responds immediately with the certificate the client asserted.
This is, by the way, how Chrome implements client auth today, even with
renego. We never reconfigure client auth mid-stream.

I think it would be helpful to have examples of exactly what the
applications look like, to know what constraints the various interested
parties are working with.

For example, Apache httpd has some high-level configuration file.
https://httpd.apache.org/docs/2.2/ssl/ssl_howto.html#arbitraryclients
Existing Apache installs can easily compatibility regardless of how the
HTTP/TLS interaction looks.

On the other extreme, if the goal is to keep Apache httpd unchanged while
only changing OpenSSL, then we have a very different picture because the
OpenSSL API is SSL_renegotiate/SSL_do_handshake (send a HelloRequest) +
SSL_set_state/SSL_do_handshake (don't continue until renego completes).
That one is quite overfit to the old flow and will be difficult to
reconcile with almost anything.

draft-thomson-http2-client-certs-00's HTTP/2 mode seems to be targeting
something in between. It's okay with adding a new application_context_id,
but the client certificate still needs to be asserted at the transport. I'm
having a hard time divining the constraints from this.

David

---

From: Mike Bishop <[email-masked]>
Date: Thu, 12 Nov 2015 21:08:57 +0000

Doing it at the HTTP layer (as an authentication mechanism) is challenging, since applications aren’t expecting to receive it that way, and moves the authenticated exchange onto a different stream than triggered it.  I know that there’s the possibility for a layer to fake the client going away while actually sending a 401, but then you have to be able to tie the client’s second attempt back to the challenge, don’t you?

When I say “application,” I mean the code being hosted by the web server that’s actually responding to the interpreted requests.  While I’d like to minimize code changes in the HTTP server, my primary constraint is that I don’t change the application they’re hosting at all.  The change to HTTP/2 and/or TLS 1.3 should be as transparent as possible.  Keeping auth that’s currently done via TLS still in TLS helps to reduce those changes at higher layers.

In the HttpBis working group meeting, there was fairly strong consensus that we needed a backward-compatibility mechanism for existing apps moving to HTTP/2 over TLS 1.[23]; there was also interest in defining something cleaner in the future for new apps that could adopt something brand new, but not at the expense of quickly enabling current apps to keep working.  The draft below is the current candidate for least-ugly compat solution.  Doing it at the framing layer is definitely a good option for the something cleaner.

From: David Benjamin [mailto:[email-masked]]
Sent: Thursday, November 12, 2015 12:43 PM
To: Yoav Nir <[email-masked]>; Adam Langley <[email-masked]>
Cc: Mike Bishop <[email-masked]>; [email-masked]
Subject: Re: [TLS] Application data during renegotiation handshake

On Wed, Nov 11, 2015 at 10:43 PM Yoav Nir <[email-masked]<mailto:[email-masked]>> wrote:

> On 12 Nov 2015, at 3:32 AM, Adam Langley <[email-masked]<mailto:[email-masked]>> wrote:
>

Using existing HTTP semantics would certainly be cleaner in a vacuum, but one could still do it in HTTP/2 layer without creating a new stream. Perhaps adapt SPDY's CREDENTIAL frame and add a new SWITCH_CREDENTIAL frame to swap a stream's credential slot mid-stream?

Alternatively, HTTP/2 frontend could make the application think there were two independent requests. Am I misunderstanding the objection? What about this:
1. Client hits HTTP/2 frontend. Frontend talks to application which decides it needs client auth, expecting it on the same stream.
2. Frontend immediately aborts that request and returns a 401 to the client. Application thinks the client just gave up.
3. Client makes a new stream, now authenticated. The frontend hits the application fresh. Application requests client auth as before and frontend responds immediately with the certificate the client asserted.
This is, by the way, how Chrome implements client auth today, even with renego. We never reconfigure client auth mid-stream.

I think it would be helpful to have examples of exactly what the applications look like, to know what constraints the various interested parties are working with.

For example, Apache httpd has some high-level configuration file.
https://httpd.apache.org/docs/2.2/ssl/ssl_howto.html#arbitraryclients
Existing Apache installs can easily compatibility regardless of how the HTTP/TLS interaction looks.

On the other extreme, if the goal is to keep Apache httpd unchanged while only changing OpenSSL, then we have a very different picture because the OpenSSL API is SSL_renegotiate/SSL_do_handshake (send a HelloRequest) + SSL_set_state/SSL_do_handshake (don't continue until renego completes). That one is quite overfit to the old flow and will be difficult to reconcile with almost anything.

draft-thomson-http2-client-certs-00's HTTP/2 mode seems to be targeting something in between. It's okay with adding a new application_context_id, but the client certificate still needs to be asserted at the transport. I'm having a hard time divining the constraints from this.

David

---

From: David Benjamin <[email-masked]>
Date: Mon, 16 Nov 2015 17:08:45 +0000

[Reordering your message slightly so the important question is first.]

[MB] When I say “application,” I mean the code being hosted by the web
server that’s actually responding to the interpreted requests.  While I’d
like to minimize code changes in the HTTP server, my primary constraint is
that I don’t change the application they’re hosting at all.  The change to
HTTP/2 and/or TLS 1.3 should be as transparent as possible.  Keeping auth
that’s currently done via TLS still in TLS helps to reduce those changes at
higher layers.

[DB] Right, this is why, again, I'm asking for what interface,
specifically, are you trying to hold fixed? I can imagine a number of
interfaces, ranging from the OpenSSL/Apache boundary (basically impossible,
but not your definition of "application") to the Apache/.htaccess boundary
(compat is trivial, but probably simpler than your "application"). Without
knowing what interface constrains you, it's very difficult to explore the
problem space.

On Thu, Nov 12, 2015 at 4:09 PM Mike Bishop <[email-masked]>
wrote:

> Doing it at the HTTP layer (as an authentication mechanism) is
> challenging, since applications aren’t expecting to receive it that way,
> and moves the authenticated exchange onto a different stream than triggered
> it.
>
Note I provided two (sketches of) proposals, only one of which switches
streams. What's incompatible with adapting the SPDY CREDENTIAL frame but
tweaking it so it is asserted mid-stream? I would prefer two separate
requests, but it seems we could avoid touching the socket layer either way.

> I know that there’s the possibility for a layer to fake the client going
> away while actually sending a 401, but then you have to be able to tie the
> client’s second attempt back to the challenge, don’t you?
>
I don't believe so. But, again, you haven't given me the actual interface,
so I have to speculate. Can't you can defer checking against the challenge
to when you receive it? So, something like:

First request:
1. Client hits frontend.
2. [frontend <-> application] Frontend forwards HTTP request to appropriate
application.
3. [frontend <-> application] Application requests certificate auth,
handing frontend information to go in CertificateRequest, along with
information on how to verify the certificate.
4. Frontend surfaces CertificateRequest information with the HTTP 401
response or similar. Request ends, frontend saves no state.
5. [frontend <-> application] Application thinks the client ran away.

Second request (maybe doesn't happen, maybe happens without the first
request, doesn't matter):
1. Client hits frontend. It authenticates the request with certificate
chain C. (I dunno, sign an exporter value or whatever. Or maybe you do the
CREDENTIAL frame + slotted SYN_STREAM route to save on signatures. Or maybe
there's something more complex with nonces. We can sort out the exact
details.)
2. Frontend checks the client is authenticated as C, but doesn't do
anything with C as it doesn't remember the application's challenge. Whether
C is a meaningful identity is not its problem yet.
3. [frontend <-> application] Frontend forwards HTTP request to appropriate
application.
4. [frontend <-> application] Application requests certificate auth,
handing frontend information to go in CertificateRequest, along with
information on how to verify the certificate. This is the same output as in
step 3 of the first request.
5. Frontend verifies C against information the application gave, etc.
Whatever it would have done before.
6. [frontend <-> application] Frontend reports that the client, remarkably
quickly :-), received the challenge and authenticated as C. Application
continues as it did with the renego hack.

> In the HttpBis working group meeting, there was fairly strong consensus
> that we needed a backward-compatibility mechanism for existing apps moving
> to HTTP/2 over TLS 1.[23]; there was also interest in defining something
> cleaner in the future for new apps that could adopt something brand new,
> but not at the expense of quickly enabling current apps to keep working.
> The draft below is the current candidate for least-ugly compat solution.
> Doing it at the framing layer is definitely a good option for the something
> cleaner.
>

It's possible that I'm misunderstanding the requirements, but if it is
possible for the "something cleaner" and "ugly compat solution" to be the
same, that is certainly preferable, no? It's possible my guesses about your
constraints are incorrect, but so far I'm not seeing any reason that
wouldn't be possible. What am I missing here?

David

>
>
> *From:* David Benjamin [mailto:[email-masked]]
> *Sent:* Thursday, November 12, 2015 12:43 PM
> *To:* Yoav Nir <[email-masked]>; Adam Langley <[email-masked]
> >
> *Cc:* Mike Bishop <[email-masked]>; [email-masked]
> *Subject:* Re: [TLS] Application data during renegotiation handshake
>
>
>
> 1. Client hits HTTP/2 frontend. Frontend talks to application which
> decides it needs client auth, expecting it on the same stream.
>