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