On Sat, May 14, 2016 at 10:46 PM, 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 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.

This is kind of expected. The problem is because the first certificate
(older version of Android) uses domain parameters; while the second
certificate (Conscrypt/OpenSSL) uses a named curve rather than domain
parameters.

I've experienced similar problems with OpenSSL servers and clients. In
fact, if a named curve is *not used*, then you will encounter an error
"no shared ciphers" under some circumstances. Also see
http://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Named_Curves.

A certificate simply binds a public key to an identity through a
trusted party's signature. Once you verify the signature on the
certificate, you should canonicalize the certificate data and then pin
the normalizedd data.

Jeff

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

Reply via email to