1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.conscrypt; 19 20 import java.security.KeyManagementException; 21 import java.security.KeyStore; 22 import java.security.KeyStoreException; 23 import java.security.NoSuchAlgorithmException; 24 import java.security.SecureRandom; 25 import java.security.UnrecoverableKeyException; 26 import java.util.Arrays; 27 import javax.net.ssl.KeyManager; 28 import javax.net.ssl.KeyManagerFactory; 29 import javax.net.ssl.TrustManager; 30 import javax.net.ssl.TrustManagerFactory; 31 import javax.net.ssl.X509KeyManager; 32 import javax.net.ssl.X509TrustManager; 33 34 /** 35 * The instances of this class encapsulate all the info 36 * about enabled cipher suites and protocols, 37 * as well as the information about client/server mode of 38 * ssl socket, whether it require/want client authentication or not, 39 * and controls whether new SSL sessions may be established by this 40 * socket or not. 41 */ 42 public class SSLParametersImpl implements Cloneable { 43 44 // default source of authentication keys 45 private static volatile X509KeyManager defaultKeyManager; 46 // default source of authentication trust decisions 47 private static volatile X509TrustManager defaultTrustManager; 48 // default source of random numbers 49 private static volatile SecureRandom defaultSecureRandom; 50 // default SSL parameters 51 private static volatile SSLParametersImpl defaultParameters; 52 53 // client session context contains the set of reusable 54 // client-side SSL sessions 55 private final ClientSessionContext clientSessionContext; 56 // server session context contains the set of reusable 57 // server-side SSL sessions 58 private final ServerSessionContext serverSessionContext; 59 // source of authentication keys 60 private X509KeyManager keyManager; 61 // source of authentication trust decisions 62 private X509TrustManager trustManager; 63 // source of random numbers 64 private SecureRandom secureRandom; 65 66 // cipher suites available for SSL connection 67 private CipherSuite[] enabledCipherSuites; 68 // string representations of available cipher suites 69 private String[] enabledCipherSuiteNames = null; 70 71 // protocols available for SSL connection 72 private String[] enabledProtocols = ProtocolVersion.supportedProtocols; 73 74 // if the peer with this parameters tuned to work in client mode 75 private boolean client_mode = true; 76 // if the peer with this parameters tuned to require client authentication 77 private boolean need_client_auth = false; 78 // if the peer with this parameters tuned to request client authentication 79 private boolean want_client_auth = false; 80 // if the peer with this parameters allowed to cteate new SSL session 81 private boolean enable_session_creation = true; 82 83 protected CipherSuite[] getEnabledCipherSuitesMember() { 84 if (enabledCipherSuites == null) { 85 this.enabledCipherSuites = CipherSuite.DEFAULT_CIPHER_SUITES; 86 } 87 return enabledCipherSuites; 88 } 89 90 /** 91 * Initializes the parameters. Naturally this constructor is used 92 * in SSLContextImpl.engineInit method which directly passes its 93 * parameters. In other words this constructor holds all 94 * the functionality provided by SSLContext.init method. 95 * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[], 96 * SecureRandom)} for more information 97 */ 98 protected SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, 99 SecureRandom sr, ClientSessionContext clientSessionContext, 100 ServerSessionContext serverSessionContext) 101 throws KeyManagementException { 102 this.serverSessionContext = serverSessionContext; 103 this.clientSessionContext = clientSessionContext; 104 105 // It's not described by the spec of SSLContext what should happen 106 // if the arrays of length 0 are specified. This implementation 107 // behave as for null arrays (i.e. use installed security providers) 108 109 // initialize keyManager 110 if ((kms == null) || (kms.length == 0)) { 111 keyManager = getDefaultKeyManager(); 112 } else { 113 keyManager = findX509KeyManager(kms); 114 } 115 116 // initialize trustManager 117 if ((tms == null) || (tms.length == 0)) { 118 trustManager = getDefaultTrustManager(); 119 } else { 120 trustManager = findX509TrustManager(tms); 121 } 122 // initialize secure random 123 // BEGIN android-removed 124 // if (sr == null) { 125 // if (defaultSecureRandom == null) { 126 // defaultSecureRandom = new SecureRandom(); 127 // } 128 // secureRandom = defaultSecureRandom; 129 // } else { 130 // secureRandom = sr; 131 // } 132 // END android-removed 133 // BEGIN android-added 134 // We simply use the SecureRandom passed in by the caller. If it's 135 // null, we don't replace it by a new instance. The native code below 136 // then directly accesses /dev/urandom. Not the most elegant solution, 137 // but faster than going through the SecureRandom object. 138 secureRandom = sr; 139 // END android-added 140 } 141 142 protected static SSLParametersImpl getDefault() throws KeyManagementException { 143 SSLParametersImpl result = defaultParameters; 144 if (result == null) { 145 // single-check idiom 146 defaultParameters = result = new SSLParametersImpl(null, 147 null, 148 null, 149 new ClientSessionContext(), 150 new ServerSessionContext()); 151 } 152 return (SSLParametersImpl) result.clone(); 153 } 154 155 /** 156 * @return server session context 157 */ 158 protected ServerSessionContext getServerSessionContext() { 159 return serverSessionContext; 160 } 161 162 /** 163 * @return client session context 164 */ 165 protected ClientSessionContext getClientSessionContext() { 166 return clientSessionContext; 167 } 168 169 /** 170 * @return key manager 171 */ 172 protected X509KeyManager getKeyManager() { 173 return keyManager; 174 } 175 176 /** 177 * @return trust manager 178 */ 179 protected X509TrustManager getTrustManager() { 180 return trustManager; 181 } 182 183 /** 184 * @return secure random 185 */ 186 protected SecureRandom getSecureRandom() { 187 if (secureRandom != null) { 188 return secureRandom; 189 } 190 SecureRandom result = defaultSecureRandom; 191 if (result == null) { 192 // single-check idiom 193 defaultSecureRandom = result = new SecureRandom(); 194 } 195 secureRandom = result; 196 return secureRandom; 197 } 198 199 /** 200 * @return the secure random member reference, even it is null 201 */ 202 protected SecureRandom getSecureRandomMember() { 203 return secureRandom; 204 } 205 206 /** 207 * @return the names of enabled cipher suites 208 */ 209 protected String[] getEnabledCipherSuites() { 210 if (enabledCipherSuiteNames == null) { 211 CipherSuite[] enabledCipherSuites = getEnabledCipherSuitesMember(); 212 enabledCipherSuiteNames = new String[enabledCipherSuites.length]; 213 for (int i = 0; i< enabledCipherSuites.length; i++) { 214 enabledCipherSuiteNames[i] = enabledCipherSuites[i].getName(); 215 } 216 } 217 return enabledCipherSuiteNames.clone(); 218 } 219 220 /** 221 * Sets the set of available cipher suites for use in SSL connection. 222 * @param suites: String[] 223 * @return 224 */ 225 protected void setEnabledCipherSuites(String[] suites) { 226 if (suites == null) { 227 throw new IllegalArgumentException("suites == null"); 228 } 229 CipherSuite[] cipherSuites = new CipherSuite[suites.length]; 230 for (int i=0; i<suites.length; i++) { 231 String suite = suites[i]; 232 if (suite == null) { 233 throw new IllegalArgumentException("suites[" + i + "] == null"); 234 } 235 cipherSuites[i] = CipherSuite.getByName(suite); 236 if (cipherSuites[i] == null || !cipherSuites[i].supported) { 237 throw new IllegalArgumentException(suite + " is not supported."); 238 } 239 } 240 enabledCipherSuites = cipherSuites; 241 enabledCipherSuiteNames = suites; 242 } 243 244 /** 245 * @return the set of enabled protocols 246 */ 247 protected String[] getEnabledProtocols() { 248 return enabledProtocols.clone(); 249 } 250 251 /** 252 * Sets the set of available protocols for use in SSL connection. 253 * @param protocols String[] 254 */ 255 protected void setEnabledProtocols(String[] protocols) { 256 if (protocols == null) { 257 throw new IllegalArgumentException("protocols == null"); 258 } 259 for (int i=0; i<protocols.length; i++) { 260 String protocol = protocols[i]; 261 if (protocol == null) { 262 throw new IllegalArgumentException("protocols[" + i + "] == null"); 263 } 264 if (!ProtocolVersion.isSupported(protocol)) { 265 throw new IllegalArgumentException("Protocol " + protocol + " is not supported."); 266 } 267 } 268 enabledProtocols = protocols; 269 } 270 271 /** 272 * Tunes the peer holding this parameters to work in client mode. 273 * @param mode if the peer is configured to work in client mode 274 */ 275 protected void setUseClientMode(boolean mode) { 276 client_mode = mode; 277 } 278 279 /** 280 * Returns the value indicating if the parameters configured to work 281 * in client mode. 282 */ 283 protected boolean getUseClientMode() { 284 return client_mode; 285 } 286 287 /** 288 * Tunes the peer holding this parameters to require client authentication 289 */ 290 protected void setNeedClientAuth(boolean need) { 291 need_client_auth = need; 292 // reset the want_client_auth setting 293 want_client_auth = false; 294 } 295 296 /** 297 * Returns the value indicating if the peer with this parameters tuned 298 * to require client authentication 299 */ 300 protected boolean getNeedClientAuth() { 301 return need_client_auth; 302 } 303 304 /** 305 * Tunes the peer holding this parameters to request client authentication 306 */ 307 protected void setWantClientAuth(boolean want) { 308 want_client_auth = want; 309 // reset the need_client_auth setting 310 need_client_auth = false; 311 } 312 313 /** 314 * Returns the value indicating if the peer with this parameters 315 * tuned to request client authentication 316 * @return 317 */ 318 protected boolean getWantClientAuth() { 319 return want_client_auth; 320 } 321 322 /** 323 * Allows/disallows the peer holding this parameters to 324 * create new SSL session 325 */ 326 protected void setEnableSessionCreation(boolean flag) { 327 enable_session_creation = flag; 328 } 329 330 /** 331 * Returns the value indicating if the peer with this parameters 332 * allowed to cteate new SSL session 333 */ 334 protected boolean getEnableSessionCreation() { 335 return enable_session_creation; 336 } 337 338 /** 339 * Returns the clone of this object. 340 * @return the clone. 341 */ 342 @Override 343 protected Object clone() { 344 try { 345 return super.clone(); 346 } catch (CloneNotSupportedException e) { 347 throw new AssertionError(e); 348 } 349 } 350 351 private static X509KeyManager getDefaultKeyManager() throws KeyManagementException { 352 X509KeyManager result = defaultKeyManager; 353 if (result == null) { 354 // single-check idiom 355 defaultKeyManager = result = createDefaultKeyManager(); 356 } 357 return result; 358 } 359 private static X509KeyManager createDefaultKeyManager() throws KeyManagementException { 360 try { 361 String algorithm = KeyManagerFactory.getDefaultAlgorithm(); 362 KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); 363 kmf.init(null, null); 364 KeyManager[] kms = kmf.getKeyManagers(); 365 return findX509KeyManager(kms); 366 } catch (NoSuchAlgorithmException e) { 367 throw new KeyManagementException(e); 368 } catch (KeyStoreException e) { 369 throw new KeyManagementException(e); 370 } catch (UnrecoverableKeyException e) { 371 throw new KeyManagementException(e); 372 } 373 } 374 private static X509KeyManager findX509KeyManager(KeyManager[] kms) throws KeyManagementException { 375 for (KeyManager km : kms) { 376 if (km instanceof X509KeyManager) { 377 return (X509KeyManager)km; 378 } 379 } 380 throw new KeyManagementException("Failed to find an X509KeyManager in " + Arrays.toString(kms)); 381 } 382 383 /** 384 * Gets the default trust manager. 385 * 386 * TODO: Move this to a published API under dalvik.system. 387 */ 388 public static X509TrustManager getDefaultTrustManager() throws KeyManagementException { 389 X509TrustManager result = defaultTrustManager; 390 if (result == null) { 391 // single-check idiom 392 defaultTrustManager = result = createDefaultTrustManager(); 393 } 394 return result; 395 } 396 private static X509TrustManager createDefaultTrustManager() throws KeyManagementException { 397 try { 398 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); 399 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 400 tmf.init((KeyStore) null); 401 TrustManager[] tms = tmf.getTrustManagers(); 402 X509TrustManager trustManager = findX509TrustManager(tms); 403 return trustManager; 404 } catch (NoSuchAlgorithmException e) { 405 throw new KeyManagementException(e); 406 } catch (KeyStoreException e) { 407 throw new KeyManagementException(e); 408 } 409 } 410 private static X509TrustManager findX509TrustManager(TrustManager[] tms) throws KeyManagementException { 411 for (TrustManager tm : tms) { 412 if (tm instanceof X509TrustManager) { 413 return (X509TrustManager)tm; 414 } 415 } 416 throw new KeyManagementException("Failed to find an X509TrustManager in " + Arrays.toString(tms)); 417 } 418 } 419