Home | History | Annotate | Download | only in jsse
      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