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