That’s interesting. With HPKP you can pin keys from existing certificates, or 
keys that are not (yet) in certificates.

One of the early deployment scenarios (which got de-emphasized later on) was 
that you include two pins: your current production key and a spare key that you 
will certify if something bad happens to the production key (like the private 
key leaking out).

So because there is more than one way to encode the public key in SPKI you 
would need to predict how your CA is going to encode the SPKI of the spare key. 
There’s a couple of obvious heuristics: assume that the SPKI will be encoded 
the same way the SPKI is encoded in the certificate request, or assume that the 
SPKI in the next certificate will be encoded the same way as in the current 
certificate. Both of these heuristics could work most of the time, but if you 
miss, your pin is invalid and your site is bricked if you move to the backup 
public key.

It gets worse. Some sites re-certify the same key over and over. But again, 
nothing is preventing the CA from encoding the SPKI differently on the next 
certificate Maybe they’ve upgraded their software.

So there could be more caveats here for using HPKP in addition to needing to 
use the SPKI bytes from your actual DER-encoded certificate.

As a procedural note, there is no longer a WebSec working group, and RFCs, once 
published, are set in stone. Someone (you?) could publish a document with a 
title like “Additional Operational Considerations in Deploying HPKP”. That 
could prove interesting.

Yoav


> On 15 May 2016, at 5:46 AM, Jesse Wilson <[email protected]> wrote:
> 
> I work on OkHttp, an Android HTTP client that implements HPKP-like 
> certificate pinning. We recently saw a problem where different versions of 
> Android returned different bytes for the ASN.1 encoding of the same 
> certificate. This is bad: the pins don’t match!
> 
> The certificate of interest uses a named curve (secp521r1) with ECC. I used 
> der2ascii <https://github.com/google/der-ascii> to view the SPKI ASN.1 bytes.
> 
> Older versions of Android (which use BouncyCastle) embed the curve:
> 
> SEQUENCE {
>   SEQUENCE {
>     # ecPublicKey
>     OBJECT_IDENTIFIER { 1.2.840.10045.2.1 }
>     SEQUENCE {
>       INTEGER { 1 }
>       SEQUENCE {
>         # prime-field
>         OBJECT_IDENTIFIER { 1.2.840.10045.1.1 }
>         INTEGER { `01ffffffffffffff...` }
>       }
>       SEQUENCE {
>         OCTET_STRING { `01ffffffffffffff...` }
>         OCTET_STRING { `0051953eb9618e1c...` }
>       }
>       OCTET_STRING { `0400c6858e06b704...` }
>       INTEGER { `01ffffffffffffff...` }
>       INTEGER { 1 }
>     }
>   }
>   BIT_STRING { `0004019519de800d...` }
> }
> But new versions of Android (which use Conscrypt/OpenSSL) reference the curve 
> by name:
> 
> SEQUENCE {
>   SEQUENCE {
>     # ecPublicKey
>     OBJECT_IDENTIFIER { 1.2.840.10045.2.1 }
>     # secp521r1
>     OBJECT_IDENTIFIER { 1.3.132.0.35 }
>   }
>   BIT_STRING { `0004019519de800d...` }
> }
> The original certificate embeds the curve.
> 
> I believe my problem is that the Java APIs I’m using don’t return raw bytes 
> from the certificate. Instead Java decodes the certificate into a model and 
> re-encodes that when the bytes are requested. The original and roundtripped 
> SPKI bytes are not identical.
> 
> Does anyone else do ASN.1 encoding in order to compute a certificate’s pin? 
> Or is it a uniquely Java problem?!
> 
> The spec should warn that a single SPKI may have multiple conflicting 
> encodings. I suggest that only encoding in the certificate should be pinned. 
> TLS server administrators should also be careful to not inadvertently 
> re-encode their SPKIs when doing maintenance.
> 
> Thanks!
> 
> _______________________________________________
> websec mailing list
> [email protected]
> https://www.ietf.org/mailman/listinfo/websec

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

Reply via email to