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 org.apache.harmony.xnet.provider.jsse.TrustManagerImpl; 21 import java.security.KeyManagementException; 22 import java.security.KeyStore; 23 import java.security.KeyStoreException; 24 import java.security.NoSuchAlgorithmException; 25 import java.security.SecureRandom; 26 import java.security.UnrecoverableKeyException; 27 import java.util.Arrays; 28 import javax.net.ssl.KeyManager; 29 import javax.net.ssl.KeyManagerFactory; 30 import javax.net.ssl.TrustManager; 31 import javax.net.ssl.TrustManagerFactory; 32 import javax.net.ssl.X509KeyManager; 33 import 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 */ 43 public 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 117 // initialize trustManager 118 if ((tms == null) || (tms.length == 0)) { 119 trustManager = getDefaultTrustManager(); 120 } else { 121 trustManager = findX509TrustManager(tms); 122 } 123 // initialize secure random 124 // BEGIN android-removed 125 // if (sr == null) { 126 // if (defaultSecureRandom == null) { 127 // defaultSecureRandom = new SecureRandom(); 128 // } 129 // secureRandom = defaultSecureRandom; 130 // } else { 131 // secureRandom = sr; 132 // } 133 // END android-removed 134 // BEGIN android-added 135 // We simply use the SecureRandom passed in by the caller. If it's 136 // null, we don't replace it by a new instance. The native code below 137 // then directly accesses /dev/urandom. Not the most elegant solution, 138 // but faster than going through the SecureRandom object. 139 secureRandom = sr; 140 // END android-added 141 } 142 143 protected static SSLParametersImpl getDefault() throws KeyManagementException { 144 SSLParametersImpl result = defaultParameters; 145 if (result == null) { 146 // single-check idiom 147 defaultParameters = result = new SSLParametersImpl(null, 148 null, 149 null, 150 new ClientSessionContext(), 151 new ServerSessionContext()); 152 } 153 return (SSLParametersImpl) result.clone(); 154 } 155 156 /** 157 * @return server session context 158 */ 159 protected ServerSessionContext getServerSessionContext() { 160 return serverSessionContext; 161 } 162 163 /** 164 * @return client session context 165 */ 166 protected ClientSessionContext getClientSessionContext() { 167 return clientSessionContext; 168 } 169 170 /** 171 * @return key manager 172 */ 173 protected X509KeyManager getKeyManager() { 174 return keyManager; 175 } 176 177 /** 178 * @return trust manager 179 */ 180 protected X509TrustManager getTrustManager() { 181 return trustManager; 182 } 183 184 /** 185 * @return secure random 186 */ 187 protected SecureRandom getSecureRandom() { 188 if (secureRandom != null) { 189 return secureRandom; 190 } 191 SecureRandom result = defaultSecureRandom; 192 if (result == null) { 193 // single-check idiom 194 defaultSecureRandom = result = new SecureRandom(); 195 } 196 secureRandom = result; 197 return secureRandom; 198 } 199 200 /** 201 * @return the secure random member reference, even it is null 202 */ 203 protected SecureRandom getSecureRandomMember() { 204 return secureRandom; 205 } 206 207 /** 208 * @return the names of enabled cipher suites 209 */ 210 protected String[] getEnabledCipherSuites() { 211 if (enabledCipherSuiteNames == null) { 212 CipherSuite[] enabledCipherSuites = getEnabledCipherSuitesMember(); 213 enabledCipherSuiteNames = new String[enabledCipherSuites.length]; 214 for (int i = 0; i< enabledCipherSuites.length; i++) { 215 enabledCipherSuiteNames[i] = enabledCipherSuites[i].getName(); 216 } 217 } 218 return enabledCipherSuiteNames.clone(); 219 } 220 221 /** 222 * Sets the set of available cipher suites for use in SSL connection. 223 * @param suites: String[] 224 * @return 225 */ 226 protected void setEnabledCipherSuites(String[] suites) { 227 if (suites == null) { 228 throw new IllegalArgumentException("suites == null"); 229 } 230 CipherSuite[] cipherSuites = new CipherSuite[suites.length]; 231 for (int i=0; i<suites.length; i++) { 232 String suite = suites[i]; 233 if (suite == null) { 234 throw new IllegalArgumentException("suites[" + i + "] == null"); 235 } 236 cipherSuites[i] = CipherSuite.getByName(suite); 237 if (cipherSuites[i] == null || !cipherSuites[i].supported) { 238 throw new IllegalArgumentException(suite + " is not supported."); 239 } 240 } 241 enabledCipherSuites = cipherSuites; 242 enabledCipherSuiteNames = suites; 243 } 244 245 /** 246 * @return the set of enabled protocols 247 */ 248 protected String[] getEnabledProtocols() { 249 return enabledProtocols.clone(); 250 } 251 252 /** 253 * Sets the set of available protocols for use in SSL connection. 254 * @param protocols String[] 255 */ 256 protected void setEnabledProtocols(String[] protocols) { 257 if (protocols == null) { 258 throw new IllegalArgumentException("protocols == null"); 259 } 260 for (int i=0; i<protocols.length; i++) { 261 String protocol = protocols[i]; 262 if (protocol == null) { 263 throw new IllegalArgumentException("protocols[" + i + "] == null"); 264 } 265 if (!ProtocolVersion.isSupported(protocol)) { 266 throw new IllegalArgumentException("Protocol " + protocol + " is not supported."); 267 } 268 } 269 enabledProtocols = protocols; 270 } 271 272 /** 273 * Tunes the peer holding this parameters to work in client mode. 274 * @param mode if the peer is configured to work in client mode 275 */ 276 protected void setUseClientMode(boolean mode) { 277 client_mode = mode; 278 } 279 280 /** 281 * Returns the value indicating if the parameters configured to work 282 * in client mode. 283 */ 284 protected boolean getUseClientMode() { 285 return client_mode; 286 } 287 288 /** 289 * Tunes the peer holding this parameters to require client authentication 290 */ 291 protected void setNeedClientAuth(boolean need) { 292 need_client_auth = need; 293 // reset the want_client_auth setting 294 want_client_auth = false; 295 } 296 297 /** 298 * Returns the value indicating if the peer with this parameters tuned 299 * to require client authentication 300 */ 301 protected boolean getNeedClientAuth() { 302 return need_client_auth; 303 } 304 305 /** 306 * Tunes the peer holding this parameters to request client authentication 307 */ 308 protected void setWantClientAuth(boolean want) { 309 want_client_auth = want; 310 // reset the need_client_auth setting 311 need_client_auth = false; 312 } 313 314 /** 315 * Returns the value indicating if the peer with this parameters 316 * tuned to request client authentication 317 * @return 318 */ 319 protected boolean getWantClientAuth() { 320 return want_client_auth; 321 } 322 323 /** 324 * Allows/disallows the peer holding this parameters to 325 * create new SSL session 326 */ 327 protected void setEnableSessionCreation(boolean flag) { 328 enable_session_creation = flag; 329 } 330 331 /** 332 * Returns the value indicating if the peer with this parameters 333 * allowed to cteate new SSL session 334 */ 335 protected boolean getEnableSessionCreation() { 336 return enable_session_creation; 337 } 338 339 /** 340 * Returns the clone of this object. 341 * @return the clone. 342 */ 343 @Override 344 protected Object clone() { 345 try { 346 return super.clone(); 347 } catch (CloneNotSupportedException e) { 348 throw new AssertionError(e); 349 } 350 } 351 352 private static X509KeyManager getDefaultKeyManager() throws KeyManagementException { 353 X509KeyManager result = defaultKeyManager; 354 if (result == null) { 355 // single-check idiom 356 defaultKeyManager = result = createDefaultKeyManager(); 357 } 358 return result; 359 } 360 private static X509KeyManager createDefaultKeyManager() throws KeyManagementException { 361 try { 362 String algorithm = KeyManagerFactory.getDefaultAlgorithm(); 363 KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); 364 kmf.init(null, null); 365 KeyManager[] kms = kmf.getKeyManagers(); 366 return findX509KeyManager(kms); 367 } catch (NoSuchAlgorithmException e) { 368 throw new KeyManagementException(e); 369 } catch (KeyStoreException e) { 370 throw new KeyManagementException(e); 371 } catch (UnrecoverableKeyException e) { 372 throw new KeyManagementException(e); 373 } 374 } 375 private static X509KeyManager findX509KeyManager(KeyManager[] kms) throws KeyManagementException { 376 for (KeyManager km : kms) { 377 if (km instanceof X509KeyManager) { 378 return (X509KeyManager)km; 379 } 380 } 381 throw new KeyManagementException("Failed to find an X509KeyManager in " + Arrays.toString(kms)); 382 } 383 384 /** 385 * Gets the default trust manager. 386 * 387 * TODO: Move this to a published API under dalvik.system. 388 */ 389 public static X509TrustManager getDefaultTrustManager() throws KeyManagementException { 390 X509TrustManager result = defaultTrustManager; 391 if (result == null) { 392 // single-check idiom 393 defaultTrustManager = result = createDefaultTrustManager(); 394 } 395 return result; 396 } 397 private static X509TrustManager createDefaultTrustManager() throws KeyManagementException { 398 try { 399 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); 400 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 401 tmf.init((KeyStore) null); 402 TrustManager[] tms = tmf.getTrustManagers(); 403 X509TrustManager trustManager = findX509TrustManager(tms); 404 return trustManager; 405 } catch (NoSuchAlgorithmException e) { 406 throw new KeyManagementException(e); 407 } catch (KeyStoreException e) { 408 throw new KeyManagementException(e); 409 } 410 } 411 private static X509TrustManager findX509TrustManager(TrustManager[] tms) throws KeyManagementException { 412 for (TrustManager tm : tms) { 413 if (tm instanceof X509TrustManager) { 414 return (X509TrustManager)tm; 415 } 416 } 417 throw new KeyManagementException("Failed to find an X509TrustManager in " + Arrays.toString(tms)); 418 } 419 } 420