use of okhttp3.tls.HandshakeCertificates in project okhttp by square.
the class CertificateChainCleanerTest method equalsFromTrustManager.
@Test
public void equalsFromTrustManager() {
HandshakeCertificates handshakeCertificates = new HandshakeCertificates.Builder().build();
X509TrustManager x509TrustManager = handshakeCertificates.trustManager();
assertThat(CertificateChainCleaner.Companion.get(x509TrustManager)).isEqualTo(CertificateChainCleaner.Companion.get(x509TrustManager));
}
use of okhttp3.tls.HandshakeCertificates in project okhttp by square.
the class MockWebServerTest method httpsWithClientAuth.
@Test
public void httpsWithClientAuth() throws Exception {
assumeFalse(getPlatform().equals("conscrypt"));
HeldCertificate clientCa = new HeldCertificate.Builder().certificateAuthority(0).build();
HeldCertificate serverCa = new HeldCertificate.Builder().certificateAuthority(0).build();
HeldCertificate serverCertificate = new HeldCertificate.Builder().signedBy(serverCa).addSubjectAlternativeName(server.getHostName()).build();
HandshakeCertificates serverHandshakeCertificates = new HandshakeCertificates.Builder().addTrustedCertificate(clientCa.certificate()).heldCertificate(serverCertificate).build();
server.useHttps(serverHandshakeCertificates.sslSocketFactory(), false);
server.enqueue(new MockResponse().setBody("abc"));
server.requestClientAuth();
HeldCertificate clientCertificate = new HeldCertificate.Builder().signedBy(clientCa).build();
HandshakeCertificates clientHandshakeCertificates = new HandshakeCertificates.Builder().addTrustedCertificate(serverCa.certificate()).heldCertificate(clientCertificate).build();
HttpUrl url = server.url("/");
HttpsURLConnection connection = (HttpsURLConnection) url.url().openConnection();
connection.setSSLSocketFactory(clientHandshakeCertificates.sslSocketFactory());
connection.setHostnameVerifier(new RecordingHostnameVerifier());
assertThat(connection.getResponseCode()).isEqualTo(HttpURLConnection.HTTP_OK);
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF_8));
assertThat(reader.readLine()).isEqualTo("abc");
RecordedRequest request = server.takeRequest();
assertThat(request.getRequestUrl().scheme()).isEqualTo("https");
Handshake handshake = request.getHandshake();
assertThat(handshake.tlsVersion()).isNotNull();
assertThat(handshake.cipherSuite()).isNotNull();
assertThat(handshake.localPrincipal()).isNotNull();
assertThat(handshake.localCertificates().size()).isEqualTo(1);
assertThat(handshake.peerPrincipal()).isNotNull();
assertThat(handshake.peerCertificates().size()).isEqualTo(1);
}
use of okhttp3.tls.HandshakeCertificates in project okhttp by square.
the class MockWebServerTest method https.
@Test
public void https() throws Exception {
HandshakeCertificates handshakeCertificates = localhost();
server.useHttps(handshakeCertificates.sslSocketFactory(), false);
server.enqueue(new MockResponse().setBody("abc"));
HttpUrl url = server.url("/");
HttpsURLConnection connection = (HttpsURLConnection) url.url().openConnection();
connection.setSSLSocketFactory(handshakeCertificates.sslSocketFactory());
connection.setHostnameVerifier(new RecordingHostnameVerifier());
assertThat(connection.getResponseCode()).isEqualTo(HttpURLConnection.HTTP_OK);
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF_8));
assertThat(reader.readLine()).isEqualTo("abc");
RecordedRequest request = server.takeRequest();
assertThat(request.getRequestUrl().scheme()).isEqualTo("https");
Handshake handshake = request.getHandshake();
assertThat(handshake.tlsVersion()).isNotNull();
assertThat(handshake.cipherSuite()).isNotNull();
assertThat(handshake.localPrincipal()).isNotNull();
assertThat(handshake.localCertificates().size()).isEqualTo(1);
assertThat(handshake.peerPrincipal()).isNull();
assertThat(handshake.peerCertificates().size()).isEqualTo(0);
}
use of okhttp3.tls.HandshakeCertificates in project okhttp by square.
the class LetsEncryptTest method getPassesAdditionalCert.
@Test
public void getPassesAdditionalCert() throws IOException, CertificateException {
boolean androidMorEarlier = Build.VERSION.SDK_INT <= 23;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (androidMorEarlier) {
String isgCert = "-----BEGIN CERTIFICATE-----\n" + "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\n" + "-----END CERTIFICATE-----";
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate isgCertificate = cf.generateCertificate(new ByteArrayInputStream(isgCert.getBytes("UTF-8")));
HandshakeCertificates certificates = new HandshakeCertificates.Builder().addTrustedCertificate((X509Certificate) isgCertificate).build();
builder.sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager());
}
OkHttpClient client = builder.build();
sendRequest(client, "https://valid-isrgrootx1.letsencrypt.org/robots.txt");
try {
sendRequest(client, "https://google.com/robots.txt");
if (androidMorEarlier) {
// will pass with default CAs on N or later
fail();
}
} catch (SSLHandshakeException sslhe) {
assertTrue(androidMorEarlier);
}
}
use of okhttp3.tls.HandshakeCertificates in project okhttp by square.
the class CertificatePinnerChainValidationTest method signersMustHaveCaBitSet.
/**
* Not checking the CA bit created a vulnerability in old OkHttp releases. It is exploited by
* triggering different chains to be discovered by the TLS engine and our chain cleaner. In this
* attack there's several different chains.
*
* <p>The victim's gets a non-CA certificate signed by a CA, and pins the CA root and/or
* intermediate. This is business as usual.
*
* <pre>{@code
*
* pinnedRoot (trusted by CertificatePinner)
* -> pinnedIntermediate (trusted by CertificatePinner)
* -> realVictim
*
* }</pre>
*
* <p>The attacker compromises a CA. They take the public key from an intermediate certificate
* signed by the compromised CA's certificate and uses it in a non-CA certificate. They ask the
* pinned CA above to sign it for non-certificate-authority uses:
*
* <pre>{@code
*
* pinnedRoot (trusted by CertificatePinner)
* -> pinnedIntermediate (trusted by CertificatePinner)
* -> attackerSwitch
*
* }</pre>
*
* <p>The attacker serves a set of certificates that yields a too-long chain in our certificate
* pinner. The served certificates (incorrectly) formed a single chain to the pinner:
*
* <pre>{@code
*
* attackerCa
* -> attackerIntermediate
* -> pinnedRoot (trusted by CertificatePinner)
* -> pinnedIntermediate (trusted by CertificatePinner)
* -> attackerSwitch (not a CA certificate!)
* -> phonyVictim
*
* }</pre>
*
* But this chain is wrong because the attackerSwitch certificate is being used in a CA role even
* though it is not a CA certificate. There are pinned certificates in the chain! The correct
* chain is much shorter because it skips the non-CA certificate.
*
* <pre>{@code
*
* attackerCa
* -> attackerIntermediate
* -> phonyVictim
*
* }</pre>
*
* Some implementations fail the TLS handshake when they see the long chain, and don't give
* CertificatePinner the opportunity to produce a different chain from their own. This includes
* the OpenJDK 11 TLS implementation, which itself fails the handshake when it encounters a non-CA
* certificate.
*/
@Test
public void signersMustHaveCaBitSet() throws Exception {
HeldCertificate attackerCa = new HeldCertificate.Builder().serialNumber(1L).certificateAuthority(4).commonName("attacker ca").build();
HeldCertificate attackerIntermediate = new HeldCertificate.Builder().serialNumber(2L).certificateAuthority(3).commonName("attacker").signedBy(attackerCa).build();
HeldCertificate pinnedRoot = new HeldCertificate.Builder().serialNumber(3L).certificateAuthority(2).commonName("pinned root").signedBy(attackerIntermediate).build();
HeldCertificate pinnedIntermediate = new HeldCertificate.Builder().serialNumber(4L).certificateAuthority(1).commonName("pinned intermediate").signedBy(pinnedRoot).build();
HeldCertificate attackerSwitch = new HeldCertificate.Builder().serialNumber(5L).keyPair(// share keys between compromised CA and leaf!
attackerIntermediate.keyPair()).commonName("attacker").addSubjectAlternativeName("attacker.com").signedBy(pinnedIntermediate).build();
HeldCertificate phonyVictim = new HeldCertificate.Builder().serialNumber(6L).signedBy(attackerSwitch).addSubjectAlternativeName("victim.com").commonName("victim").build();
CertificatePinner certificatePinner = new CertificatePinner.Builder().add(server.getHostName(), CertificatePinner.pin(pinnedRoot.certificate())).build();
HandshakeCertificates handshakeCertificates = new HandshakeCertificates.Builder().addTrustedCertificate(pinnedRoot.certificate()).addTrustedCertificate(attackerCa.certificate()).build();
OkHttpClient client = clientTestRule.newClientBuilder().sslSocketFactory(handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager()).hostnameVerifier(new RecordingHostnameVerifier()).certificatePinner(certificatePinner).build();
HandshakeCertificates serverHandshakeCertificates = new HandshakeCertificates.Builder().heldCertificate(phonyVictim, attackerSwitch.certificate(), pinnedIntermediate.certificate(), pinnedRoot.certificate(), attackerIntermediate.certificate()).build();
server.useHttps(serverHandshakeCertificates.sslSocketFactory(), false);
server.enqueue(new MockResponse());
// Make a request from client to server. It should succeed certificate checks (unfortunately the
// rogue CA is trusted) but it should fail certificate pinning.
Request request = new Request.Builder().url(server.url("/")).build();
Call call = client.newCall(request);
try (Response response = call.execute()) {
fail("expected connection failure but got " + response);
} catch (SSLPeerUnverifiedException expected) {
// Certificate pinning fails!
String message = expected.getMessage();
assertThat(message).startsWith("Certificate pinning failure!");
} catch (SSLHandshakeException expected) {
// We didn't have the opportunity to do certificate pinning because the handshake failed.
assertThat(expected).hasMessageContaining("this is not a CA certificate");
}
}
Aggregations