public final class CertificatePinner extends Object
This class currently pins a certificate's Subject Public Key Info as described on Adam Langley's Weblog. Pins are either base64 SHA-256 hashes as in HTTP Public Key Pinning (HPKP) or SHA-1 base64 hashes as in Chromium's static certificates.
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, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .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: sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=publicobject.com, OU=PositiveSSL sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root Pinned certificates for publicobject.com: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= at okhttp3.CertificatePinner.check(CertificatePinner.java) at okhttp3.Connection.upgradeToTls(Connection.java) at okhttp3.Connection.connect(Connection.java) at okhttp3.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", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") .add("publicobject.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=") .add("publicobject.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=") .add("publicobject.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=") .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:
* 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. * cannot match across domain name labels. For example, *.example.com matches test.example.com but does not match sub.test.example.com. *.example.com pinned with
pin1 and
a.example.com pinned with
pin2, to check
a.example.com both
pin1 and
pin2 will be used.
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!
CertificatePinner can not be used to pin self-signed certificate if such certificate is not accepted by TrustManager.
| Modifier and Type | Class and Description |
|---|---|
static class |
CertificatePinner
Builds a configured certificate pinner.
|
| Modifier and Type | Field and Description |
|---|---|
static CertificatePinner |
DEFAULT
|
| Modifier and Type | Method and Description |
|---|---|
void |
check(String
Deprecated.
replaced with
check(String, List).
|
void |
check(String
Confirms that at least one of the certificates pinned for
hostname is in
peerCertificates.
|
static String |
pin(Certificate
Returns the SHA-256 of
certificate's public key.
|
public static final CertificatePinnerDEFAULT
public void check(Stringhostname, List <Certificate > peerCertificates) throws SSLPeerUnverifiedException
hostname is in
peerCertificates. Does nothing if there are no certificates pinned for
hostname. OkHttp calls this after a successful TLS handshake, but before the connection is used.
SSLPeerUnverifiedException - if
peerCertificates don't match the certificates pinned for
hostname.
public void check(Stringhostname, Certificate ... peerCertificates) throws SSLPeerUnverifiedException
check(String, List).
SSLPeerUnverifiedException
public static Stringpin(Certificate certificate)
certificate's public key.
In OkHttp 3.1.2 and earlier, this returned a SHA-1 hash of the public key. Both types are supported, but SHA-256 is preferred.