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