OSDN Git Service

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