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 org.conscrypt.util.EmptyArray;
     21 import java.io.IOException;
     22 import java.io.UnsupportedEncodingException;
     23 import java.security.InvalidKeyException;
     24 import java.security.KeyManagementException;
     25 import java.security.KeyStore;
     26 import java.security.KeyStoreException;
     27 import java.security.NoSuchAlgorithmException;
     28 import java.security.PrivateKey;
     29 import java.security.SecureRandom;
     30 import java.security.UnrecoverableKeyException;
     31 import java.security.cert.CertificateEncodingException;
     32 import java.security.cert.X509Certificate;
     33 import java.util.Arrays;
     34 import java.util.HashSet;
     35 import java.util.Set;
     36 import javax.crypto.SecretKey;
     37 import javax.net.ssl.KeyManager;
     38 import javax.net.ssl.KeyManagerFactory;
     39 import javax.net.ssl.SSLException;
     40 import javax.net.ssl.SSLHandshakeException;
     41 import javax.net.ssl.TrustManager;
     42 import javax.net.ssl.TrustManagerFactory;
     43 import javax.net.ssl.X509ExtendedKeyManager;
     44 import javax.net.ssl.X509KeyManager;
     45 import javax.net.ssl.X509TrustManager;
     46 import javax.security.auth.x500.X500Principal;
     47 
     48 /**
     49  * The instances of this class encapsulate all the info
     50  * about enabled cipher suites and protocols,
     51  * as well as the information about client/server mode of
     52  * ssl socket, whether it require/want client authentication or not,
     53  * and controls whether new SSL sessions may be established by this
     54  * socket or not.
     55  */
     56 public class SSLParametersImpl implements Cloneable {
     57 
     58     // default source of X.509 certificate based authentication keys
     59     private static volatile X509KeyManager defaultX509KeyManager;
     60     // default source of X.509 certificate based authentication trust decisions
     61     private static volatile X509TrustManager defaultX509TrustManager;
     62     // default source of random numbers
     63     private static volatile SecureRandom defaultSecureRandom;
     64     // default SSL parameters
     65     private static volatile SSLParametersImpl defaultParameters;
     66 
     67     // client session context contains the set of reusable
     68     // client-side SSL sessions
     69     private final ClientSessionContext clientSessionContext;
     70     // server session context contains the set of reusable
     71     // server-side SSL sessions
     72     private final ServerSessionContext serverSessionContext;
     73     // source of X.509 certificate based authentication keys or null if not provided
     74     private final X509KeyManager x509KeyManager;
     75     // source of Pre-Shared Key (PSK) authentication keys or null if not provided.
     76     private final PSKKeyManager pskKeyManager;
     77     // source of X.509 certificate based authentication trust decisions or null if not provided
     78     private final X509TrustManager x509TrustManager;
     79     // source of random numbers
     80     private SecureRandom secureRandom;
     81 
     82     // protocols enabled for SSL connection
     83     private String[] enabledProtocols;
     84     // cipher suites enabled for SSL connection
     85     private String[] enabledCipherSuites;
     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     private String endpointIdentificationAlgorithm;
     96 
     97     byte[] npnProtocols;
     98     byte[] alpnProtocols;
     99     boolean useSessionTickets;
    100     private Boolean useSni;
    101 
    102     /**
    103      * Whether the TLS Channel ID extension is enabled. This field is
    104      * server-side only.
    105      */
    106     boolean channelIdEnabled;
    107 
    108     /**
    109      * Initializes the parameters. Naturally this constructor is used
    110      * in SSLContextImpl.engineInit method which directly passes its
    111      * parameters. In other words this constructor holds all
    112      * the functionality provided by SSLContext.init method.
    113      * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[],
    114      * SecureRandom)} for more information
    115      */
    116     protected SSLParametersImpl(KeyManager[] kms, TrustManager[] tms,
    117             SecureRandom sr, ClientSessionContext clientSessionContext,
    118             ServerSessionContext serverSessionContext)
    119             throws KeyManagementException {
    120         this.serverSessionContext = serverSessionContext;
    121         this.clientSessionContext = clientSessionContext;
    122 
    123         // initialize key managers
    124         if (kms == null) {
    125             x509KeyManager = getDefaultX509KeyManager();
    126             // There's no default PSK key manager
    127             pskKeyManager = null;
    128         } else {
    129             x509KeyManager = findFirstX509KeyManager(kms);
    130             pskKeyManager = findFirstPSKKeyManager(kms);
    131         }
    132 
    133         // initialize x509TrustManager
    134         if (tms == null) {
    135             x509TrustManager = getDefaultX509TrustManager();
    136         } else {
    137             x509TrustManager = findFirstX509TrustManager(tms);
    138         }
    139 
    140         // initialize secure random
    141         // We simply use the SecureRandom passed in by the caller. If it's
    142         // null, we don't replace it by a new instance. The native code below
    143         // then directly accesses /dev/urandom. Not the most elegant solution,
    144         // but faster than going through the SecureRandom object.
    145         secureRandom = sr;
    146 
    147         // initialize the list of cipher suites and protocols enabled by default
    148         enabledProtocols = getDefaultProtocols();
    149         boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
    150         boolean pskCipherSuitesNeeded = pskKeyManager != null;
    151         enabledCipherSuites = getDefaultCipherSuites(
    152                 x509CipherSuitesNeeded, pskCipherSuitesNeeded);
    153     }
    154 
    155     protected static SSLParametersImpl getDefault() throws KeyManagementException {
    156         SSLParametersImpl result = defaultParameters;
    157         if (result == null) {
    158             // single-check idiom
    159             defaultParameters = result = new SSLParametersImpl(null,
    160                                                                null,
    161                                                                null,
    162                                                                new ClientSessionContext(),
    163                                                                new ServerSessionContext());
    164         }
    165         return (SSLParametersImpl) result.clone();
    166     }
    167 
    168     /**
    169      * Returns the appropriate session context.
    170      */
    171     public AbstractSessionContext getSessionContext() {
    172         return client_mode ? clientSessionContext : serverSessionContext;
    173     }
    174 
    175     /**
    176      * @return server session context
    177      */
    178     protected ServerSessionContext getServerSessionContext() {
    179         return serverSessionContext;
    180     }
    181 
    182     /**
    183      * @return client session context
    184      */
    185     protected ClientSessionContext getClientSessionContext() {
    186         return clientSessionContext;
    187     }
    188 
    189     /**
    190      * @return X.509 key manager or {@code null} for none.
    191      */
    192     protected X509KeyManager getX509KeyManager() {
    193         return x509KeyManager;
    194     }
    195 
    196     /**
    197      * @return Pre-Shared Key (PSK) key manager or {@code null} for none.
    198      */
    199     protected PSKKeyManager getPSKKeyManager() {
    200         return pskKeyManager;
    201     }
    202 
    203     /**
    204      * @return X.509 trust manager or {@code null} for none.
    205      */
    206     protected X509TrustManager getX509TrustManager() {
    207         return x509TrustManager;
    208     }
    209 
    210     /**
    211      * @return secure random
    212      */
    213     protected SecureRandom getSecureRandom() {
    214         if (secureRandom != null) {
    215             return secureRandom;
    216         }
    217         SecureRandom result = defaultSecureRandom;
    218         if (result == null) {
    219             // single-check idiom
    220             defaultSecureRandom = result = new SecureRandom();
    221         }
    222         secureRandom = result;
    223         return secureRandom;
    224     }
    225 
    226     /**
    227      * @return the secure random member reference, even it is null
    228      */
    229     protected SecureRandom getSecureRandomMember() {
    230         return secureRandom;
    231     }
    232 
    233     /**
    234      * @return the names of enabled cipher suites
    235      */
    236     protected String[] getEnabledCipherSuites() {
    237         return enabledCipherSuites.clone();
    238     }
    239 
    240     /**
    241      * Sets the enabled cipher suites after filtering through OpenSSL.
    242      */
    243     protected void setEnabledCipherSuites(String[] cipherSuites) {
    244         enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(cipherSuites).clone();
    245     }
    246 
    247     /**
    248      * @return the set of enabled protocols
    249      */
    250     protected String[] getEnabledProtocols() {
    251         return enabledProtocols.clone();
    252     }
    253 
    254     /**
    255      * Sets the set of available protocols for use in SSL connection.
    256      * @param protocols String[]
    257      */
    258     protected void setEnabledProtocols(String[] protocols) {
    259         enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols).clone();
    260     }
    261 
    262     /**
    263      * Tunes the peer holding this parameters to work in client mode.
    264      * @param   mode if the peer is configured to work in client mode
    265      */
    266     protected void setUseClientMode(boolean mode) {
    267         client_mode = mode;
    268     }
    269 
    270     /**
    271      * Returns the value indicating if the parameters configured to work
    272      * in client mode.
    273      */
    274     protected boolean getUseClientMode() {
    275         return client_mode;
    276     }
    277 
    278     /**
    279      * Tunes the peer holding this parameters to require client authentication
    280      */
    281     protected void setNeedClientAuth(boolean need) {
    282         need_client_auth = need;
    283         // reset the want_client_auth setting
    284         want_client_auth = false;
    285     }
    286 
    287     /**
    288      * Returns the value indicating if the peer with this parameters tuned
    289      * to require client authentication
    290      */
    291     protected boolean getNeedClientAuth() {
    292         return need_client_auth;
    293     }
    294 
    295     /**
    296      * Tunes the peer holding this parameters to request client authentication
    297      */
    298     protected void setWantClientAuth(boolean want) {
    299         want_client_auth = want;
    300         // reset the need_client_auth setting
    301         need_client_auth = false;
    302     }
    303 
    304     /**
    305      * Returns the value indicating if the peer with this parameters
    306      * tuned to request client authentication
    307      */
    308     protected boolean getWantClientAuth() {
    309         return want_client_auth;
    310     }
    311 
    312     /**
    313      * Allows/disallows the peer holding this parameters to
    314      * create new SSL session
    315      */
    316     protected void setEnableSessionCreation(boolean flag) {
    317         enable_session_creation = flag;
    318     }
    319 
    320     /**
    321      * Returns the value indicating if the peer with this parameters
    322      * allowed to cteate new SSL session
    323      */
    324     protected boolean getEnableSessionCreation() {
    325         return enable_session_creation;
    326     }
    327 
    328     /**
    329      * Whether connections using this SSL connection should use the TLS
    330      * extension Server Name Indication (SNI).
    331      */
    332     protected void setUseSni(boolean flag) {
    333         useSni = Boolean.valueOf(flag);
    334     }
    335 
    336     /**
    337      * Returns whether connections using this SSL connection should use the TLS
    338      * extension Server Name Indication (SNI).
    339      */
    340     protected boolean getUseSni() {
    341         return useSni != null ? useSni.booleanValue() : isSniEnabledByDefault();
    342     }
    343 
    344     static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
    345             throws CertificateEncodingException {
    346         byte[][] principalBytes = new byte[certificates.length][];
    347         for (int i = 0; i < certificates.length; i++) {
    348             principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
    349         }
    350         return principalBytes;
    351     }
    352 
    353     /**
    354      * Return a possibly null array of X509Certificates given the possibly null
    355      * array of DER encoded bytes.
    356      */
    357     private static OpenSSLX509Certificate[] createCertChain(long[] certificateRefs)
    358             throws IOException {
    359         if (certificateRefs == null) {
    360             return null;
    361         }
    362         OpenSSLX509Certificate[] certificates = new OpenSSLX509Certificate[certificateRefs.length];
    363         for (int i = 0; i < certificateRefs.length; i++) {
    364             certificates[i] = new OpenSSLX509Certificate(certificateRefs[i]);
    365         }
    366         return certificates;
    367     }
    368 
    369     OpenSSLSessionImpl getSessionToReuse(long sslNativePointer, String hostname, int port)
    370             throws SSLException {
    371         final OpenSSLSessionImpl sessionToReuse;
    372         if (client_mode) {
    373             // look for client session to reuse
    374             sessionToReuse = getCachedClientSession(clientSessionContext, hostname, port);
    375             if (sessionToReuse != null) {
    376                 NativeCrypto.SSL_set_session(sslNativePointer,
    377                         sessionToReuse.sslSessionNativePointer);
    378             }
    379         } else {
    380             sessionToReuse = null;
    381         }
    382         return sessionToReuse;
    383     }
    384 
    385     void setTlsChannelId(long sslNativePointer, OpenSSLKey channelIdPrivateKey)
    386             throws SSLHandshakeException, SSLException {
    387         // TLS Channel ID
    388         if (channelIdEnabled) {
    389             if (client_mode) {
    390                 // Client-side TLS Channel ID
    391                 if (channelIdPrivateKey == null) {
    392                     throw new SSLHandshakeException("Invalid TLS channel ID key specified");
    393                 }
    394                 NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer,
    395                         channelIdPrivateKey.getPkeyContext());
    396             } else {
    397                 // Server-side TLS Channel ID
    398                 NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
    399             }
    400         }
    401     }
    402 
    403     void setCertificate(long sslNativePointer, String alias) throws CertificateEncodingException,
    404             SSLException {
    405         if (alias == null) {
    406             return;
    407         }
    408         X509KeyManager keyManager = getX509KeyManager();
    409         if (keyManager == null) {
    410             return;
    411         }
    412         PrivateKey privateKey = keyManager.getPrivateKey(alias);
    413         if (privateKey == null) {
    414             return;
    415         }
    416         X509Certificate[] certificates = keyManager.getCertificateChain(alias);
    417         if (certificates == null) {
    418             return;
    419         }
    420 
    421         /*
    422          * Make sure we keep a reference to the OpenSSLX509Certificate by using
    423          * this array. Otherwise, if they're not OpenSSLX509Certificate
    424          * instances originally, they may be garbage collected before we
    425          * complete our JNI calls.
    426          */
    427         OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[certificates.length];
    428         long[] x509refs = new long[certificates.length];
    429         for (int i = 0; i < certificates.length; i++) {
    430             OpenSSLX509Certificate openSslCert = OpenSSLX509Certificate
    431                     .fromCertificate(certificates[i]);
    432             openSslCerts[i] = openSslCert;
    433             x509refs[i] = openSslCert.getContext();
    434         }
    435 
    436         // Note that OpenSSL says to use SSL_use_certificate before
    437         // SSL_use_PrivateKey.
    438         NativeCrypto.SSL_use_certificate(sslNativePointer, x509refs);
    439 
    440         final OpenSSLKey key;
    441         try {
    442             key = OpenSSLKey.fromPrivateKey(privateKey);
    443             NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext());
    444         } catch (InvalidKeyException e) {
    445             throw new SSLException(e);
    446         }
    447 
    448         // We may not have access to all the information to check the private key
    449         // if it's a wrapped platform key, so skip this check.
    450         if (!key.isWrapped()) {
    451             // Makes sure the set PrivateKey and X509Certificate refer to the same
    452             // key by comparing the public values.
    453             NativeCrypto.SSL_check_private_key(sslNativePointer);
    454         }
    455     }
    456 
    457     void setSSLParameters(long sslCtxNativePointer, long sslNativePointer, AliasChooser chooser,
    458             PSKCallbacks pskCallbacks, String sniHostname) throws SSLException, IOException {
    459         if (npnProtocols != null) {
    460             NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
    461         }
    462 
    463         if (client_mode && alpnProtocols != null) {
    464             NativeCrypto.SSL_set_alpn_protos(sslNativePointer, alpnProtocols);
    465         }
    466 
    467         NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
    468         NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
    469 
    470         // setup server certificates and private keys.
    471         // clients will receive a call back to request certificates.
    472         if (!client_mode) {
    473             Set<String> keyTypes = new HashSet<String>();
    474             for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(sslNativePointer)) {
    475                 String keyType = getServerX509KeyType(sslCipherNativePointer);
    476                 if (keyType != null) {
    477                     keyTypes.add(keyType);
    478                 }
    479             }
    480             X509KeyManager keyManager = getX509KeyManager();
    481             if (keyManager != null) {
    482                 for (String keyType : keyTypes) {
    483                     try {
    484                         setCertificate(sslNativePointer,
    485                                 chooser.chooseServerAlias(x509KeyManager, keyType));
    486                     } catch (CertificateEncodingException e) {
    487                         throw new IOException(e);
    488                     }
    489                 }
    490             }
    491         }
    492 
    493         // Enable Pre-Shared Key (PSK) key exchange if requested
    494         PSKKeyManager pskKeyManager = getPSKKeyManager();
    495         if (pskKeyManager != null) {
    496             boolean pskEnabled = false;
    497             for (String enabledCipherSuite : enabledCipherSuites) {
    498                 if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
    499                     pskEnabled = true;
    500                     break;
    501                 }
    502             }
    503             if (pskEnabled) {
    504                 if (client_mode) {
    505                     NativeCrypto.set_SSL_psk_client_callback_enabled(sslNativePointer, true);
    506                 } else {
    507                     NativeCrypto.set_SSL_psk_server_callback_enabled(sslNativePointer, true);
    508                     String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager);
    509                     NativeCrypto.SSL_use_psk_identity_hint(sslNativePointer, identityHint);
    510                 }
    511             }
    512         }
    513 
    514         if (useSessionTickets) {
    515             NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
    516         }
    517         if (getUseSni() && AddressUtils.isValidSniHostname(sniHostname)) {
    518             NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, sniHostname);
    519         }
    520 
    521         // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites
    522         // with TLSv1 and SSLv3).
    523         NativeCrypto.SSL_set_mode(sslNativePointer, NativeCrypto.SSL_MODE_CBC_RECORD_SPLITTING);
    524 
    525         boolean enableSessionCreation = getEnableSessionCreation();
    526         if (!enableSessionCreation) {
    527             NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, enableSessionCreation);
    528         }
    529     }
    530 
    531     /**
    532      * Returns true when the supplied hostname is valid for SNI purposes.
    533      */
    534     private static boolean isValidSniHostname(String sniHostname) {
    535         if (sniHostname == null) {
    536             return false;
    537         }
    538 
    539         // Must be a FQDN.
    540         if (sniHostname.indexOf('.') == -1) {
    541             return false;
    542         }
    543 
    544         if (Platform.isLiteralIpAddress(sniHostname)) {
    545             return false;
    546         }
    547 
    548         return true;
    549     }
    550 
    551     /**
    552      * Returns whether Server Name Indication (SNI) is enabled by default for
    553      * sockets. For more information on SNI, see RFC 6066 section 3.
    554      */
    555     private boolean isSniEnabledByDefault() {
    556         String enableSNI = System.getProperty("jsse.enableSNIExtension",
    557                 Platform.isSniEnabledByDefault() ? "true" : "false");
    558         if ("true".equalsIgnoreCase(enableSNI)) {
    559             return true;
    560         } else if ("false".equalsIgnoreCase(enableSNI)) {
    561             return false;
    562         } else {
    563             throw new RuntimeException(
    564                     "Can only set \"jsse.enableSNIExtension\" to \"true\" or \"false\"");
    565         }
    566     }
    567 
    568     void setCertificateValidation(long sslNativePointer) throws IOException {
    569         // setup peer certificate verification
    570         if (!client_mode) {
    571             // needing client auth takes priority...
    572             boolean certRequested;
    573             if (getNeedClientAuth()) {
    574                 NativeCrypto.SSL_set_verify(sslNativePointer,
    575                                             NativeCrypto.SSL_VERIFY_PEER
    576                                             | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
    577                 certRequested = true;
    578             // ... over just wanting it...
    579             } else if (getWantClientAuth()) {
    580                 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER);
    581                 certRequested = true;
    582             // ... and we must disable verification if we don't want client auth.
    583             } else {
    584                 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_NONE);
    585                 certRequested = false;
    586             }
    587 
    588             if (certRequested) {
    589                 X509TrustManager trustManager = getX509TrustManager();
    590                 X509Certificate[] issuers = trustManager.getAcceptedIssuers();
    591                 if (issuers != null && issuers.length != 0) {
    592                     byte[][] issuersBytes;
    593                     try {
    594                         issuersBytes = encodeIssuerX509Principals(issuers);
    595                     } catch (CertificateEncodingException e) {
    596                         throw new IOException("Problem encoding principals", e);
    597                     }
    598                     NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
    599                 }
    600             }
    601         }
    602     }
    603 
    604     OpenSSLSessionImpl setupSession(long sslSessionNativePointer, long sslNativePointer,
    605             final OpenSSLSessionImpl sessionToReuse, String hostname, int port,
    606             boolean handshakeCompleted) throws IOException {
    607         OpenSSLSessionImpl sslSession = null;
    608         byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
    609         if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
    610             sslSession = sessionToReuse;
    611             sslSession.lastAccessedTime = System.currentTimeMillis();
    612             NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
    613         } else {
    614             if (!getEnableSessionCreation()) {
    615                 // Should have been prevented by
    616                 // NativeCrypto.SSL_set_session_creation_enabled
    617                 throw new IllegalStateException("SSL Session may not be created");
    618             }
    619             X509Certificate[] localCertificates = createCertChain(NativeCrypto
    620                     .SSL_get_certificate(sslNativePointer));
    621             X509Certificate[] peerCertificates = createCertChain(NativeCrypto
    622                     .SSL_get_peer_cert_chain(sslNativePointer));
    623             sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
    624                     peerCertificates, hostname, port, getSessionContext());
    625             // if not, putSession later in handshakeCompleted() callback
    626             if (handshakeCompleted) {
    627                 getSessionContext().putSession(sslSession);
    628             }
    629         }
    630         return sslSession;
    631     }
    632 
    633     void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals,
    634             long sslNativePointer, AliasChooser chooser) throws SSLException,
    635             CertificateEncodingException {
    636         String[] keyTypes = new String[keyTypeBytes.length];
    637         for (int i = 0; i < keyTypeBytes.length; i++) {
    638             keyTypes[i] = getClientKeyType(keyTypeBytes[i]);
    639         }
    640 
    641         X500Principal[] issuers;
    642         if (asn1DerEncodedPrincipals == null) {
    643             issuers = null;
    644         } else {
    645             issuers = new X500Principal[asn1DerEncodedPrincipals.length];
    646             for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
    647                 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
    648             }
    649         }
    650         X509KeyManager keyManager = getX509KeyManager();
    651         String alias = (keyManager != null) ? chooser.chooseClientAlias(keyManager, issuers,
    652                 keyTypes) : null;
    653         setCertificate(sslNativePointer, alias);
    654     }
    655 
    656     /**
    657      * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[])
    658      */
    659     int clientPSKKeyRequested(
    660             String identityHint, byte[] identityBytesOut, byte[] key, PSKCallbacks pskCallbacks) {
    661         PSKKeyManager pskKeyManager = getPSKKeyManager();
    662         if (pskKeyManager == null) {
    663             return 0;
    664         }
    665 
    666         String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint);
    667         // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut
    668         byte[] identityBytes;
    669         if (identity == null) {
    670             identity = "";
    671             identityBytes = EmptyArray.BYTE;
    672         } else if (identity.isEmpty()) {
    673             identityBytes = EmptyArray.BYTE;
    674         } else {
    675             try {
    676                 identityBytes = identity.getBytes("UTF-8");
    677             } catch (UnsupportedEncodingException e) {
    678                 throw new RuntimeException("UTF-8 encoding not supported", e);
    679             }
    680         }
    681         if (identityBytes.length + 1 > identityBytesOut.length) {
    682             // Insufficient space in the output buffer
    683             return 0;
    684         }
    685         if (identityBytes.length > 0) {
    686             System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length);
    687         }
    688         identityBytesOut[identityBytes.length] = 0;
    689 
    690         SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
    691         byte[] secretKeyBytes = secretKey.getEncoded();
    692         if (secretKeyBytes == null) {
    693             return 0;
    694         } else if (secretKeyBytes.length > key.length) {
    695             // Insufficient space in the output buffer
    696             return 0;
    697         }
    698         System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
    699         return secretKeyBytes.length;
    700     }
    701 
    702     /**
    703      * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[])
    704      */
    705     int serverPSKKeyRequested(
    706             String identityHint, String identity, byte[] key, PSKCallbacks pskCallbacks) {
    707         PSKKeyManager pskKeyManager = getPSKKeyManager();
    708         if (pskKeyManager == null) {
    709             return 0;
    710         }
    711         SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
    712         byte[] secretKeyBytes = secretKey.getEncoded();
    713         if (secretKeyBytes == null) {
    714             return 0;
    715         } else if (secretKeyBytes.length > key.length) {
    716             return 0;
    717         }
    718         System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
    719         return secretKeyBytes.length;
    720     }
    721 
    722     /**
    723      * Gets the suitable session reference from the session cache container.
    724      */
    725     OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext, String hostName,
    726             int port) {
    727         if (hostName == null) {
    728             return null;
    729         }
    730         OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
    731         if (session == null) {
    732             return null;
    733         }
    734 
    735         String protocol = session.getProtocol();
    736         boolean protocolFound = false;
    737         for (String enabledProtocol : enabledProtocols) {
    738             if (protocol.equals(enabledProtocol)) {
    739                 protocolFound = true;
    740                 break;
    741             }
    742         }
    743         if (!protocolFound) {
    744             return null;
    745         }
    746 
    747         String cipherSuite = session.getCipherSuite();
    748         boolean cipherSuiteFound = false;
    749         for (String enabledCipherSuite : enabledCipherSuites) {
    750             if (cipherSuite.equals(enabledCipherSuite)) {
    751                 cipherSuiteFound = true;
    752                 break;
    753             }
    754         }
    755         if (!cipherSuiteFound) {
    756             return null;
    757         }
    758 
    759         return session;
    760     }
    761 
    762     /**
    763      * For abstracting the X509KeyManager calls between
    764      * {@link X509KeyManager#chooseClientAlias(String[], java.security.Principal[], java.net.Socket)}
    765      * and
    766      * {@link X509ExtendedKeyManager#chooseEngineClientAlias(String[], java.security.Principal[], javax.net.ssl.SSLEngine)}
    767      */
    768     public interface AliasChooser {
    769         String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
    770                 String[] keyTypes);
    771 
    772         String chooseServerAlias(X509KeyManager keyManager, String keyType);
    773     }
    774 
    775     /**
    776      * For abstracting the {@code PSKKeyManager} calls between those taking an {@code SSLSocket} and
    777      * those taking an {@code SSLEngine}.
    778      */
    779     public interface PSKCallbacks {
    780         String chooseServerPSKIdentityHint(PSKKeyManager keyManager);
    781         String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint);
    782         SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity);
    783     }
    784 
    785     /**
    786      * Returns the clone of this object.
    787      * @return the clone.
    788      */
    789     @Override
    790     protected Object clone() {
    791         try {
    792             return super.clone();
    793         } catch (CloneNotSupportedException e) {
    794             throw new AssertionError(e);
    795         }
    796     }
    797 
    798     private static X509KeyManager getDefaultX509KeyManager() throws KeyManagementException {
    799         X509KeyManager result = defaultX509KeyManager;
    800         if (result == null) {
    801             // single-check idiom
    802             defaultX509KeyManager = result = createDefaultX509KeyManager();
    803         }
    804         return result;
    805     }
    806     private static X509KeyManager createDefaultX509KeyManager() throws KeyManagementException {
    807         try {
    808             String algorithm = KeyManagerFactory.getDefaultAlgorithm();
    809             KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
    810             kmf.init(null, null);
    811             KeyManager[] kms = kmf.getKeyManagers();
    812             X509KeyManager result = findFirstX509KeyManager(kms);
    813             if (result == null) {
    814                 throw new KeyManagementException("No X509KeyManager among default KeyManagers: "
    815                         + Arrays.toString(kms));
    816             }
    817             return result;
    818         } catch (NoSuchAlgorithmException e) {
    819             throw new KeyManagementException(e);
    820         } catch (KeyStoreException e) {
    821             throw new KeyManagementException(e);
    822         } catch (UnrecoverableKeyException e) {
    823             throw new KeyManagementException(e);
    824         }
    825     }
    826 
    827     /**
    828      * Finds the first {@link X509KeyManager} element in the provided array.
    829      *
    830      * @return the first {@code X509KeyManager} or {@code null} if not found.
    831      */
    832     private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) {
    833         for (KeyManager km : kms) {
    834             if (km instanceof X509KeyManager) {
    835                 return (X509KeyManager)km;
    836             }
    837         }
    838         return null;
    839     }
    840 
    841     /**
    842      * Finds the first {@link PSKKeyManager} element in the provided array.
    843      *
    844      * @return the first {@code PSKKeyManager} or {@code null} if not found.
    845      */
    846     private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) {
    847         for (KeyManager km : kms) {
    848             if (km instanceof PSKKeyManager) {
    849                 return (PSKKeyManager)km;
    850             }
    851         }
    852         return null;
    853     }
    854 
    855     /**
    856      * Gets the default X.509 trust manager.
    857      *
    858      * TODO: Move this to a published API under dalvik.system.
    859      */
    860     public static X509TrustManager getDefaultX509TrustManager()
    861             throws KeyManagementException {
    862         X509TrustManager result = defaultX509TrustManager;
    863         if (result == null) {
    864             // single-check idiom
    865             defaultX509TrustManager = result = createDefaultX509TrustManager();
    866         }
    867         return result;
    868     }
    869 
    870     private static X509TrustManager createDefaultX509TrustManager()
    871             throws KeyManagementException {
    872         try {
    873             String algorithm = TrustManagerFactory.getDefaultAlgorithm();
    874             TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
    875             tmf.init((KeyStore) null);
    876             TrustManager[] tms = tmf.getTrustManagers();
    877             X509TrustManager trustManager = findFirstX509TrustManager(tms);
    878             if (trustManager == null) {
    879                 throw new KeyManagementException(
    880                         "No X509TrustManager in among default TrustManagers: "
    881                                 + Arrays.toString(tms));
    882             }
    883             return trustManager;
    884         } catch (NoSuchAlgorithmException e) {
    885             throw new KeyManagementException(e);
    886         } catch (KeyStoreException e) {
    887             throw new KeyManagementException(e);
    888         }
    889     }
    890 
    891     /**
    892      * Finds the first {@link X509TrustManager} element in the provided array.
    893      *
    894      * @return the first {@code X509TrustManager} or {@code null} if not found.
    895      */
    896     private static X509TrustManager findFirstX509TrustManager(TrustManager[] tms) {
    897         for (TrustManager tm : tms) {
    898             if (tm instanceof X509TrustManager) {
    899                 return (X509TrustManager) tm;
    900             }
    901         }
    902         return null;
    903     }
    904 
    905     public String getEndpointIdentificationAlgorithm() {
    906         return endpointIdentificationAlgorithm;
    907     }
    908 
    909     public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) {
    910         this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
    911     }
    912 
    913     /** Key type: RSA. */
    914     private static final String KEY_TYPE_RSA = "RSA";
    915 
    916     /** Key type: DSA. */
    917     private static final String KEY_TYPE_DSA = "DSA";
    918 
    919     /** Key type: Diffie-Hellman with RSA signature. */
    920     private static final String KEY_TYPE_DH_RSA = "DH_RSA";
    921 
    922     /** Key type: Diffie-Hellman with DSA signature. */
    923     private static final String KEY_TYPE_DH_DSA = "DH_DSA";
    924 
    925     /** Key type: Elliptic Curve. */
    926     private static final String KEY_TYPE_EC = "EC";
    927 
    928     /** Key type: Eliiptic Curve with ECDSA signature. */
    929     private static final String KEY_TYPE_EC_EC = "EC_EC";
    930 
    931     /** Key type: Eliiptic Curve with RSA signature. */
    932     private static final String KEY_TYPE_EC_RSA = "EC_RSA";
    933 
    934     /**
    935      * Returns key type constant suitable for calling X509KeyManager.chooseServerAlias or
    936      * X509ExtendedKeyManager.chooseEngineServerAlias. Returns {@code null} for key exchanges that
    937      * do not use X.509 for server authentication.
    938      */
    939     private static String getServerX509KeyType(long sslCipherNative) throws SSLException {
    940         int algorithm_mkey = NativeCrypto.get_SSL_CIPHER_algorithm_mkey(sslCipherNative);
    941         int algorithm_auth = NativeCrypto.get_SSL_CIPHER_algorithm_auth(sslCipherNative);
    942         switch (algorithm_mkey) {
    943             case NativeCrypto.SSL_kRSA:
    944                 return KEY_TYPE_RSA;
    945             case NativeCrypto.SSL_kEDH:
    946                 switch (algorithm_auth) {
    947                     case NativeCrypto.SSL_aDSS:
    948                         return KEY_TYPE_DSA;
    949                     case NativeCrypto.SSL_aRSA:
    950                         return KEY_TYPE_RSA;
    951                     case NativeCrypto.SSL_aNULL:
    952                         return null;
    953                 }
    954                 break;
    955             case NativeCrypto.SSL_kECDHr:
    956                 return KEY_TYPE_EC_RSA;
    957             case NativeCrypto.SSL_kECDHe:
    958                 return KEY_TYPE_EC_EC;
    959             case NativeCrypto.SSL_kEECDH:
    960                 switch (algorithm_auth) {
    961                     case NativeCrypto.SSL_aECDSA:
    962                         return KEY_TYPE_EC_EC;
    963                     case NativeCrypto.SSL_aRSA:
    964                         return KEY_TYPE_RSA;
    965                     case NativeCrypto.SSL_aPSK:
    966                         return null;
    967                     case NativeCrypto.SSL_aNULL:
    968                         return null;
    969                 }
    970                 break;
    971             case NativeCrypto.SSL_kPSK:
    972                 return null;
    973         }
    974 
    975         throw new SSLException("Unsupported key exchange. "
    976                 + "mkey: 0x" + Long.toHexString(algorithm_mkey & 0xffffffffL)
    977                 + ", auth: 0x" + Long.toHexString(algorithm_auth & 0xffffffffL));
    978     }
    979 
    980     /**
    981      * Similar to getServerKeyType, but returns value given TLS
    982      * ClientCertificateType byte values from a CertificateRequest
    983      * message for use with X509KeyManager.chooseClientAlias or
    984      * X509ExtendedKeyManager.chooseEngineClientAlias.
    985      */
    986     public static String getClientKeyType(byte keyType) {
    987         // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
    988         switch (keyType) {
    989             case NativeCrypto.TLS_CT_RSA_SIGN:
    990                 return KEY_TYPE_RSA; // RFC rsa_sign
    991             case NativeCrypto.TLS_CT_DSS_SIGN:
    992                 return KEY_TYPE_DSA; // RFC dss_sign
    993             case NativeCrypto.TLS_CT_RSA_FIXED_DH:
    994                 return KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
    995             case NativeCrypto.TLS_CT_DSS_FIXED_DH:
    996                 return KEY_TYPE_DH_DSA; // RFC dss_fixed_dh
    997             case NativeCrypto.TLS_CT_ECDSA_SIGN:
    998                 return KEY_TYPE_EC; // RFC ecdsa_sign
    999             case NativeCrypto.TLS_CT_RSA_FIXED_ECDH:
   1000                 return KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
   1001             case NativeCrypto.TLS_CT_ECDSA_FIXED_ECDH:
   1002                 return KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
   1003             default:
   1004                 return null;
   1005         }
   1006     }
   1007 
   1008     private static String[] getDefaultCipherSuites(
   1009             boolean x509CipherSuitesNeeded,
   1010             boolean pskCipherSuitesNeeded) {
   1011         if (x509CipherSuitesNeeded) {
   1012             // X.509 based cipher suites need to be listed.
   1013             if (pskCipherSuitesNeeded) {
   1014                 // Both X.509 and PSK based cipher suites need to be listed. Because TLS-PSK is not
   1015                 // normally used, we assume that when PSK cipher suites are requested here they
   1016                 // should be preferred over other cipher suites. Thus, we give PSK cipher suites
   1017                 // higher priority than X.509 cipher suites.
   1018                 // NOTE: There are cipher suites that use both X.509 and PSK (e.g., those based on
   1019                 // RSA_PSK key exchange). However, these cipher suites are not currently supported.
   1020                 return concat(
   1021                         NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
   1022                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
   1023                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
   1024             } else {
   1025                 // Only X.509 cipher suites need to be listed.
   1026                 return concat(
   1027                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
   1028                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
   1029             }
   1030         } else if (pskCipherSuitesNeeded) {
   1031             // Only PSK cipher suites need to be listed.
   1032             return concat(
   1033                     NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
   1034                     new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
   1035         } else {
   1036             // Neither X.509 nor PSK cipher suites need to be listed.
   1037             return new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV};
   1038         }
   1039     }
   1040 
   1041     private static String[] getDefaultProtocols() {
   1042         return NativeCrypto.DEFAULT_PROTOCOLS.clone();
   1043     }
   1044 
   1045     private static String[] concat(String[]... arrays) {
   1046         int resultLength = 0;
   1047         for (String[] array : arrays) {
   1048             resultLength += array.length;
   1049         }
   1050         String[] result = new String[resultLength];
   1051         int resultOffset = 0;
   1052         for (String[] array : arrays) {
   1053             System.arraycopy(array, 0, result, resultOffset, array.length);
   1054             resultOffset += array.length;
   1055         }
   1056         return result;
   1057     }
   1058 }
   1059