| /* |
| * 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.apache.harmony.xnet.provider.jsse; |
| |
| 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.security.InvalidAlgorithmParameterException; |
| import java.security.cert.CertificateEncodingException; |
| |
| 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 incapsulate 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. |
| */ |
| // BEGIN android-changed |
| public class SSLParameters implements Cloneable { |
| // END android-changed |
| |
| // default source of authentication keys |
| private static X509KeyManager defaultKeyManager; |
| // default source of authentication trust decisions |
| private static X509TrustManager defaultTrustManager; |
| // default source of random numbers |
| private static SecureRandom defaultSecureRandom; |
| // default SSL parameters |
| private static SSLParameters defaultParameters; |
| |
| // client session context contains the set of reusable |
| // client-side SSL sessions |
| // BEGIN android-changed |
| private final ClientSessionContext clientSessionContext; |
| // server session context contains the set of reusable |
| // server-side SSL sessions |
| private final ServerSessionContext serverSessionContext; |
| // END android-changed |
| // 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 |
| // BEGIN android-changed |
| private CipherSuite[] enabledCipherSuites; |
| // END android-changed |
| // 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; |
| |
| // BEGIN android-changed |
| protected CipherSuite[] getEnabledCipherSuitesMember() { |
| if (enabledCipherSuites == null) this.enabledCipherSuites = CipherSuite.defaultCipherSuites; |
| return enabledCipherSuites; |
| } |
| |
| /** |
| * Holds a pointer to our native SSL context. |
| */ |
| private int ssl_ctx = 0; |
| |
| /** |
| * Initializes our native SSL context. |
| */ |
| private native int nativeinitsslctx(); |
| |
| /** |
| * Returns the native SSL context, creating it on-the-fly, if necessary. |
| */ |
| protected synchronized int getSSLCTX() { |
| if (ssl_ctx == 0) ssl_ctx = nativeinitsslctx(); |
| return ssl_ctx; |
| } |
| // END android-changed |
| |
| /** |
| * Initializes the parameters. Naturally this constructor is used |
| * in SSLContextImpl.engineInit method which dirrectly 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 SSLParameters(KeyManager[] kms, TrustManager[] tms, |
| // BEGIN android-changed |
| SecureRandom sr, SSLClientSessionCache clientCache, |
| SSLServerSessionCache serverCache) |
| throws KeyManagementException { |
| this.serverSessionContext |
| = new ServerSessionContext(this, serverCache); |
| this.clientSessionContext |
| = new ClientSessionContext(this, clientCache); |
| // END android-changed |
| try { |
| // initialize key manager |
| boolean initialize_default = false; |
| // 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) |
| if ((kms == null) || (kms.length == 0)) { |
| if (defaultKeyManager == null) { |
| KeyManagerFactory kmf = KeyManagerFactory.getInstance( |
| KeyManagerFactory.getDefaultAlgorithm()); |
| kmf.init(null, null); |
| kms = kmf.getKeyManagers(); |
| // tell that we are trying to initialize defaultKeyManager |
| initialize_default = true; |
| } else { |
| keyManager = defaultKeyManager; |
| } |
| } |
| if (keyManager == null) { // was not initialized by default |
| for (int i = 0; i < kms.length; i++) { |
| if (kms[i] instanceof X509KeyManager) { |
| keyManager = (X509KeyManager)kms[i]; |
| break; |
| } |
| } |
| if (keyManager == null) { |
| throw new KeyManagementException("No X509KeyManager found"); |
| } |
| if (initialize_default) { |
| // found keyManager is default key manager |
| defaultKeyManager = keyManager; |
| } |
| } |
| |
| // initialize trust manager |
| initialize_default = false; |
| if ((tms == null) || (tms.length == 0)) { |
| if (defaultTrustManager == null) { |
| TrustManagerFactory tmf = TrustManagerFactory |
| .getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
| tmf.init((KeyStore)null); |
| tms = tmf.getTrustManagers(); |
| initialize_default = true; |
| } else { |
| trustManager = defaultTrustManager; |
| } |
| } |
| if (trustManager == null) { // was not initialized by default |
| for (int i = 0; i < tms.length; i++) { |
| if (tms[i] instanceof X509TrustManager) { |
| trustManager = (X509TrustManager)tms[i]; |
| break; |
| } |
| } |
| if (trustManager == null) { |
| throw new KeyManagementException("No X509TrustManager found"); |
| } |
| if (initialize_default) { |
| // found trustManager is default trust manager |
| defaultTrustManager = trustManager; |
| // BEGIN android-added |
| if (trustManager instanceof TrustManagerImpl) { |
| ((TrustManagerImpl) trustManager).indexTrustAnchors(); |
| } |
| // END android-added |
| } |
| } |
| } catch (NoSuchAlgorithmException e) { |
| throw new KeyManagementException(e); |
| } catch (KeyStoreException e) { |
| throw new KeyManagementException(e); |
| } catch (UnrecoverableKeyException e) { |
| throw new KeyManagementException(e); |
| // BEGIN android-added |
| } catch (CertificateEncodingException e) { |
| throw new KeyManagementException(e); |
| } catch (InvalidAlgorithmParameterException e) { |
| throw new KeyManagementException(e); |
| // END android-added |
| } |
| // 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 SSLParameters getDefault() throws KeyManagementException { |
| if (defaultParameters == null) { |
| // BEGIN android-changed |
| defaultParameters = new SSLParameters(null, null, null, null, null); |
| // END android-changed |
| } |
| return (SSLParameters) defaultParameters.clone(); |
| } |
| |
| /** |
| * @return server session context |
| */ |
| // BEGIN android-changed |
| protected ServerSessionContext getServerSessionContext() { |
| // END android-changed |
| return serverSessionContext; |
| } |
| |
| /** |
| * @return client session context |
| */ |
| // BEGIN android-changed |
| protected ClientSessionContext getClientSessionContext() { |
| // END android-changed |
| return clientSessionContext; |
| } |
| |
| /** |
| * @return key manager |
| */ |
| protected X509KeyManager getKeyManager() { |
| return keyManager; |
| } |
| |
| /** |
| * @return trust manager |
| */ |
| protected X509TrustManager getTrustManager() { |
| return trustManager; |
| } |
| |
| /** |
| * @return secure random |
| */ |
| protected SecureRandom getSecureRandom() { |
| // BEGIN android-removed |
| // return secureRandom; |
| // END android-removed |
| // BEGIN android-added |
| if (secureRandom != null) return secureRandom; |
| if (defaultSecureRandom == null) |
| { |
| defaultSecureRandom = new SecureRandom(); |
| } |
| secureRandom = defaultSecureRandom; |
| // END android-added |
| return secureRandom; |
| } |
| |
| // BEGIN android-added |
| /** |
| * @return the secure random member reference, even it is null |
| */ |
| protected SecureRandom getSecureRandomMember() { |
| return secureRandom; |
| } |
| // END android-added |
| |
| /** |
| * @return the names of enabled cipher suites |
| */ |
| protected String[] getEnabledCipherSuites() { |
| if (enabledCipherSuiteNames == null) { |
| // BEGIN android-added |
| CipherSuite[] enabledCipherSuites = getEnabledCipherSuitesMember(); |
| // END android-added |
| 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("Provided parameter is null"); |
| } |
| CipherSuite[] cipherSuites = new CipherSuite[suites.length]; |
| for (int i=0; i<suites.length; i++) { |
| cipherSuites[i] = CipherSuite.getByName(suites[i]); |
| if (cipherSuites[i] == null || !cipherSuites[i].supported) { |
| throw new IllegalArgumentException(suites[i] + |
| " is not supported."); |
| } |
| } |
| enabledCipherSuites = cipherSuites; |
| enabledCipherSuiteNames = suites; |
| } |
| |
| /** |
| * @return the set of enabled protocols |
| */ |
| protected String[] getEnabledProtocols() { |
| return enabledProtocols.clone(); |
| } |
| |
| /** |
| * Sets the set of available protocols for use in SSL connection. |
| * @param protocols String[] |
| */ |
| protected void setEnabledProtocols(String[] protocols) { |
| if (protocols == null) { |
| throw new IllegalArgumentException("Provided parameter is null"); |
| } |
| for (int i=0; i<protocols.length; i++) { |
| if (!ProtocolVersion.isSupported(protocols[i])) { |
| throw new IllegalArgumentException("Protocol " + protocols[i] + |
| " is not supported."); |
| } |
| } |
| enabledProtocols = protocols; |
| } |
| |
| /** |
| * Tunes the peer holding this parameters to work in client mode. |
| * @param mode if the peer is configured to work in client mode |
| */ |
| protected void setUseClientMode(boolean mode) { |
| client_mode = mode; |
| } |
| |
| /** |
| * Returns the value indicating if the parameters configured to work |
| * in client mode. |
| */ |
| protected boolean getUseClientMode() { |
| return client_mode; |
| } |
| |
| /** |
| * Tunes the peer holding this parameters to require client authentication |
| */ |
| protected void setNeedClientAuth(boolean need) { |
| need_client_auth = need; |
| // reset the want_client_auth setting |
| want_client_auth = false; |
| } |
| |
| /** |
| * Returns the value indicating if the peer with this parameters tuned |
| * to require client authentication |
| */ |
| protected boolean getNeedClientAuth() { |
| return need_client_auth; |
| } |
| |
| /** |
| * Tunes the peer holding this parameters to request client authentication |
| */ |
| protected void setWantClientAuth(boolean want) { |
| want_client_auth = want; |
| // reset the need_client_auth setting |
| need_client_auth = false; |
| } |
| |
| /** |
| * Returns the value indicating if the peer with this parameters |
| * tuned to request client authentication |
| * @return |
| */ |
| protected boolean getWantClientAuth() { |
| return want_client_auth; |
| } |
| |
| /** |
| * Allows/disallows the peer holding this parameters to |
| * create new SSL session |
| */ |
| protected void setEnableSessionCreation(boolean flag) { |
| enable_session_creation = flag; |
| } |
| |
| /** |
| * Returns the value indicating if the peer with this parameters |
| * allowed to cteate new SSL session |
| */ |
| protected boolean getEnableSessionCreation() { |
| return enable_session_creation; |
| } |
| |
| /** |
| * Returns the clone of this object. |
| * @return the clone. |
| */ |
| @Override |
| protected Object clone() { |
| // BEGIN android-changed |
| try { |
| return super.clone(); |
| } catch (CloneNotSupportedException e) { |
| throw new AssertionError(e); |
| } |
| // END android-changed |
| } |
| |
| /** |
| * Gets the default trust manager. |
| * |
| * TODO: Move this to a published API under dalvik.system. |
| */ |
| public static X509TrustManager getDefaultTrustManager() { |
| return defaultTrustManager; |
| } |
| } |