Home | History | Annotate | Download | only in conscrypt
      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.conscrypt;
     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.util.ArrayList;
     27 import java.util.Arrays;
     28 import javax.crypto.SecretKey;
     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.X509ExtendedKeyManager;
     34 import javax.net.ssl.X509KeyManager;
     35 import javax.net.ssl.X509TrustManager;
     36 import javax.security.auth.x500.X500Principal;
     37 
     38 /**
     39  * The instances of this class encapsulate all the info
     40  * about enabled cipher suites and protocols,
     41  * as well as the information about client/server mode of
     42  * ssl socket, whether it require/want client authentication or not,
     43  * and controls whether new SSL sessions may be established by this
     44  * socket or not.
     45  */
     46 final class SSLParametersImpl implements Cloneable {
     47 
     48     // default source of X.509 certificate based authentication keys
     49     private static volatile X509KeyManager defaultX509KeyManager;
     50     // default source of X.509 certificate based authentication trust decisions
     51     private static volatile X509TrustManager defaultX509TrustManager;
     52     // default SSL parameters
     53     private static volatile SSLParametersImpl defaultParameters;
     54 
     55     // client session context contains the set of reusable
     56     // client-side SSL sessions
     57     private final ClientSessionContext clientSessionContext;
     58     // server session context contains the set of reusable
     59     // server-side SSL sessions
     60     private final ServerSessionContext serverSessionContext;
     61     // source of X.509 certificate based authentication keys or null if not provided
     62     private final X509KeyManager x509KeyManager;
     63     // source of Pre-Shared Key (PSK) authentication keys or null if not provided.
     64     @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
     65     private final PSKKeyManager pskKeyManager;
     66     // source of X.509 certificate based authentication trust decisions or null if not provided
     67     private final X509TrustManager x509TrustManager;
     68 
     69     // protocols enabled for SSL connection
     70     String[] enabledProtocols;
     71     // set to indicate when obsolete protocols are filtered
     72     boolean isEnabledProtocolsFiltered;
     73     // cipher suites enabled for SSL connection
     74     String[] enabledCipherSuites;
     75 
     76     // if the peer with this parameters tuned to work in client mode
     77     private boolean client_mode = true;
     78     // if the peer with this parameters tuned to require client authentication
     79     private boolean need_client_auth = false;
     80     // if the peer with this parameters tuned to request client authentication
     81     private boolean want_client_auth = false;
     82     // if the peer with this parameters allowed to cteate new SSL session
     83     private boolean enable_session_creation = true;
     84     // Endpoint identification algorithm (e.g., HTTPS)
     85     private String endpointIdentificationAlgorithm;
     86     // Whether to use the local cipher suites order
     87     private boolean useCipherSuitesOrder;
     88 
     89     // client-side only, bypasses the property based configuration, used for tests
     90     private boolean ctVerificationEnabled;
     91 
     92     // server-side only. SCT and OCSP data to send to clients which request it
     93     byte[] sctExtension;
     94     byte[] ocspResponse;
     95 
     96     byte[] applicationProtocols = EmptyArray.BYTE;
     97     ApplicationProtocolSelectorAdapter applicationProtocolSelector;
     98     boolean useSessionTickets;
     99     private Boolean useSni;
    100 
    101     /**
    102      * Whether the TLS Channel ID extension is enabled. This field is
    103      * server-side only.
    104      */
    105     boolean channelIdEnabled;
    106 
    107     /**
    108      * Initializes the parameters. Naturally this constructor is used
    109      * in SSLContextImpl.engineInit method which directly passes its
    110      * parameters. In other words this constructor holds all
    111      * the functionality provided by SSLContext.init method.
    112      * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[],
    113      * SecureRandom)} for more information
    114      */
    115     SSLParametersImpl(KeyManager[] kms, TrustManager[] tms,
    116             SecureRandom sr, ClientSessionContext clientSessionContext,
    117             ServerSessionContext serverSessionContext, String[] protocols)
    118             throws KeyManagementException {
    119         this.serverSessionContext = serverSessionContext;
    120         this.clientSessionContext = clientSessionContext;
    121 
    122         // initialize key managers
    123         if (kms == null) {
    124             x509KeyManager = getDefaultX509KeyManager();
    125             // There's no default PSK key manager
    126             pskKeyManager = null;
    127         } else {
    128             x509KeyManager = findFirstX509KeyManager(kms);
    129             pskKeyManager = findFirstPSKKeyManager(kms);
    130         }
    131 
    132         // initialize x509TrustManager
    133         if (tms == null) {
    134             x509TrustManager = getDefaultX509TrustManager();
    135         } else {
    136             x509TrustManager = findFirstX509TrustManager(tms);
    137         }
    138 
    139         // initialize the list of cipher suites and protocols enabled by default
    140         enabledProtocols = NativeCrypto.checkEnabledProtocols(
    141                 protocols == null ? NativeCrypto.DEFAULT_PROTOCOLS : protocols).clone();
    142         boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
    143         boolean pskCipherSuitesNeeded = pskKeyManager != null;
    144         enabledCipherSuites = getDefaultCipherSuites(
    145                 x509CipherSuitesNeeded, pskCipherSuitesNeeded);
    146 
    147         // We ignore the SecureRandom passed in by the caller. The native code below
    148         // directly accesses /dev/urandom, which makes it irrelevant.
    149     }
    150 
    151     static SSLParametersImpl getDefault() throws KeyManagementException {
    152         SSLParametersImpl result = defaultParameters;
    153         if (result == null) {
    154             // single-check idiom
    155             defaultParameters = result = new SSLParametersImpl(null,
    156                                                                null,
    157                                                                null,
    158                                                                new ClientSessionContext(),
    159                                                                new ServerSessionContext(),
    160                                                                null);
    161         }
    162         return (SSLParametersImpl) result.clone();
    163     }
    164 
    165     /**
    166      * Returns the appropriate session context.
    167      */
    168     AbstractSessionContext getSessionContext() {
    169         return client_mode ? clientSessionContext : serverSessionContext;
    170     }
    171 
    172     /**
    173      * @return client session context
    174      */
    175     ClientSessionContext getClientSessionContext() {
    176         return clientSessionContext;
    177     }
    178 
    179     /**
    180      * @return X.509 key manager or {@code null} for none.
    181      */
    182     X509KeyManager getX509KeyManager() {
    183         return x509KeyManager;
    184     }
    185 
    186     /**
    187      * @return Pre-Shared Key (PSK) key manager or {@code null} for none.
    188      */
    189     @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
    190     PSKKeyManager getPSKKeyManager() {
    191         return pskKeyManager;
    192     }
    193 
    194     /**
    195      * @return X.509 trust manager or {@code null} for none.
    196      */
    197     X509TrustManager getX509TrustManager() {
    198         return x509TrustManager;
    199     }
    200 
    201     /**
    202      * @return the names of enabled cipher suites
    203      */
    204     String[] getEnabledCipherSuites() {
    205         return enabledCipherSuites.clone();
    206     }
    207 
    208     /**
    209      * Sets the enabled cipher suites after filtering through OpenSSL.
    210      */
    211     void setEnabledCipherSuites(String[] cipherSuites) {
    212         enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(cipherSuites).clone();
    213     }
    214 
    215     /**
    216      * @return the set of enabled protocols
    217      */
    218     String[] getEnabledProtocols() {
    219         return enabledProtocols.clone();
    220     }
    221 
    222     /**
    223      * Sets the list of available protocols for use in SSL connection.
    224      * @throws IllegalArgumentException if {@code protocols == null}
    225      */
    226     void setEnabledProtocols(String[] protocols) {
    227         if (protocols == null) {
    228             throw new IllegalArgumentException("protocols == null");
    229         }
    230         String[] filteredProtocols =
    231                 filterFromProtocols(protocols, NativeCrypto.OBSOLETE_PROTOCOL_SSLV3);
    232         isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length;
    233         enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone();
    234     }
    235 
    236     /**
    237      * Sets the list of ALPN protocols.
    238      *
    239      * @param protocols the list of ALPN protocols
    240      */
    241     void setApplicationProtocols(String[] protocols) {
    242         this.applicationProtocols = SSLUtils.encodeProtocols(protocols);
    243     }
    244 
    245     String[] getApplicationProtocols() {
    246         return SSLUtils.decodeProtocols(applicationProtocols);
    247     }
    248 
    249     /**
    250      * Used for server-mode only. Sets or clears the application-provided ALPN protocol selector.
    251      * If set, will override the protocol list provided by {@link #setApplicationProtocols(String[])}.
    252      */
    253     void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter applicationProtocolSelector) {
    254         this.applicationProtocolSelector = applicationProtocolSelector;
    255     }
    256 
    257     /**
    258      * Tunes the peer holding this parameters to work in client mode.
    259      * @param   mode if the peer is configured to work in client mode
    260      */
    261     void setUseClientMode(boolean mode) {
    262         client_mode = mode;
    263     }
    264 
    265     /**
    266      * Returns the value indicating if the parameters configured to work
    267      * in client mode.
    268      */
    269     boolean getUseClientMode() {
    270         return client_mode;
    271     }
    272 
    273     /**
    274      * Tunes the peer holding this parameters to require client authentication
    275      */
    276     void setNeedClientAuth(boolean need) {
    277         need_client_auth = need;
    278         // reset the want_client_auth setting
    279         want_client_auth = false;
    280     }
    281 
    282     /**
    283      * Returns the value indicating if the peer with this parameters tuned
    284      * to require client authentication
    285      */
    286     boolean getNeedClientAuth() {
    287         return need_client_auth;
    288     }
    289 
    290     /**
    291      * Tunes the peer holding this parameters to request client authentication
    292      */
    293     void setWantClientAuth(boolean want) {
    294         want_client_auth = want;
    295         // reset the need_client_auth setting
    296         need_client_auth = false;
    297     }
    298 
    299     /**
    300      * Returns the value indicating if the peer with this parameters
    301      * tuned to request client authentication
    302      */
    303     boolean getWantClientAuth() {
    304         return want_client_auth;
    305     }
    306 
    307     /**
    308      * Allows/disallows the peer holding this parameters to
    309      * create new SSL session
    310      */
    311     void setEnableSessionCreation(boolean flag) {
    312         enable_session_creation = flag;
    313     }
    314 
    315     /**
    316      * Returns the value indicating if the peer with this parameters
    317      * allowed to cteate new SSL session
    318      */
    319     boolean getEnableSessionCreation() {
    320         return enable_session_creation;
    321     }
    322 
    323     void setUseSessionTickets(boolean useSessionTickets) {
    324         this.useSessionTickets = useSessionTickets;
    325     }
    326 
    327     /**
    328      * Whether connections using this SSL connection should use the TLS
    329      * extension Server Name Indication (SNI).
    330      */
    331     void setUseSni(boolean flag) {
    332         useSni = flag;
    333     }
    334 
    335     /**
    336      * Returns whether connections using this SSL connection should use the TLS
    337      * extension Server Name Indication (SNI).
    338      */
    339     boolean getUseSni() {
    340         return useSni != null ? useSni : isSniEnabledByDefault();
    341     }
    342 
    343     /**
    344      * For testing only.
    345      */
    346     void setCTVerificationEnabled(boolean enabled) {
    347         ctVerificationEnabled = enabled;
    348     }
    349 
    350     /**
    351      * For testing only.
    352      */
    353     void setSCTExtension(byte[] extension) {
    354         sctExtension = extension;
    355     }
    356 
    357     /**
    358      * For testing only.
    359      */
    360     void setOCSPResponse(byte[] response) {
    361         ocspResponse = response;
    362     }
    363 
    364     byte[] getOCSPResponse() {
    365         return ocspResponse;
    366     }
    367 
    368     /**
    369      * This filters {@code obsoleteProtocol} from the list of {@code protocols}
    370      * down to help with app compatibility.
    371      */
    372     private static String[] filterFromProtocols(String[] protocols, String obsoleteProtocol) {
    373         if (protocols.length == 1 && obsoleteProtocol.equals(protocols[0])) {
    374             return EMPTY_STRING_ARRAY;
    375         }
    376 
    377         ArrayList<String> newProtocols = new ArrayList<String>();
    378         for (String protocol : protocols) {
    379             if (!obsoleteProtocol.equals(protocol)) {
    380                 newProtocols.add(protocol);
    381             }
    382         }
    383         return newProtocols.toArray(EMPTY_STRING_ARRAY);
    384     }
    385 
    386     private static final String[] EMPTY_STRING_ARRAY = new String[0];
    387 
    388     /**
    389      * Returns whether Server Name Indication (SNI) is enabled by default for
    390      * sockets. For more information on SNI, see RFC 6066 section 3.
    391      */
    392     private boolean isSniEnabledByDefault() {
    393         try {
    394             String enableSNI = System.getProperty("jsse.enableSNIExtension", "true");
    395             if ("true".equalsIgnoreCase(enableSNI)) {
    396                 return true;
    397             } else if ("false".equalsIgnoreCase(enableSNI)) {
    398                 return false;
    399             } else {
    400                 throw new RuntimeException(
    401                         "Can only set \"jsse.enableSNIExtension\" to \"true\" or \"false\"");
    402             }
    403         } catch (SecurityException e) {
    404             return true;
    405         }
    406     }
    407 
    408     /**
    409      * For abstracting the X509KeyManager calls between
    410      * {@link X509KeyManager#chooseClientAlias(String[], java.security.Principal[], java.net.Socket)}
    411      * and
    412      * {@link X509ExtendedKeyManager#chooseEngineClientAlias(String[], java.security.Principal[], javax.net.ssl.SSLEngine)}
    413      */
    414     interface AliasChooser {
    415         String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
    416                 String[] keyTypes);
    417 
    418         String chooseServerAlias(X509KeyManager keyManager, String keyType);
    419     }
    420 
    421     /**
    422      * For abstracting the {@code PSKKeyManager} calls between those taking an {@code SSLSocket} and
    423      * those taking an {@code SSLEngine}.
    424      */
    425     @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
    426     interface PSKCallbacks {
    427         String chooseServerPSKIdentityHint(PSKKeyManager keyManager);
    428         String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint);
    429         SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity);
    430     }
    431 
    432     /**
    433      * Returns the clone of this object.
    434      * @return the clone.
    435      */
    436     @Override
    437     protected Object clone() {
    438         try {
    439             return super.clone();
    440         } catch (CloneNotSupportedException e) {
    441             throw new AssertionError(e);
    442         }
    443     }
    444 
    445     private static X509KeyManager getDefaultX509KeyManager() throws KeyManagementException {
    446         X509KeyManager result = defaultX509KeyManager;
    447         if (result == null) {
    448             // single-check idiom
    449             defaultX509KeyManager = result = createDefaultX509KeyManager();
    450         }
    451         return result;
    452     }
    453     private static X509KeyManager createDefaultX509KeyManager() throws KeyManagementException {
    454         try {
    455             String algorithm = KeyManagerFactory.getDefaultAlgorithm();
    456             KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
    457             kmf.init(null, null);
    458             KeyManager[] kms = kmf.getKeyManagers();
    459             X509KeyManager result = findFirstX509KeyManager(kms);
    460             if (result == null) {
    461                 throw new KeyManagementException("No X509KeyManager among default KeyManagers: "
    462                         + Arrays.toString(kms));
    463             }
    464             return result;
    465         } catch (NoSuchAlgorithmException e) {
    466             throw new KeyManagementException(e);
    467         } catch (KeyStoreException e) {
    468             throw new KeyManagementException(e);
    469         } catch (UnrecoverableKeyException e) {
    470             throw new KeyManagementException(e);
    471         }
    472     }
    473 
    474     /**
    475      * Finds the first {@link X509KeyManager} element in the provided array.
    476      *
    477      * @return the first {@code X509KeyManager} or {@code null} if not found.
    478      */
    479     private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) {
    480         for (KeyManager km : kms) {
    481             if (km instanceof X509KeyManager) {
    482                 return (X509KeyManager)km;
    483             }
    484         }
    485         return null;
    486     }
    487 
    488     /**
    489      * Finds the first {@link PSKKeyManager} element in the provided array.
    490      *
    491      * @return the first {@code PSKKeyManager} or {@code null} if not found.
    492      */
    493     @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
    494     private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) {
    495         for (KeyManager km : kms) {
    496             if (km instanceof PSKKeyManager) {
    497                 return (PSKKeyManager)km;
    498             } else if (km != null) {
    499                 try {
    500                     return DuckTypedPSKKeyManager.getInstance(km);
    501                 } catch (NoSuchMethodException ignored) {}
    502             }
    503         }
    504         return null;
    505     }
    506 
    507     /**
    508      * Gets the default X.509 trust manager.
    509      */
    510     static X509TrustManager getDefaultX509TrustManager()
    511             throws KeyManagementException {
    512         X509TrustManager result = defaultX509TrustManager;
    513         if (result == null) {
    514             // single-check idiom
    515             defaultX509TrustManager = result = createDefaultX509TrustManager();
    516         }
    517         return result;
    518     }
    519 
    520     private static X509TrustManager createDefaultX509TrustManager()
    521             throws KeyManagementException {
    522         try {
    523             String algorithm = TrustManagerFactory.getDefaultAlgorithm();
    524             TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
    525             tmf.init((KeyStore) null);
    526             TrustManager[] tms = tmf.getTrustManagers();
    527             X509TrustManager trustManager = findFirstX509TrustManager(tms);
    528             if (trustManager == null) {
    529                 throw new KeyManagementException(
    530                         "No X509TrustManager in among default TrustManagers: "
    531                                 + Arrays.toString(tms));
    532             }
    533             return trustManager;
    534         } catch (NoSuchAlgorithmException e) {
    535             throw new KeyManagementException(e);
    536         } catch (KeyStoreException e) {
    537             throw new KeyManagementException(e);
    538         }
    539     }
    540 
    541     /**
    542      * Finds the first {@link X509TrustManager} element in the provided array.
    543      *
    544      * @return the first {@code X509ExtendedTrustManager} or
    545      *         {@code X509TrustManager} or {@code null} if not found.
    546      */
    547     private static X509TrustManager findFirstX509TrustManager(TrustManager[] tms) {
    548         for (TrustManager tm : tms) {
    549             if (tm instanceof X509TrustManager) {
    550                 return (X509TrustManager) tm;
    551             }
    552         }
    553         return null;
    554     }
    555 
    556     String getEndpointIdentificationAlgorithm() {
    557         return endpointIdentificationAlgorithm;
    558     }
    559 
    560     void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) {
    561         this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
    562     }
    563 
    564     boolean getUseCipherSuitesOrder() {
    565         return useCipherSuitesOrder;
    566     }
    567 
    568     void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) {
    569         this.useCipherSuitesOrder = useCipherSuitesOrder;
    570     }
    571 
    572     private static String[] getDefaultCipherSuites(
    573             boolean x509CipherSuitesNeeded,
    574             boolean pskCipherSuitesNeeded) {
    575         if (x509CipherSuitesNeeded) {
    576             // X.509 based cipher suites need to be listed.
    577             if (pskCipherSuitesNeeded) {
    578                 // Both X.509 and PSK based cipher suites need to be listed. Because TLS-PSK is not
    579                 // normally used, we assume that when PSK cipher suites are requested here they
    580                 // should be preferred over other cipher suites. Thus, we give PSK cipher suites
    581                 // higher priority than X.509 cipher suites.
    582                 // NOTE: There are cipher suites that use both X.509 and PSK (e.g., those based on
    583                 // RSA_PSK key exchange). However, these cipher suites are not currently supported.
    584                 return concat(
    585                         NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
    586                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
    587                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
    588             } else {
    589                 // Only X.509 cipher suites need to be listed.
    590                 return concat(
    591                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
    592                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
    593             }
    594         } else if (pskCipherSuitesNeeded) {
    595             // Only PSK cipher suites need to be listed.
    596             return concat(
    597                     NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
    598                     new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
    599         } else {
    600             // Neither X.509 nor PSK cipher suites need to be listed.
    601             return new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV};
    602         }
    603     }
    604 
    605     private static String[] concat(String[]... arrays) {
    606         int resultLength = 0;
    607         for (String[] array : arrays) {
    608             resultLength += array.length;
    609         }
    610         String[] result = new String[resultLength];
    611         int resultOffset = 0;
    612         for (String[] array : arrays) {
    613             System.arraycopy(array, 0, result, resultOffset, array.length);
    614             resultOffset += array.length;
    615         }
    616         return result;
    617     }
    618 
    619     /**
    620      * Check if SCT verification is enforced for a given hostname.
    621      */
    622     boolean isCTVerificationEnabled(String hostname) {
    623         if (hostname == null) {
    624             return false;
    625         }
    626 
    627         // Bypass the check. This is used for testing only
    628         if (ctVerificationEnabled) {
    629             return true;
    630         }
    631         return Platform.isCTVerificationRequired(hostname);
    632     }
    633 }
    634