Search in sources :

Example 21 with Handshake

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();
}
Also used : Response(okhttp3.Response) MockResponse(mockwebserver3.MockResponse) MockResponse(mockwebserver3.MockResponse) Test(org.junit.jupiter.api.Test)

Example 22 with Handshake

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);
}
Also used : InputStreamReader(java.io.InputStreamReader) HandshakeCertificates(okhttp3.tls.HandshakeCertificates) BufferedReader(java.io.BufferedReader) HttpUrl(okhttp3.HttpUrl) HttpsURLConnection(javax.net.ssl.HttpsURLConnection) RecordingHostnameVerifier(okhttp3.RecordingHostnameVerifier) Handshake(okhttp3.Handshake) Test(org.junit.jupiter.api.Test)

Example 23 with Handshake

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");
    }
}
Also used : MockResponse(mockwebserver3.MockResponse) Call(okhttp3.Call) OkHttpClient(okhttp3.OkHttpClient) HandshakeCertificates(okhttp3.tls.HandshakeCertificates) CertificatePinner(okhttp3.CertificatePinner) SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) HeldCertificate(okhttp3.tls.HeldCertificate) Request(okhttp3.Request) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) Response(okhttp3.Response) MockResponse(mockwebserver3.MockResponse) RecordingHostnameVerifier(okhttp3.RecordingHostnameVerifier) Test(org.junit.jupiter.api.Test)

Example 24 with Handshake

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) {
    }
}
Also used : MockResponse(mockwebserver3.MockResponse) Call(okhttp3.Call) OkHttpClient(okhttp3.OkHttpClient) HandshakeCertificates(okhttp3.tls.HandshakeCertificates) CertificatePinner(okhttp3.CertificatePinner) HeldCertificate(okhttp3.tls.HeldCertificate) Request(okhttp3.Request) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) Response(okhttp3.Response) MockResponse(mockwebserver3.MockResponse) RecordingHostnameVerifier(okhttp3.RecordingHostnameVerifier) Test(org.junit.jupiter.api.Test)

Example 25 with Handshake

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();
}
Also used : MockResponse(mockwebserver3.MockResponse) MockResponse(mockwebserver3.MockResponse) MockDuplexResponseBody(mockwebserver3.internal.duplex.MockDuplexResponseBody) AsyncRequestBody(okhttp3.internal.duplex.AsyncRequestBody) BufferedSink(okio.BufferedSink) BufferedSource(okio.BufferedSource) Test(org.junit.jupiter.api.Test)

Aggregations

Handshake (okhttp3.Handshake)13 Request (okhttp3.Request)12 Response (okhttp3.Response)11 Test (org.junit.jupiter.api.Test)9 Certificate (java.security.cert.Certificate)7 HttpsURLConnection (javax.net.ssl.HttpsURLConnection)7 RecordingHostnameVerifier (okhttp3.RecordingHostnameVerifier)7 HandshakeCertificates (okhttp3.tls.HandshakeCertificates)7 CacheResponse (java.net.CacheResponse)6 SecureCacheResponse (java.net.SecureCacheResponse)6 SSLPeerUnverifiedException (javax.net.ssl.SSLPeerUnverifiedException)5 MockResponse (mockwebserver3.MockResponse)5 HeldCertificate (okhttp3.tls.HeldCertificate)5 Test (org.junit.Test)5 BufferedReader (java.io.BufferedReader)4 IOException (java.io.IOException)4 InputStreamReader (java.io.InputStreamReader)4 Headers (okhttp3.Headers)4 HttpUrl (okhttp3.HttpUrl)4 ResponseBody (okhttp3.ResponseBody)4