/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.conscrypt; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.util.Arrays; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509TrustManager; /** * The instances of this class encapsulate all the info * about enabled cipher suites and protocols, * as well as the information about client/server mode of * ssl socket, whether it require/want client authentication or not, * and controls whether new SSL sessions may be established by this * socket or not. */ public class SSLParametersImpl implements Cloneable { // default source of authentication keys private static volatile X509KeyManager defaultKeyManager; // default source of authentication trust decisions private static volatile X509TrustManager defaultTrustManager; // default source of random numbers private static volatile SecureRandom defaultSecureRandom; // default SSL parameters private static volatile SSLParametersImpl defaultParameters; // client session context contains the set of reusable // client-side SSL sessions private final ClientSessionContext clientSessionContext; // server session context contains the set of reusable // server-side SSL sessions private final ServerSessionContext serverSessionContext; // source of authentication keys private X509KeyManager keyManager; // source of authentication trust decisions private X509TrustManager trustManager; // source of random numbers private SecureRandom secureRandom; // cipher suites available for SSL connection private CipherSuite[] enabledCipherSuites; // string representations of available cipher suites private String[] enabledCipherSuiteNames = null; // protocols available for SSL connection private String[] enabledProtocols = ProtocolVersion.supportedProtocols; // if the peer with this parameters tuned to work in client mode private boolean client_mode = true; // if the peer with this parameters tuned to require client authentication private boolean need_client_auth = false; // if the peer with this parameters tuned to request client authentication private boolean want_client_auth = false; // if the peer with this parameters allowed to cteate new SSL session private boolean enable_session_creation = true; protected CipherSuite[] getEnabledCipherSuitesMember() { if (enabledCipherSuites == null) { this.enabledCipherSuites = CipherSuite.DEFAULT_CIPHER_SUITES; } return enabledCipherSuites; } /** * Initializes the parameters. Naturally this constructor is used * in SSLContextImpl.engineInit method which directly passes its * parameters. In other words this constructor holds all * the functionality provided by SSLContext.init method. * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[], * SecureRandom)} for more information */ protected SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, SecureRandom sr, ClientSessionContext clientSessionContext, ServerSessionContext serverSessionContext) throws KeyManagementException { this.serverSessionContext = serverSessionContext; this.clientSessionContext = clientSessionContext; // It's not described by the spec of SSLContext what should happen // if the arrays of length 0 are specified. This implementation // behave as for null arrays (i.e. use installed security providers) // initialize keyManager if ((kms == null) || (kms.length == 0)) { keyManager = getDefaultKeyManager(); } else { keyManager = findX509KeyManager(kms); } // initialize trustManager if ((tms == null) || (tms.length == 0)) { trustManager = getDefaultTrustManager(); } else { trustManager = findX509TrustManager(tms); } // initialize secure random // BEGIN android-removed // if (sr == null) { // if (defaultSecureRandom == null) { // defaultSecureRandom = new SecureRandom(); // } // secureRandom = defaultSecureRandom; // } else { // secureRandom = sr; // } // END android-removed // BEGIN android-added // We simply use the SecureRandom passed in by the caller. If it's // null, we don't replace it by a new instance. The native code below // then directly accesses /dev/urandom. Not the most elegant solution, // but faster than going through the SecureRandom object. secureRandom = sr; // END android-added } protected static SSLParametersImpl getDefault() throws KeyManagementException { SSLParametersImpl result = defaultParameters; if (result == null) { // single-check idiom defaultParameters = result = new SSLParametersImpl(null, null, null, new ClientSessionContext(), new ServerSessionContext()); } return (SSLParametersImpl) result.clone(); } /** * @return server session context */ protected ServerSessionContext getServerSessionContext() { return serverSessionContext; } /** * @return client session context */ protected ClientSessionContext getClientSessionContext() { return clientSessionContext; } /** * @return key manager */ protected X509KeyManager getKeyManager() { return keyManager; } /** * @return trust manager */ protected X509TrustManager getTrustManager() { return trustManager; } /** * @return secure random */ protected SecureRandom getSecureRandom() { if (secureRandom != null) { return secureRandom; } SecureRandom result = defaultSecureRandom; if (result == null) { // single-check idiom defaultSecureRandom = result = new SecureRandom(); } secureRandom = result; return secureRandom; } /** * @return the secure random member reference, even it is null */ protected SecureRandom getSecureRandomMember() { return secureRandom; } /** * @return the names of enabled cipher suites */ protected String[] getEnabledCipherSuites() { if (enabledCipherSuiteNames == null) { CipherSuite[] enabledCipherSuites = getEnabledCipherSuitesMember(); enabledCipherSuiteNames = new String[enabledCipherSuites.length]; for (int i = 0; i< enabledCipherSuites.length; i++) { enabledCipherSuiteNames[i] = enabledCipherSuites[i].getName(); } } return enabledCipherSuiteNames.clone(); } /** * Sets the set of available cipher suites for use in SSL connection. * @param suites: String[] * @return */ protected void setEnabledCipherSuites(String[] suites) { if (suites == null) { throw new IllegalArgumentException("suites == null"); } CipherSuite[] cipherSuites = new CipherSuite[suites.length]; for (int i=0; i