• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.squareup.okhttp;
17 
18 import java.util.Arrays;
19 import java.util.LinkedHashSet;
20 import java.util.Set;
21 import java.util.concurrent.CopyOnWriteArraySet;
22 import javax.net.ssl.SSLSocket;
23 import javax.net.ssl.SSLSocketFactory;
24 import org.junit.Assume;
25 import org.junit.Test;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32 
33 public final class ConnectionSpecTest {
noTlsVersions()34   @Test public void noTlsVersions() throws Exception {
35     try {
36       new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
37           .tlsVersions(new TlsVersion[0])
38           .build();
39       fail();
40     } catch (IllegalArgumentException expected) {
41       assertEquals("At least one TLS version is required", expected.getMessage());
42     }
43   }
44 
noCipherSuites()45   @Test public void noCipherSuites() throws Exception {
46     try {
47       new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
48           .cipherSuites(new CipherSuite[0])
49           .build();
50       fail();
51     } catch (IllegalArgumentException expected) {
52       assertEquals("At least one cipher suite is required", expected.getMessage());
53     }
54   }
55 
cleartextBuilder()56   @Test public void cleartextBuilder() throws Exception {
57     ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(false).build();
58     assertFalse(cleartextSpec.isTls());
59   }
60 
tlsBuilder_explicitCiphers()61   @Test public void tlsBuilder_explicitCiphers() throws Exception {
62     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
63         .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
64         .tlsVersions(TlsVersion.TLS_1_2)
65         .supportsTlsExtensions(true)
66         .build();
67     assertEquals(Arrays.asList(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA), tlsSpec.cipherSuites());
68     assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions());
69     assertTrue(tlsSpec.supportsTlsExtensions());
70   }
71 
tlsBuilder_defaultCiphers()72   @Test public void tlsBuilder_defaultCiphers() throws Exception {
73     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
74         .tlsVersions(TlsVersion.TLS_1_2)
75         .supportsTlsExtensions(true)
76         .build();
77     assertNull(tlsSpec.cipherSuites());
78     assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions());
79     assertTrue(tlsSpec.supportsTlsExtensions());
80   }
81 
tls_defaultCiphers_noFallbackIndicator()82   @Test public void tls_defaultCiphers_noFallbackIndicator() throws Exception {
83     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
84         // Android-changed: Use TLS 1.3 and 1.2 for testing
85         .tlsVersions(TlsVersion.TLS_1_3)
86         .supportsTlsExtensions(false)
87         .build();
88 
89     SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
90     socket.setEnabledCipherSuites(new String[] {
91         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
92         // Android-changed: USe TLS 1.3 and 1.2 for testing - TLS 1.3 suites are implicit
93         // CipherSuite.TLS_AES_128_GCM_SHA384.javaName,
94     });
95     socket.setEnabledProtocols(new String[] {
96         // Android-changed: Use TLS 1.3 and 1.2 for testing
97         TlsVersion.TLS_1_3.javaName,
98         TlsVersion.TLS_1_2.javaName,
99     });
100 
101     assertTrue(tlsSpec.isCompatible(socket));
102     tlsSpec.apply(socket, false /* isFallback */);
103 
104     // Android-changed: Use TLS 1.3 and 1.2 for testing
105     assertEquals(set(TlsVersion.TLS_1_3.javaName), set(socket.getEnabledProtocols()));
106 
107     Set<String> expectedCipherSet =
108         set(
109             CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
110             // Android-changed: USe TLS 1.3 and 1.2 for testing - TLS 1.3 suites are implicit
111             CipherSuite.TLS_AES_128_GCM_SHA256.javaName,
112             CipherSuite.TLS_AES_256_GCM_SHA384.javaName,
113             CipherSuite.TLS_CHACHA20_POLY1305_SHA256.javaName);
114     assertEquals(expectedCipherSet, set(socket.getEnabledCipherSuites()));
115   }
116 
tls_defaultCiphers_withFallbackIndicator()117   @Test public void tls_defaultCiphers_withFallbackIndicator() throws Exception {
118     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
119         // Android-changed: Use TLS 1.3 and 1.2 for testing
120         .tlsVersions(TlsVersion.TLS_1_3)
121         .supportsTlsExtensions(false)
122         .build();
123 
124     SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
125     socket.setEnabledCipherSuites(new String[] {
126         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
127         // Android-changed: USe TLS 1.3 and 1.2 for testing - TLS 1.3 suites are implicit
128         // CipherSuite.TLS_AES_128_GCM_SHA384.javaName,
129     });
130     socket.setEnabledProtocols(new String[] {
131         // Android-changed: Use TLS 1.3 and 1.2 for testing
132         TlsVersion.TLS_1_3.javaName,
133         TlsVersion.TLS_1_2.javaName,
134     });
135 
136     assertTrue(tlsSpec.isCompatible(socket));
137     tlsSpec.apply(socket, true /* isFallback */);
138 
139     // Android-changed: Use TLS 1.3 and 1.2 for testing
140     assertEquals(set(TlsVersion.TLS_1_3.javaName), set(socket.getEnabledProtocols()));
141 
142     Set<String> expectedCipherSet =
143         set(
144             CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
145             // Android-changed: USe TLS 1.3 and 1.2 for testing - TLS 1.3 suites are implicit
146             CipherSuite.TLS_AES_128_GCM_SHA256.javaName,
147             CipherSuite.TLS_AES_256_GCM_SHA384.javaName,
148             CipherSuite.TLS_CHACHA20_POLY1305_SHA256.javaName);
149     if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) {
150       expectedCipherSet.add("TLS_FALLBACK_SCSV");
151     }
152     assertEquals(expectedCipherSet, set(socket.getEnabledCipherSuites()));
153   }
154 
tls_explicitCiphers()155   @Test public void tls_explicitCiphers() throws Exception {
156     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
157         .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
158         .tlsVersions(TlsVersion.TLS_1_2)
159         .supportsTlsExtensions(false)
160         .build();
161 
162     SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
163     socket.setEnabledCipherSuites(new String[] {
164         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
165         // Android-changed: USe TLS 1.3 and 1.2 for testing - TLS 1.3 suites are implicit
166         // CipherSuite.TLS_AES_128_GCM_SHA384.javaName,
167     });
168     socket.setEnabledProtocols(new String[] {
169         // Android-changed: Use TLS 1.3 and 1.2 for testing
170         TlsVersion.TLS_1_3.javaName,
171         TlsVersion.TLS_1_2.javaName,
172     });
173 
174     assertTrue(tlsSpec.isCompatible(socket));
175     tlsSpec.apply(socket, true /* isFallback */);
176 
177     assertEquals(set(TlsVersion.TLS_1_2.javaName), set(socket.getEnabledProtocols()));
178 
179     Set<String> expectedCipherSet = set(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName);
180     if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) {
181       expectedCipherSet.add("TLS_FALLBACK_SCSV");
182     }
183     assertEquals(expectedCipherSet, expectedCipherSet);
184   }
185 
tls_stringCiphersAndVersions()186   @Test public void tls_stringCiphersAndVersions() throws Exception {
187     // Supporting arbitrary input strings allows users to enable suites and versions that are not
188     // yet known to the library, but are supported by the platform.
189     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
190         .cipherSuites("MAGIC-CIPHER")
191         .tlsVersions("TLS9k")
192         .build();
193   }
194 
tls_missingRequiredCipher()195   @Test public void tls_missingRequiredCipher() throws Exception {
196     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
197         .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
198         .tlsVersions(TlsVersion.TLS_1_2)
199         .supportsTlsExtensions(false)
200         .build();
201 
202     SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
203     socket.setEnabledProtocols(new String[] {
204         // Android-changed: Use TLS 1.3 and 1.2 for testing
205         TlsVersion.TLS_1_3.javaName,
206         TlsVersion.TLS_1_2.javaName,
207     });
208 
209     socket.setEnabledCipherSuites(new String[] {
210         // Android-changed: Replace removed CBC cipher with GCM version
211         CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256.javaName,
212         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
213     });
214     assertTrue(tlsSpec.isCompatible(socket));
215 
216     socket.setEnabledCipherSuites(new String[] {
217         // Android-changed: Replace removed CBC cipher with GCM version
218         CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256.javaName,
219     });
220     assertFalse(tlsSpec.isCompatible(socket));
221   }
222 
allEnabledCipherSuites()223   @Test public void allEnabledCipherSuites() throws Exception {
224     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
225         .allEnabledCipherSuites()
226         .build();
227     assertNull(tlsSpec.cipherSuites());
228 
229     SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
230     sslSocket.setEnabledCipherSuites(new String[] {
231         // Android-changed: Replace removed CBC cipher with GCM version
232         CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256.javaName,
233         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
234     });
235 
236     tlsSpec.apply(sslSocket, false);
237     assertEquals(Arrays.asList(
238             // Android-changed: Replace removed CBC cipher with GCM version
239             CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256.javaName,
240             CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName),
241         Arrays.asList(sslSocket.getEnabledCipherSuites()));
242   }
243 
allEnabledTlsVersions()244   @Test public void allEnabledTlsVersions() throws Exception {
245     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
246         .allEnabledTlsVersions()
247         .build();
248     assertNull(tlsSpec.tlsVersions());
249 
250     SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
251     sslSocket.setEnabledProtocols(new String[] {
252         // Android-changed: Use TLS 1.3 and 1.2 for testing
253         TlsVersion.TLS_1_2.javaName,
254         TlsVersion.TLS_1_3.javaName,
255     });
256 
257     tlsSpec.apply(sslSocket, false);
258     // Android-changed: Use TLS 1.3 and 1.2 for testing
259     assertEquals(Arrays.asList(TlsVersion.TLS_1_2.javaName(), TlsVersion.TLS_1_3.javaName()),
260         Arrays.asList(sslSocket.getEnabledProtocols()));
261   }
262 
tls_missingTlsVersion()263   @Test public void tls_missingTlsVersion() throws Exception {
264     ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true)
265         .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
266         .tlsVersions(TlsVersion.TLS_1_2)
267         .supportsTlsExtensions(false)
268         .build();
269 
270     SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
271     // Android-changed: Only testable if TLS v1.1 is available as TLS 1.3 ciphers are
272     // not changeable on Android.
273     Assume.assumeTrue(
274         Arrays.asList(socket.getEnabledProtocols()).contains(TlsVersion.TLS_1_1.javaName));
275 
276     socket.setEnabledCipherSuites(new String[] {
277         CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName,
278     });
279 
280     socket.setEnabledProtocols(
281         new String[] { TlsVersion.TLS_1_2.javaName, TlsVersion.TLS_1_1.javaName });
282     assertTrue(tlsSpec.isCompatible(socket));
283 
284     socket.setEnabledProtocols(new String[] { TlsVersion.TLS_1_1.javaName });
285     assertFalse(tlsSpec.isCompatible(socket));
286   }
287 
equalsAndHashCode()288   @Test public void equalsAndHashCode() throws Exception {
289     ConnectionSpec allCipherSuites = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
290         .allEnabledCipherSuites()
291         .build();
292     ConnectionSpec allTlsVersions = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
293         .allEnabledTlsVersions()
294         .build();
295 
296     Set<Object> set = new CopyOnWriteArraySet<>();
297     assertTrue(set.add(ConnectionSpec.MODERN_TLS));
298     assertTrue(set.add(ConnectionSpec.COMPATIBLE_TLS));
299     assertTrue(set.add(ConnectionSpec.CLEARTEXT));
300     assertTrue(set.add(allTlsVersions));
301     assertTrue(set.add(allCipherSuites));
302 
303     assertTrue(set.remove(ConnectionSpec.MODERN_TLS));
304     assertTrue(set.remove(ConnectionSpec.COMPATIBLE_TLS));
305     assertTrue(set.remove(ConnectionSpec.CLEARTEXT));
306     assertTrue(set.remove(allTlsVersions));
307     assertTrue(set.remove(allCipherSuites));
308     assertTrue(set.isEmpty());
309   }
310 
allEnabledToString()311   @Test public void allEnabledToString() throws Exception {
312     ConnectionSpec connectionSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
313         .allEnabledTlsVersions()
314         .allEnabledCipherSuites()
315         .build();
316     assertEquals("ConnectionSpec(cipherSuites=[all enabled], tlsVersions=[all enabled], "
317         + "supportsTlsExtensions=true)", connectionSpec.toString());
318   }
319 
simpleToString()320   @Test public void simpleToString() throws Exception {
321     ConnectionSpec connectionSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
322         .tlsVersions(TlsVersion.TLS_1_2)
323         .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
324         .build();
325     assertEquals("ConnectionSpec(cipherSuites=[TLS_RSA_WITH_AES_128_CBC_SHA], tlsVersions=[TLS_1_2], "
326         + "supportsTlsExtensions=true)", connectionSpec.toString());
327   }
328 
set(T... values)329   private static <T> Set<T> set(T... values) {
330     return new LinkedHashSet<>(Arrays.asList(values));
331   }
332 }
333