Subject: [websec] Pin activation in HPKP

From: Trevor Perrin <[email-masked]>
Date: Mon, 15 Apr 2013 17:23:34 -0700

Hi websec,

Long email, sorry!

TLDR:  HPKP could do TACK-like "pin activation" for safer pinning.

-----

At one point, the HPKP draft mentioned "pin activation" a la TACK [1].
 In TACK's algorithm, a client has to observe a pin assertion multiple
times before "activating" a pin.  After the first observation,
subsequent observations cause the pin to be activated for a period
equal to the span in which the client has observed the assertion, or a
max of 30 days.

The goal of this is to limit damage from malicious or mistaken "bad
pins", with a side benefit of simplifying deployment:

 * If connections to a domain are being hijacked (due to DNS
hijacking, domain name theft, an intercepted Wifi connection, etc.),
and the attacker is atttempting to set a malicious pin, the resultant
pin will not last longer than the attacker has already controlled the
connection for (e.g., if you're at a coffee-shop for 2 hours, it can't
set bad pins that last more than 2 hours; if a domain name is hijacked
for 2 days, bad pins will expire 2 days afterwards; etc.)

 * If a site advertises bad pins for itself, perhaps due to a
configuration mistake, a hacker, or a disgruntled system
administrator, damage will be limited if the mistake is noticed and
corrected quickly.

 * Since pin lifetimes are automatically scaled in a way which allows
safe rollout (with quick removal an option if things go wrong), we can
potentially do without an explicit max-age, making deployment simpler
(one less knob the deployer has to turn).

-- 

I had discussed this with Chris and Ryan, and applying this algorithm
to HPKP seemed difficult.  The algorithm requires clients make
observations which either "confirm" or "contradict" an existing pin.
This has three complications in HPKP:

First, an HPKP header may assert a list of pinned keys which overlaps
but doesn't exactly match a previous header.  It's not instantly
obvious how to handle this.

Second, a TACK pin requires a matching tack to be present in every
(non-resumed) TLS handshake, or the pin is contradicted.  Thus, a bad
pin set by an attacker can be contradicted when the client visits the
legitimate site, whether the legitimate site is aware of TACK or not.
In HPKP, on the other hand, HPKP headers are *not* required to be
present in HTTP responses from pinned sites, so there wouldn't be as
much benefit from regular sites "contradicting" bad pins.

Third, "include_subdomains" (which TACK does not have) adds a wrinkle
(if a pin is set at A.com, can B.A.com activate it?, etc.)

--

On further thought, I think the first problem can be solved by
adapting TACK's "overlapping pins" notion, where a client can have 2
pins active at once: this allows the new pin to be activated *prior
to* removing the old one.

The second problem may or may not be solvable, depending on whether
HPKP is willing to require HPKP headers be present in responses from a
pinned site.  However, I think the algorithm has value even without
this.

The third problem (include_subdomains) needs more analysis.  There are
ways pin activation could work with include_subdomains, but it adds
more complexity.  I'm not quite sure the value of
"include_subdomains".  According to HSTS [2] section 14.4, it protects
cookies.  But there are other ways to protect cookies (see the TACK
draft section 8.1) which are usable by all sites, not just those
willing to pin their subdomains.  And cookies should be replaced
anyways, which I believe this WG is looking into.

--

Anyways, here's a sketch of a "pin activation" algorithm for HPKP.
This algorithm is basically the same as TACK (section 4.3.4), so it
creates opportunites for sharing code / analysis / deployment advice
etc.  I'm omitting "max-age" and "includeSubdomains", but if the group
is interested, we can discuss how to do them.

Definition of "HPKP pin":
 - a set of public-key hashes
 - "initial time" when pin was created
 - "end time" when pin ceases to be active (or 0)

Definition of "HPKP pin assertion":
 - A set of public key hashes presented in an HPKP header

A client may store 0, 1, or 2 HPKP pins for a single domain name.  A
server may present 0, 1, or 2 HPKP pin assertions in a single HTTP
response header (syntax TBD).

Client connections to domains with an active pin or pins MUST match
these pins or the connection is considered "contradicted" by the pin
(e.g. if a client has 2 active pins for "example.com", the connection
must have a certificate path that overlaps at least one key from each
pin).

If the connection is not contradicted, then the following steps are performed:
 1. Any inactive pins are deleted if they don't overlap the
certificate chain, or if there is an HPKP header that doesn't reassert
the inactive pin.
 2. If there are pins that are re-asserted by the HPKP header (i.e. a
pin assertion lists the exact same keys as the pin), their active
period is set by:

  end_time = current + MIN(30 days, current - initial_time)

 3. Any new pin assertions create new inactive pins with initial_time
= current and end_time = 0.

--

So on deploying an initial pin assertion, clients will begin creating
and activating pins.  If problems are detected in the first (minutes /
hours / days) of rollout, the assertion can be taken down, and
problems will subside fairly quickly, as no client will have yet
activated a long-lived pin.

To change pins, the server simply deploys the new assertion alongside
the old one.  After 60 days, the old assertion may be removed.  This
guarantees that a client who is contacting the server at intervals of
30 days or less will never receive less than a full 30-day active
period, to either the new or old pin, during the transition.

If the server needs to switch more quickly from the old to new
assertion it can do so, but this may create a window where clients
have deleted the old pin but the new one is not yet receiving full
30-day active periods.  By allowing "overlapping" pins and pin
assertions, we avoid this in the case where servers are making
carefully-planned transitions from one pin to another.

Anyways, yes, this is complicated to analyze but it's fairly simple to
implement.  I'm sure I explained some of this badly, so please ask
questions!  I hope we can discuss this more...

Trevor