public final class CertificatePinner
extends java.lang.Object
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.
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. To pin both publicobject.com
and www.publicobject.com
, you must configure both hostnames.
Modifier and Type | Class and Description |
---|---|
static class |
CertificatePinner.Builder
Builds a configured certificate pinner.
|
Modifier and Type | Field and Description |
---|---|
static CertificatePinner |
DEFAULT |
Modifier and Type | Method and Description |
---|---|
void |
check(java.lang.String hostname,
java.security.cert.Certificate... peerCertificates)
Confirms that at least one of the certificates pinned for
hostname
is in peerCertificates . |
static java.lang.String |
pin(java.security.cert.Certificate certificate)
Returns the SHA-1 of
certificate 's public key. |
public static final CertificatePinner DEFAULT
public void check(java.lang.String hostname, java.security.cert.Certificate... peerCertificates) throws javax.net.ssl.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.javax.net.ssl.SSLPeerUnverifiedException
- if peerCertificates
don't match
the certificates pinned for hostname
.public static java.lang.String pin(java.security.cert.Certificate certificate)
certificate
's public key. This uses the
mechanism Moxie Marlinspike describes in Android Pinning.Copyright © 2014. All Rights Reserved.