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 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