blob: d91388a2886d274d599cfb162da6815b54407288 [file] [log] [blame]
/*
* 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.
*/
/**
* @author Alexander Y. Kleymenov
* @version $Revision$
*/
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 (String[]) 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 (String[]) 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.
*/
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;
}
}