forked from square/okhttp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Modify the cipher suite / TLS version selection behavior
Motivation 1: Cipher selection and TLS protocol version selection should be performed over "enabled", not "support" values. Otherwise, ciphers / protocols that are disabled by default are re-enabled. Android would like to avoid enabling values that are considered unsafe and are disabled by the platform, apps or GMS core. Motivation 2: Opinionated cipher suite selection makes sense for OkHttp when bundled with apps. OkHttp probably has the best/newest information available when compared with the socket factory it encounters. However, with the Android platform usecase the socket factory (i.e. one from the platform, from GMS core, or installed by the app) might have better information (or reasons why specific suites should not be used and so it modifies the "enabled" set). Android would therefore prefer OkHttp to select from a default set specified by the socket factory, not a list hard-coded at release time. Unlike ciphers, for protocols there is no current need to go with the default enabled set so supporting "null" / "use default" is not required for protocols. Other change: The ConnectionSpec caching (see supportedSpec) has been removed from ConnectionSpec. This seems like an risky optimization to me in an environment where different SocketFactory instances could be encountered and doing it properly seems costly and of limited benefit.
- Loading branch information
Showing
2 changed files
with
209 additions
and
22 deletions.
There are no files selected for viewing
172 changes: 172 additions & 0 deletions
172
okhttp-tests/src/test/java/com/squareup/okhttp/ConnectionSpecTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.squareup.okhttp; | ||
|
||
import com.squareup.okhttp.internal.http.AuthenticatorAdapter; | ||
|
||
import org.junit.Test; | ||
|
||
import java.net.InetSocketAddress; | ||
import java.net.Proxy; | ||
import java.net.ProxySelector; | ||
import java.util.Arrays; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import javax.net.ssl.SSLSocket; | ||
import javax.net.ssl.SSLSocketFactory; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertFalse; | ||
import static org.junit.Assert.assertNull; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
public final class ConnectionSpecTest { | ||
|
||
private static final Proxy PROXY = Proxy.NO_PROXY; | ||
private static final InetSocketAddress INET_SOCKET_ADDRESS = | ||
InetSocketAddress.createUnresolved("host", 443); | ||
private static final Address HTTPS_ADDRESS = new Address( | ||
INET_SOCKET_ADDRESS.getHostString(), INET_SOCKET_ADDRESS.getPort(), null, null, null, null, | ||
AuthenticatorAdapter.INSTANCE, PROXY, Arrays.asList(Protocol.HTTP_1_1), | ||
Arrays.asList(ConnectionSpec.MODERN_TLS), ProxySelector.getDefault()); | ||
|
||
@Test | ||
public void cleartextBuilder() throws Exception { | ||
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(false).build(); | ||
assertFalse(cleartextSpec.isTls()); | ||
} | ||
|
||
@Test | ||
public void tlsBuilder_explicitCiphers() throws Exception { | ||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) | ||
.cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) | ||
.tlsVersions(TlsVersion.TLS_1_2) | ||
.supportsTlsExtensions(true) | ||
.build(); | ||
assertEquals(Arrays.asList(CipherSuite.TLS_RSA_WITH_RC4_128_MD5), tlsSpec.cipherSuites()); | ||
assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions()); | ||
assertTrue(tlsSpec.supportsTlsExtensions()); | ||
} | ||
|
||
@Test | ||
public void tlsBuilder_defaultCiphers() throws Exception { | ||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) | ||
.tlsVersions(TlsVersion.TLS_1_2) | ||
.supportsTlsExtensions(true) | ||
.build(); | ||
assertNull(tlsSpec.cipherSuites()); | ||
assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions()); | ||
assertTrue(tlsSpec.supportsTlsExtensions()); | ||
} | ||
|
||
@Test | ||
public void tls_defaultCiphers_noFallbackIndicator() throws Exception { | ||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) | ||
.tlsVersions(TlsVersion.TLS_1_2) | ||
.supportsTlsExtensions(false) | ||
.build(); | ||
|
||
SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); | ||
socket.setEnabledCipherSuites(new String[] { | ||
CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName, | ||
CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName, | ||
}); | ||
socket.setEnabledProtocols(new String[] { | ||
TlsVersion.TLS_1_2.javaName, | ||
TlsVersion.TLS_1_1.javaName, | ||
}); | ||
|
||
Route route = new Route(HTTPS_ADDRESS, PROXY, INET_SOCKET_ADDRESS, tlsSpec, | ||
false /* shouldSendTlsFallbackIndicator */); | ||
tlsSpec.apply(socket, route); | ||
|
||
assertEquals(createSet(TlsVersion.TLS_1_2.javaName), createSet(socket.getEnabledProtocols())); | ||
|
||
Set<String> expectedCipherSet = | ||
createSet( | ||
CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName, | ||
CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName); | ||
assertEquals(expectedCipherSet, expectedCipherSet); | ||
} | ||
|
||
@Test | ||
public void tls_defaultCiphers_withFallbackIndicator() throws Exception { | ||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) | ||
.tlsVersions(TlsVersion.TLS_1_2) | ||
.supportsTlsExtensions(false) | ||
.build(); | ||
|
||
SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); | ||
socket.setEnabledCipherSuites(new String[] { | ||
CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName, | ||
CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName, | ||
}); | ||
socket.setEnabledProtocols(new String[] { | ||
TlsVersion.TLS_1_2.javaName, | ||
TlsVersion.TLS_1_1.javaName, | ||
}); | ||
|
||
Route route = new Route(HTTPS_ADDRESS, PROXY, INET_SOCKET_ADDRESS, tlsSpec, | ||
true /* shouldSendTlsFallbackIndicator */); | ||
tlsSpec.apply(socket, route); | ||
|
||
assertEquals(createSet(TlsVersion.TLS_1_2.javaName), createSet(socket.getEnabledProtocols())); | ||
|
||
Set<String> expectedCipherSet = | ||
createSet( | ||
CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName, | ||
CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName); | ||
if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) { | ||
expectedCipherSet.add("TLS_FALLBACK_SCSV"); | ||
} | ||
assertEquals(expectedCipherSet, expectedCipherSet); | ||
} | ||
|
||
@Test | ||
public void tls_explicitCiphers() throws Exception { | ||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) | ||
.cipherSuites(CipherSuite.TLS_RSA_WITH_RC4_128_MD5) | ||
.tlsVersions(TlsVersion.TLS_1_2) | ||
.supportsTlsExtensions(false) | ||
.build(); | ||
|
||
SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); | ||
socket.setEnabledCipherSuites(new String[] { | ||
CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName, | ||
CipherSuite.TLS_RSA_WITH_RC4_128_SHA.javaName, | ||
}); | ||
socket.setEnabledProtocols(new String[] { | ||
TlsVersion.TLS_1_2.javaName, | ||
TlsVersion.TLS_1_1.javaName, | ||
}); | ||
|
||
Route route = new Route(HTTPS_ADDRESS, PROXY, INET_SOCKET_ADDRESS, tlsSpec, | ||
true /* shouldSendTlsFallbackIndicator */); | ||
tlsSpec.apply(socket, route); | ||
|
||
assertEquals(createSet(TlsVersion.TLS_1_2.javaName), createSet(socket.getEnabledProtocols())); | ||
|
||
Set<String> expectedCipherSet = createSet(CipherSuite.TLS_RSA_WITH_RC4_128_MD5.javaName); | ||
if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) { | ||
expectedCipherSet.add("TLS_FALLBACK_SCSV"); | ||
} | ||
assertEquals(expectedCipherSet, expectedCipherSet); | ||
} | ||
|
||
private static Set<String> createSet(String... values) { | ||
return new HashSet<String>(Arrays.asList(values)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters