//okhttp/okhttp3/CertificatePinner
CertificatePinner¶
[jvm]\ class CertificatePinner
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 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 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, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
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();
Domain Patterns¶
Pinning is per-hostname and/or per-wildcard pattern. To pin both publicobject.com
and www.publicobject.com
you must configure both hostnames. Or you may use patterns to match sets of related domain names. The following forms are permitted:
- Full domain name: you may pin an exact domain name like
www.publicobject.com
. It won’t match additional prefixes (us-west.www.publicobject.com
) or suffixes (publicobject.com
). - Any number of subdomains: Use two asterisks to like
**.publicobject.com
to match any number of prefixes (us-west.www.publicobject.com
,www.publicobject.com
) including no prefix at all (publicobject.com
). For most applications this is the best way to configure certificate pinning. - Exactly one subdomain: Use a single asterisk like
*.publicobject.com
to match exactly one prefix (www.publicobject.com
,api.publicobject.com
). Be careful with this approach as no pinning will be enforced if additional prefixes are present, or if no prefixes are present.
Note that any other form is unsupported. You may not use asterisks in any position other than the leftmost label.
If multiple patterns match a hostname, any match is sufficient. For example, suppose pin A applies to *.publicobject.com
and pin B applies to api.publicobject.com
. Handshakes for api.publicobject.com
are valid if either A’s or B’s certificate is in the chain.
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 javax.net.ssl.TrustManager.
See also OWASP: Certificate and Public Key Pinning.
Types¶
Name | Summary |
---|---|
Builder | [jvm] class Builder Builds a configured certificate pinner. |
Companion | [jvm] object Companion |
Pin | [jvm] class Pin(pattern: String, pin: String) A hostname pattern and certificate hash for Certificate Pinning. |
Functions¶
Name | Summary |
---|---|
check | [jvm] fun check(hostname: String, peerCertificates: List<Certificate>) Confirms that at least one of the certificates pinned for 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. |
equals | [jvm] open operator override fun equals(other: Any?): Boolean |
findMatchingPins | [jvm] fun findMatchingPins(hostname: String): List<CertificatePinner.Pin> Returns list of matching certificates’ pins for the hostname. Returns an empty list if the hostname does not have pinned certificates. |
hashCode | [jvm] open override fun hashCode(): Int |
Properties¶
Name | Summary |
---|---|
pins | [jvm] val pins: Set<CertificatePinner.Pin> |