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 java.io.FileDescriptor;
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.io.OutputStream;
     24 import java.net.InetAddress;
     25 import java.net.Socket;
     26 import java.net.SocketException;
     27 import java.security.PrivateKey;
     28 import java.security.SecureRandom;
     29 import java.security.cert.CertificateEncodingException;
     30 import java.security.cert.CertificateException;
     31 import java.security.cert.X509Certificate;
     32 import java.util.ArrayList;
     33 import java.util.concurrent.atomic.AtomicInteger;
     34 import java.util.logging.Logger;
     35 import javax.net.ssl.HandshakeCompletedEvent;
     36 import javax.net.ssl.HandshakeCompletedListener;
     37 import javax.net.ssl.SSLException;
     38 import javax.net.ssl.SSLPeerUnverifiedException;
     39 import javax.net.ssl.SSLSession;
     40 import javax.security.auth.x500.X500Principal;
     41 import org.apache.harmony.security.provider.cert.X509CertImpl;
     42 
     43 /**
     44  * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
     45  * <p>
     46  * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
     47  * later, for example in the package.html or a separate reference document.
     48  * <p>
     49  * Extensions to SSLSocket include:
     50  * <ul>
     51  * <li>handshake timeout
     52  * <li>compression methods
     53  * <li>session tickets
     54  * <li>Server Name Indication
     55  * </ul>
     56  */
     57 public class OpenSSLSocketImpl
     58         extends javax.net.ssl.SSLSocket
     59         implements NativeCrypto.SSLHandshakeCallbacks {
     60 
     61     private int sslNativePointer;
     62     private InputStream is;
     63     private OutputStream os;
     64     private final Object handshakeLock = new Object();
     65     private final Object readLock = new Object();
     66     private final Object writeLock = new Object();
     67     private SSLParametersImpl sslParameters;
     68     private String[] enabledProtocols;
     69     private String[] enabledCipherSuites;
     70     private String[] enabledCompressionMethods;
     71     private boolean useSessionTickets;
     72     private String hostname;
     73     private OpenSSLSessionImpl sslSession;
     74     private final Socket socket;
     75     private final FileDescriptor fd;
     76     private boolean autoClose;
     77     private boolean handshakeStarted = false;
     78 
     79     /**
     80      * Not set to true until the update from native that tells us the
     81      * full handshake is complete, since SSL_do_handshake can return
     82      * before the handshake is completely done due to
     83      * handshake_cutthrough support.
     84      */
     85     private boolean handshakeCompleted = false;
     86 
     87     private ArrayList<HandshakeCompletedListener> listeners;
     88 
     89     /**
     90      * Local cache of timeout to avoid getsockopt on every read and
     91      * write for non-wrapped sockets. Note that
     92      * OpenSSLSocketImplWrapper overrides setSoTimeout and
     93      * getSoTimeout to delegate to the wrapped socket.
     94      */
     95     private int timeoutMilliseconds = 0;
     96 
     97     // BEGIN android-added
     98     private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
     99     // END android-added
    100     private String wrappedHost;
    101     private int wrappedPort;
    102 
    103     private static final AtomicInteger instanceCount = new AtomicInteger(0);
    104 
    105     public static int getInstanceCount() {
    106         return instanceCount.get();
    107     }
    108 
    109     private static void updateInstanceCount(int amount) {
    110         instanceCount.addAndGet(amount);
    111     }
    112 
    113     /**
    114      * Class constructor with 1 parameter
    115      *
    116      * @param sslParameters Parameters for the SSL
    117      *            context
    118      * @throws IOException if network fails
    119      */
    120     protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
    121         super();
    122         this.socket = this;
    123         this.fd = NativeCrypto.getFileDescriptor(socket);
    124         init(sslParameters);
    125     }
    126 
    127     /**
    128      * Create an OpenSSLSocketImpl from an OpenSSLServerSocketImpl
    129      *
    130      * @param sslParameters Parameters for the SSL
    131      *            context
    132      * @throws IOException if network fails
    133      */
    134     protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
    135                                 String[] enabledProtocols,
    136                                 String[] enabledCipherSuites,
    137                                 String[] enabledCompressionMethods) throws IOException {
    138         super();
    139         this.socket = this;
    140         this.fd = NativeCrypto.getFileDescriptor(socket);
    141         init(sslParameters, enabledProtocols, enabledCipherSuites, enabledCompressionMethods);
    142     }
    143 
    144     /**
    145      * Class constructor with 3 parameters
    146      *
    147      * @throws IOException if network fails
    148      * @throws java.net.UnknownHostException host not defined
    149      */
    150     protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
    151             throws IOException {
    152         super(host, port);
    153         this.socket = this;
    154         this.fd = NativeCrypto.getFileDescriptor(socket);
    155         init(sslParameters);
    156     }
    157 
    158     /**
    159      * Class constructor with 3 parameters: 1st is InetAddress
    160      *
    161      * @throws IOException if network fails
    162      * @throws java.net.UnknownHostException host not defined
    163      */
    164     protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
    165             throws IOException {
    166         super(address, port);
    167         this.socket = this;
    168         this.fd = NativeCrypto.getFileDescriptor(socket);
    169         init(sslParameters);
    170     }
    171 
    172 
    173     /**
    174      * Class constructor with 5 parameters: 1st is host
    175      *
    176      * @throws IOException if network fails
    177      * @throws java.net.UnknownHostException host not defined
    178      */
    179     protected OpenSSLSocketImpl(String host, int port,
    180                                 InetAddress clientAddress, int clientPort,
    181                                 SSLParametersImpl sslParameters)
    182             throws IOException {
    183         super(host, port, clientAddress, clientPort);
    184         this.socket = this;
    185         this.fd = NativeCrypto.getFileDescriptor(socket);
    186         init(sslParameters);
    187     }
    188 
    189     /**
    190      * Class constructor with 5 parameters: 1st is InetAddress
    191      *
    192      * @throws IOException if network fails
    193      * @throws java.net.UnknownHostException host not defined
    194      */
    195     protected OpenSSLSocketImpl(InetAddress address, int port,
    196                                 InetAddress clientAddress, int clientPort,
    197                                 SSLParametersImpl sslParameters)
    198             throws IOException {
    199         super(address, port, clientAddress, clientPort);
    200         this.socket = this;
    201         this.fd = NativeCrypto.getFileDescriptor(socket);
    202         init(sslParameters);
    203     }
    204 
    205     /**
    206      * Constructor with 5 parameters: 1st is socket. Enhances an existing socket
    207      * with SSL functionality. Invoked via OpenSSLSocketImplWrapper constructor.
    208      *
    209      * @throws IOException if network fails
    210      */
    211     protected OpenSSLSocketImpl(Socket socket, String host, int port,
    212             boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
    213         super();
    214         this.socket = socket;
    215         this.fd = NativeCrypto.getFileDescriptor(socket);
    216         this.wrappedHost = host;
    217         this.wrappedPort = port;
    218         this.autoClose = autoClose;
    219         init(sslParameters);
    220 
    221         // this.timeout is not set intentionally.
    222         // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
    223         // to wrapped socket
    224     }
    225 
    226     /**
    227      * Initialize the SSL socket and set the certificates for the
    228      * future handshaking.
    229      */
    230     private void init(SSLParametersImpl sslParameters) throws IOException {
    231         init(sslParameters,
    232              NativeCrypto.getSupportedProtocols(),
    233              NativeCrypto.getDefaultCipherSuites(),
    234              NativeCrypto.getDefaultCompressionMethods());
    235     }
    236 
    237     /**
    238      * Initialize the SSL socket and set the certificates for the
    239      * future handshaking.
    240      */
    241     private void init(SSLParametersImpl sslParameters,
    242                       String[] enabledProtocols,
    243                       String[] enabledCipherSuites,
    244                       String[] enabledCompressionMethods) throws IOException {
    245         this.sslParameters = sslParameters;
    246         this.enabledProtocols = enabledProtocols;
    247         this.enabledCipherSuites = enabledCipherSuites;
    248         this.enabledCompressionMethods = enabledCompressionMethods;
    249         updateInstanceCount(1);
    250     }
    251 
    252     /**
    253      * Gets the suitable session reference from the session cache container.
    254      *
    255      * @return OpenSSLSessionImpl
    256      */
    257     private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
    258         if (super.getInetAddress() == null ||
    259                 super.getInetAddress().getHostAddress() == null ||
    260                 super.getInetAddress().getHostName() == null) {
    261             return null;
    262         }
    263         OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(
    264                 super.getInetAddress().getHostName(),
    265                 super.getPort());
    266         if (session == null) {
    267             return null;
    268         }
    269 
    270         String protocol = session.getProtocol();
    271         boolean protocolFound = false;
    272         for (String enabledProtocol : enabledProtocols) {
    273             if (protocol.equals(enabledProtocol)) {
    274                 protocolFound = true;
    275                 break;
    276             }
    277         }
    278         if (!protocolFound) {
    279             return null;
    280         }
    281 
    282         String cipherSuite = session.getCipherSuite();
    283         boolean cipherSuiteFound = false;
    284         for (String enabledCipherSuite : enabledCipherSuites) {
    285             if (cipherSuite.equals(enabledCipherSuite)) {
    286                 cipherSuiteFound = true;
    287                 break;
    288             }
    289         }
    290         if (!cipherSuiteFound) {
    291             return null;
    292         }
    293 
    294         String compressionMethod = session.getCompressionMethod();
    295         boolean compressionMethodFound = false;
    296         for (String enabledCompressionMethod : enabledCompressionMethods) {
    297             if (compressionMethod.equals(enabledCompressionMethod)) {
    298                 compressionMethodFound = true;
    299                 break;
    300             }
    301         }
    302         if (!compressionMethodFound) {
    303             return null;
    304         }
    305 
    306         return session;
    307     }
    308 
    309     /**
    310      * Ensures that logger is lazily loaded. The outer class seems to load
    311      * before logging is ready.
    312      */
    313     static class LoggerHolder {
    314         static final Logger logger = Logger.getLogger(OpenSSLSocketImpl.class.getName());
    315     }
    316 
    317     /**
    318      * Starts a TLS/SSL handshake on this connection using some native methods
    319      * from the OpenSSL library. It can negotiate new encryption keys, change
    320      * cipher suites, or initiate a new session. The certificate chain is
    321      * verified if the correspondent property in java.Security is set. All
    322      * listeners are notified at the end of the TLS/SSL handshake.
    323      *
    324      * @throws <code>IOException</code> if network fails
    325      */
    326     @Override
    327     public void startHandshake() throws IOException {
    328         startHandshake(true);
    329     }
    330 
    331     /**
    332      * Checks whether the socket is closed, and throws an exception.
    333      *
    334      * @throws SocketException
    335      *             if the socket is closed.
    336      */
    337     private void checkOpen() throws SocketException {
    338         if (isClosed()) {
    339             throw new SocketException("Socket is closed");
    340         }
    341     }
    342 
    343     /**
    344      * Perform the handshake
    345      * @param full If true, disable handshake cutthrough for a fully synchronous handshake
    346      */
    347     public synchronized void startHandshake(boolean full) throws IOException {
    348         synchronized (handshakeLock) {
    349             checkOpen();
    350             if (!handshakeStarted) {
    351                 handshakeStarted = true;
    352             } else {
    353                 return;
    354             }
    355         }
    356 
    357         // note that this modifies the global seed, not something specific to the connection
    358         final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
    359         final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
    360         if (secureRandom == null) {
    361             NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
    362         } else {
    363             NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
    364         }
    365 
    366         final boolean client = sslParameters.getUseClientMode();
    367 
    368         final int sslCtxNativePointer = (client) ?
    369             sslParameters.getClientSessionContext().sslCtxNativePointer :
    370             sslParameters.getServerSessionContext().sslCtxNativePointer;
    371 
    372         this.sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
    373 
    374         // setup server certificates and private keys.
    375         // clients will receive a call back to request certificates.
    376         if (!client) {
    377             for (String keyType : NativeCrypto.KEY_TYPES) {
    378                 try {
    379                     setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
    380                                                                                    null,
    381                                                                                    this));
    382                 } catch (CertificateEncodingException e) {
    383                     throw new IOException(e);
    384                 }
    385             }
    386         }
    387 
    388         NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
    389         NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
    390         if (enabledCompressionMethods.length != 0) {
    391             NativeCrypto.setEnabledCompressionMethods(sslNativePointer, enabledCompressionMethods);
    392         }
    393         if (useSessionTickets) {
    394             NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
    395         }
    396         if (hostname != null) {
    397             NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
    398         }
    399 
    400         boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
    401         if (!enableSessionCreation) {
    402             NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
    403                                                           enableSessionCreation);
    404         }
    405 
    406         AbstractSessionContext sessionContext;
    407         OpenSSLSessionImpl session;
    408         if (client) {
    409             // look for client session to reuse
    410             ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
    411             sessionContext = clientSessionContext;
    412             session = getCachedClientSession(clientSessionContext);
    413             if (session != null) {
    414                 NativeCrypto.SSL_set_session(sslNativePointer,  session.sslSessionNativePointer);
    415             }
    416         } else {
    417             sessionContext = sslParameters.getServerSessionContext();
    418             session = null;
    419         }
    420 
    421         // setup peer certificate verification
    422         if (client) {
    423             // TODO support for anonymous cipher would require us to
    424             // conditionally use SSL_VERIFY_NONE
    425         } else {
    426             // needing client auth takes priority...
    427             boolean certRequested = false;
    428             if (sslParameters.getNeedClientAuth()) {
    429                 NativeCrypto.SSL_set_verify(sslNativePointer,
    430                                             NativeCrypto.SSL_VERIFY_PEER
    431                                             | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
    432                 certRequested = true;
    433             // ... over just wanting it...
    434             } else if (sslParameters.getWantClientAuth()) {
    435                 NativeCrypto.SSL_set_verify(sslNativePointer,
    436                                             NativeCrypto.SSL_VERIFY_PEER);
    437                 certRequested = true;
    438             // ... and it defaults properly so we don't need call SSL_set_verify in the common case.
    439             } else {
    440                 certRequested = false;
    441             }
    442 
    443             if (certRequested) {
    444                 X509Certificate[] issuers = sslParameters.getTrustManager().getAcceptedIssuers();
    445                 if (issuers != null && issuers.length != 0) {
    446                     byte[][] issuersBytes;
    447                     try {
    448                         issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
    449                     } catch (CertificateEncodingException e) {
    450                         throw new IOException("Problem encoding principals", e);
    451                     }
    452                     NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
    453                 }
    454             }
    455         }
    456 
    457         if (client && full) {
    458             // we want to do a full synchronous handshake, so turn off cutthrough
    459             NativeCrypto.SSL_clear_mode(sslNativePointer,
    460                                         NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
    461         }
    462 
    463         // BEGIN android-added
    464         // Temporarily use a different timeout for the handshake process
    465         int savedTimeoutMilliseconds = getSoTimeout();
    466         if (handshakeTimeoutMilliseconds >= 0) {
    467             setSoTimeout(handshakeTimeoutMilliseconds);
    468         }
    469         // END android-added
    470 
    471 
    472         int sslSessionNativePointer;
    473         try {
    474             sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer, fd, this,
    475                                                                     getSoTimeout(), client);
    476         } catch (CertificateException e) {
    477             throw new SSLPeerUnverifiedException(e.getMessage());
    478         }
    479         byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
    480         sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
    481         if (sslSession != null) {
    482             sslSession.lastAccessedTime = System.currentTimeMillis();
    483             LoggerHolder.logger.fine("Reused cached session for "
    484                                      + getInetAddress() + ".");
    485             NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
    486         } else {
    487             if (!enableSessionCreation) {
    488                 // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
    489                 throw new IllegalStateException("SSL Session may not be created");
    490             }
    491             X509Certificate[] localCertificates
    492                     = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
    493             X509Certificate[] peerCertificates
    494                     = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
    495             if (wrappedHost == null) {
    496                 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
    497                                                     localCertificates, peerCertificates,
    498                                                     super.getInetAddress().getHostName(),
    499                                                     super.getPort(), sessionContext);
    500             } else  {
    501                 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
    502                                                     localCertificates, peerCertificates,
    503                                                     wrappedHost, wrappedPort,
    504                                                     sessionContext);
    505             }
    506             // if not, putSession later in handshakeCompleted() callback
    507             if (handshakeCompleted) {
    508                 sessionContext.putSession(sslSession);
    509             }
    510             LoggerHolder.logger.fine("Created new session for "
    511                                      + getInetAddress().getHostName() + ".");
    512         }
    513 
    514         // BEGIN android-added
    515         // Restore the original timeout now that the handshake is complete
    516         if (handshakeTimeoutMilliseconds >= 0) {
    517             setSoTimeout(savedTimeoutMilliseconds);
    518         }
    519         // END android-added
    520 
    521         // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
    522         if (handshakeCompleted) {
    523             notifyHandshakeCompletedListeners();
    524         }
    525     }
    526 
    527     /**
    528      * Return a possibly null array of X509Certificates given the
    529      * possibly null array of DER encoded bytes.
    530      */
    531     private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
    532         if (certificatesBytes == null) {
    533             return null;
    534         }
    535         X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
    536         for (int i = 0; i < certificatesBytes.length; i++) {
    537             try {
    538                 certificates[i] = new X509CertImpl(certificatesBytes[i]);
    539             } catch (IOException e) {
    540                 return null;
    541             }
    542         }
    543         return certificates;
    544     }
    545 
    546     private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
    547         if (alias == null) {
    548             return;
    549         }
    550 
    551         PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
    552         byte[] privateKeyBytes = privateKey.getEncoded();
    553         NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
    554 
    555         X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
    556         byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
    557         NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
    558 
    559         // checks the last installed private key and certificate,
    560         // so need to do this once per loop iteration
    561         NativeCrypto.SSL_check_private_key(sslNativePointer);
    562     }
    563 
    564     /**
    565      * Implementation of NativeCrypto.SSLHandshakeCallbacks
    566      * invoked via JNI from client_cert_cb
    567      */
    568     public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
    569             throws CertificateEncodingException, SSLException {
    570 
    571         String[] keyTypes = new String[keyTypeBytes.length];
    572         for (int i = 0; i < keyTypeBytes.length; i++) {
    573             keyTypes[i] = NativeCrypto.keyType(keyTypeBytes[i]);
    574         }
    575 
    576         X500Principal[] issuers;
    577         if (asn1DerEncodedPrincipals == null) {
    578             issuers = null;
    579         } else {
    580             issuers = new X500Principal[asn1DerEncodedPrincipals.length];
    581             for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
    582                 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
    583             }
    584         }
    585         setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
    586     }
    587 
    588     /**
    589      * Implementation of NativeCrypto.SSLHandshakeCallbacks
    590      * invoked via JNI from info_callback
    591      */
    592     public void handshakeCompleted() {
    593         handshakeCompleted = true;
    594 
    595         // If sslSession is null, the handshake was completed during
    596         // the call to NativeCrypto.SSL_do_handshake and not during a
    597         // later read operation. That means we do not need to fixup
    598         // the SSLSession and session cache or notify
    599         // HandshakeCompletedListeners, it will be done in
    600         // startHandshake.
    601         if (sslSession == null) {
    602             return;
    603         }
    604 
    605         // reset session id from the native pointer and update the
    606         // appropriate cache.
    607         sslSession.resetId();
    608         AbstractSessionContext sessionContext =
    609             (sslParameters.getUseClientMode())
    610             ? sslParameters.getClientSessionContext()
    611                 : sslParameters.getServerSessionContext();
    612         sessionContext.putSession(sslSession);
    613 
    614         // let listeners know we are finally done
    615         notifyHandshakeCompletedListeners();
    616     }
    617 
    618     private void notifyHandshakeCompletedListeners() {
    619         if (listeners != null && !listeners.isEmpty()) {
    620             // notify the listeners
    621             HandshakeCompletedEvent event =
    622                 new HandshakeCompletedEvent(this, sslSession);
    623             for (HandshakeCompletedListener listener : listeners) {
    624                 try {
    625                     listener.handshakeCompleted(event);
    626                 } catch (RuntimeException e) {
    627                     // The RI runs the handlers in a separate thread,
    628                     // which we do not. But we try to preserve their
    629                     // behavior of logging a problem and not killing
    630                     // the handshaking thread just because a listener
    631                     // has a problem.
    632                     Thread thread = Thread.currentThread();
    633                     thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
    634                 }
    635             }
    636         }
    637     }
    638 
    639     /**
    640      * Implementation of NativeCrypto.SSLHandshakeCallbacks
    641      *
    642      * @param bytes An array of ASN.1 DER encoded certficates
    643      * @param authMethod auth algorithm name
    644      *
    645      * @throws CertificateException if the certificate is untrusted
    646      */
    647     @SuppressWarnings("unused")
    648     public void verifyCertificateChain(byte[][] bytes, String authMethod)
    649             throws CertificateException {
    650         try {
    651             if (bytes == null || bytes.length == 0) {
    652                 throw new SSLException("Peer sent no certificate");
    653             }
    654             X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
    655             for (int i = 0; i < bytes.length; i++) {
    656                 peerCertificateChain[i] =
    657                     new X509CertImpl(
    658                         javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded());
    659             }
    660             boolean client = sslParameters.getUseClientMode();
    661             if (client) {
    662                 sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
    663                                                                    authMethod);
    664             } else {
    665                 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
    666                                                                    authMethod);
    667             }
    668 
    669         } catch (CertificateException e) {
    670             throw e;
    671         } catch (Exception e) {
    672             throw new RuntimeException(e);
    673         }
    674     }
    675 
    676     /**
    677      * Returns an input stream for this SSL socket using native calls to the
    678      * OpenSSL library.
    679      *
    680      * @return: an input stream for reading bytes from this socket.
    681      * @throws: <code>IOException</code> if an I/O error occurs when creating
    682      *          the input stream, the socket is closed, the socket is not
    683      *          connected, or the socket input has been shutdown.
    684      */
    685     @Override
    686     public InputStream getInputStream() throws IOException {
    687         checkOpen();
    688         synchronized (this) {
    689             if (is == null) {
    690                 is = new SSLInputStream();
    691             }
    692 
    693             return is;
    694         }
    695     }
    696 
    697     /**
    698      * Returns an output stream for this SSL socket using native calls to the
    699      * OpenSSL library.
    700      *
    701      * @return an output stream for writing bytes to this socket.
    702      * @throws <code>IOException</code> if an I/O error occurs when creating
    703      *             the output stream, or no connection to the socket exists.
    704      */
    705     @Override
    706     public OutputStream getOutputStream() throws IOException {
    707         checkOpen();
    708         synchronized (this) {
    709             if (os == null) {
    710                 os = new SSLOutputStream();
    711             }
    712 
    713             return os;
    714         }
    715     }
    716 
    717     /**
    718      * This method is not supported for this SSLSocket implementation
    719      * because reading from an SSLSocket may involve writing to the
    720      * network.
    721      */
    722     @Override
    723     public void shutdownInput() throws IOException {
    724         throw new UnsupportedOperationException();
    725     }
    726 
    727     /**
    728      * This method is not supported for this SSLSocket implementation
    729      * because writing to an SSLSocket may involve reading from the
    730      * network.
    731      */
    732     @Override
    733     public void shutdownOutput() throws IOException {
    734         throw new UnsupportedOperationException();
    735     }
    736 
    737     /**
    738      * This inner class provides input data stream functionality
    739      * for the OpenSSL native implementation. It is used to
    740      * read data received via SSL protocol.
    741      */
    742     private class SSLInputStream extends InputStream {
    743         SSLInputStream() throws IOException {
    744             /**
    745             /* Note: When startHandshake() throws an exception, no
    746              * SSLInputStream object will be created.
    747              */
    748             OpenSSLSocketImpl.this.startHandshake(false);
    749         }
    750 
    751         /**
    752          * Reads one byte. If there is no data in the underlying buffer,
    753          * this operation can block until the data will be
    754          * available.
    755          * @return read value.
    756          * @throws <code>IOException</code>
    757          */
    758         @Override
    759         public int read() throws IOException {
    760             BlockGuard.getThreadPolicy().onNetwork();
    761             synchronized (readLock) {
    762                 checkOpen();
    763                 return NativeCrypto.SSL_read_byte(sslNativePointer, fd, OpenSSLSocketImpl.this,
    764                                                   getSoTimeout());
    765             }
    766         }
    767 
    768         /**
    769          * Method acts as described in spec for superclass.
    770          * @see java.io.InputStream#read(byte[],int,int)
    771          */
    772         @Override
    773         public int read(byte[] b, int off, int len) throws IOException {
    774             BlockGuard.getThreadPolicy().onNetwork();
    775             synchronized (readLock) {
    776                 checkOpen();
    777                 if (b == null) {
    778                     throw new NullPointerException("b == null");
    779                 }
    780                 if ((len | off) < 0 || len > b.length - off) {
    781                     throw new IndexOutOfBoundsException();
    782                 }
    783                 if (0 == len) {
    784                     return 0;
    785                 }
    786                 return NativeCrypto.SSL_read(sslNativePointer, fd, OpenSSLSocketImpl.this,
    787                                              b, off, len, getSoTimeout());
    788             }
    789         }
    790     }
    791 
    792     /**
    793      * This inner class provides output data stream functionality
    794      * for the OpenSSL native implementation. It is used to
    795      * write data according to the encryption parameters given in SSL context.
    796      */
    797     private class SSLOutputStream extends OutputStream {
    798         SSLOutputStream() throws IOException {
    799             /**
    800             /* Note: When startHandshake() throws an exception, no
    801              * SSLOutputStream object will be created.
    802              */
    803             OpenSSLSocketImpl.this.startHandshake(false);
    804         }
    805 
    806         /**
    807          * Method acts as described in spec for superclass.
    808          * @see java.io.OutputStream#write(int)
    809          */
    810         @Override
    811         public void write(int b) throws IOException {
    812             BlockGuard.getThreadPolicy().onNetwork();
    813             synchronized (writeLock) {
    814                 checkOpen();
    815                 NativeCrypto.SSL_write_byte(sslNativePointer, fd, OpenSSLSocketImpl.this, b);
    816             }
    817         }
    818 
    819         /**
    820          * Method acts as described in spec for superclass.
    821          * @see java.io.OutputStream#write(byte[],int,int)
    822          */
    823         @Override
    824         public void write(byte[] b, int start, int len) throws IOException {
    825             BlockGuard.getThreadPolicy().onNetwork();
    826             synchronized (writeLock) {
    827                 checkOpen();
    828                 if (b == null) {
    829                     throw new NullPointerException("b == null");
    830                 }
    831                 if ((len | start) < 0 || len > b.length - start) {
    832                     throw new IndexOutOfBoundsException();
    833                 }
    834                 if (len == 0) {
    835                     return;
    836                 }
    837                 NativeCrypto.SSL_write(sslNativePointer, fd, OpenSSLSocketImpl.this, b, start, len);
    838             }
    839         }
    840     }
    841 
    842 
    843     /**
    844      * The SSL session used by this connection is returned. The SSL session
    845      * determines which cipher suite should be used by all connections within
    846      * that session and which identities have the session's client and server.
    847      * This method starts the SSL handshake.
    848      * @return the SSLSession.
    849      * @throws <code>IOException</code> if the handshake fails
    850      */
    851     @Override
    852     public SSLSession getSession() {
    853         if (sslSession == null) {
    854             try {
    855                 startHandshake(true);
    856             } catch (IOException e) {
    857 
    858                 // return an invalid session with
    859                 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
    860                 return SSLSessionImpl.NULL_SESSION;
    861             }
    862         }
    863         return sslSession;
    864     }
    865 
    866     /**
    867      * Registers a listener to be notified that a SSL handshake
    868      * was successfully completed on this connection.
    869      * @throws <code>IllegalArgumentException</code> if listener is null.
    870      */
    871     @Override
    872     public void addHandshakeCompletedListener(
    873             HandshakeCompletedListener listener) {
    874         if (listener == null) {
    875             throw new IllegalArgumentException("Provided listener is null");
    876         }
    877         if (listeners == null) {
    878             listeners = new ArrayList();
    879         }
    880         listeners.add(listener);
    881     }
    882 
    883     /**
    884      * The method removes a registered listener.
    885      * @throws IllegalArgumentException if listener is null or not registered
    886      */
    887     @Override
    888     public void removeHandshakeCompletedListener(
    889             HandshakeCompletedListener listener) {
    890         if (listener == null) {
    891             throw new IllegalArgumentException("Provided listener is null");
    892         }
    893         if (listeners == null) {
    894             throw new IllegalArgumentException(
    895                     "Provided listener is not registered");
    896         }
    897         if (!listeners.remove(listener)) {
    898             throw new IllegalArgumentException(
    899                     "Provided listener is not registered");
    900         }
    901     }
    902 
    903     /**
    904      * Returns true if new SSL sessions may be established by this socket.
    905      *
    906      * @return true if the session may be created; false if a session already
    907      *         exists and must be resumed.
    908      */
    909     @Override
    910     public boolean getEnableSessionCreation() {
    911         return sslParameters.getEnableSessionCreation();
    912     }
    913 
    914     /**
    915      * Set a flag for the socket to inhibit or to allow the creation of a new
    916      * SSL sessions. If the flag is set to false, and there are no actual
    917      * sessions to resume, then there will be no successful handshaking.
    918      *
    919      * @param flag true if session may be created; false
    920      *            if a session already exists and must be resumed.
    921      */
    922     @Override
    923     public void setEnableSessionCreation(boolean flag) {
    924         sslParameters.setEnableSessionCreation(flag);
    925     }
    926 
    927     /**
    928      * The names of the cipher suites which could be used by the SSL connection
    929      * are returned.
    930      * @return an array of cipher suite names
    931      */
    932     @Override
    933     public String[] getSupportedCipherSuites() {
    934         return NativeCrypto.getSupportedCipherSuites();
    935     }
    936 
    937     /**
    938      * The names of the cipher suites that are in use in the actual the SSL
    939      * connection are returned.
    940      *
    941      * @return an array of cipher suite names
    942      */
    943     @Override
    944     public String[] getEnabledCipherSuites() {
    945         return enabledCipherSuites.clone();
    946     }
    947 
    948     /**
    949      * This method enables the cipher suites listed by
    950      * getSupportedCipherSuites().
    951      *
    952      * @param suites names of all the cipher suites to
    953      *            put on use
    954      * @throws IllegalArgumentException when one or more of the
    955      *             ciphers in array suites are not supported, or when the array
    956      *             is null.
    957      */
    958     @Override
    959     public void setEnabledCipherSuites(String[] suites) {
    960         enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
    961     }
    962 
    963     /**
    964      * The names of the protocols' versions that may be used on this SSL
    965      * connection.
    966      * @return an array of protocols names
    967      */
    968     @Override
    969     public String[] getSupportedProtocols() {
    970         return NativeCrypto.getSupportedProtocols();
    971     }
    972 
    973     /**
    974      * The names of the protocols' versions that are in use on this SSL
    975      * connection.
    976      *
    977      * @return an array of protocols names
    978      */
    979     @Override
    980     public String[] getEnabledProtocols() {
    981         return enabledProtocols.clone();
    982     }
    983 
    984     /**
    985      * This method enables the protocols' versions listed by
    986      * getSupportedProtocols().
    987      *
    988      * @param protocols The names of all the protocols to allow
    989      *
    990      * @throws IllegalArgumentException when one or more of the names in the
    991      *             array are not supported, or when the array is null.
    992      */
    993     @Override
    994     public void setEnabledProtocols(String[] protocols) {
    995         enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
    996     }
    997 
    998     /**
    999      * The names of the compression methods that may be used on this SSL
   1000      * connection.
   1001      * @return an array of compression methods
   1002      */
   1003     public String[] getSupportedCompressionMethods() {
   1004         return NativeCrypto.getSupportedCompressionMethods();
   1005     }
   1006 
   1007     /**
   1008      * The names of the compression methods versions that are in use
   1009      * on this SSL connection.
   1010      *
   1011      * @return an array of compression methods
   1012      */
   1013     public String[] getEnabledCompressionMethods() {
   1014         return enabledCompressionMethods.clone();
   1015     }
   1016 
   1017     /**
   1018      * This method enables the compression method listed by
   1019      * getSupportedCompressionMethods().
   1020      *
   1021      * @param methods The names of all the compression methods to allow
   1022      *
   1023      * @throws IllegalArgumentException when one or more of the names in the
   1024      *             array are not supported, or when the array is null.
   1025      */
   1026     public void setEnabledCompressionMethods (String[] methods) {
   1027         enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
   1028     }
   1029 
   1030     /**
   1031      * This method enables session ticket support.
   1032      *
   1033      * @param useSessionTickets True to enable session tickets
   1034      */
   1035     public void setUseSessionTickets(boolean useSessionTickets) {
   1036         this.useSessionTickets = useSessionTickets;
   1037     }
   1038 
   1039     /**
   1040      * This method gives true back if the SSL socket is set to client mode.
   1041      *
   1042      * @return true if the socket should do the handshaking as client.
   1043      */
   1044     public boolean getUseSessionTickets() {
   1045         return useSessionTickets;
   1046     }
   1047 
   1048     /**
   1049      * This method enables Server Name Indication
   1050      *
   1051      * @param hostname the desired SNI hostname, or null to disable
   1052      */
   1053     public void setHostname(String hostname) {
   1054         this.hostname = hostname;
   1055     }
   1056 
   1057     /**
   1058      * This method returns the current SNI hostname
   1059      *
   1060      * @return a host name if SNI is enabled, or null otherwise
   1061      */
   1062     public String getHostname() {
   1063         return hostname;
   1064     }
   1065 
   1066     /**
   1067      * This method gives true back if the SSL socket is set to client mode.
   1068      *
   1069      * @return true if the socket should do the handshaking as client.
   1070      */
   1071     public boolean getUseClientMode() {
   1072         return sslParameters.getUseClientMode();
   1073     }
   1074 
   1075     /**
   1076      * This method set the actual SSL socket to client mode.
   1077      *
   1078      * @param mode true if the socket starts in client
   1079      *            mode
   1080      * @throws IllegalArgumentException if mode changes during
   1081      *             handshake.
   1082      */
   1083     @Override
   1084     public void setUseClientMode(boolean mode) {
   1085         if (handshakeStarted) {
   1086             throw new IllegalArgumentException(
   1087             "Could not change the mode after the initial handshake has begun.");
   1088         }
   1089         sslParameters.setUseClientMode(mode);
   1090     }
   1091 
   1092     /**
   1093      * Returns true if the SSL socket requests client's authentication. Relevant
   1094      * only for server sockets!
   1095      *
   1096      * @return true if client authentication is desired, false if not.
   1097      */
   1098     @Override
   1099     public boolean getWantClientAuth() {
   1100         return sslParameters.getWantClientAuth();
   1101     }
   1102 
   1103     /**
   1104      * Returns true if the SSL socket needs client's authentication. Relevant
   1105      * only for server sockets!
   1106      *
   1107      * @return true if client authentication is desired, false if not.
   1108      */
   1109     @Override
   1110     public boolean getNeedClientAuth() {
   1111         return sslParameters.getNeedClientAuth();
   1112     }
   1113 
   1114     /**
   1115      * Sets the SSL socket to use client's authentication. Relevant only for
   1116      * server sockets!
   1117      *
   1118      * @param need true if client authentication is
   1119      *            desired, false if not.
   1120      */
   1121     @Override
   1122     public void setNeedClientAuth(boolean need) {
   1123         sslParameters.setNeedClientAuth(need);
   1124     }
   1125 
   1126     /**
   1127      * Sets the SSL socket to use client's authentication. Relevant only for
   1128      * server sockets! Notice that in contrast to setNeedClientAuth(..) this
   1129      * method will continue the negotiation if the client decide not to send
   1130      * authentication credentials.
   1131      *
   1132      * @param want true if client authentication is
   1133      *            desired, false if not.
   1134      */
   1135     @Override
   1136     public void setWantClientAuth(boolean want) {
   1137         sslParameters.setWantClientAuth(want);
   1138     }
   1139 
   1140     /**
   1141      * This method is not supported for SSLSocket implementation.
   1142      */
   1143     @Override
   1144     public void sendUrgentData(int data) throws IOException {
   1145         throw new SocketException(
   1146                 "Method sendUrgentData() is not supported.");
   1147     }
   1148 
   1149     /**
   1150      * This method is not supported for SSLSocket implementation.
   1151      */
   1152     @Override
   1153     public void setOOBInline(boolean on) throws SocketException {
   1154         throw new SocketException(
   1155                 "Methods sendUrgentData, setOOBInline are not supported.");
   1156     }
   1157 
   1158     /**
   1159      * Set the read timeout on this socket. The SO_TIMEOUT option, is specified
   1160      * in milliseconds. The read operation will block indefinitely for a zero
   1161      * value.
   1162      *
   1163      * @param timeout the read timeout value
   1164      * @throws SocketException if an error occurs setting the option
   1165      */
   1166     @Override
   1167     public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
   1168         super.setSoTimeout(timeoutMilliseconds);
   1169         this.timeoutMilliseconds = timeoutMilliseconds;
   1170     }
   1171 
   1172     @Override
   1173     public int getSoTimeout() throws SocketException {
   1174         return timeoutMilliseconds;
   1175     }
   1176 
   1177     // BEGIN android-added
   1178     /**
   1179      * Set the handshake timeout on this socket.  This timeout is specified in
   1180      * milliseconds and will be used only during the handshake process.
   1181      *
   1182      * @param timeout the handshake timeout value
   1183      */
   1184     public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
   1185         this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
   1186     }
   1187     // END android-added
   1188 
   1189     /**
   1190      * Closes the SSL socket. Once closed, a socket is not available for further
   1191      * use anymore under any circumstance. A new socket must be created.
   1192      *
   1193      * @throws <code>IOException</code> if an I/O error happens during the
   1194      *             socket's closure.
   1195      */
   1196     @Override
   1197     public void close() throws IOException {
   1198         // TODO: Close SSL sockets using a background thread so they close
   1199         // gracefully.
   1200 
   1201         synchronized (handshakeLock) {
   1202             if (!handshakeStarted) {
   1203                 // prevent further attemps to start handshake
   1204                 handshakeStarted = true;
   1205 
   1206                 synchronized (this) {
   1207                     free();
   1208 
   1209                     if (socket != this) {
   1210                         if (autoClose && !socket.isClosed()) socket.close();
   1211                     } else {
   1212                         if (!super.isClosed()) super.close();
   1213                     }
   1214                 }
   1215 
   1216                 return;
   1217             }
   1218         }
   1219 
   1220         NativeCrypto.SSL_interrupt(sslNativePointer);
   1221 
   1222         synchronized (this) {
   1223             synchronized (writeLock) {
   1224                 synchronized (readLock) {
   1225 
   1226                     IOException pendingException = null;
   1227 
   1228                     // Shut down the SSL connection, per se.
   1229                     try {
   1230                         if (handshakeStarted) {
   1231                             BlockGuard.getThreadPolicy().onNetwork();
   1232                             NativeCrypto.SSL_shutdown(sslNativePointer, fd, this);
   1233                         }
   1234                     } catch (IOException ex) {
   1235                         /*
   1236                          * Note the exception at this point, but try to continue
   1237                          * to clean the rest of this all up before rethrowing.
   1238                          */
   1239                         pendingException = ex;
   1240                     }
   1241 
   1242                     /*
   1243                      * Even if the above call failed, it is still safe to free
   1244                      * the native structs, and we need to do so lest we leak
   1245                      * memory.
   1246                      */
   1247                     free();
   1248 
   1249                     if (socket != this) {
   1250                         if (autoClose && !socket.isClosed())
   1251                             socket.close();
   1252                     } else {
   1253                         if (!super.isClosed())
   1254                             super.close();
   1255                     }
   1256 
   1257                     if (pendingException != null) {
   1258                         throw pendingException;
   1259                     }
   1260                 }
   1261             }
   1262         }
   1263     }
   1264 
   1265     private void free() {
   1266         if (sslNativePointer == 0) {
   1267             return;
   1268         }
   1269         NativeCrypto.SSL_free(sslNativePointer);
   1270         sslNativePointer = 0;
   1271     }
   1272 
   1273     @Override protected void finalize() throws Throwable {
   1274         try {
   1275             /*
   1276              * Just worry about our own state. Notably we do not try and
   1277              * close anything. The SocketImpl, either our own
   1278              * PlainSocketImpl, or the Socket we are wrapping, will do
   1279              * that. This might mean we do not properly SSL_shutdown, but
   1280              * if you want to do that, properly close the socket yourself.
   1281              *
   1282              * The reason why we don't try to SSL_shutdown, is that there
   1283              * can be a race between finalizers where the PlainSocketImpl
   1284              * finalizer runs first and closes the socket. However, in the
   1285              * meanwhile, the underlying file descriptor could be reused
   1286              * for another purpose. If we call SSL_shutdown, the
   1287              * underlying socket BIOs still have the old file descriptor
   1288              * and will write the close notify to some unsuspecting
   1289              * reader.
   1290              */
   1291             updateInstanceCount(-1);
   1292             free();
   1293         } finally {
   1294             super.finalize();
   1295         }
   1296     }
   1297 }
   1298