use of okhttp3.Handshake in project okhttp by square.
the class LoggingEventListenerTest method secureGet.
@Test
public void secureGet() throws Exception {
TestUtil.assumeNotWindows();
platform.assumeNotBouncyCastle();
server.useHttps(handshakeCertificates.sslSocketFactory(), false);
url = server.url("/");
server.enqueue(new MockResponse());
Response response = client.newCall(request().build()).execute();
assertThat(response.body()).isNotNull();
response.body().bytes();
platform.assumeHttp2Support();
logRecorder.assertLogMatch("callStart: Request\\{method=GET, url=" + url + "\\}").assertLogMatch("proxySelectStart: " + url).assertLogMatch("proxySelectEnd: \\[DIRECT\\]").assertLogMatch("dnsStart: " + url.host()).assertLogMatch("dnsEnd: \\[.+\\]").assertLogMatch("connectStart: " + url.host() + "/.+ DIRECT").assertLogMatch("secureConnectStart").assertLogMatch("secureConnectEnd: Handshake\\{" + "tlsVersion=TLS_1_[23] " + "cipherSuite=TLS_.* " + "peerCertificates=\\[CN=localhost\\] " + "localCertificates=\\[\\]}").assertLogMatch("connectEnd: h2").assertLogMatch("connectionAcquired: Connection\\{" + url.host() + ":\\d+, proxy=DIRECT hostAddress=" + url.host() + "/.+ cipherSuite=.+ protocol=h2\\}").assertLogMatch("requestHeadersStart").assertLogMatch("requestHeadersEnd").assertLogMatch("responseHeadersStart").assertLogMatch("responseHeadersEnd: Response\\{protocol=h2, code=200, message=, url=" + url + "\\}").assertLogMatch("responseBodyStart").assertLogMatch("responseBodyEnd: byteCount=0").assertLogMatch("connectionReleased").assertLogMatch("callEnd").assertNoMoreLogs();
}
use of okhttp3.Handshake 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.Handshake 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");
}
}
use of okhttp3.Handshake in project okhttp by square.
the class CertificatePinnerChainValidationTest method intermediateMustNotHaveMoreIntermediatesThanSigner.
/**
* Attack the CA intermediates check by presenting unrelated chains to the handshake vs.
* certificate pinner.
*
* This chain is valid but not pinned:
*
* <pre>{@code
*
* attackerCa
* -> phonyVictim
*
* }</pre>
*
* This chain is pinned but not valid:
*
* <pre>{@code
*
* attackerCa
* -> pinnedRoot (trusted by CertificatePinner)
* -> compromisedIntermediate (max intermediates: 0)
* -> attackerIntermediate (max intermediates: 0)
* -> phonyVictim
* }</pre>
*/
@Test
public void intermediateMustNotHaveMoreIntermediatesThanSigner() throws Exception {
HeldCertificate attackerCa = new HeldCertificate.Builder().serialNumber(1L).certificateAuthority(2).commonName("attacker ca").build();
HeldCertificate pinnedRoot = new HeldCertificate.Builder().serialNumber(2L).certificateAuthority(1).commonName("pinned root").signedBy(attackerCa).build();
HeldCertificate compromisedIntermediate = new HeldCertificate.Builder().serialNumber(3L).certificateAuthority(0).commonName("compromised intermediate").signedBy(pinnedRoot).build();
HeldCertificate attackerIntermediate = new HeldCertificate.Builder().keyPair(// Share keys between compromised CA and intermediate!
attackerCa.keyPair()).serialNumber(4L).certificateAuthority(// More intermediates than permitted by signer!
0).commonName("attacker intermediate").signedBy(compromisedIntermediate).build();
HeldCertificate phonyVictim = new HeldCertificate.Builder().serialNumber(5L).signedBy(attackerIntermediate).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, attackerIntermediate.certificate(), compromisedIntermediate.certificate(), pinnedRoot.certificate()).build();
server.useHttps(serverHandshakeCertificates.sslSocketFactory(), false);
server.enqueue(new MockResponse());
// Make a request from client to server. It should not succeed certificate checks.
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 (SSLHandshakeException expected) {
}
}
use of okhttp3.Handshake in project okhttp by square.
the class DuplexTest method fullCallTimeoutDoesNotApplyOnceConnected.
@Test
public void fullCallTimeoutDoesNotApplyOnceConnected() throws Exception {
enableProtocol(Protocol.HTTP_2);
MockDuplexResponseBody mockDuplexResponseBody = enqueueResponseWithBody(new MockResponse().clearHeaders(), new MockDuplexResponseBody().sendResponse("response A\n").sleep(750, TimeUnit.MILLISECONDS).sendResponse("response B\n").receiveRequest("request C\n").exhaustResponse().exhaustRequest());
Request request = new Request.Builder().url(server.url("/")).post(new AsyncRequestBody()).build();
Call call = client.newCall(request);
// Long enough for the first TLS handshake.
call.timeout().timeout(500, TimeUnit.MILLISECONDS);
try (Response response = call.execute()) {
BufferedSink requestBody = ((AsyncRequestBody) call.request().body()).takeSink();
BufferedSource responseBody = response.body().source();
assertThat(responseBody.readUtf8Line()).isEqualTo("response A");
assertThat(responseBody.readUtf8Line()).isEqualTo("response B");
requestBody.writeUtf8("request C\n");
requestBody.close();
assertThat(responseBody.readUtf8Line()).isNull();
}
mockDuplexResponseBody.awaitSuccess();
}
Aggregations