Difffent ways to authenticate (Was: Re: Report on preliminary decision on TLS 1.3 and client auth)

On Wed, Sep 23, 2015 at 08:41:24PM -0700, Martin Thomson wrote:
> On 23 September 2015 at 19:02, Amos Jeffries <squid3@treenet.co.nz> wrote:
> >
> > 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".
> 
> 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.

Thinking about problem space of this certificate authentication in
HTTP/2 (long, given that this is about just about every way I can
come up with, including ones I don't think work):

(The terminology choices are probably pretty horrible).


On high level, one needs mechanisms for two things:
1) Client to authenticate that it can represent given authority
   (anonymous authority can always be represented, also "authority"
   here has nothing to do with :authority pseudo-header).
2) Client to associate authority it can represent (does not guarantee
   the server will authorize the request!) with every request (HTTP
   is stateless by nature!).

There are essentially two ways to do the latter:

a) Select authority used by connection request is routed to/from
b) Select authority used by in-band indication.


If selecting 1), select authority by connection, the obvious choice
for authenticating the authority is TLS client certs. There remains
choice on how to handle the case where authority with no existing
connection exists:

c) Change authority of existing connection (open new connection if
   old authority is needed again).
d) Open a new connection with desired authority, possibly keeping
   the old one.

The problem with c) is that the existing connection can have active
transfers and can't change authority until those transfers either
end or are aborted (to do otherwise could very well create races
that are exploitable for privilege escalation). d) Creates more
connections, but the number should remain fairly limited (much
less than HTTP/1.1 in the same situation).

I think d) is clearer of those two (it is essentially what
CANT+CARE(?) proposal was).


If selecting 2), select authority by in-band indication, the TLS
client certs don't work, because one needs to authenticate multiple
authorities on one connection, and there can be only one TLS
client cert.

Thus the certificate sending and verification needs to be implemented
at HTTP/2 level. The main choices are:

e) PUT/POST special resource
f) New HTTP verb
g) New HTTP/2 frame type.

Now, this kind of authentication is inherently hop-by-hop and could
target destination other than origin, so e) doesn't actually work
properly. HTTP verbs could be useful if one wanted to also make the
mechanism also work for HTTP/1.1, but as we see when considering
request authority designation, this type of mechanism doesn't work
properly in HTTP/1.1. This leaves new HTTP/2 frame type.

The choices for how the in-band indication for request authority
is done are:

h) New pseudo-header
i) New header
j) New HEADERS flag + field
k) New HTTP/2 frame that changes authority newly opened streams
   get.
l) SETTINGS that sets the authority for newly opened streams.


h) Doesn't work: HTTP/1.1 doesn't have pseudo-headers and HTTP/2
forbids defining new ones. i) Doesn't work either, since the mechanism
is hop-by-hop by nature and HTTP/2 does not have per-hop headers (other
than one or two special cases).

This leaves j), k) and l), which both seem workable (but HTTP/2-
specfic). In k), the frame could theoretically be combined with the
frame that shows the client can represent the authority, but in
practice this might be a bad idea due to bandwidth usage (certificates
might not be exactly small and changes might not be rare).

k) and l) need to be synchronous against stream opens (SETTINGS is
already synchronous against everything it can appear in middle of)
so to avoid race conditions resulting server misinterpretting
client request.


For reference, the SPDY client auth was equivalent to g) and j)
(frame type for showing client can represent authority and header
frame field for authority designation).

For in-band operation, I think either g)+j) or g)+l) is the
cleanest (the remaining one seems quite odd to me), with maybe a
slight preference for g)+j).

As note: Originally I had h)-k), but then noticed that the authority
designation fits in SETTINGS value (even 32 bits is overkill) so I
added l) to the list.


Finally, some considerations on adding HTTP-level certificate
verification mechanism:
- Only signature certificates work, but fortunately non-signature
  certificates are close to non-existent.
- Use channel bindings to bind to lower layer. Make sure those
  bindings are actually bindings (i.e. nonces, e.g. TLS THS attack)!
- The data to be signed should include the lower layer name, so if
  the thing runs on top of multiple lower layer protocols (HTTPS
  definition says "secure transport" not "TLS"!) one doesn't get
  cross-protocol attacks.
- Sign the certificate too, some signature schemes don't even
  bind the key properly and nothing binds certificate.
- One probably wants to keep support for crap like (non-EC) DSA or
  SHA-1 (or worse, MD5!) out entierely.
- Copying TLS 1.3 client signature format (but with different
  context) might be a good idea.


> 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.

I think reasonable way to handle authority of server pushed streams
would be for those to inherit authority of the associated stream.


-Ilari

Received on Thursday, 1 October 2015 14:58:20 UTC