Class CertificatePinner


  • public final class CertificatePinner
    extends Object
    Constrains which certificates are trusted. Pinning certificates defends against attacks on certificate authorities. It also prevents connections through man-in-the-middle certificate authorities either known or unknown to the application's user.

    This class currently pins a certificate's Subject Public Key Info as described on Adam Langley's Weblog. Pins are base-64 SHA-1 hashes, consistent with the format Chromium uses for static certificates. See Chromium's pinsets for hostnames that are pinned in that browser.

    Setting up Certificate Pinning

    The easiest way to pin a host is turn on pinning with a broken configuration and read the expected configuration when the connection fails. Be sure to do this on a trusted network, and without man-in-the-middle tools like Charles or Fiddler.

    For example, to pin https://publicobject.com, start with a broken configuration:

       
    
         String hostname = "publicobject.com";
         CertificatePinner certificatePinner = new CertificatePinner.Builder()
             .add(hostname, "sha1/BOGUSPIN")
             .build();
         OkHttpClient client = new OkHttpClient();
         client.setCertificatePinner(certificatePinner);
    
         Request request = new Request.Builder()
             .url("https://" + hostname)
             .build();
         client.newCall(request).execute();
     
    As expected, this fails with a certificate pinning exception:
       
    
     javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
       Peer certificate chain:
         sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=: CN=publicobject.com, OU=PositiveSSL
         sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=: CN=COMODO RSA Domain Validation Secure Server CA
         sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=: CN=COMODO RSA Certification Authority
         sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=: CN=AddTrust External CA Root
       Pinned certificates for publicobject.com:
         sha1/BOGUSPIN
       at com.squareup.okhttp.CertificatePinner.check(CertificatePinner.java)
       at com.squareup.okhttp.Connection.upgradeToTls(Connection.java)
       at com.squareup.okhttp.Connection.connect(Connection.java)
       at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java)
     
    Follow up by pasting the public key hashes from the exception into the certificate pinner's configuration:
       
    
         CertificatePinner certificatePinner = new CertificatePinner.Builder()
           .add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
           .add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
           .add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
           .add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
           .build();
     
    Pinning is per-hostname and/or per-wildcard pattern. To pin both publicobject.com and www.publicobject.com, you must configure both hostnames.

    Wildcard pattern rules:

    1. Asterisk * is only permitted in the left-most domain name label and must be the only character in that label (i.e., must match the whole left-most label). For example, *.example.com is permitted, while *a.example.com, a*.example.com, a*b.example.com, a.*.example.com are not permitted.
    2. Asterisk * cannot match across domain name labels. For example, *.example.com matches test.example.com but does not match sub.test.example.com.
    3. Wildcard patterns for single-label domain names are not permitted.
    If hostname pinned directly and via wildcard pattern, both direct and wildcard pins will be used. For example: *.example.com pinned with pin1 and a.example.com pinned with pin2, to check a.example.com both pin1 and pin2 will be used.

    Warning: Certificate Pinning is Dangerous!

    Pinning certificates limits your server team's abilities to update their TLS certificates. By pinning certificates, you take on additional operational complexity and limit your ability to migrate between certificate authorities. Do not use certificate pinning without the blessing of your server's TLS administrator!

    Note about self-signed certificates

    CertificatePinner can not be used to pin self-signed certificate if such certificate is not accepted by TrustManager.
    See Also:
    OWASP: Certificate and Public Key Pinning