• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     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      */
SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, SecureRandom sr, ClientSessionContext clientSessionContext, ServerSessionContext serverSessionContext)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 
getDefault()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      */
getSessionContext()171     public AbstractSessionContext getSessionContext() {
172         return client_mode ? clientSessionContext : serverSessionContext;
173     }
174 
175     /**
176      * @return server session context
177      */
getServerSessionContext()178     protected ServerSessionContext getServerSessionContext() {
179         return serverSessionContext;
180     }
181 
182     /**
183      * @return client session context
184      */
getClientSessionContext()185     protected ClientSessionContext getClientSessionContext() {
186         return clientSessionContext;
187     }
188 
189     /**
190      * @return X.509 key manager or {@code null} for none.
191      */
getX509KeyManager()192     protected X509KeyManager getX509KeyManager() {
193         return x509KeyManager;
194     }
195 
196     /**
197      * @return Pre-Shared Key (PSK) key manager or {@code null} for none.
198      */
getPSKKeyManager()199     protected PSKKeyManager getPSKKeyManager() {
200         return pskKeyManager;
201     }
202 
203     /**
204      * @return X.509 trust manager or {@code null} for none.
205      */
getX509TrustManager()206     protected X509TrustManager getX509TrustManager() {
207         return x509TrustManager;
208     }
209 
210     /**
211      * @return secure random
212      */
getSecureRandom()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      */
getSecureRandomMember()229     protected SecureRandom getSecureRandomMember() {
230         return secureRandom;
231     }
232 
233     /**
234      * @return the names of enabled cipher suites
235      */
getEnabledCipherSuites()236     protected String[] getEnabledCipherSuites() {
237         return enabledCipherSuites.clone();
238     }
239 
240     /**
241      * Sets the enabled cipher suites after filtering through OpenSSL.
242      */
setEnabledCipherSuites(String[] cipherSuites)243     protected void setEnabledCipherSuites(String[] cipherSuites) {
244         enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(cipherSuites).clone();
245     }
246 
247     /**
248      * @return the set of enabled protocols
249      */
getEnabledProtocols()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      */
setEnabledProtocols(String[] protocols)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      */
setUseClientMode(boolean mode)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      */
getUseClientMode()274     protected boolean getUseClientMode() {
275         return client_mode;
276     }
277 
278     /**
279      * Tunes the peer holding this parameters to require client authentication
280      */
setNeedClientAuth(boolean need)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      */
getNeedClientAuth()291     protected boolean getNeedClientAuth() {
292         return need_client_auth;
293     }
294 
295     /**
296      * Tunes the peer holding this parameters to request client authentication
297      */
setWantClientAuth(boolean want)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      */
getWantClientAuth()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      */
setEnableSessionCreation(boolean flag)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      */
getEnableSessionCreation()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      */
setUseSni(boolean flag)332     protected void setUseSni(boolean flag) {
333         useSni = flag;
334     }
335 
336     /**
337      * Returns whether connections using this SSL connection should use the TLS
338      * extension Server Name Indication (SNI).
339      */
getUseSni()340     protected boolean getUseSni() {
341         return useSni;
342     }
343 
encodeIssuerX509Principals(X509Certificate[] certificates)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      */
createCertChain(long[] certificateRefs)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 
getSessionToReuse(long sslNativePointer, String hostname, int port)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 
setTlsChannelId(long sslNativePointer, OpenSSLKey channelIdPrivateKey)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 
setCertificate(long sslNativePointer, String alias)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         try {
441             final OpenSSLKey key = OpenSSLKey.fromPrivateKey(privateKey);
442             NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext());
443         } catch (InvalidKeyException e) {
444             throw new SSLException(e);
445         }
446 
447         // checks the last installed private key and certificate,
448         // so need to do this once per loop iteration
449         NativeCrypto.SSL_check_private_key(sslNativePointer);
450     }
451 
setSSLParameters(long sslCtxNativePointer, long sslNativePointer, AliasChooser chooser, PSKCallbacks pskCallbacks, String hostname)452     void setSSLParameters(long sslCtxNativePointer, long sslNativePointer, AliasChooser chooser,
453             PSKCallbacks pskCallbacks, String hostname) throws SSLException, IOException {
454         if (npnProtocols != null) {
455             NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
456         }
457 
458         if (client_mode && alpnProtocols != null) {
459             NativeCrypto.SSL_set_alpn_protos(sslNativePointer, alpnProtocols);
460         }
461 
462         NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
463         NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
464 
465         // setup server certificates and private keys.
466         // clients will receive a call back to request certificates.
467         if (!client_mode) {
468             Set<String> keyTypes = new HashSet<String>();
469             for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(sslNativePointer)) {
470                 String keyType = getServerX509KeyType(sslCipherNativePointer);
471                 if (keyType != null) {
472                     keyTypes.add(keyType);
473                 }
474             }
475             X509KeyManager keyManager = getX509KeyManager();
476             if (keyManager != null) {
477                 for (String keyType : keyTypes) {
478                     try {
479                         setCertificate(sslNativePointer,
480                                 chooser.chooseServerAlias(x509KeyManager, keyType));
481                     } catch (CertificateEncodingException e) {
482                         throw new IOException(e);
483                     }
484                 }
485             }
486         }
487 
488         // Enable Pre-Shared Key (PSK) key exchange if requested
489         PSKKeyManager pskKeyManager = getPSKKeyManager();
490         if (pskKeyManager != null) {
491             boolean pskEnabled = false;
492             for (String enabledCipherSuite : enabledCipherSuites) {
493                 if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) {
494                     pskEnabled = true;
495                     break;
496                 }
497             }
498             if (pskEnabled) {
499                 if (client_mode) {
500                     NativeCrypto.set_SSL_psk_client_callback_enabled(sslNativePointer, true);
501                 } else {
502                     NativeCrypto.set_SSL_psk_server_callback_enabled(sslNativePointer, true);
503                     String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager);
504                     NativeCrypto.SSL_use_psk_identity_hint(sslNativePointer, identityHint);
505                 }
506             }
507         }
508 
509         if (useSessionTickets) {
510             NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
511         }
512         if (useSni) {
513             NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
514         }
515 
516         // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites
517         // with TLSv1 and SSLv3).
518         NativeCrypto.SSL_set_mode(sslNativePointer, NativeCrypto.SSL_MODE_CBC_RECORD_SPLITTING);
519 
520         boolean enableSessionCreation = getEnableSessionCreation();
521         if (!enableSessionCreation) {
522             NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, enableSessionCreation);
523         }
524     }
525 
setCertificateValidation(long sslNativePointer)526     void setCertificateValidation(long sslNativePointer) throws IOException {
527         // setup peer certificate verification
528         if (!client_mode) {
529             // needing client auth takes priority...
530             boolean certRequested;
531             if (getNeedClientAuth()) {
532                 NativeCrypto.SSL_set_verify(sslNativePointer,
533                                             NativeCrypto.SSL_VERIFY_PEER
534                                             | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
535                 certRequested = true;
536             // ... over just wanting it...
537             } else if (getWantClientAuth()) {
538                 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER);
539                 certRequested = true;
540             // ... and we must disable verification if we don't want client auth.
541             } else {
542                 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_NONE);
543                 certRequested = false;
544             }
545 
546             if (certRequested) {
547                 X509TrustManager trustManager = getX509TrustManager();
548                 X509Certificate[] issuers = trustManager.getAcceptedIssuers();
549                 if (issuers != null && issuers.length != 0) {
550                     byte[][] issuersBytes;
551                     try {
552                         issuersBytes = encodeIssuerX509Principals(issuers);
553                     } catch (CertificateEncodingException e) {
554                         throw new IOException("Problem encoding principals", e);
555                     }
556                     NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
557                 }
558             }
559         }
560     }
561 
setupSession(long sslSessionNativePointer, long sslNativePointer, final OpenSSLSessionImpl sessionToReuse, String hostname, int port, boolean handshakeCompleted)562     OpenSSLSessionImpl setupSession(long sslSessionNativePointer, long sslNativePointer,
563             final OpenSSLSessionImpl sessionToReuse, String hostname, int port,
564             boolean handshakeCompleted) throws IOException {
565         OpenSSLSessionImpl sslSession = null;
566         byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
567         if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
568             sslSession = sessionToReuse;
569             sslSession.lastAccessedTime = System.currentTimeMillis();
570             NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
571         } else {
572             if (!getEnableSessionCreation()) {
573                 // Should have been prevented by
574                 // NativeCrypto.SSL_set_session_creation_enabled
575                 throw new IllegalStateException("SSL Session may not be created");
576             }
577             X509Certificate[] localCertificates = createCertChain(NativeCrypto
578                     .SSL_get_certificate(sslNativePointer));
579             X509Certificate[] peerCertificates = createCertChain(NativeCrypto
580                     .SSL_get_peer_cert_chain(sslNativePointer));
581             sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
582                     peerCertificates, hostname, port, getSessionContext());
583             // if not, putSession later in handshakeCompleted() callback
584             if (handshakeCompleted) {
585                 getSessionContext().putSession(sslSession);
586             }
587         }
588         return sslSession;
589     }
590 
chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals, long sslNativePointer, AliasChooser chooser)591     void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals,
592             long sslNativePointer, AliasChooser chooser) throws SSLException,
593             CertificateEncodingException {
594         String[] keyTypes = new String[keyTypeBytes.length];
595         for (int i = 0; i < keyTypeBytes.length; i++) {
596             keyTypes[i] = getClientKeyType(keyTypeBytes[i]);
597         }
598 
599         X500Principal[] issuers;
600         if (asn1DerEncodedPrincipals == null) {
601             issuers = null;
602         } else {
603             issuers = new X500Principal[asn1DerEncodedPrincipals.length];
604             for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
605                 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
606             }
607         }
608         X509KeyManager keyManager = getX509KeyManager();
609         String alias = (keyManager != null) ? chooser.chooseClientAlias(keyManager, issuers,
610                 keyTypes) : null;
611         setCertificate(sslNativePointer, alias);
612     }
613 
614     /**
615      * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[])
616      */
clientPSKKeyRequested( String identityHint, byte[] identityBytesOut, byte[] key, PSKCallbacks pskCallbacks)617     int clientPSKKeyRequested(
618             String identityHint, byte[] identityBytesOut, byte[] key, PSKCallbacks pskCallbacks) {
619         PSKKeyManager pskKeyManager = getPSKKeyManager();
620         if (pskKeyManager == null) {
621             return 0;
622         }
623 
624         String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint);
625         // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut
626         byte[] identityBytes;
627         if (identity == null) {
628             identity = "";
629             identityBytes = EmptyArray.BYTE;
630         } else if (identity.isEmpty()) {
631             identityBytes = EmptyArray.BYTE;
632         } else {
633             try {
634                 identityBytes = identity.getBytes("UTF-8");
635             } catch (UnsupportedEncodingException e) {
636                 throw new RuntimeException("UTF-8 encoding not supported", e);
637             }
638         }
639         if (identityBytes.length + 1 > identityBytesOut.length) {
640             // Insufficient space in the output buffer
641             return 0;
642         }
643         if (identityBytes.length > 0) {
644             System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length);
645         }
646         identityBytesOut[identityBytes.length] = 0;
647 
648         SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
649         byte[] secretKeyBytes = secretKey.getEncoded();
650         if (secretKeyBytes == null) {
651             return 0;
652         } else if (secretKeyBytes.length > key.length) {
653             // Insufficient space in the output buffer
654             return 0;
655         }
656         System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
657         return secretKeyBytes.length;
658     }
659 
660     /**
661      * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[])
662      */
serverPSKKeyRequested( String identityHint, String identity, byte[] key, PSKCallbacks pskCallbacks)663     int serverPSKKeyRequested(
664             String identityHint, String identity, byte[] key, PSKCallbacks pskCallbacks) {
665         PSKKeyManager pskKeyManager = getPSKKeyManager();
666         if (pskKeyManager == null) {
667             return 0;
668         }
669         SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity);
670         byte[] secretKeyBytes = secretKey.getEncoded();
671         if (secretKeyBytes == null) {
672             return 0;
673         } else if (secretKeyBytes.length > key.length) {
674             return 0;
675         }
676         System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length);
677         return secretKeyBytes.length;
678     }
679 
680     /**
681      * Gets the suitable session reference from the session cache container.
682      */
getCachedClientSession(ClientSessionContext sessionContext, String hostName, int port)683     OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext, String hostName,
684             int port) {
685         if (hostName == null) {
686             return null;
687         }
688         OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
689         if (session == null) {
690             return null;
691         }
692 
693         String protocol = session.getProtocol();
694         boolean protocolFound = false;
695         for (String enabledProtocol : enabledProtocols) {
696             if (protocol.equals(enabledProtocol)) {
697                 protocolFound = true;
698                 break;
699             }
700         }
701         if (!protocolFound) {
702             return null;
703         }
704 
705         String cipherSuite = session.getCipherSuite();
706         boolean cipherSuiteFound = false;
707         for (String enabledCipherSuite : enabledCipherSuites) {
708             if (cipherSuite.equals(enabledCipherSuite)) {
709                 cipherSuiteFound = true;
710                 break;
711             }
712         }
713         if (!cipherSuiteFound) {
714             return null;
715         }
716 
717         return session;
718     }
719 
720     /**
721      * For abstracting the X509KeyManager calls between
722      * {@link X509KeyManager#chooseClientAlias(String[], java.security.Principal[], java.net.Socket)}
723      * and
724      * {@link X509ExtendedKeyManager#chooseEngineClientAlias(String[], java.security.Principal[], javax.net.ssl.SSLEngine)}
725      */
726     public interface AliasChooser {
chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes)727         String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
728                 String[] keyTypes);
729 
chooseServerAlias(X509KeyManager keyManager, String keyType)730         String chooseServerAlias(X509KeyManager keyManager, String keyType);
731     }
732 
733     /**
734      * For abstracting the {@code PSKKeyManager} calls between those taking an {@code SSLSocket} and
735      * those taking an {@code SSLEngine}.
736      */
737     public interface PSKCallbacks {
chooseServerPSKIdentityHint(PSKKeyManager keyManager)738         String chooseServerPSKIdentityHint(PSKKeyManager keyManager);
chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint)739         String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint);
getPSKKey(PSKKeyManager keyManager, String identityHint, String identity)740         SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity);
741     }
742 
743     /**
744      * Returns the clone of this object.
745      * @return the clone.
746      */
747     @Override
clone()748     protected Object clone() {
749         try {
750             return super.clone();
751         } catch (CloneNotSupportedException e) {
752             throw new AssertionError(e);
753         }
754     }
755 
getDefaultX509KeyManager()756     private static X509KeyManager getDefaultX509KeyManager() throws KeyManagementException {
757         X509KeyManager result = defaultX509KeyManager;
758         if (result == null) {
759             // single-check idiom
760             defaultX509KeyManager = result = createDefaultX509KeyManager();
761         }
762         return result;
763     }
createDefaultX509KeyManager()764     private static X509KeyManager createDefaultX509KeyManager() throws KeyManagementException {
765         try {
766             String algorithm = KeyManagerFactory.getDefaultAlgorithm();
767             KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
768             kmf.init(null, null);
769             KeyManager[] kms = kmf.getKeyManagers();
770             X509KeyManager result = findFirstX509KeyManager(kms);
771             if (result == null) {
772                 throw new KeyManagementException("No X509KeyManager among default KeyManagers: "
773                         + Arrays.toString(kms));
774             }
775             return result;
776         } catch (NoSuchAlgorithmException e) {
777             throw new KeyManagementException(e);
778         } catch (KeyStoreException e) {
779             throw new KeyManagementException(e);
780         } catch (UnrecoverableKeyException e) {
781             throw new KeyManagementException(e);
782         }
783     }
784 
785     /**
786      * Finds the first {@link X509KeyManager} element in the provided array.
787      *
788      * @return the first {@code X509KeyManager} or {@code null} if not found.
789      */
findFirstX509KeyManager(KeyManager[] kms)790     private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) {
791         for (KeyManager km : kms) {
792             if (km instanceof X509KeyManager) {
793                 return (X509KeyManager)km;
794             }
795         }
796         return null;
797     }
798 
799     /**
800      * Finds the first {@link PSKKeyManager} element in the provided array.
801      *
802      * @return the first {@code PSKKeyManager} or {@code null} if not found.
803      */
findFirstPSKKeyManager(KeyManager[] kms)804     private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) {
805         for (KeyManager km : kms) {
806             if (km instanceof PSKKeyManager) {
807                 return (PSKKeyManager)km;
808             }
809         }
810         return null;
811     }
812 
813     /**
814      * Gets the default X.509 trust manager.
815      *
816      * TODO: Move this to a published API under dalvik.system.
817      */
getDefaultX509TrustManager()818     public static X509TrustManager getDefaultX509TrustManager()
819             throws KeyManagementException {
820         X509TrustManager result = defaultX509TrustManager;
821         if (result == null) {
822             // single-check idiom
823             defaultX509TrustManager = result = createDefaultX509TrustManager();
824         }
825         return result;
826     }
827 
createDefaultX509TrustManager()828     private static X509TrustManager createDefaultX509TrustManager()
829             throws KeyManagementException {
830         try {
831             String algorithm = TrustManagerFactory.getDefaultAlgorithm();
832             TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
833             tmf.init((KeyStore) null);
834             TrustManager[] tms = tmf.getTrustManagers();
835             X509TrustManager trustManager = findFirstX509TrustManager(tms);
836             if (trustManager == null) {
837                 throw new KeyManagementException(
838                         "No X509TrustManager in among default TrustManagers: "
839                                 + Arrays.toString(tms));
840             }
841             return trustManager;
842         } catch (NoSuchAlgorithmException e) {
843             throw new KeyManagementException(e);
844         } catch (KeyStoreException e) {
845             throw new KeyManagementException(e);
846         }
847     }
848 
849     /**
850      * Finds the first {@link X509TrustManager} element in the provided array.
851      *
852      * @return the first {@code X509TrustManager} or {@code null} if not found.
853      */
findFirstX509TrustManager(TrustManager[] tms)854     private static X509TrustManager findFirstX509TrustManager(TrustManager[] tms) {
855         for (TrustManager tm : tms) {
856             if (tm instanceof X509TrustManager) {
857                 return (X509TrustManager) tm;
858             }
859         }
860         return null;
861     }
862 
getEndpointIdentificationAlgorithm()863     public String getEndpointIdentificationAlgorithm() {
864         return endpointIdentificationAlgorithm;
865     }
866 
setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm)867     public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) {
868         this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
869     }
870 
871     /** Key type: RSA. */
872     private static final String KEY_TYPE_RSA = "RSA";
873 
874     /** Key type: DSA. */
875     private static final String KEY_TYPE_DSA = "DSA";
876 
877     /** Key type: Diffie-Hellman with RSA signature. */
878     private static final String KEY_TYPE_DH_RSA = "DH_RSA";
879 
880     /** Key type: Diffie-Hellman with DSA signature. */
881     private static final String KEY_TYPE_DH_DSA = "DH_DSA";
882 
883     /** Key type: Elliptic Curve. */
884     private static final String KEY_TYPE_EC = "EC";
885 
886     /** Key type: Eliiptic Curve with ECDSA signature. */
887     private static final String KEY_TYPE_EC_EC = "EC_EC";
888 
889     /** Key type: Eliiptic Curve with RSA signature. */
890     private static final String KEY_TYPE_EC_RSA = "EC_RSA";
891 
892     /**
893      * Returns key type constant suitable for calling X509KeyManager.chooseServerAlias or
894      * X509ExtendedKeyManager.chooseEngineServerAlias. Returns {@code null} for key exchanges that
895      * do not use X.509 for server authentication.
896      */
getServerX509KeyType(long sslCipherNative)897     private static String getServerX509KeyType(long sslCipherNative) throws SSLException {
898         int algorithm_mkey = NativeCrypto.get_SSL_CIPHER_algorithm_mkey(sslCipherNative);
899         int algorithm_auth = NativeCrypto.get_SSL_CIPHER_algorithm_auth(sslCipherNative);
900         switch (algorithm_mkey) {
901             case NativeCrypto.SSL_kRSA:
902                 return KEY_TYPE_RSA;
903             case NativeCrypto.SSL_kEDH:
904                 switch (algorithm_auth) {
905                     case NativeCrypto.SSL_aDSS:
906                         return KEY_TYPE_DSA;
907                     case NativeCrypto.SSL_aRSA:
908                         return KEY_TYPE_RSA;
909                     case NativeCrypto.SSL_aNULL:
910                         return null;
911                 }
912                 break;
913             case NativeCrypto.SSL_kECDHr:
914                 return KEY_TYPE_EC_RSA;
915             case NativeCrypto.SSL_kECDHe:
916                 return KEY_TYPE_EC_EC;
917             case NativeCrypto.SSL_kEECDH:
918                 switch (algorithm_auth) {
919                     case NativeCrypto.SSL_aECDSA:
920                         return KEY_TYPE_EC_EC;
921                     case NativeCrypto.SSL_aRSA:
922                         return KEY_TYPE_RSA;
923                     case NativeCrypto.SSL_aPSK:
924                         return null;
925                     case NativeCrypto.SSL_aNULL:
926                         return null;
927                 }
928                 break;
929             case NativeCrypto.SSL_kPSK:
930                 return null;
931         }
932 
933         throw new SSLException("Unsupported key exchange. "
934                 + "mkey: 0x" + Long.toHexString(algorithm_mkey & 0xffffffffL)
935                 + ", auth: 0x" + Long.toHexString(algorithm_auth & 0xffffffffL));
936     }
937 
938     /**
939      * Similar to getServerKeyType, but returns value given TLS
940      * ClientCertificateType byte values from a CertificateRequest
941      * message for use with X509KeyManager.chooseClientAlias or
942      * X509ExtendedKeyManager.chooseEngineClientAlias.
943      */
getClientKeyType(byte keyType)944     public static String getClientKeyType(byte keyType) {
945         // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
946         switch (keyType) {
947             case NativeCrypto.TLS_CT_RSA_SIGN:
948                 return KEY_TYPE_RSA; // RFC rsa_sign
949             case NativeCrypto.TLS_CT_DSS_SIGN:
950                 return KEY_TYPE_DSA; // RFC dss_sign
951             case NativeCrypto.TLS_CT_RSA_FIXED_DH:
952                 return KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
953             case NativeCrypto.TLS_CT_DSS_FIXED_DH:
954                 return KEY_TYPE_DH_DSA; // RFC dss_fixed_dh
955             case NativeCrypto.TLS_CT_ECDSA_SIGN:
956                 return KEY_TYPE_EC; // RFC ecdsa_sign
957             case NativeCrypto.TLS_CT_RSA_FIXED_ECDH:
958                 return KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
959             case NativeCrypto.TLS_CT_ECDSA_FIXED_ECDH:
960                 return KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
961             default:
962                 return null;
963         }
964     }
965 
getDefaultCipherSuites( boolean x509CipherSuitesNeeded, boolean pskCipherSuitesNeeded)966     private static String[] getDefaultCipherSuites(
967             boolean x509CipherSuitesNeeded,
968             boolean pskCipherSuitesNeeded) {
969         if (x509CipherSuitesNeeded) {
970             // X.509 based cipher suites need to be listed.
971             if (pskCipherSuitesNeeded) {
972                 // Both X.509 and PSK based cipher suites need to be listed. Because TLS-PSK is not
973                 // normally used, we assume that when PSK cipher suites are requested here they
974                 // should be preferred over other cipher suites. Thus, we give PSK cipher suites
975                 // higher priority than X.509 cipher suites.
976                 // NOTE: There are cipher suites that use both X.509 and PSK (e.g., those based on
977                 // RSA_PSK key exchange). However, these cipher suites are not currently supported.
978                 return concat(
979                         NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
980                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
981                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
982             } else {
983                 // Only X.509 cipher suites need to be listed.
984                 return concat(
985                         NativeCrypto.DEFAULT_X509_CIPHER_SUITES,
986                         new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
987             }
988         } else if (pskCipherSuitesNeeded) {
989             // Only PSK cipher suites need to be listed.
990             return concat(
991                     NativeCrypto.DEFAULT_PSK_CIPHER_SUITES,
992                     new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV});
993         } else {
994             // Neither X.509 nor PSK cipher suites need to be listed.
995             return new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV};
996         }
997     }
998 
getDefaultProtocols()999     private static String[] getDefaultProtocols() {
1000         return NativeCrypto.DEFAULT_PROTOCOLS.clone();
1001     }
1002 
concat(String[].... arrays)1003     private static String[] concat(String[]... arrays) {
1004         int resultLength = 0;
1005         for (String[] array : arrays) {
1006             resultLength += array.length;
1007         }
1008         String[] result = new String[resultLength];
1009         int resultOffset = 0;
1010         for (String[] array : arrays) {
1011             System.arraycopy(array, 0, result, resultOffset, array.length);
1012             resultOffset += array.length;
1013         }
1014         return result;
1015     }
1016 }
1017