Subject: Report on preliminary decision on TLS 1.3 and client auth

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Sep 2015 10:16:42 -0700

The minutes of the TLS interim have been posted. Some decisions regard
client authentication were made.

https://www.ietf.org/proceedings/interim/2015/09/21/tls/minutes/minutes-interim-2015-tls-3

Here is a summary of the applicable pieces, plus what I options it provides
HTTP/2...

(Caveat here: aspects of this could change if new information is presented,
but it seems unlikely that there will be changes that will affect the core
decisions.)
The big change is that a server can request client authentication at any
time. A server may also make multiple such requests. Those multiple
requests could even be concurrent.

The security claims associated with client authentication require more
analysis before we can be certain, but the basic idea is that
authentication merely provides the proof that a server needs to regard the
entire session to be authentic. In other words, client authentication will
apply retroactively. This could allow a request sent prior to
authentication to be considered authenticated. This is a property that is
implicitly relied on for the existing renegotiation cases and one that we
might want to exploit.

Each certificate request includes an identifier that allows it to be
correlated with the certificate that is produced in response. This also
allows for correlating with application context. This is what I think that
we can use to fix HTTP/2.

Clients cannot spontaneously authenticate, which invalidates the designs I
have proposed, however, the basic structure is the basis for the first
option that I will suggest.

Option 1 uses a new authentication scheme. A request that causes a server
to require a client certificate is responded to with a 4xx response
containing a ClientCertificate challenge. That challenge includes an
identifier.  The server also sends - at the TLS layer - a
CertificateRequest containing the same identifier, allowing the client to
correlate it's HTTP request with the server's CertificateRequest.

Client@HTTP/2:
HEADERS
  :method = GET ...

Server@HTTP/2:
HEADERS
  :status = 401
  authorization = ClientCertificate req="option 1"

Server@TLS:
CertificateRequest { id: "option 1" }

Client@TLS:
Certificate+CertificateVerify { id: "option 1", certificates... }

Client@HTTP/2:
HEADERS
  :method = GET ...

Server@HTTP/2:
HEADERS
  :status = 200

Option 2 aims to more closely replicate the experience we get from
renegotiation in HTTP/1.1 + TLS <= 1.2.  Rather than rejecting the request,
the server sends an HTTP/2 frame on the stream to indicate to the client to
expect a CertificateRequest. That frame includes the identifier.

Client@HTTP/2:
HEADERS
  :method = GET ...

Server@HTTP/2:
EXPECT_AUTH
  id = option 2

Server@TLS:
CertificateRequest { id: "option 2" }

Client@TLS:
Certificate+CertificateVerify { id: "option 2", certificates... }

Server@HTTP/2:
HEADERS
  :status = 200

In this case, the server probably wants to know that the client is willing
to respond to these requests, otherwise it will want to use
HTTP_1_1_REQUIRED or 421.  So a companion setting to enable this is a good
idea (the semantics of the setting that Microsoft use for renegotiation is
pretty much exactly what we'd need).

I think that the first option has some architectural advantages, but that
is all.  The latter more closely replicates what people do today and for
that reason, I think that it is the best option.

As for how to implement this same basic mechanism in TLS 1.2, I have an
idea that will work for either option, but it's a bit disgusting, so I'll
save that for a follow-up email.

---

From: Amos Jeffries <[email-masked]>
Date: Thu, 24 Sep 2015 14:02:07 +1200

> save that for a follow-up email.

Option 1 re-introduces all the same problems NTLM and Negotiate have
over HTTP in the presence of proxy and gateway intermediaries. By using
single-connectin authorization over a multiplexed connection environment.

It would either need to be restricted to Proxy-Authorization or some
complex logic used to determine whether Authorization or
Proxy-Authorization was the proper response header.

Lets not go there.

Option 2 risks the same mess if the AUTH frame is defined end-to-end.
But a per-hop frame would work nicely as long as it is clear to server
implementers that intermediaries may be the source of the certificate.
Not some "user".

An option 3 might be to use a SETTINGS instead of dedicated AUTH frame.
So that the per-hop nature is made extra clear. That would also be more
backward compatible with older h2 implementations and work in with
clearing dynamic compression contexts at the same time as authenticating.

Amos

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Sep 2015 20:41:24 -0700

> implementers that intermediaries may be the source of the certificate.

This would naturally be hop-by-hop, by virtue of extensions being
hop-by-hop and by virtue of the setting that enables it also being
hop-by-hop.

> clearing dynamic compression contexts at the same time as authenticating.

SETTINGS wouldn't allow the server to correlate the CertificateRequest
with a specific request/response exchange.

Also, while I think of it, we should probably forbid the use of this
on server-initiated streams (i.e., with server push).  That could
cause problems.

---

From: Amos Jeffries <[email-masked]>
Date: Thu, 24 Sep 2015 15:56:10 +1200

On 24/09/2015 3:41 p.m., Martin Thomson wrote:
> On 23 September 2015 at 19:02, Amos Jeffries wrote:
>>

Ah. Sorry I seem to have misunderstood yoru meaning of "provides the
proof that a server needs to regard the entire session to be authentic"
to mean the cert was connection-wide.

If it is stream-specific in terms of HTTP/2 streams rather than TLS
streams, then the frame as in option 2 should be okay. Option 1 still
has major issues with www-auth vs proxy-auth.

> on server-initiated streams (i.e., with server push).  That could

I can see that as being a SHOULD NOT, or forbid on PUSH_PROMISE
specifically. But using a more general definitio like "server initiated"
may cause conflicts with the bi-directional h2 extension.

Amos

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Sep 2015 21:17:10 -0700

> has major issues with www-auth vs proxy-auth.

Right.  To expand on the problem here, at least in the browser context
- and likely in other cases as well - it is important for the client
to be able to identify which request triggered the certificate
request.  If there are requests from multiple browser windows (or even
applications) sharing the same connection and a CertificateRequest
appears, the client needs to know where to show the associated UX, if
there is any.

I certainly agree about the e2e and hbh concerns.  An end-to-end
message would prevent the hop-by-hop TLS from being tweaked.

> may cause conflicts with the bi-directional h2 extension.

mhm.

---

From: Ilari Liusvaara <[email-masked]>
Date: Thu, 24 Sep 2015 22:21:58 +0300

> we can use to fix HTTP/2.

How do you deal with server sending reauthentication request (even associated
with some stream) when client has unauthenticable streams (no credentials or
cross-origin coalescing)?

Reset the streams blocking authentication? Refuse identity change? Open
a new connection?

Also, what if after authentication no credentials request is made?
Refuse request with network error? Open a new connection?

With CANT+CARE, it was pretty obvious that client would just route requests
to connections (if needed, opening a new one) in order to deal with these
kind of issues.

>From some comments it seems "unsolicited client auth" isn't about CARE type
stuff but client just plain sending its CC/CCV mid-connection?

-Ilari

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Fri, 25 Sep 2015 09:18:22 +0000

--------

>to mean the cert was connection-wide.

I would like to remind people that, contrary to widespread assumptions,
HTTP doesn't have "sessions".

Sessions are typically implemented by mistaking (groups of) connections
for a session, or by means of opaque unstandardized cookies.

A client cert most naturally applies to the session between the
client and the server, no matter which connections and requests
that session might consist of.

But there is no way at the standardized protocol level to tell which
connections and requests belong to any particular sessions.

The only two architecturally clean solutions I can see are:

A)      Add the concept of sessions to HTTP, so we can tie the
	client cert to one of them.

B)	Point people to the End-to-End Argument, and make the client
	sign each subsequent request with its cert.

A is at best a long term goal.  Probably worth persuing for this
and many other reasons, but unlikely to happen until HTTP/3.

B is interesting in that it is relatively straightforward, can be
applied to all versions of HTTP (if done right) and lays down
ground-work which can later be extended to offer integrity (in both
directions) without the excess baggage of secrecy.

There are some issue with B, in particularly the part about what
headers gets signed and what to do if proxies munge them along the
way.

I'd probably just let the signature enumerate which headers it signs,
and make it a policy issue which headers it is a good idea to sign.

In real life, the server would return a indication to the client
along the lines of "I'd like you to sign your headers, using a
cert matching this expression", and if it does, fine, if not
the server will have to check policy for what to do.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: Yoav Nir <[email-masked]>
Date: Fri, 25 Sep 2015 12:56:21 +0300

> On Sep 25, 2015, at 12:18 PM, Poul-Henning Kamp <[email-masked]> wrote:
> 
> --------

Why do you call cookies unstandardized?

Yoav

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Fri, 25 Sep 2015 10:14:41 +0000

--------
>Why do you call cookies unstandardized?

Cookies are standardized just fine.

What I tried to say above is that we don't know which cookie
identifies the session.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 25 Sep 2015 10:08:50 -0700

> What I tried to say above is that we don't know which cookie

That's definitely true.  Cookies are a pretty crude tool for something
like this.

I think that your general observation about client certificates is
overwhelmingly true.  On the web at least, I'm seeing a general trend
away from using the TLS layer to authenticate clients.  If cookies are
crude, client certificates make them look like a picture of
sophistication by comparison.  As you say, they are a poor fit for
both the protocol and the architecture.

What I neglected to mention earlier is that client certificate
mechanism that was being added was viewed more as a necessary evil
than an important feature.  No one liked having to do this, but as
Mark pointed out, there are far more people relying on having the
functionality than we previously thought.

I'd like to find other solutions for the use cases that drive this,
but the view was that we still needed something like this so that we
don't strand those users on old protocols.  We don't have to *like* it
though.

There was strong agreement that this feature would be accompanied by a
prominent and severe admonishment against using it.  I definitely want
to talk about what the alternatives look like, but perhaps we should
start a separate thread on that subject.

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Fri, 25 Sep 2015 17:20:23 +0000

--------
In message <[email-masked]>
, Martin Thomson writes:
>[...]

I think in the current climate, we have a lot of lattitude for
doing things right, and telling people why they should migrate
to something safer, so we should seriously consider skipping
the workarounds and aim for something that will hold up well
under pressure.

---

From: Kyle Rose <[email-masked]>
Date: Fri, 25 Sep 2015 13:24:32 -0400

> start a separate thread on that subject.

For a variety of reasons, certificate-based browser authentication is
not going away, so in light of this I would be very interested in
helping formulate a replacement either at the protocol layer or at the
application layer with the proper hooks to allow for apps to present a
good UI to the user in ambiguous cases.

In the meantime, the options presented seem no worse than what we're
doing today with HTTP/1.1 and TLS <= 1.2, and clearly better than the
alternatives in the sense that they won't require clients to downgrade
to 1.1 for what is a "normal" case in a lot of places.

Kyle

---

From: Martin Thomson <[email-masked]>
Date: Fri, 25 Sep 2015 10:32:49 -0700

> the workarounds and aim for something that will hold up well

I want to do that to, but if that generates too much incentive to
remain on old protocols, I don't think that is the only thing we can
do.

Note that there are a lot of alternatives out there already.  For
instance, the widely deployed OAuth-based systems.  There are some
small differences in their security properties, which might be
critical.

However, I confess that I don't know whether that is a consideration
as much as pure inertia.  Maybe application developers that use client
certificates really like the fact that they have terrible privacy
characteristics.

Either way, I don't believe that we get to play the dictator here.
People will do what they feel that they need to.  If we don't help,
they will implement options that are even worse than those that I
described.

---

From: Willy Tarreau <[email-masked]>
Date: Sat, 26 Sep 2015 08:37:38 +0200

On Fri, Sep 25, 2015 at 10:08:50AM -0700, Martin Thomson wrote:
> away from using the TLS layer to authenticate clients.

On the *browser* web that's true, and the main reason is that if you
don't have your cert, you can't connect and you get a connect error
instead of a nice page delivered by the application proposing you to
regenerate your cert. Note: some sites manage to get it right, but
it's really complicated because the application needs to be aware of
what happens at the transport layer and needs to trust itself as much
as the transport layer, which is hardly a good thing to do by todays
development standards... And keep in mind that certs are a pain to
manage. Client certs are even worse because you have to support them
at the edge and manage them in the backend from the application. In
the end it provides no better security than the weakest point : the
application, which may sometimes be forced to generate rogue certs
due to regular bugs, but with a longer effect since these certs can
be abused even after the application bugs are fixed!

Between reverse-proxies and servers, or between servers, client certs
are much more common and perfectly fit the purpose : guarantee to each
side that they're talking with whom they believe they're talking. For
example, you don't forward an online payment request from an application
server on DC A to a payment server on DC B without client auth, or you're
definitely seeking for trouble. Just like you may only accept incoming
connections from your CDN.

> start a separate thread on that subject.

We should always be careful not to make security look evil just because
it comes with privacy concerns. If I go to my bank and want to make a
wire transfer, I have to show my ID card. If at some point people feel
concerned that the person they're talking to suddenly knows their name
and that it's a privacy concern and that they'd rather not ask for the
ID card, I would feel much less safe because I would have a harder way
to prove I'm the one I'm claiming, and others could pretend to be me.

And if I had the choice between having to show my ID card to everyone
in the queue at the same time as the bank's employee, or murmuring a
secret word hoping noone else hears it, guess what ? I'd prefer to show
my ID card to everyone, because as long as I have it and I keep my face,
I'm sure to be the only one to be able to do this wire transfer, while
the secret word can leak and be reused (even by the employee after he
leaves the bank and ends up in the same queue as me).

There are many situations where identification and authentication are
required. And by doing so we have to disclose our identity. We just
have not to abuse this, and possibly remind those who request it that
those who are asked to provide it may feel uncomfortable and that
sometimes alternatives are just as good. But we should not make this
mechanism look evil because it does more good than bad.

Regards,
Willy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Sat, 26 Sep 2015 07:11:20 +0000

--------
In message <[email-masked]>, Willy Tarreau writes:

>side that they're talking with whom they believe they're talking.

Which only works by defining "session" to be "connection".

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 26 Sep 2015 11:01:44 +0300

> to prove I'm the one I'm claiming, and others could pretend to be me.

IMO, there are two kinds of certs in web environment (service to
service and non-web client-to-server are different ballgames):

1) "global": Shared among all authorized origins.
- Breaks SOP, making these highly privileged.
- Not automatable given the privilege involved.
- Private parts on smartcards or softokens.
- Usually identifies user
- Serious privacy concerns (but sometimes needed).

2) "local": Single origin
- Respects SOP.
- Can be almost entierely automatic (relatively unprivileged).
- Webcrypto, FIDO, etc...
- Usually pseudonymous
- Privacy concerns on level of things like LocalStorage.

There is friction with HTTP/2 connection coalescing here:
- "Global": If connection is for origins A and B, even if cert is
  authorized for A, it might not be authorized for B.
- "Local": If connection is for origins A and B, there can't be
  any single cert for the connection.

Also, some requests can't be sent with client cert at all (cross-origin
non-credentials fetch() for instance), even if target origin has
associated client cert.

-Ilari

---

From: Willy Tarreau <[email-masked]>
Date: Sat, 26 Sep 2015 10:26:21 +0200

> Which only works by defining "session" to be "connection".

absolutely, but you know, I avoid to use the term "session" because
it means different things to different people.

willy

---

From: Willy Tarreau <[email-masked]>
Date: Sat, 26 Sep 2015 11:14:57 +0200

>   authorized for A, it might not be authorized for B.

Note, connection coalescing can only be performed by an entity
having access to the cert, simply because HTTP passes *over*
the authenticated TLS connection. Thus when it can happen
(eg: reverse proxy, or CDN), it's the equipement's cert that
will be presented to the server.

However we still need to make it possible and standard to pass
the client-auth information *inside* HTTP so that each stream
can carry the relevant information. That's what many SSL gateways
do by adding X-SSL-whatever headers right now, and which could be
much cleaner in HTTP/2.

Regards,
Willy