Subject: [websec] New draft of HTTP header-based public key pinning

From: Chris Palmer <[email-masked]>
Date: Tue, 8 Nov 2011 15:57:07 -0800

Hi all,

I tried to get this in by the deadline last week, but I had formatting
errors at the last minute (the draft name had changed to reflect its
non-HSTS nature, so the submission form rejected my version of -01!
Sigh), and then it cuts you off at 5:00 PST. Ah well. I've attached
the .txt form of the latest draft, and Ian Fette and Wan-Teh Chang
will be with you in Taipei. Only Ian has officially signed on to
represent this proposal at the meeting, though.

I changed a lot in this document, thanks to all your excellent
suggestions. Especially Jeff Hodges! This is a significantly different
and simpler document than the previous versions, although I'm sure
it's still not perfect — blame me for those parts.

---

From: Tom Ritter <[email-masked]>
Date: Tue, 8 Nov 2011 19:31:37 -0500

My notes:

I believe the BNF (pseudo-BNF?) is incorrect:

Public-Key-Pins = "Public-Key-Pins" ":" LWS directives

   directives      = max-age LWS ";" LWS fingerprints
                     / fingerprints LWS ";" LWS max-age

   max-age         = "max-age" LWS "=" LWS delta-seconds

   pins            = "pins" LWS "=" LWS fingerprints

   fingerprints    = fingerprint
                     / fingerprint "," fingerprints

   fingerprint     = fp-type "-" base64-digits

   fp-type         = "sha1"
                     / "sha256"
					
I believe 'directives' should replace "fingerprints" with "pins":

   directives      = max-age LWS ";" LWS pins
                     / pins LWS ";" LWS max-age
					
================

I think this paragraph is misworded:

UAs MUST have a way for users to clear current pins that were set by
   HSTS.  UAs SHOULD have a way for users to query the current state of
   Pinned Hosts.

Instead of HSTS, should that be "Public Key Pinning"?  If not, pins
set during HSTS must be flagged and treated differently - why?

================

Miscellany:

 - There is no directive or suggestion to User Agents about saving or
not saving pins received in a private browsing mode.  Maybe there
shouldn't be, but if a User-Agent does save them, the same 304/ETag
trick malicious sites use to track users can be created using certs
and subdomains.
 - The "Pinning Self-Signed End Entities" section was a bit confusing,
I had to read it a couple times to be sure you were talking about a
server's self-signed cert, and not a client cert.
 - The Pin-Break mechanism gets more complicated which each revision.
I know it's being shopped around for both this and the approach to put
pinning in the TLS layer (TACK), but does its removal implies pin
break codes are not intended to go into the final version of this
document, or will it be added later after the first bit is worked out?

Thanks Chris(es)!

-tom

---

From: Chris Palmer <[email-masked]>
Date: Tue, 8 Nov 2011 17:30:52 -0800

>                     / pins LWS ";" LWS max-age

You are right. Fixed.

> set during HSTS must be flagged and treated differently - why?

You are right. I now say:

UAs MUST have a way for users to clear current pins for Pinned Hosts.
UAs SHOULD have a way for users to query the current state of Pinned
Hosts.

> trick malicious sites use to track users can be created using certs

Yes, another person raised this concern, and it is real. I don't see a
way to resolve this problem; perhaps I am not smart enough, but I
can't see a way to have both dynamic pinning AND avoid this tracking
attack.

I am willing to add a paragraph about what browsers should do in
private browsing mode, and I am willing to go either way on what the
requirement should be. I don't know what is best.

> server's self-signed cert, and not a client cert.

Now I say:

If UAs accept hosts that authenticate themselves with self-signed end
entity certificates, they MAY also allow hosts to pin the public keys
in such certificates. The usability and security implications of this
practice are outside the scope of this specification.

Is that better?

>  - The Pin-Break mechanism gets more complicated which each revision.

Yeah, that's why I just dropped it.

> document, or will it be added later after the first bit is worked out?

For now my plan is to ship a trial implementation of HTTP header-based
dynamic pinning without pin break codes, and see how people like it.
It might turn out that nobody likes pinning at all, or that people
like X.509-based dynamic pinning better, and either approach with or
without TACK/pin break codes. To get that trial implementation off the
ground, I'm doing The Simplest Thing That Could Possibly Work.

If it happens that (a) we standardize it without pin break codes and
(b) after a year everyone says, "this is great but it really needs pin
break codes to be awesome", we'll just update the spec and the
implementations.

---

From: "Steingruebl, Andy" <[email-masked]>
Date: Tue, 8 Nov 2011 20:48:02 -0700

> -----Original Message-----
> From:  Chris Palmer

> Yes, another person raised this concern, and it is real. I don't see a way to
> resolve this problem; perhaps I am not smart enough, but I can't see a way to
> have both dynamic pinning AND avoid this tracking attack.
> 
> I am willing to add a paragraph about what browsers should do in private
> browsing mode, and I am willing to go either way on what the requirement
> should be. I don't know what is best.

We battled this problem with HSTS as well.  I think what Mozilla settled on (and I don't remember the Chrome solution) is to use a different storage mechanism when HSTS is *set* during private browsing mode, and clear on exit from private browsing.  

Clearing history/cookies on the browser is similarly problematic for HSTS and pinning.  This is unfortunate in that we'd really like it to be hard for users to clear HSTS state because it is "good for them".  Not clear whether this belongs in the spec, or a set of implementation guidelines.  Folks got squeamish here about talking about exact UA behavior, etc.

There is a Firefox bugzilla bug about this issue, I'll try to go find it and post back here unless someone beats me to it.

- Andy

---

From: Chris Evans <[email-masked]>
Date: Tue, 8 Nov 2011 19:59:57 -0800

On Tue, Nov 8, 2011 at 7:48 PM, Steingruebl, Andy <
[email-masked]> wrote:

> way to
> We battled this problem with HSTS as well.  I think what Mozilla settled
> on (and I don't remember the Chrome solution) is to use a different storage
> mechanism when HSTS is *set* during private browsing mode, and clear on
> exit from private browsing.
>

I recently fixed Chrome's behaviour here to be (barring regressions):
- _New_ HSTS metadata encountered in incognito mode is saved in-memory for
the duration of the incognito session, but never persisted to disk, or seen
outside of the incognito windows.
- Incognito mode _will_ use HSTS metadata that was already persisted to
disk at the start of the incognito session.

That seemed like a solid balance between the various privacy vs. security
concerns.

> Clearing history/cookies on the browser is similarly problematic for HSTS
> and pinning.  This is unfortunate in that we'd really like it to be hard
> for users to clear HSTS state because it is "good for them".  Not clear
> whether this belongs in the spec, or a set of implementation guidelines.
>  Folks got squeamish here about talking about exact UA behavior, etc.
>

For Chrome, I believe it is tied to cookies: "Cookies and other site data".
Last I talked with Sid at Firefox, they were thinking of splitting off
cookies from other site data. I'm not sure where that went. It also gets
complicated: is HTML5 database / indexed storage "cookies" or "other site
data", etc. etc.

I'd recommend we stay out of providing exact UA requirements here other
than a "SHOULD" for providing _some_ user-friendly way to clear HSTS
metadata. Realistically, it's a pretty small percentage of the browsing
population that go in and fiddle with storage settings.

Cheers
Chris

> There is a Firefox bugzilla bug about this issue, I'll try to go find it
> and post back here unless someone beats me to it.
>
> - Andy
>
>

---

From: Yoav Nir <[email-masked]>
Date: Wed, 9 Nov 2011 09:09:51 +0200

>represent this proposal at the meeting, though.

Hi Chris.

In case you don't know, the embargo on submitting drafts is lifted when
IETF week starts, so that's next Monday, plenty of time before the meeting
on Wednesday.

I don't really understand the logic of this, but you can.

Yoav

---

From: Julian Reschke <[email-masked]>
Date: Wed, 09 Nov 2011 09:34:44 +0100

On 2011-11-09 01:31, Tom Ritter wrote:
> ...

By all means *please* consider re-using the syntax of an existing header 
field. In particular, please read

<http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-17.html#rfc.section.3.1>

So decide whether you want to allow multiple header fields (in which 
case you should use the ABNF list notation used in 2616/HTTPbis), *or* 
define the syntax so that a "," introduced by header field recombination 
can be detected by recipients.

Best regards, Julian

---

From: Adam Barth <[email-masked]>
Date: Wed, 9 Nov 2011 01:20:27 -0800

> We battled this problem with HSTS as well.  I think what Mozilla settled on (and I don't remember the Chrome solution) is to use a different storage mechanism when HSTS is *set* during private brow…

It's been a while since I wrote that code, but I'm pretty sure that's
how it works in Chrome too.  There's a separate memory-only HSTS store
that's used for incognito.  That's consistent with how we handle other
host-specific data stored by the network layer, such as cookies.

Adam

> _______________________________________________
> websec mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/websec
>

---

From: "Steingruebl, Andy" <[email-masked]>
Date: Wed, 9 Nov 2011 09:38:13 -0700

> From: Adam Barth [mailto:[email-masked]]

> > We battled this problem with HSTS as well.  I think what Mozilla settled on
> (and I don't remember the Chrome solution) is to use a different storage
> It's been a while since I wrote that code, but I'm pretty sure that's how it
> works in Chrome too.  There's a separate memory-only HSTS store that's
> used for incognito.  That's consistent with how we handle other host-specific
> data stored by the network layer, such as cookies.

Is this documented anywhere?  Where should it be?  Maybe add a section to the browser security handbook, if nowhere else, so at least we all have it written down what the browsers have implemented?

And, since we decided these specifics don't belong in the IETF  HSTS spec, where could we document them for real?

- Andy

---

From: Adam Barth <[email-masked]>
Date: Wed, 9 Nov 2011 09:03:19 -0800

> Is this documented anywhere?  Where should it be?  Maybe add a section to the browser security handbook, if nowhere else, so at least we all have it written down what the browsers have implemented?

I don't believe it's documented anywhere.

> And, since we decided these specifics don't belong in the IETF  HSTS spec, where could we document them for real?

Typically, incognito mode hasn't been standardized anywhere.  The
general concept is that it should follow all the other standards, but
act as a short-lived user agent.  For example, you can imagine that
the user agent is created when the user enters incognito and destroyed
when the user leaves incognito.

If we were to standardize the mode, we'd probably do it in a working
group similar to http://www.w3.org/2006/WSC/.  However, I'm not sure
how much interest there is around that task.

Adam

---

From: Paul Hoffman <[email-masked]>
Date: Wed, 9 Nov 2011 10:04:32 -0800

> how much interest there is around that task.

Another option is a short Internet Draft that would become an independent submission RFC that says "here is how a few browser vendors define the problem and solve it, at the time that this is published". That is *exactly* what the independent submission RFCs are good for. No wide IETF review, no need to listen to anyone who thinks you should do it differently; just "here is what we do, and why".

--Paul Hoffman

---

From: Adam Barth <[email-masked]>
Date: Wed, 9 Nov 2011 10:15:26 -0800

> Another option is a short Internet Draft that would become an independent submission RFC that says "here is how a few browser vendors define the problem and solve it, at the time that this is publi…

That sounds like a reasonable plan.  Collin Jackson has written up a
detailed analysis of the current state of affairs in this paper:

http://www.collinjackson.com/research/private-browsing.pdf

Adam

---

From: Chris Palmer <[email-masked]>
Date: Wed, 9 Nov 2011 12:09:52 -0800

On Wed, Nov 9, 2011 at 12:34 AM, Julian Reschke <[email-masked]> wrote:

> So decide whether you want to allow multiple header fields (in which case
> you should use the ABNF list notation used in 2616/HTTPbis), *or* define the
> syntax so that a "," introduced by header field recombination can be
> detected by recipients.

I'm sorry, I don't know what you mean by "a ',' introduced by header
field recombination".

What grammar do you prefer?

---

From: Julian Reschke <[email-masked]>
Date: Wed, 09 Nov 2011 21:24:56 +0100

On 2011-11-09 21:09, Chris Palmer wrote:
> On Wed, Nov 9, 2011 at 12:34 AM, Julian Reschke<[email-masked]>  wrote:
>

<http://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.4.2.p.5>

> What grammar do you prefer?

I would recommend a syntax that uses a single delimiter. If you use ";", 
you'd be able to detect the case mentioned above. If you use ",", you 
could support multiple header fields (if this is desired).

By using both however, you gain nothing (IHMO), and create potential 
problems.

Let's assume it's ";". In that case I would write:

directives      = max-age LWS *( ";" LWS [ fingerprint ] )

thus require max-age to be always first (your grammar allows it at the 
beginning and at the end, but not inbetween; this is likely to cause 
confusion.

Then make fingerprint a proper name/value pair, as in other HTTP 
parameters, and put the name of the hash into the parameter name. So 
instead of

    Public-Key-Pins: max-age=31536000;
        pins=sha1-4n972HfV354KP560yw4uqe/baXc=,
        sha256-LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=

you'd have

    Public-Key-Pins: max-age=31536000;
        pins-sha1=4n972HfV354KP560yw4uqe/baXc=;
        pins-sha256=LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=

Finally, allow quoted-string notation,

    Public-Key-Pins: max-age=31536000;
        pins-sha1="4n972HfV354KP560yw4uqe/baXc=";
        pins-sha256="LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="

so that characters not allowed (such as "/") in HTTP tokens work.

Best regards, Julian

Best regards, Julian

---

From: Chris Palmer <[email-masked]>
Date: Wed, 9 Nov 2011 13:28:32 -0800

>From what I can gather, there is a thing called "header field
recombination", in which a proxy or something collapses two or more
headers of the same type into one, and joins their values with a ",".
Therefore, I should not list multiple pins separated with a "," in the
PKP header. OK.

(This is new to me. Are there MITMs that really do this? Why?)

(FWIW, the only relevant hit in the first page of Google results for [
header field recombination ] is
http://svn.tools.ietf.org/wg/httpbis/trac/ticket/231.)

>       pins-sha256=LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=

OK. I suppose now we might as well get rid of the "pins-" too.

> so that characters not allowed (such as "/") in HTTP tokens work.

But if "/" is not allowed in HTTP tokens, we have to require
quoted-string notation, and not merely allow it. Right?

Could anyone propose exact ABNF grammar that is acceptable given the
above constraints? Currently, I have it as:

fp-type         = "sha1"
                  / "sha256"

Thanks!

---

From: Julian Reschke <[email-masked]>
Date: Wed, 09 Nov 2011 22:45:04 +0100

> (This is new to me. Are there MITMs that really do this? Why?)

I know of *libraries* that do this, and I wouldn't rule out 
intermediates using those.

> OK. I suppose now we might as well get rid of the "pins-" too.

Unless you need an extension point for other parameters.

> quoted-string notation, and not merely allow it. Right?

Indeed. But they are used in base64, unless you switch to 
<https://tools.ietf.org/html/rfc4648#section-5>.

> above constraints? Currently, I have it as:

I made a proposal; is there something specific you didn't like?

Best regards, Julian

---

From: Chris Palmer <[email-masked]>
Date: Wed, 9 Nov 2011 13:50:18 -0800

> I made a proposal; is there something specific you didn't like?

Your proposal is fine — thank you! It's just that I am almost
certainly going to write the ABNF wrong, and then we'll have a whole
long thread about that. :)

---

From: "Ryan Sleevi" <[email-masked]>
Date: Wed, 9 Nov 2011 17:03:22 -0500

>  long thread about that. :)

While revisiting the ABNF, should "fp-type" be made into 'token' instead
of an explicit list ( "sha1" / "sha256" )? Rather than dealing with the
minimal set of "must-implements" in the grammar, define it in the text for
processing rules. This is similar to the conversation that happened for
the STS grammar rules.

I'm just wondering how legacy parsers would be expected to handle future
versions with say, SHA-3. Defining it as a token would at least allow it
to be syntactically valid and parsed, even if fingerprints of that type
are not understood/supported.

---

From: Chris Palmer <[email-masked]>
Date: Thu, 10 Nov 2011 11:35:46 -0800

> processing rules. This is similar to the conversation that happened for

Here is what I have now:

<figure anchor="header-abnf">
<artwork>
Public-Key-Pins = "Public-Key-Pins" ":" LWS directives

pins            = pin
                  / pin LWS ";" LWS pins

pin             = "pin-" token LWS "=" LWS quoted-string
</artwork>
</figure>

<t>In the pin rule, the token is the name of a cryptographic hash algorithm,
and MUST be either "sha1" or "sha256". (Future versions of this
specification may change the hash functions.) The quoted-string is a
sequence of base64 digits: a base64-encoded hash. See <xref
target="pin-semantics"/>.</t>