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
18package org.conscrypt;
19
20import org.conscrypt.util.EmptyArray;
21import java.io.IOException;
22import java.io.UnsupportedEncodingException;
23import java.security.InvalidKeyException;
24import java.security.KeyManagementException;
25import java.security.KeyStore;
26import java.security.KeyStoreException;
27import java.security.NoSuchAlgorithmException;
28import java.security.PrivateKey;
29import java.security.SecureRandom;
30import java.security.UnrecoverableKeyException;
31import java.security.cert.CertificateEncodingException;
32import java.security.cert.X509Certificate;
33import java.util.Arrays;
34import java.util.HashSet;
35import java.util.Set;
36import javax.crypto.SecretKey;
37import javax.net.ssl.KeyManager;
38import javax.net.ssl.KeyManagerFactory;
39import javax.net.ssl.SSLException;
40import javax.net.ssl.SSLHandshakeException;
41import javax.net.ssl.TrustManager;
42import javax.net.ssl.TrustManagerFactory;
43import javax.net.ssl.X509ExtendedKeyManager;
44import javax.net.ssl.X509KeyManager;
45import javax.net.ssl.X509TrustManager;
46import 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 */
56public 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