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.Test; 25 26 import static org.junit.Assert.assertEquals; 27 import static org.junit.Assert.assertFalse; 28 import static org.junit.Assert.assertNull; 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assert.fail; 31 32 public final class ConnectionSpecTest { noTlsVersions()33 @Test public void noTlsVersions() throws Exception { 34 try { 35 new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 36 .tlsVersions(new TlsVersion[0]) 37 .build(); 38 fail(); 39 } catch (IllegalArgumentException expected) { 40 assertEquals("At least one TLS version is required", expected.getMessage()); 41 } 42 } 43 noCipherSuites()44 @Test public void noCipherSuites() throws Exception { 45 try { 46 new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 47 .cipherSuites(new CipherSuite[0]) 48 .build(); 49 fail(); 50 } catch (IllegalArgumentException expected) { 51 assertEquals("At least one cipher suite is required", expected.getMessage()); 52 } 53 } 54 cleartextBuilder()55 @Test public void cleartextBuilder() throws Exception { 56 ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(false).build(); 57 assertFalse(cleartextSpec.isTls()); 58 } 59 tlsBuilder_explicitCiphers()60 @Test public void tlsBuilder_explicitCiphers() throws Exception { 61 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 62 .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA) 63 .tlsVersions(TlsVersion.TLS_1_2) 64 .supportsTlsExtensions(true) 65 .build(); 66 assertEquals(Arrays.asList(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA), tlsSpec.cipherSuites()); 67 assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions()); 68 assertTrue(tlsSpec.supportsTlsExtensions()); 69 } 70 tlsBuilder_defaultCiphers()71 @Test public void tlsBuilder_defaultCiphers() throws Exception { 72 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 73 .tlsVersions(TlsVersion.TLS_1_2) 74 .supportsTlsExtensions(true) 75 .build(); 76 assertNull(tlsSpec.cipherSuites()); 77 assertEquals(Arrays.asList(TlsVersion.TLS_1_2), tlsSpec.tlsVersions()); 78 assertTrue(tlsSpec.supportsTlsExtensions()); 79 } 80 tls_defaultCiphers_noFallbackIndicator()81 @Test public void tls_defaultCiphers_noFallbackIndicator() throws Exception { 82 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 83 .tlsVersions(TlsVersion.TLS_1_2) 84 .supportsTlsExtensions(false) 85 .build(); 86 87 SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 88 socket.setEnabledCipherSuites(new String[] { 89 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 90 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 91 }); 92 socket.setEnabledProtocols(new String[] { 93 TlsVersion.TLS_1_2.javaName, 94 TlsVersion.TLS_1_1.javaName, 95 }); 96 97 assertTrue(tlsSpec.isCompatible(socket)); 98 tlsSpec.apply(socket, false /* isFallback */); 99 100 assertEquals(set(TlsVersion.TLS_1_2.javaName), set(socket.getEnabledProtocols())); 101 102 Set<String> expectedCipherSet = 103 set( 104 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 105 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName); 106 assertEquals(expectedCipherSet, expectedCipherSet); 107 } 108 tls_defaultCiphers_withFallbackIndicator()109 @Test public void tls_defaultCiphers_withFallbackIndicator() throws Exception { 110 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 111 .tlsVersions(TlsVersion.TLS_1_2) 112 .supportsTlsExtensions(false) 113 .build(); 114 115 SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 116 socket.setEnabledCipherSuites(new String[] { 117 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 118 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 119 }); 120 socket.setEnabledProtocols(new String[] { 121 TlsVersion.TLS_1_2.javaName, 122 TlsVersion.TLS_1_1.javaName, 123 }); 124 125 assertTrue(tlsSpec.isCompatible(socket)); 126 tlsSpec.apply(socket, true /* isFallback */); 127 128 assertEquals(set(TlsVersion.TLS_1_2.javaName), set(socket.getEnabledProtocols())); 129 130 Set<String> expectedCipherSet = 131 set( 132 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 133 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName); 134 if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) { 135 expectedCipherSet.add("TLS_FALLBACK_SCSV"); 136 } 137 assertEquals(expectedCipherSet, expectedCipherSet); 138 } 139 tls_explicitCiphers()140 @Test public void tls_explicitCiphers() throws Exception { 141 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 142 .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA) 143 .tlsVersions(TlsVersion.TLS_1_2) 144 .supportsTlsExtensions(false) 145 .build(); 146 147 SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 148 socket.setEnabledCipherSuites(new String[] { 149 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 150 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 151 }); 152 socket.setEnabledProtocols(new String[] { 153 TlsVersion.TLS_1_2.javaName, 154 TlsVersion.TLS_1_1.javaName, 155 }); 156 157 assertTrue(tlsSpec.isCompatible(socket)); 158 tlsSpec.apply(socket, true /* isFallback */); 159 160 assertEquals(set(TlsVersion.TLS_1_2.javaName), set(socket.getEnabledProtocols())); 161 162 Set<String> expectedCipherSet = set(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName); 163 if (Arrays.asList(socket.getSupportedCipherSuites()).contains("TLS_FALLBACK_SCSV")) { 164 expectedCipherSet.add("TLS_FALLBACK_SCSV"); 165 } 166 assertEquals(expectedCipherSet, expectedCipherSet); 167 } 168 tls_stringCiphersAndVersions()169 @Test public void tls_stringCiphersAndVersions() throws Exception { 170 // Supporting arbitrary input strings allows users to enable suites and versions that are not 171 // yet known to the library, but are supported by the platform. 172 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 173 .cipherSuites("MAGIC-CIPHER") 174 .tlsVersions("TLS9k") 175 .build(); 176 } 177 tls_missingRequiredCipher()178 @Test public void tls_missingRequiredCipher() throws Exception { 179 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 180 .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA) 181 .tlsVersions(TlsVersion.TLS_1_2) 182 .supportsTlsExtensions(false) 183 .build(); 184 185 SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 186 socket.setEnabledProtocols(new String[] { 187 TlsVersion.TLS_1_2.javaName, 188 TlsVersion.TLS_1_1.javaName, 189 }); 190 191 socket.setEnabledCipherSuites(new String[] { 192 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 193 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 194 }); 195 assertTrue(tlsSpec.isCompatible(socket)); 196 197 socket.setEnabledCipherSuites(new String[] { 198 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 199 }); 200 assertFalse(tlsSpec.isCompatible(socket)); 201 } 202 allEnabledCipherSuites()203 @Test public void allEnabledCipherSuites() throws Exception { 204 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 205 .allEnabledCipherSuites() 206 .build(); 207 assertNull(tlsSpec.cipherSuites()); 208 209 SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 210 sslSocket.setEnabledCipherSuites(new String[] { 211 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 212 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 213 }); 214 215 tlsSpec.apply(sslSocket, false); 216 assertEquals(Arrays.asList( 217 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256.javaName, 218 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName), 219 Arrays.asList(sslSocket.getEnabledCipherSuites())); 220 } 221 allEnabledTlsVersions()222 @Test public void allEnabledTlsVersions() throws Exception { 223 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 224 .allEnabledTlsVersions() 225 .build(); 226 assertNull(tlsSpec.tlsVersions()); 227 228 SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 229 sslSocket.setEnabledProtocols(new String[] { 230 TlsVersion.TLS_1_0.javaName(), 231 TlsVersion.TLS_1_1.javaName() 232 }); 233 234 tlsSpec.apply(sslSocket, false); 235 assertEquals(Arrays.asList(TlsVersion.TLS_1_0.javaName(), TlsVersion.TLS_1_1.javaName()), 236 Arrays.asList(sslSocket.getEnabledProtocols())); 237 } 238 tls_missingTlsVersion()239 @Test public void tls_missingTlsVersion() throws Exception { 240 ConnectionSpec tlsSpec = new ConnectionSpec.Builder(true) 241 .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA) 242 .tlsVersions(TlsVersion.TLS_1_2) 243 .supportsTlsExtensions(false) 244 .build(); 245 246 SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); 247 socket.setEnabledCipherSuites(new String[] { 248 CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.javaName, 249 }); 250 251 socket.setEnabledProtocols( 252 new String[] { TlsVersion.TLS_1_2.javaName, TlsVersion.TLS_1_1.javaName }); 253 assertTrue(tlsSpec.isCompatible(socket)); 254 255 socket.setEnabledProtocols(new String[] { TlsVersion.TLS_1_1.javaName }); 256 assertFalse(tlsSpec.isCompatible(socket)); 257 } 258 equalsAndHashCode()259 @Test public void equalsAndHashCode() throws Exception { 260 ConnectionSpec allCipherSuites = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 261 .allEnabledCipherSuites() 262 .build(); 263 ConnectionSpec allTlsVersions = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 264 .allEnabledTlsVersions() 265 .build(); 266 267 Set<Object> set = new CopyOnWriteArraySet<>(); 268 assertTrue(set.add(ConnectionSpec.MODERN_TLS)); 269 assertTrue(set.add(ConnectionSpec.COMPATIBLE_TLS)); 270 assertTrue(set.add(ConnectionSpec.CLEARTEXT)); 271 assertTrue(set.add(allTlsVersions)); 272 assertTrue(set.add(allCipherSuites)); 273 274 assertTrue(set.remove(ConnectionSpec.MODERN_TLS)); 275 assertTrue(set.remove(ConnectionSpec.COMPATIBLE_TLS)); 276 assertTrue(set.remove(ConnectionSpec.CLEARTEXT)); 277 assertTrue(set.remove(allTlsVersions)); 278 assertTrue(set.remove(allCipherSuites)); 279 assertTrue(set.isEmpty()); 280 } 281 allEnabledToString()282 @Test public void allEnabledToString() throws Exception { 283 ConnectionSpec connectionSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 284 .allEnabledTlsVersions() 285 .allEnabledCipherSuites() 286 .build(); 287 assertEquals("ConnectionSpec(cipherSuites=[all enabled], tlsVersions=[all enabled], " 288 + "supportsTlsExtensions=true)", connectionSpec.toString()); 289 } 290 simpleToString()291 @Test public void simpleToString() throws Exception { 292 ConnectionSpec connectionSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 293 .tlsVersions(TlsVersion.TLS_1_2) 294 .cipherSuites(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA) 295 .build(); 296 assertEquals("ConnectionSpec(cipherSuites=[TLS_RSA_WITH_AES_128_CBC_SHA], tlsVersions=[TLS_1_2], " 297 + "supportsTlsExtensions=true)", connectionSpec.toString()); 298 } 299 set(T... values)300 private static <T> Set<T> set(T... values) { 301 return new LinkedHashSet<>(Arrays.asList(values)); 302 } 303 } 304