Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.conscrypt;
     18 
     19 import dalvik.system.BlockGuard;
     20 import dalvik.system.CloseGuard;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.net.InetAddress;
     26 import java.net.Socket;
     27 import java.net.SocketException;
     28 import java.security.InvalidKeyException;
     29 import java.security.PrivateKey;
     30 import java.security.SecureRandom;
     31 import java.security.cert.CertificateEncodingException;
     32 import java.security.cert.CertificateException;
     33 import java.security.cert.X509Certificate;
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.HashSet;
     37 import java.util.Set;
     38 import javax.net.ssl.HandshakeCompletedEvent;
     39 import javax.net.ssl.HandshakeCompletedListener;
     40 import javax.net.ssl.SSLException;
     41 import javax.net.ssl.SSLHandshakeException;
     42 import javax.net.ssl.SSLPeerUnverifiedException;
     43 import javax.net.ssl.SSLProtocolException;
     44 import javax.net.ssl.SSLSession;
     45 import javax.net.ssl.X509TrustManager;
     46 import javax.security.auth.x500.X500Principal;
     47 import static libcore.io.OsConstants.*;
     48 import libcore.io.ErrnoException;
     49 import libcore.io.Libcore;
     50 import libcore.io.Streams;
     51 import libcore.io.StructTimeval;
     52 
     53 /**
     54  * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
     55  * <p>
     56  * Extensions to SSLSocket include:
     57  * <ul>
     58  * <li>handshake timeout
     59  * <li>session tickets
     60  * <li>Server Name Indication
     61  * </ul>
     62  */
     63 public class OpenSSLSocketImpl
     64         extends javax.net.ssl.SSLSocket
     65         implements NativeCrypto.SSLHandshakeCallbacks {
     66 
     67     private long sslNativePointer;
     68     private InputStream is;
     69     private OutputStream os;
     70     private final Object handshakeLock = new Object();
     71     private final Object readLock = new Object();
     72     private final Object writeLock = new Object();
     73     private SSLParametersImpl sslParameters;
     74     private byte[] npnProtocols;
     75     private byte[] alpnProtocols;
     76     private String[] enabledProtocols;
     77     private String[] enabledCipherSuites;
     78     private boolean useSessionTickets;
     79     private String hostname;
     80     /** Whether the TLS Channel ID extension is enabled. This field is server-side only. */
     81     private boolean channelIdEnabled;
     82     /** Private key for the TLS Channel ID extension. This field is client-side only. */
     83     private OpenSSLKey channelIdPrivateKey;
     84     private OpenSSLSessionImpl sslSession;
     85     private final Socket socket;
     86     private boolean autoClose;
     87     private boolean handshakeStarted = false;
     88     private final CloseGuard guard = CloseGuard.get();
     89 
     90     /**
     91      * Not set to true until the update from native that tells us the
     92      * full handshake is complete, since SSL_do_handshake can return
     93      * before the handshake is completely done due to
     94      * handshake_cutthrough support.
     95      */
     96     private boolean handshakeCompleted = false;
     97 
     98     private ArrayList<HandshakeCompletedListener> listeners;
     99 
    100     /**
    101      * Local cache of timeout to avoid getsockopt on every read and
    102      * write for non-wrapped sockets. Note that
    103      * OpenSSLSocketImplWrapper overrides setSoTimeout and
    104      * getSoTimeout to delegate to the wrapped socket.
    105      */
    106     private int readTimeoutMilliseconds = 0;
    107     private int writeTimeoutMilliseconds = 0;
    108 
    109     private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
    110     private String wrappedHost;
    111     private int wrappedPort;
    112 
    113     protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
    114         this.socket = this;
    115         init(sslParameters);
    116     }
    117 
    118     protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
    119                                 String[] enabledProtocols,
    120                                 String[] enabledCipherSuites) throws IOException {
    121         this.socket = this;
    122         init(sslParameters, enabledProtocols, enabledCipherSuites);
    123     }
    124 
    125     protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
    126             throws IOException {
    127         super(host, port);
    128         this.socket = this;
    129         init(sslParameters);
    130     }
    131 
    132     protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
    133             throws IOException {
    134         super(address, port);
    135         this.socket = this;
    136         init(sslParameters);
    137     }
    138 
    139 
    140     protected OpenSSLSocketImpl(String host, int port,
    141                                 InetAddress clientAddress, int clientPort,
    142                                 SSLParametersImpl sslParameters) throws IOException {
    143         super(host, port, clientAddress, clientPort);
    144         this.socket = this;
    145         init(sslParameters);
    146     }
    147 
    148     protected OpenSSLSocketImpl(InetAddress address, int port,
    149                                 InetAddress clientAddress, int clientPort,
    150                                 SSLParametersImpl sslParameters) throws IOException {
    151         super(address, port, clientAddress, clientPort);
    152         this.socket = this;
    153         init(sslParameters);
    154     }
    155 
    156     /**
    157      * Create an SSL socket that wraps another socket. Invoked by
    158      * OpenSSLSocketImplWrapper constructor.
    159      */
    160     protected OpenSSLSocketImpl(Socket socket, String host, int port,
    161             boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
    162         this.socket = socket;
    163         this.wrappedHost = host;
    164         this.wrappedPort = port;
    165         this.autoClose = autoClose;
    166         init(sslParameters);
    167 
    168         // this.timeout is not set intentionally.
    169         // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
    170         // to wrapped socket
    171     }
    172 
    173     /**
    174      * Initialize the SSL socket and set the certificates for the
    175      * future handshaking.
    176      */
    177     private void init(SSLParametersImpl sslParameters) throws IOException {
    178         init(sslParameters,
    179              NativeCrypto.getDefaultProtocols(),
    180              NativeCrypto.getDefaultCipherSuites());
    181     }
    182 
    183     /**
    184      * Initialize the SSL socket and set the certificates for the
    185      * future handshaking.
    186      */
    187     private void init(SSLParametersImpl sslParameters,
    188                       String[] enabledProtocols,
    189                       String[] enabledCipherSuites) throws IOException {
    190         this.sslParameters = sslParameters;
    191         this.enabledProtocols = enabledProtocols;
    192         this.enabledCipherSuites = enabledCipherSuites;
    193     }
    194 
    195     /**
    196      * Gets the suitable session reference from the session cache container.
    197      */
    198     private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
    199         String hostName = getPeerHostName();
    200         int port = getPeerPort();
    201         if (hostName == null) {
    202             return null;
    203         }
    204         OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
    205         if (session == null) {
    206             return null;
    207         }
    208 
    209         String protocol = session.getProtocol();
    210         boolean protocolFound = false;
    211         for (String enabledProtocol : enabledProtocols) {
    212             if (protocol.equals(enabledProtocol)) {
    213                 protocolFound = true;
    214                 break;
    215             }
    216         }
    217         if (!protocolFound) {
    218             return null;
    219         }
    220 
    221         String cipherSuite = session.getCipherSuite();
    222         boolean cipherSuiteFound = false;
    223         for (String enabledCipherSuite : enabledCipherSuites) {
    224             if (cipherSuite.equals(enabledCipherSuite)) {
    225                 cipherSuiteFound = true;
    226                 break;
    227             }
    228         }
    229         if (!cipherSuiteFound) {
    230             return null;
    231         }
    232 
    233         return session;
    234     }
    235 
    236     private void checkOpen() throws SocketException {
    237         if (isClosed()) {
    238             throw new SocketException("Socket is closed");
    239         }
    240     }
    241 
    242     /**
    243      * Starts a TLS/SSL handshake on this connection using some native methods
    244      * from the OpenSSL library. It can negotiate new encryption keys, change
    245      * cipher suites, or initiate a new session. The certificate chain is
    246      * verified if the correspondent property in java.Security is set. All
    247      * listeners are notified at the end of the TLS/SSL handshake.
    248      */
    249     @Override public synchronized void startHandshake() throws IOException {
    250         synchronized (handshakeLock) {
    251             checkOpen();
    252             if (!handshakeStarted) {
    253                 handshakeStarted = true;
    254             } else {
    255                 return;
    256             }
    257         }
    258 
    259         // note that this modifies the global seed, not something specific to the connection
    260         final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
    261         final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
    262         if (secureRandom == null) {
    263             NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
    264         } else {
    265             NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
    266         }
    267 
    268         final boolean client = sslParameters.getUseClientMode();
    269 
    270         final long sslCtxNativePointer = (client) ?
    271             sslParameters.getClientSessionContext().sslCtxNativePointer :
    272             sslParameters.getServerSessionContext().sslCtxNativePointer;
    273 
    274         this.sslNativePointer = 0;
    275         boolean exception = true;
    276         try {
    277             sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
    278             guard.open("close");
    279 
    280             if (npnProtocols != null) {
    281                 NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
    282             }
    283 
    284             if (client && alpnProtocols != null) {
    285                 NativeCrypto.SSL_CTX_set_alpn_protos(sslCtxNativePointer, alpnProtocols);
    286             }
    287 
    288             // setup server certificates and private keys.
    289             // clients will receive a call back to request certificates.
    290             if (!client) {
    291                 Set<String> keyTypes = new HashSet<String>();
    292                 for (String enabledCipherSuite : enabledCipherSuites) {
    293                     if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
    294                         continue;
    295                     }
    296                     String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
    297                     if (keyType != null) {
    298                         keyTypes.add(keyType);
    299                     }
    300                 }
    301                 for (String keyType : keyTypes) {
    302                     try {
    303                         setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
    304                                                                                        null,
    305                                                                                        this));
    306                     } catch (CertificateEncodingException e) {
    307                         throw new IOException(e);
    308                     }
    309                 }
    310             }
    311 
    312             NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
    313             NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
    314             if (useSessionTickets) {
    315                 NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
    316             }
    317             if (hostname != null) {
    318                 NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
    319             }
    320 
    321             boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
    322             if (!enableSessionCreation) {
    323                 NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
    324                                                               enableSessionCreation);
    325             }
    326 
    327             AbstractSessionContext sessionContext;
    328             OpenSSLSessionImpl sessionToReuse;
    329             if (client) {
    330                 // look for client session to reuse
    331                 ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
    332                 sessionContext = clientSessionContext;
    333                 sessionToReuse = getCachedClientSession(clientSessionContext);
    334                 if (sessionToReuse != null) {
    335                     NativeCrypto.SSL_set_session(sslNativePointer,
    336                                                  sessionToReuse.sslSessionNativePointer);
    337                 }
    338             } else {
    339                 sessionContext = sslParameters.getServerSessionContext();
    340                 sessionToReuse = null;
    341             }
    342 
    343             // setup peer certificate verification
    344             if (client) {
    345                 // TODO support for anonymous cipher would require us to
    346                 // conditionally use SSL_VERIFY_NONE
    347             } else {
    348                 // needing client auth takes priority...
    349                 boolean certRequested;
    350                 if (sslParameters.getNeedClientAuth()) {
    351                     NativeCrypto.SSL_set_verify(sslNativePointer,
    352                                                 NativeCrypto.SSL_VERIFY_PEER
    353                                                 | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
    354                     certRequested = true;
    355                 // ... over just wanting it...
    356                 } else if (sslParameters.getWantClientAuth()) {
    357                     NativeCrypto.SSL_set_verify(sslNativePointer,
    358                                                 NativeCrypto.SSL_VERIFY_PEER);
    359                     certRequested = true;
    360                 // ... and it defaults properly so don't call SSL_set_verify in the common case.
    361                 } else {
    362                     certRequested = false;
    363                 }
    364 
    365                 if (certRequested) {
    366                     X509TrustManager trustManager = sslParameters.getTrustManager();
    367                     X509Certificate[] issuers = trustManager.getAcceptedIssuers();
    368                     if (issuers != null && issuers.length != 0) {
    369                         byte[][] issuersBytes;
    370                         try {
    371                             issuersBytes = encodeIssuerX509Principals(issuers);
    372                         } catch (CertificateEncodingException e) {
    373                             throw new IOException("Problem encoding principals", e);
    374                         }
    375                         NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
    376                     }
    377                 }
    378             }
    379 
    380             // Temporarily use a different timeout for the handshake process
    381             int savedReadTimeoutMilliseconds = getSoTimeout();
    382             int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
    383             if (handshakeTimeoutMilliseconds >= 0) {
    384                 setSoTimeout(handshakeTimeoutMilliseconds);
    385                 setSoWriteTimeout(handshakeTimeoutMilliseconds);
    386             }
    387 
    388             // TLS Channel ID
    389             if (channelIdEnabled) {
    390                 if (client) {
    391                     // Client-side TLS Channel ID
    392                     if (channelIdPrivateKey == null) {
    393                         throw new SSLHandshakeException("Invalid TLS channel ID key specified");
    394                     }
    395                     NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer,
    396                             channelIdPrivateKey.getPkeyContext());
    397                 } else {
    398                     // Server-side TLS Channel ID
    399                     NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
    400                 }
    401             }
    402 
    403             int sslSessionNativePointer;
    404             try {
    405                 sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
    406                         socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols,
    407                         client ? null : alpnProtocols);
    408             } catch (CertificateException e) {
    409                 SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
    410                 wrapper.initCause(e);
    411                 throw wrapper;
    412             }
    413             byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
    414             if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
    415                 this.sslSession = sessionToReuse;
    416                 sslSession.lastAccessedTime = System.currentTimeMillis();
    417                 NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
    418             } else {
    419                 if (!enableSessionCreation) {
    420                     // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
    421                     throw new IllegalStateException("SSL Session may not be created");
    422                 }
    423                 X509Certificate[] localCertificates
    424                         = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
    425                 X509Certificate[] peerCertificates
    426                         = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
    427                 this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
    428                         peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
    429                 // if not, putSession later in handshakeCompleted() callback
    430                 if (handshakeCompleted) {
    431                     sessionContext.putSession(sslSession);
    432                 }
    433             }
    434 
    435             // Restore the original timeout now that the handshake is complete
    436             if (handshakeTimeoutMilliseconds >= 0) {
    437                 setSoTimeout(savedReadTimeoutMilliseconds);
    438                 setSoWriteTimeout(savedWriteTimeoutMilliseconds);
    439             }
    440 
    441             // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
    442             if (handshakeCompleted) {
    443                 notifyHandshakeCompletedListeners();
    444             }
    445 
    446             exception = false;
    447         } catch (SSLProtocolException e) {
    448             throw new SSLHandshakeException(e);
    449         } finally {
    450             // on exceptional exit, treat the socket as closed
    451             if (exception) {
    452                 close();
    453             }
    454         }
    455     }
    456 
    457     private static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
    458             throws CertificateEncodingException {
    459         byte[][] principalBytes = new byte[certificates.length][];
    460         for (int i = 0; i < certificates.length; i++) {
    461             principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
    462         }
    463         return principalBytes;
    464     }
    465 
    466     String getPeerHostName() {
    467         if (wrappedHost != null) {
    468             return wrappedHost;
    469         }
    470         InetAddress inetAddress = super.getInetAddress();
    471         if (inetAddress != null) {
    472             return inetAddress.getHostName();
    473         }
    474         return null;
    475     }
    476 
    477     int getPeerPort() {
    478         return wrappedHost == null ? super.getPort() : wrappedPort;
    479     }
    480 
    481     /**
    482      * Return a possibly null array of X509Certificates given the
    483      * possibly null array of DER encoded bytes.
    484      */
    485     private static X509Certificate[] createCertChain(byte[][] certificatesBytes) throws IOException {
    486         if (certificatesBytes == null) {
    487             return null;
    488         }
    489         X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
    490         for (int i = 0; i < certificatesBytes.length; i++) {
    491             certificates[i] = OpenSSLX509Certificate.fromX509Der(certificatesBytes[i]);
    492         }
    493         return certificates;
    494     }
    495 
    496     private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
    497         if (alias == null) {
    498             return;
    499         }
    500         PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
    501         if (privateKey == null) {
    502             return;
    503         }
    504         X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
    505         if (certificates == null) {
    506             return;
    507         }
    508 
    509         // Note that OpenSSL says to use SSL_use_certificate before SSL_use_PrivateKey.
    510 
    511         byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
    512         NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
    513 
    514         try {
    515             final OpenSSLKey key = OpenSSLKey.fromPrivateKey(privateKey);
    516             NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext());
    517         } catch (InvalidKeyException e) {
    518             throw new SSLException(e);
    519         }
    520 
    521         // checks the last installed private key and certificate,
    522         // so need to do this once per loop iteration
    523         NativeCrypto.SSL_check_private_key(sslNativePointer);
    524     }
    525 
    526     @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
    527     public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
    528             throws CertificateEncodingException, SSLException {
    529 
    530         String[] keyTypes = new String[keyTypeBytes.length];
    531         for (int i = 0; i < keyTypeBytes.length; i++) {
    532             keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
    533         }
    534 
    535         X500Principal[] issuers;
    536         if (asn1DerEncodedPrincipals == null) {
    537             issuers = null;
    538         } else {
    539             issuers = new X500Principal[asn1DerEncodedPrincipals.length];
    540             for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
    541                 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
    542             }
    543         }
    544         setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
    545     }
    546 
    547     @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
    548     public void handshakeCompleted() {
    549         handshakeCompleted = true;
    550 
    551         // If sslSession is null, the handshake was completed during
    552         // the call to NativeCrypto.SSL_do_handshake and not during a
    553         // later read operation. That means we do not need to fix up
    554         // the SSLSession and session cache or notify
    555         // HandshakeCompletedListeners, it will be done in
    556         // startHandshake.
    557         if (sslSession == null) {
    558             return;
    559         }
    560 
    561         // reset session id from the native pointer and update the
    562         // appropriate cache.
    563         sslSession.resetId();
    564         AbstractSessionContext sessionContext =
    565             (sslParameters.getUseClientMode())
    566             ? sslParameters.getClientSessionContext()
    567                 : sslParameters.getServerSessionContext();
    568         sessionContext.putSession(sslSession);
    569 
    570         // let listeners know we are finally done
    571         notifyHandshakeCompletedListeners();
    572     }
    573 
    574     private void notifyHandshakeCompletedListeners() {
    575         if (listeners != null && !listeners.isEmpty()) {
    576             // notify the listeners
    577             HandshakeCompletedEvent event =
    578                 new HandshakeCompletedEvent(this, sslSession);
    579             for (HandshakeCompletedListener listener : listeners) {
    580                 try {
    581                     listener.handshakeCompleted(event);
    582                 } catch (RuntimeException e) {
    583                     // The RI runs the handlers in a separate thread,
    584                     // which we do not. But we try to preserve their
    585                     // behavior of logging a problem and not killing
    586                     // the handshaking thread just because a listener
    587                     // has a problem.
    588                     Thread thread = Thread.currentThread();
    589                     thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
    590                 }
    591             }
    592         }
    593     }
    594 
    595     @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
    596     @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
    597             throws CertificateException {
    598         try {
    599             if (bytes == null || bytes.length == 0) {
    600                 throw new SSLException("Peer sent no certificate");
    601             }
    602             X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
    603             for (int i = 0; i < bytes.length; i++) {
    604                 peerCertificateChain[i] = OpenSSLX509Certificate.fromX509Der(bytes[i]);
    605             }
    606             boolean client = sslParameters.getUseClientMode();
    607             if (client) {
    608                 X509TrustManager x509tm = sslParameters.getTrustManager();
    609                 if (x509tm instanceof TrustManagerImpl) {
    610                     TrustManagerImpl tm = (TrustManagerImpl) x509tm;
    611                     tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
    612                 } else {
    613                     x509tm.checkServerTrusted(peerCertificateChain, authMethod);
    614                 }
    615             } else {
    616                 String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
    617                 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
    618                                                                    authType);
    619             }
    620 
    621         } catch (CertificateException e) {
    622             throw e;
    623         } catch (Exception e) {
    624             throw new CertificateException(e);
    625         }
    626     }
    627 
    628     @Override public InputStream getInputStream() throws IOException {
    629         checkOpen();
    630         synchronized (this) {
    631             if (is == null) {
    632                 is = new SSLInputStream();
    633             }
    634 
    635             return is;
    636         }
    637     }
    638 
    639     @Override public OutputStream getOutputStream() throws IOException {
    640         checkOpen();
    641         synchronized (this) {
    642             if (os == null) {
    643                 os = new SSLOutputStream();
    644             }
    645 
    646             return os;
    647         }
    648     }
    649 
    650     /**
    651      * This inner class provides input data stream functionality
    652      * for the OpenSSL native implementation. It is used to
    653      * read data received via SSL protocol.
    654      */
    655     private class SSLInputStream extends InputStream {
    656         SSLInputStream() throws IOException {
    657             /*
    658              * Note: When startHandshake() throws an exception, no
    659              * SSLInputStream object will be created.
    660              */
    661             OpenSSLSocketImpl.this.startHandshake();
    662         }
    663 
    664         /**
    665          * Reads one byte. If there is no data in the underlying buffer,
    666          * this operation can block until the data will be
    667          * available.
    668          * @return read value.
    669          * @throws <code>IOException</code>
    670          */
    671         @Override
    672         public int read() throws IOException {
    673             return Streams.readSingleByte(this);
    674         }
    675 
    676         /**
    677          * Method acts as described in spec for superclass.
    678          * @see java.io.InputStream#read(byte[],int,int)
    679          */
    680         @Override
    681         public int read(byte[] buf, int offset, int byteCount) throws IOException {
    682             BlockGuard.getThreadPolicy().onNetwork();
    683             synchronized (readLock) {
    684                 checkOpen();
    685                 Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    686                 if (byteCount == 0) {
    687                     return 0;
    688                 }
    689                 return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
    690                         OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
    691             }
    692         }
    693     }
    694 
    695     /**
    696      * This inner class provides output data stream functionality
    697      * for the OpenSSL native implementation. It is used to
    698      * write data according to the encryption parameters given in SSL context.
    699      */
    700     private class SSLOutputStream extends OutputStream {
    701         SSLOutputStream() throws IOException {
    702             /*
    703              * Note: When startHandshake() throws an exception, no
    704              * SSLOutputStream object will be created.
    705              */
    706             OpenSSLSocketImpl.this.startHandshake();
    707         }
    708 
    709         /**
    710          * Method acts as described in spec for superclass.
    711          * @see java.io.OutputStream#write(int)
    712          */
    713         @Override
    714         public void write(int oneByte) throws IOException {
    715             Streams.writeSingleByte(this, oneByte);
    716         }
    717 
    718         /**
    719          * Method acts as described in spec for superclass.
    720          * @see java.io.OutputStream#write(byte[],int,int)
    721          */
    722         @Override
    723         public void write(byte[] buf, int offset, int byteCount) throws IOException {
    724             BlockGuard.getThreadPolicy().onNetwork();
    725             synchronized (writeLock) {
    726                 checkOpen();
    727                 Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    728                 if (byteCount == 0) {
    729                     return;
    730                 }
    731                 NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
    732                         OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
    733             }
    734         }
    735     }
    736 
    737 
    738     @Override public SSLSession getSession() {
    739         if (sslSession == null) {
    740             try {
    741                 startHandshake();
    742             } catch (IOException e) {
    743                 // return an invalid session with
    744                 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
    745                 return SSLSessionImpl.getNullSession();
    746             }
    747         }
    748         return sslSession;
    749     }
    750 
    751     @Override public void addHandshakeCompletedListener(
    752             HandshakeCompletedListener listener) {
    753         if (listener == null) {
    754             throw new IllegalArgumentException("Provided listener is null");
    755         }
    756         if (listeners == null) {
    757             listeners = new ArrayList<HandshakeCompletedListener>();
    758         }
    759         listeners.add(listener);
    760     }
    761 
    762     @Override public void removeHandshakeCompletedListener(
    763             HandshakeCompletedListener listener) {
    764         if (listener == null) {
    765             throw new IllegalArgumentException("Provided listener is null");
    766         }
    767         if (listeners == null) {
    768             throw new IllegalArgumentException(
    769                     "Provided listener is not registered");
    770         }
    771         if (!listeners.remove(listener)) {
    772             throw new IllegalArgumentException(
    773                     "Provided listener is not registered");
    774         }
    775     }
    776 
    777     @Override public boolean getEnableSessionCreation() {
    778         return sslParameters.getEnableSessionCreation();
    779     }
    780 
    781     @Override public void setEnableSessionCreation(boolean flag) {
    782         sslParameters.setEnableSessionCreation(flag);
    783     }
    784 
    785     @Override public String[] getSupportedCipherSuites() {
    786         return NativeCrypto.getSupportedCipherSuites();
    787     }
    788 
    789     @Override public String[] getEnabledCipherSuites() {
    790         return enabledCipherSuites.clone();
    791     }
    792 
    793     @Override public void setEnabledCipherSuites(String[] suites) {
    794         enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
    795     }
    796 
    797     @Override public String[] getSupportedProtocols() {
    798         return NativeCrypto.getSupportedProtocols();
    799     }
    800 
    801     @Override public String[] getEnabledProtocols() {
    802         return enabledProtocols.clone();
    803     }
    804 
    805     @Override public void setEnabledProtocols(String[] protocols) {
    806         enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
    807     }
    808 
    809     /**
    810      * This method enables session ticket support.
    811      *
    812      * @param useSessionTickets True to enable session tickets
    813      */
    814     public void setUseSessionTickets(boolean useSessionTickets) {
    815         this.useSessionTickets = useSessionTickets;
    816     }
    817 
    818     /**
    819      * This method enables Server Name Indication
    820      *
    821      * @param hostname the desired SNI hostname, or null to disable
    822      */
    823     public void setHostname(String hostname) {
    824         this.hostname = hostname;
    825     }
    826 
    827     /**
    828      * Enables/disables TLS Channel ID for this server socket.
    829      *
    830      * <p>This method needs to be invoked before the handshake starts.
    831      *
    832      * @throws IllegalStateException if this is a client socket or if the handshake has already
    833      *         started.
    834 
    835      */
    836     public void setChannelIdEnabled(boolean enabled) {
    837         if (getUseClientMode()) {
    838             throw new IllegalStateException("Client mode");
    839         }
    840         if (handshakeStarted) {
    841             throw new IllegalStateException(
    842                     "Could not enable/disable Channel ID after the initial handshake has"
    843                     + " begun.");
    844         }
    845         this.channelIdEnabled = enabled;
    846     }
    847 
    848     /**
    849      * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
    850      * handshake completes.
    851      *
    852      * @return channel ID or {@code null} if not available.
    853      *
    854      * @throws IllegalStateException if this is a client socket or if the handshake has not yet
    855      *         completed.
    856      * @throws SSLException if channel ID is available but could not be obtained.
    857      */
    858     public byte[] getChannelId() throws SSLException {
    859         if (getUseClientMode()) {
    860             throw new IllegalStateException("Client mode");
    861         }
    862         if (!handshakeCompleted) {
    863             throw new IllegalStateException(
    864                     "Channel ID is only available after handshake completes");
    865         }
    866         return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
    867     }
    868 
    869     /**
    870      * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
    871      *
    872      * <p>This method needs to be invoked before the handshake starts.
    873      *
    874      * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
    875      *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
    876      *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
    877      *
    878      * @throws IllegalStateException if this is a server socket or if the handshake has already
    879      *         started.
    880      */
    881     public void setChannelIdPrivateKey(PrivateKey privateKey) {
    882         if (!getUseClientMode()) {
    883             throw new IllegalStateException("Server mode");
    884         }
    885         if (handshakeStarted) {
    886             throw new IllegalStateException(
    887                     "Could not change Channel ID private key after the initial handshake has"
    888                     + " begun.");
    889         }
    890         if (privateKey == null) {
    891             this.channelIdEnabled = false;
    892             this.channelIdPrivateKey = null;
    893         } else {
    894             this.channelIdEnabled = true;
    895             try {
    896                 this.channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
    897             } catch (InvalidKeyException e) {
    898                 // Will have error in startHandshake
    899             }
    900         }
    901     }
    902 
    903     @Override public boolean getUseClientMode() {
    904         return sslParameters.getUseClientMode();
    905     }
    906 
    907     @Override public void setUseClientMode(boolean mode) {
    908         if (handshakeStarted) {
    909             throw new IllegalArgumentException(
    910                     "Could not change the mode after the initial handshake has begun.");
    911         }
    912         sslParameters.setUseClientMode(mode);
    913     }
    914 
    915     @Override public boolean getWantClientAuth() {
    916         return sslParameters.getWantClientAuth();
    917     }
    918 
    919     @Override public boolean getNeedClientAuth() {
    920         return sslParameters.getNeedClientAuth();
    921     }
    922 
    923     @Override public void setNeedClientAuth(boolean need) {
    924         sslParameters.setNeedClientAuth(need);
    925     }
    926 
    927     @Override public void setWantClientAuth(boolean want) {
    928         sslParameters.setWantClientAuth(want);
    929     }
    930 
    931     @Override public void sendUrgentData(int data) throws IOException {
    932         throw new SocketException("Method sendUrgentData() is not supported.");
    933     }
    934 
    935     @Override public void setOOBInline(boolean on) throws SocketException {
    936         throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
    937     }
    938 
    939     @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
    940         super.setSoTimeout(readTimeoutMilliseconds);
    941         this.readTimeoutMilliseconds = readTimeoutMilliseconds;
    942     }
    943 
    944     @Override public int getSoTimeout() throws SocketException {
    945         return readTimeoutMilliseconds;
    946     }
    947 
    948     /**
    949      * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
    950      */
    951     public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
    952         this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
    953 
    954         StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
    955         try {
    956             Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
    957         } catch (ErrnoException errnoException) {
    958             throw errnoException.rethrowAsSocketException();
    959         }
    960     }
    961 
    962     /**
    963      * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
    964      */
    965     public int getSoWriteTimeout() throws SocketException {
    966         return writeTimeoutMilliseconds;
    967     }
    968 
    969     /**
    970      * Set the handshake timeout on this socket.  This timeout is specified in
    971      * milliseconds and will be used only during the handshake process.
    972      */
    973     public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
    974         this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
    975     }
    976 
    977     @Override public void close() throws IOException {
    978         // TODO: Close SSL sockets using a background thread so they close gracefully.
    979 
    980         synchronized (handshakeLock) {
    981             if (!handshakeStarted) {
    982                 // prevent further attempts to start handshake
    983                 handshakeStarted = true;
    984 
    985                 synchronized (this) {
    986                     free();
    987 
    988                     if (socket != this) {
    989                         if (autoClose && !socket.isClosed()) socket.close();
    990                     } else {
    991                         if (!super.isClosed()) super.close();
    992                     }
    993                 }
    994 
    995                 return;
    996             }
    997         }
    998 
    999         synchronized (this) {
   1000 
   1001             // Interrupt any outstanding reads or writes before taking the writeLock and readLock
   1002             NativeCrypto.SSL_interrupt(sslNativePointer);
   1003 
   1004             synchronized (writeLock) {
   1005                 synchronized (readLock) {
   1006                     // Shut down the SSL connection, per se.
   1007                     try {
   1008                         if (handshakeStarted) {
   1009                             BlockGuard.getThreadPolicy().onNetwork();
   1010                             NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
   1011                                     this);
   1012                         }
   1013                     } catch (IOException ignored) {
   1014                         /*
   1015                          * Note that although close() can throw
   1016                          * IOException, the RI does not throw if there
   1017                          * is problem sending a "close notify" which
   1018                          * can happen if the underlying socket is closed.
   1019                          */
   1020                     } finally {
   1021                         /*
   1022                          * Even if the above call failed, it is still safe to free
   1023                          * the native structs, and we need to do so lest we leak
   1024                          * memory.
   1025                          */
   1026                         free();
   1027 
   1028                         if (socket != this) {
   1029                             if (autoClose && !socket.isClosed()) {
   1030                                 socket.close();
   1031                             }
   1032                         } else {
   1033                             if (!super.isClosed()) {
   1034                                 super.close();
   1035                             }
   1036                         }
   1037                     }
   1038                 }
   1039             }
   1040         }
   1041     }
   1042 
   1043     private void free() {
   1044         if (sslNativePointer == 0) {
   1045             return;
   1046         }
   1047         NativeCrypto.SSL_free(sslNativePointer);
   1048         sslNativePointer = 0;
   1049         guard.close();
   1050     }
   1051 
   1052     @Override protected void finalize() throws Throwable {
   1053         try {
   1054             /*
   1055              * Just worry about our own state. Notably we do not try and
   1056              * close anything. The SocketImpl, either our own
   1057              * PlainSocketImpl, or the Socket we are wrapping, will do
   1058              * that. This might mean we do not properly SSL_shutdown, but
   1059              * if you want to do that, properly close the socket yourself.
   1060              *
   1061              * The reason why we don't try to SSL_shutdown, is that there
   1062              * can be a race between finalizers where the PlainSocketImpl
   1063              * finalizer runs first and closes the socket. However, in the
   1064              * meanwhile, the underlying file descriptor could be reused
   1065              * for another purpose. If we call SSL_shutdown, the
   1066              * underlying socket BIOs still have the old file descriptor
   1067              * and will write the close notify to some unsuspecting
   1068              * reader.
   1069              */
   1070             if (guard != null) {
   1071                 guard.warnIfOpen();
   1072             }
   1073             free();
   1074         } finally {
   1075             super.finalize();
   1076         }
   1077     }
   1078 
   1079     @Override
   1080     public FileDescriptor getFileDescriptor$() {
   1081         if (socket == this) {
   1082             return super.getFileDescriptor$();
   1083         } else {
   1084             return socket.getFileDescriptor$();
   1085         }
   1086     }
   1087 
   1088     /**
   1089      * Returns the protocol agreed upon by client and server, or null if no
   1090      * protocol was agreed upon.
   1091      */
   1092     public byte[] getNpnSelectedProtocol() {
   1093         return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
   1094     }
   1095 
   1096     /**
   1097      * Returns the protocol agreed upon by client and server, or {@code null} if
   1098      * no protocol was agreed upon.
   1099      */
   1100     public byte[] getAlpnSelectedProtocol() {
   1101         return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
   1102     }
   1103 
   1104     /**
   1105      * Sets the list of protocols this peer is interested in. If null no
   1106      * protocols will be used.
   1107      *
   1108      * @param npnProtocols a non-empty array of protocol names. From
   1109      *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
   1110      *     strings. The length byte itself is not included in the length. A byte
   1111      *     string of length 0 is invalid. No byte string may be truncated.".
   1112      */
   1113     public void setNpnProtocols(byte[] npnProtocols) {
   1114         if (npnProtocols != null && npnProtocols.length == 0) {
   1115             throw new IllegalArgumentException("npnProtocols.length == 0");
   1116         }
   1117         this.npnProtocols = npnProtocols;
   1118     }
   1119 
   1120     /**
   1121      * Sets the list of protocols this peer is interested in. If the list is
   1122      * {@code null}, no protocols will be used.
   1123      *
   1124      * @param alpnProtocols a non-empty array of protocol names. From
   1125      *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
   1126      *            strings. The length byte itself is not included in the length.
   1127      *            A byte string of length 0 is invalid. No byte string may be
   1128      *            truncated.".
   1129      */
   1130     public void setAlpnProtocols(byte[] alpnProtocols) {
   1131         if (alpnProtocols != null && alpnProtocols.length == 0) {
   1132             throw new IllegalArgumentException("alpnProtocols.length == 0");
   1133         }
   1134         this.alpnProtocols = alpnProtocols;
   1135     }
   1136 }
   1137