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