-
public final class CertificatePinnerConstrains 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 either base64 SHA-256 hashes as in HTTP Public Key Pinning (HPKP) or SHA-1 base64 hashes as in Chromium's static certificates.
Setting up Certificate PinningThe 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
{@code https://publicobject.com}, start with a broken configuration:
As expected, this fails with a certificate pinning exception:{@code * * String hostname = "publicobject.com"; * CertificatePinner certificatePinner = new CertificatePinner.Builder() * .add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") * .build(); * MobonOkHttpClient client = MobonOkHttpClient.Builder() * .certificatePinner(certificatePinner) * .build(); * * MobonRequest mobonRequest = new MobonRequest.Builder() * .url("https://" + hostname) * .build(); * client.newCall(mobonRequest).execute(); * }
Follow up by pasting the public key hashes from the exception into the certificate pinner's configuration:{@code * * 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) * }
Pinning is per-hostname and/or per-wildcard pattern. To pin both{@code * * 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(); * }{@code publicobject.com}and{@code www.publicobject.com}, you must configure both hostnames.Wildcard pattern rules:
- Asterisk
{@code *}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,{@code *.example.com}is permitted, while{@code *a.example.com},{@code a*.example.com},{@code a*b.example.com},{@code a.*.example.com}are not permitted. - Asterisk
{@code *}cannot match across domain name labels. For example,{@code *.example.com}matches{@code test.example.com}but does not match{@code sub.test.example.com}. - Wildcard patterns for single-label domain names are not permitted.
{@code *.example.com}pinned with{@code pin1}and{@code a.example.com}pinned with{@code pin2}, to check{@code a.example.com}both{@code pin1}and{@code 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 certificatesCertificatePinner can not be used to pin self-signed certificate if such certificate is not accepted by javax.net.ssl.TrustManager.
- Asterisk
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public final classCertificatePinner.BuilderBuilds a configured certificate pinner.
-
Field Summary
Fields Modifier and Type Field Description public final static CertificatePinnerDEFAULT
-
Method Summary
Modifier and Type Method Description booleanequals(@Nullable() Object other)inthashCode()voidcheck(String hostname, List<Certificate> peerCertificates)Confirms that at least one of the certificates pinned for {@code hostname}is in{@code * peerCertificates}.voidcheck(String hostname, Array<Certificate> peerCertificates)static Stringpin(Certificate certificate)Returns the SHA-256 of {@code certificate}'s public key.-
-
Method Detail
-
hashCode
int hashCode()
-
check
void check(String hostname, List<Certificate> peerCertificates)
Confirms that at least one of the certificates pinned for
{@code hostname}is in{@code * peerCertificates}. Does nothing if there are no certificates pinned for{@code hostname}.OkHttp calls this after a successful TLS handshake, but before the connection is used.
-
check
void check(String hostname, Array<Certificate> peerCertificates)
-
pin
static String pin(Certificate certificate)
Returns the SHA-256 of
{@code certificate}'s public key.In OkHttp 3.1.2 and earlier, this returned a SHA-1 hash of the public key. Both types aresupported, but SHA-256 is preferred.
-
-
-
-