Subject: forward HTTPS proxy | Re: The future of forward proxy servers in an http/2 over TLS world

From: Kari Hurtta <[email-masked]>
Date: Wed, 1 Mar 2017 21:26:31 +0200 (EET)

( Kari Hurtta <[email-masked]> was bouncing after MX change.
  I reverted that change. )

Alex Rousskov <[email-masked]> 
https://lists.w3.org/Archives/Public/ietf-http-wg/2017JanMar/0377.html

> To be more precise, the _browser_ needs that, but, yes, this is probably
> required, and that is exactly why I mentioned secure response signing
> (or something like that) as a prerequisite. The proxy would need to
> somehow forward origin's response signature or public certificate (at
> least). This is where an HTTP extension is required. Everything else is
> already supported (at the protocol level) AFAICT.

If HTTP/2 can be assumed for that https connection from browser to proxy,
the that extension can be new HTTP/2 frame. I think that this fits
to that place. 

Proxy sends that frame to browser before responses HEADERS frame.

This allows browser only show status after the fact. Browser
can not examine origin's certificate before it sends to proxy

HEADERS
     + END_STREAM
     + END_HEADERS
       :method = GET
       :scheme = https
       :path = /
       :authority = example.com

Willy Tarreau <[email-masked]> 
https://lists.w3.org/Archives/Public/ietf-http-wg/2017JanMar/0375.html

> That's why I think that a technical solution like trusted proxies can be
> good. Let the user know whether he can have a TLS tunnel to the origin or
> has to retry in clear using "GET https://". Let's have the same warnings
> as when I'm asked whether or not I want to share my location with the site.

That can be new HTTP response code for CONNECT.

I think these are new protocol components which are needed on that solution.

/ Kari Hurtta

---

From: Mike Bishop <[email-masked]>
Date: Wed, 1 Mar 2017 22:35:11 +0000

A couple problems with that model.  First, the wholly protocol-based:  A stream is opened by a HEADERS frame; sending an earlier frame on a stream is a breaking protocol change that would require negotiation prior to use.  (Sending the frame between HEADERS and DATA, and requiring a zero-length DATA frame to close the stream might be a reasonable workaround to this.)

More fundamentally broken is that you have to believe the proxy when it claims the server certificate to be something.  The server doesn't have access to the certificate, and so can't sign any nonce the client might request.  It might be an acceptable fallback, but the ideal is to have full authentication of all parties and integrity along the path.

Previous proposals have involved a TLS-in-TLS proposal, where you would have:

Client <= Auth + Encryption + Integrity => Proxy <= Auth + Encryption + Integrity => Server

Client <============================ Auth + Integrity =============================> Server

This has some properties which are desirable - notably the ability to authenticate the intermediary, still authenticate the end-server, and have an integrity-protected exchange with the end-server.  The intermediary can kill the connection if it sees something it doesn't like, but can't actually modify anything if it allows the connection to continue.

However, this also has some strongly negative properties.  As a technical matter, it requires a change not only on the proxy, but on *every* end server on the planet to accept a TLS-in-TLS connection.  There are ways around that; for example, having the proxy's TLS connection to the server offer an ALPN token for inspected TLS being the next layer.  If the server doesn't support it, it doesn't pick that token, and the proxy and client each have to decide what to do next.  As a political matter, though, it standardizes a method for intermediary inspection.  The IETF has historically been opposed to this unilaterally; see RFC 2804.

I'm personally less opposed when the inspector has control of the client's configuration, which is the scenario you seem most concerned about.  Also, note that defining how an explicitly-configured proxy might handle a requirement to inspect traffic actually doesn't constitute wiretapping in the definition given by that RFC - in particular, the definition says that neither the sender nor any receivers know about the third party.  A system in which the sender must know about the third party (proxy) and the receiver has the opportunity to know might have a chance.  (A snowball's chance, as the saying goes, but a chance nonetheless.)

-----Original Message-----
From: [email-masked] [mailto:[email-masked]] On Behalf Of Kari Hurtta
Sent: Wednesday, March 1, 2017 11:27 AM
To: Alex Rousskov <[email-masked]>; Willy Tarreau <[email-masked]>
Cc: Kari Hurtta <[email-masked]>; HTTP working group mailing list <[email-masked]>
Subject: forward HTTPS proxy | Re: The future of forward proxy servers in an http/2 over TLS world

( Kari Hurtta <[email-masked]<mailto:[email-masked]>> was bouncing after MX change.

Alex Rousskov <[email-masked]<mailto:[email-masked]>>

> To be more precise, the _browser_ needs that, but, yes, this is

> probably required, and that is exactly why I mentioned secure response

> signing (or something like that) as a prerequisite. The proxy would

> need to somehow forward origin's response signature or public

> certificate (at least). This is where an HTTP extension is required.

> Everything else is already supported (at the protocol level) AFAICT.

If HTTP/2 can be assumed for that https connection from browser to proxy, the that extension can be new HTTP/2 frame. I think that this fits to that place.

This allows browser only show status after the fact. Browser can not examine origin's certificate before it sends to proxy

HEADERS

     + END_STREAM

     + END_HEADERS

       :method = GET

       :scheme = https

       :path = /

       :authority = example.com

Willy Tarreau <[email-masked]<mailto:[email-masked]>>

> That's why I think that a technical solution like trusted proxies can

> be good. Let the user know whether he can have a TLS tunnel to the

> origin or has to retry in clear using "GET https://". Let's have the

> same warnings as when I'm asked whether or not I want to share my location with the site.

/ Kari Hurtta

---

From: Alex Rousskov <[email-masked]>
Date: Wed, 1 Mar 2017 17:25:15 -0700

On 03/01/2017 03:35 PM, Mike Bishop wrote:

> More fundamentally broken is that you have to /believe/ the proxy when
> it claims the server certificate to be something.

In this model, the user has instructed the browser to believe the proxy.
There are other models, of course, but I do not see anything
_fundamentally broken_ with this approach. While it may feel
uncomfortable for a browser to obey the user decision, it is not
fundamental breakage IMHO.

This is similar to saying that saving an HTTPS web page to a PDF file is
fundamentally broken because the browser has to believe the PDF reader
not to screw up with validated content. Can that PDF reader change
content or otherwise mislead the user? Absolutely! Is that possibility a
good enough excuse to block "Save As PDF" export? No.

Another example are CDNs. Their model is as "fundamentally broken" as
the secure proxy model, but browsers do not seem to be fighting them.
Why is a browser happy with the certificate provided by a CDN? In both
cases, we are dealing with a single-party consent: The user does not
authorize CDN usage and the origin server does not authorize proxy
usage. Why is it acceptable for a bleeding CDN but not for a forward
proxy to risk betraying our trust in the infrastructure as a whole?

> The server doesn't
> have access to the certificate, and so can't sign any nonce the client
> might request.

In this model, the user did not ask the browser to validate the origin
response against the origin certificate. In this model, the user trusts
the proxy to do that. The browser may display (and can even validate!)
the origin certificate.

As you said, other, more complex models may give browsers more control
at the expense of adding their own "strongly negative properties".

Alex.

> ( Kari Hurtta <[email-masked]
> <mailto:[email-masked]>> was bouncing after MX change.
> 
> Alex Rousskov <[email-masked]
> <mailto:[email-masked]>>
> 
> If HTTP/2 can be assumed for that https connection from browser to
> proxy, the that extension can be new HTTP/2 frame. I think that this
> fits to that place.
> 
>  
> 
> This allows browser only show status after the fact. Browser can not
> examine origin's certificate before it sends to proxy
> 
>  
> 
> HEADERS
> 
>      + END_STREAM
> 
>      + END_HEADERS
> 
>        :method = GET
> 
>        :scheme = https
> 
>        :path = /
> 
>        :authority = example.com
> 
>  
> 
>  
> 
> Willy Tarreau <[email-masked] <mailto:[email-masked]>>
>

---

From: Kari Hurtta <[email-masked]>
Date: Thu, 2 Mar 2017 07:14:14 +0200 (EET)

Mike Bishop <[email-masked]>: (Thu Mar  2 00:35:11 2017)
> A couple problems with that model.  First, the wholly protocol-based:  A stream is opened by a HEADERS frame; sending an earlier frame on a stream is a breaking protocol change that would require n…

http://httpwg.org/specs/rfc7540.html

| Sending or receiving a HEADERS frame causes the stream to become "open". The stream 
| identifier is selected as described in Section 5.1.1. The same HEADERS frame can also 
| cause a stream to immediately become "half-closed".

My reading is:

It is HEADERS frame for browser to proxy which opens stream, not
HEADERS frame on proxy's response from proxy to browser.

1) From browser to proxy

HEADERS
     + END_STREAM
     + END_HEADERS
       :method = GET
       :scheme = https
       :path = /
       :authority = example.com

2) From proxy to browser

"Origin certificate"

HEADERS
    + END_HEADERS
    - END_STREAM
	:status = 200
	content-type = text/html;charset=utf-8
	{other headers]

DATA
    + END_STREAM
     payload

----

/ Kari Hurtta

---

From: Kari Hurtta <[email-masked]>
Date: Thu, 2 Mar 2017 20:15:54 +0200 (EET)

> > A couple problems with that model.  First, the wholly protocol-based:  A stream is opened by a HEADERS frame; sending an earlier frame on a stream is a breaking protocol change that would require…

There may be reason to send SETTINGS frame with

  TRUSTED_PROXY_CONFIGURED = 1

from browser to proxy, but reason is not
"Origin certificate" -frame. I think
that stream is open on that situation even
when it is first frame on direction
proxy -> browser.

> 	content-type = text/html;charset=utf-8

Sequence A:  (HTTP/2 inside of TLS connection between browser and broxy)

browser => proxy  
HEADERS			(stream 1)
      - END_STREAM
      + END_HEADERS
	:method = CONNECT
	:authority = example.com

proxy => browser						(XXXXXX)
HEADERS                 (stream 1)
      - END_STREAM 
      + END_HEADERS
      	:status = 5xx	(Content Inspection Required)
	content-type = text/html;charset=utf-8

proxy => browser
DATA			(stream 1)
      + END_STREAM
<body>
Connection to example.com refused by Content Inspection Gateway
</body>

proxy => browser 
RST_STREAM 		(stream 1)
	
browser => proxy
HEADERS			(stream 3)
      + END_STREAM
      + END_HEADERS
        :method = GET
	:scheme = https
	:path = /
	:authority = example.com

proxy => browser 
ORIGINCERT		(stream 3)

HEADERS			(stream 3)
      + END_HEADERS
      - END_STREAM
	:status = 200

DATA			(stream 3)
     + END_STREAM
       payload

But why proxy on (XXXXXX)  will return 5xx   (Content Inspection Required).
It does not know that browser understand that
or that browser is willing ask data with GET -method
to https -URL.

So it assumes that browser have proxy's CA certificate
installed as CA on browsers certificate store and does:

Sequence B:  (HTTP/2 inside of TLS connection between browser and broxy)

browser => proxy
HEADERS                 (stream 1)
      - END_STREAM
      + END_HEADERS
        :method = CONNECT
        :authority = example.com

proxy => browser                                                (XXXXXX)
HEADERS                 (stream 1)
      - END_STREAM
      + END_HEADERS
        :status = 200

browser => proxy
DATA			(stream 1)
     - END_STREAM
ClientHello

<Proxy generates certificate for example.com and signs it with proxy's
 CA certificate>

proxy => browser 
DATA			(stream 1)
     - END_STREAM
ServerHello
Certificate for example.com generated by proxy

So for Sequence A something like
TRUSTED_PROXY_CONFIGURED = 1
is needed if another possibility is
use proxy generated certificate to 
imporsonate origin.

But then next question is that why not just
use ORIGINCERT -frame from Sequence A
and otherwise just proxy generated 
certificate. This gives same information
to browser.

Sequence C:  (HTTP/2 inside of TLS connection between browser and broxy)

browser => proxy
HEADERS                 (stream 1)
      - END_STREAM
      + END_HEADERS
        :method = CONNECT
        :authority = example.com

proxy => browser                                                (XXXXXX)
HEADERS                 (stream 1)
      - END_STREAM
      + END_HEADERS
        :status = 200

proxy => browser
ORIGINCERT              (stream 1)

browser => proxy
DATA                    (stream 1)
     - END_STREAM
ClientHello

<Proxy generates certificate for example.com and signs it with proxy's
 CA certificate>

proxy => browser
DATA                    (stream 1)
     - END_STREAM
ServerHello
Certificate for example.com generated by proxy

Now browser knows that there is origin
server impersonated because proxy informed
about that.

Alternatively browser can know that origin
server is imporsonated if browser have separate
certificate store for proxy CA certicate,
which implicate that origin server is
impersonated if server certificate is signed by
that certificate.

Mike Bishop <[email-masked]>
https://lists.w3.org/Archives/Public/ietf-http-wg/2017JanMar/0384.html

> Also, note that defining how an explicitly-configured proxy might handle a requirement to 
> inspect traffic actually doesn't constitute wiretapping in the definition given by that 
> RFC - in particular, the definition says that neither the sender nor any receivers know 
> about the third party.

Separate certificate store for proxy CA certicate seems to be
minimal method to achieve knowledge that third party is present.

/ Kari Hurtta

---

From: Kari Hurtta <[email-masked]>
Date: Fri, 3 Mar 2017 07:11:38 +0200 (EET)

> 	content-type = text/html;charset=utf-8

There is another use case what that does not
yet solve.

browser: (or user  actually)

	 I want proxy cache pages if I know
	 that proxy supports https forwarding
	 and  that proxy does certificate checks.

	 ( And I want use tunnel instead if origin
	   have EV certificate ? )

In that case proxy never does
	:status = 5xx   (Content Inspection Required)
for CONNECT request. 

SETTINGS
	TRUSTED_PROXY_CONFIGURED = 1
from browser to proxy does not help.

So proxy needs tells that "I support GET https"
( and proxy needs to cache origin'n certificate
  for cached pages so that it can send "ORIGINCERT"
  frame. )

But WG is solving that caching problem from
origin server's direction (where 
draft-ietf-httpbis-encryption-encoding
is one part of that.)

So it is not easy to decide when do 

browser => proxy
HEADERS                    
       + END_STREAM
       + END_HEADERS
        :method = GET
        :scheme = https
        :path = /
        :authority = example.com

/ Kari Hurtta