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 java.io.ByteArrayOutputStream;
     20 import java.io.IOException;
     21 import java.io.InputStream;
     22 import java.io.OutputStream;
     23 import java.io.OutputStreamWriter;
     24 import java.net.InetAddress;
     25 import java.net.InetSocketAddress;
     26 import java.net.Socket;
     27 import java.net.SocketException;
     28 import java.security.PrivateKey;
     29 import java.security.cert.CertificateException;
     30 import java.security.cert.X509Certificate;
     31 import java.security.interfaces.RSAPublicKey;
     32 import java.util.ArrayList;
     33 import java.util.concurrent.atomic.AtomicInteger;
     34 import java.util.logging.Level;
     35 import java.util.logging.Logger;
     36 
     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.SSLSession;
     42 
     43 import org.apache.harmony.security.provider.cert.X509CertImpl;
     44 import org.bouncycastle.openssl.PEMWriter;
     45 
     46 /**
     47  * Implementation of the class OpenSSLSocketImpl
     48  * based on OpenSSL. The JNI native interface for some methods
     49  * of this this class are defined in the file:
     50  * org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
     51  *
     52  * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
     53  * later, for example in the package.html or a separate reference document.
     54  */
     55 public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
     56     private int ssl_ctx;
     57     private int ssl;
     58     private InputStream is;
     59     private OutputStream os;
     60     private final Object handshakeLock = new Object();
     61     private Object readLock = new Object();
     62     private Object writeLock = new Object();
     63     private SSLParameters sslParameters;
     64     private OpenSSLSessionImpl sslSession;
     65     private Socket socket;
     66     private boolean autoClose;
     67     private boolean handshakeStarted = false;
     68     private ArrayList<HandshakeCompletedListener> listeners;
     69     private long ssl_op_no = 0x00000000L;
     70     private int timeout = 0;
     71     // BEGIN android-added
     72     private int handshakeTimeout = -1;  // -1 = same as timeout; 0 = infinite
     73     // END android-added
     74     private InetSocketAddress address;
     75 
     76     private static final String[] supportedProtocols = new String[] {
     77         "SSLv3",
     78         "TLSv1"
     79         };
     80 
     81     private static final AtomicInteger instanceCount = new AtomicInteger(0);
     82 
     83     public static int getInstanceCount() {
     84         return instanceCount.get();
     85     }
     86 
     87     private static void updateInstanceCount(int amount) {
     88         instanceCount.addAndGet(amount);
     89     }
     90 
     91     /**
     92      * Initialize OpenSSL library.
     93      */
     94     private native static void nativeinitstatic();
     95 
     96     static {
     97         nativeinitstatic();
     98     }
     99 
    100     private native void nativeinit(String privatekey, String certificate, byte[] seed);
    101 
    102     /**
    103      * Initialize the SSL socket and set the certificates for the
    104      * future handshaking.
    105      */
    106     private void init() throws IOException {
    107         String alias = sslParameters.getKeyManager().chooseClientAlias(new String[] { "RSA" }, null, null);
    108         if (alias != null) {
    109             PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
    110             X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
    111 
    112             ByteArrayOutputStream privateKeyOS = new ByteArrayOutputStream();
    113             PEMWriter privateKeyPEMWriter = new PEMWriter(new OutputStreamWriter(privateKeyOS));
    114             privateKeyPEMWriter.writeObject(privateKey);
    115             privateKeyPEMWriter.close();
    116 
    117             ByteArrayOutputStream certificateOS = new ByteArrayOutputStream();
    118             PEMWriter certificateWriter = new PEMWriter(new OutputStreamWriter(certificateOS));
    119 
    120             for (int i = 0; i < certificates.length; i++) {
    121                 certificateWriter.writeObject(certificates[i]);
    122             }
    123             certificateWriter.close();
    124 
    125             nativeinit(privateKeyOS.toString(), certificateOS.toString(),
    126                     sslParameters.getSecureRandomMember() != null ?
    127                     sslParameters.getSecureRandomMember().generateSeed(1024) : null);
    128         } else {
    129             nativeinit(null, null,
    130                     sslParameters.getSecureRandomMember() != null ?
    131                     sslParameters.getSecureRandomMember().generateSeed(1024) : null);
    132         }
    133     }
    134 
    135     /**
    136      * Class constructor with 2 parameters
    137      *
    138      * @param sslParameters Parameters for the SSL
    139      *            context
    140      * @param ssl_op_no Parameter to set the enabled
    141      *            protocols
    142      * @throws IOException if network fails
    143      */
    144     protected OpenSSLSocketImpl(SSLParameters sslParameters, long ssl_op_no) throws IOException {
    145         super();
    146         this.sslParameters = sslParameters;
    147         this.ssl_op_no = ssl_op_no;
    148         updateInstanceCount(1);
    149     }
    150 
    151     /**
    152      * Class constructor with 1 parameter
    153      *
    154      * @param sslParameters Parameters for the SSL
    155      *            context
    156      * @throws IOException if network fails
    157      */
    158     protected OpenSSLSocketImpl(SSLParameters sslParameters) throws IOException {
    159         super();
    160         this.sslParameters = sslParameters;
    161         init();
    162         updateInstanceCount(1);
    163     }
    164 
    165     /**
    166      * Class constructor with 3 parameters
    167      *
    168      * @throws IOException if network fails
    169      * @throws java.net.UnknownHostException host not defined
    170      */
    171     protected OpenSSLSocketImpl(String host, int port,
    172             SSLParameters sslParameters)
    173         throws IOException {
    174         super(host, port);
    175         this.sslParameters = sslParameters;
    176         init();
    177         updateInstanceCount(1);
    178     }
    179 
    180 
    181     /**
    182      * Class constructor with 3 parameters: 1st is InetAddress
    183      *
    184      * @throws IOException if network fails
    185      * @throws java.net.UnknownHostException host not defined
    186      */
    187     protected OpenSSLSocketImpl(InetAddress address, int port,
    188             SSLParameters sslParameters)
    189         throws IOException {
    190         super(address, port);
    191         this.sslParameters = sslParameters;
    192         init();
    193         updateInstanceCount(1);
    194     }
    195 
    196 
    197     /**
    198      * Class constructor with 5 parameters: 1st is host
    199      *
    200      * @throws IOException if network fails
    201      * @throws java.net.UnknownHostException host not defined
    202      */
    203     protected OpenSSLSocketImpl(String host, int port, InetAddress clientAddress,
    204             int clientPort, SSLParameters sslParameters)
    205         throws IOException {
    206         super(host, port, clientAddress, clientPort);
    207         this.sslParameters = sslParameters;
    208         init();
    209         updateInstanceCount(1);
    210     }
    211 
    212     /**
    213      * Class constructor with 5 parameters: 1st is InetAddress
    214      *
    215      * @throws IOException if network fails
    216      * @throws java.net.UnknownHostException host not defined
    217      */
    218     protected OpenSSLSocketImpl(InetAddress address, int port,
    219             InetAddress clientAddress, int clientPort, SSLParameters sslParameters)
    220         throws IOException {
    221         super(address, port, clientAddress, clientPort);
    222         this.sslParameters = sslParameters;
    223         init();
    224         updateInstanceCount(1);
    225     }
    226 
    227     /**
    228      * Constructor with 5 parameters: 1st is socket. Enhances an existing socket
    229      * with SSL functionality.
    230      *
    231      * @throws IOException if network fails
    232      */
    233     protected OpenSSLSocketImpl(Socket socket, String host, int port,
    234             boolean autoClose, SSLParameters sslParameters) throws IOException {
    235         super();
    236         this.socket = socket;
    237         this.timeout = socket.getSoTimeout();
    238         this.address = new InetSocketAddress(host, port);
    239         this.autoClose = autoClose;
    240         this.sslParameters = sslParameters;
    241         init();
    242         updateInstanceCount(1);
    243     }
    244 
    245     /**
    246      * Adds OpenSSL functionality to the existing socket and starts the SSL
    247      * handshaking.
    248      */
    249     private native boolean nativeconnect(int ctx, Socket sock, boolean client_mode, int sslsession) throws IOException;
    250     private native int nativegetsslsession(int ssl);
    251     private native String nativecipherauthenticationmethod();
    252 
    253     /**
    254      * Gets the suitable session reference from the session cache container.
    255      *
    256      * @return OpenSSLSessionImpl
    257      */
    258     private OpenSSLSessionImpl getCachedClientSession() {
    259         if (super.getInetAddress() == null ||
    260                 super.getInetAddress().getHostAddress() == null ||
    261                 super.getInetAddress().getHostName() == null) {
    262             return null;
    263         }
    264         ClientSessionContext sessionContext
    265                 = sslParameters.getClientSessionContext();
    266         return (OpenSSLSessionImpl) sessionContext.getSession(
    267                 super.getInetAddress().getHostName(),
    268                 super.getPort());
    269     }
    270 
    271     /**
    272      * Ensures that logger is lazily loaded. The outer class seems to load
    273      * before logging is ready.
    274      */
    275     static class LoggerHolder {
    276         static final Logger logger = Logger.getLogger(
    277                 OpenSSLSocketImpl.class.getName());
    278     }
    279 
    280     /**
    281      * Starts a TLS/SSL handshake on this connection using some native methods
    282      * from the OpenSSL library. It can negotiate new encryption keys, change
    283      * cipher suites, or initiate a new session. The certificate chain is
    284      * verified if the correspondent property in java.Security is set. All
    285      * listensers are notified at the end of the TLS/SSL handshake.
    286      *
    287      * @throws <code>IOException</code> if network fails
    288      */
    289     public synchronized void startHandshake() throws IOException {
    290         synchronized (handshakeLock) {
    291             if (!handshakeStarted) {
    292                 handshakeStarted = true;
    293             } else {
    294                 return;
    295             }
    296         }
    297 
    298         OpenSSLSessionImpl session = getCachedClientSession();
    299 
    300         // Check if it's allowed to create a new session (default is true)
    301         if (session == null && !sslParameters.getEnableSessionCreation()) {
    302             throw new SSLHandshakeException("SSL Session may not be created");
    303         } else {
    304             // BEGIN android-added
    305             // Temporarily use a different timeout for the handshake process
    306             int savedTimeout = timeout;
    307             if (handshakeTimeout >= 0) {
    308                 setSoTimeout(handshakeTimeout);
    309             }
    310             // END android-added
    311 
    312             Socket socket = this.socket != null ? this.socket : this;
    313             int sessionId = session != null ? session.session : 0;
    314             boolean reusedSession;
    315             synchronized (OpenSSLSocketImpl.class) {
    316                 reusedSession = nativeconnect(ssl_ctx, socket,
    317                         sslParameters.getUseClientMode(), sessionId);
    318             }
    319             if (reusedSession) {
    320                 // nativeconnect shouldn't return true if the session is not
    321                 // done
    322                 session.lastAccessedTime = System.currentTimeMillis();
    323                 sslSession = session;
    324 
    325                 LoggerHolder.logger.fine("Reused cached session for "
    326                         + getInetAddress().getHostName() + ".");
    327             } else {
    328                 if (session != null) {
    329                     LoggerHolder.logger.fine("Reuse of cached session for "
    330                             + getInetAddress().getHostName() + " failed.");
    331                 } else {
    332                     LoggerHolder.logger.fine("Created new session for "
    333                             + getInetAddress().getHostName() + ".");
    334                 }
    335 
    336                 ClientSessionContext sessionContext
    337                         = sslParameters.getClientSessionContext();
    338                 synchronized (OpenSSLSocketImpl.class) {
    339                     sessionId = nativegetsslsession(ssl);
    340                 }
    341                 if (address == null) {
    342                     sslSession = new OpenSSLSessionImpl(
    343                             sessionId, sslParameters,
    344                             super.getInetAddress().getHostName(),
    345                             super.getPort(), sessionContext);
    346                 } else  {
    347                     sslSession = new OpenSSLSessionImpl(
    348                             sessionId, sslParameters,
    349                             address.getHostName(), address.getPort(),
    350                             sessionContext);
    351                 }
    352 
    353                 try {
    354                     X509Certificate[] peerCertificates = (X509Certificate[])
    355                             sslSession.getPeerCertificates();
    356 
    357                     if (peerCertificates == null
    358                             || peerCertificates.length == 0) {
    359                         throw new SSLException("Server sends no certificate");
    360                     }
    361 
    362                     String authMethod;
    363                     synchronized (OpenSSLSocketImpl.class) {
    364                         authMethod = nativecipherauthenticationmethod();
    365                     }
    366                     sslParameters.getTrustManager().checkServerTrusted(
    367                             peerCertificates,
    368                             authMethod);
    369                     sessionContext.putSession(sslSession);
    370                 } catch (CertificateException e) {
    371                     throw new SSLException("Not trusted server certificate", e);
    372                 }
    373             }
    374 
    375             // BEGIN android-added
    376             // Restore the original timeout now that the handshake is complete
    377             if (handshakeTimeout >= 0) {
    378                 setSoTimeout(savedTimeout);
    379             }
    380             // END android-added
    381         }
    382 
    383         if (listeners != null) {
    384             // notify the listeners
    385             HandshakeCompletedEvent event =
    386                 new HandshakeCompletedEvent(this, sslSession);
    387             int size = listeners.size();
    388             for (int i = 0; i < size; i++) {
    389                 listeners.get(i).handshakeCompleted(event);
    390             }
    391         }
    392     }
    393 
    394     // To be synchronized because of the verify_callback
    395     native synchronized void nativeaccept(Socket socketObject, int m_ctx, boolean client_mode);
    396 
    397     /**
    398      * Performs the first part of a SSL/TLS handshaking process with a given
    399      * 'host' connection and initializes the SSLSession.
    400      */
    401     protected void accept(int m_ctx, boolean client_mode) throws IOException {
    402         // Must be set because no handshaking is necessary
    403         // in this situation
    404         handshakeStarted = true;
    405 
    406         nativeaccept(this, m_ctx, client_mode);
    407 
    408         ServerSessionContext sessionContext
    409                 = sslParameters.getServerSessionContext();
    410         sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl),
    411                 sslParameters, super.getInetAddress().getHostName(),
    412                 super.getPort(), sessionContext);
    413         sslSession.lastAccessedTime = System.currentTimeMillis();
    414         sessionContext.putSession(sslSession);
    415     }
    416 
    417     /**
    418      * Callback methode for the OpenSSL native certificate verification process.
    419      *
    420      * @param bytes Byte array containing the cert's
    421      *            information.
    422      * @return 0 if the certificate verification fails or 1 if OK
    423      */
    424     @SuppressWarnings("unused")
    425     private int verify_callback(byte[][] bytes) {
    426         try {
    427             X509Certificate[] peerCertificateChain
    428                     = new X509Certificate[bytes.length];
    429             for(int i = 0; i < bytes.length; i++) {
    430                 peerCertificateChain[i] =
    431                     new X509CertImpl(javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded());
    432             }
    433 
    434             try {
    435                 // TODO "null" String
    436                 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain, "null");
    437             } catch (CertificateException e) {
    438                 throw new AlertException(AlertProtocol.BAD_CERTIFICATE,
    439                         new SSLException("Not trusted server certificate", e));
    440             }
    441         } catch (javax.security.cert.CertificateException e) {
    442             return 0;
    443         } catch (IOException e) {
    444             return 0;
    445         }
    446         return 1;
    447     }
    448 
    449     /**
    450      * Returns an input stream for this SSL socket using native calls to the
    451      * OpenSSL library.
    452      *
    453      * @return: an input stream for reading bytes from this socket.
    454      * @throws: <code>IOException</code> if an I/O error occurs when creating
    455      *          the input stream, the socket is closed, the socket is not
    456      *          connected, or the socket input has been shutdown.
    457      */
    458     public InputStream getInputStream() throws IOException {
    459         synchronized(this) {
    460             if (is == null) {
    461                 is = new SSLInputStream();
    462             }
    463 
    464             return is;
    465         }
    466     }
    467 
    468     /**
    469      * Returns an output stream for this SSL socket using native calls to the
    470      * OpenSSL library.
    471      *
    472      * @return an output stream for writing bytes to this socket.
    473      * @throws <code>IOException</code> if an I/O error occurs when creating
    474      *             the output stream, or no connection to the socket exists.
    475      */
    476     public OutputStream getOutputStream() throws IOException {
    477         synchronized(this) {
    478             if (os == null) {
    479                 os = new SSLOutputStream();
    480             }
    481 
    482             return os;
    483         }
    484     }
    485 
    486     /**
    487      * This method is not supported for this SSLSocket implementation.
    488      */
    489     public void shutdownInput() throws IOException {
    490         throw new UnsupportedOperationException(
    491         "Method shutdownInput() is not supported.");
    492     }
    493 
    494     /**
    495      * This method is not supported for this SSLSocket implementation.
    496      */
    497     public void shutdownOutput() throws IOException {
    498         throw new UnsupportedOperationException(
    499         "Method shutdownOutput() is not supported.");
    500     }
    501 
    502     /**
    503      * Reads with the native SSL_read function from the encrypted data stream
    504      * @return -1 if error or the end of the stream is reached.
    505      */
    506     private native int nativeread(int timeout) throws IOException;
    507     private native int nativeread(byte[] b, int off, int len, int timeout) throws IOException;
    508 
    509     /**
    510      * This inner class provides input data stream functionality
    511      * for the OpenSSL native implementation. It is used to
    512      * read data received via SSL protocol.
    513      */
    514     private class SSLInputStream extends InputStream {
    515         SSLInputStream() throws IOException {
    516             /**
    517             /* Note: When startHandshake() throws an exception, no
    518              * SSLInputStream object will be created.
    519              */
    520             OpenSSLSocketImpl.this.startHandshake();
    521         }
    522 
    523         /**
    524          * Reads one byte. If there is no data in the underlying buffer,
    525          * this operation can block until the data will be
    526          * available.
    527          * @return read value.
    528          * @throws <code>IOException</code>
    529          */
    530         public int read() throws IOException {
    531             synchronized(readLock) {
    532                 return OpenSSLSocketImpl.this.nativeread(timeout);
    533             }
    534         }
    535 
    536         /**
    537          * Method acts as described in spec for superclass.
    538          * @see java.io.InputStream#read(byte[],int,int)
    539          */
    540         public int read(byte[] b, int off, int len) throws IOException {
    541             synchronized(readLock) {
    542                 return OpenSSLSocketImpl.this.nativeread(b, off, len, timeout);
    543             }
    544         }
    545     }
    546 
    547     /**
    548      * Writes with the native SSL_write function to the encrypted data stream.
    549      */
    550     private native void nativewrite(int b) throws IOException;
    551     private native void nativewrite(byte[] b, int off, int len) throws IOException;
    552 
    553     /**
    554      * This inner class provides output data stream functionality
    555      * for the OpenSSL native implementation. It is used to
    556      * write data according to the encryption parameters given in SSL context.
    557      */
    558     private class SSLOutputStream extends OutputStream {
    559         SSLOutputStream() throws IOException {
    560             /**
    561             /* Note: When startHandshake() throws an exception, no
    562              * SSLInputStream object will be created.
    563              */
    564             OpenSSLSocketImpl.this.startHandshake();
    565         }
    566 
    567         /**
    568          * Method acts as described in spec for superclass.
    569          * @see java.io.OutputStream#write(int)
    570          */
    571         public void write(int b) throws IOException {
    572             synchronized(writeLock) {
    573                 OpenSSLSocketImpl.this.nativewrite(b);
    574             }
    575         }
    576 
    577         /**
    578          * Method acts as described in spec for superclass.
    579          * @see java.io.OutputStream#write(byte[],int,int)
    580          */
    581         public void write(byte[] b, int start, int len) throws IOException {
    582             synchronized(writeLock) {
    583                 OpenSSLSocketImpl.this.nativewrite(b, start, len);
    584             }
    585         }
    586     }
    587 
    588 
    589     /**
    590      * The SSL session used by this connection is returned. The SSL session
    591      * determines which cipher suite should be used by all connections within
    592      * that session and which identities have the session's client and server.
    593      * This method starts the SSL handshake.
    594      * @return the SSLSession.
    595      * @throws <code>IOException</code> if the handshake fails
    596      */
    597     public SSLSession getSession() {
    598         try {
    599             startHandshake();
    600         } catch (IOException e) {
    601             Logger.getLogger(getClass().getName()).log(Level.WARNING,
    602                     "Error negotiating SSL connection.", e);
    603 
    604             // return an invalid session with
    605             // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
    606             return SSLSessionImpl.NULL_SESSION;
    607         }
    608         return sslSession;
    609     }
    610 
    611     /**
    612      * Registers a listener to be notified that a SSL handshake
    613      * was successfully completed on this connection.
    614      * @throws <code>IllegalArgumentException</code> if listener is null.
    615      */
    616     public void addHandshakeCompletedListener(
    617             HandshakeCompletedListener listener) {
    618         if (listener == null) {
    619             throw new IllegalArgumentException("Provided listener is null");
    620         }
    621         if (listeners == null) {
    622             listeners = new ArrayList();
    623         }
    624         listeners.add(listener);
    625     }
    626 
    627     /**
    628      * The method removes a registered listener.
    629      * @throws IllegalArgumentException if listener is null or not registered
    630      */
    631     public void removeHandshakeCompletedListener(
    632             HandshakeCompletedListener listener) {
    633         if (listener == null) {
    634             throw new IllegalArgumentException("Provided listener is null");
    635         }
    636         if (listeners == null) {
    637             throw new IllegalArgumentException(
    638                     "Provided listener is not registered");
    639         }
    640         if (!listeners.remove(listener)) {
    641             throw new IllegalArgumentException(
    642                     "Provided listener is not registered");
    643         }
    644     }
    645 
    646     /**
    647      * Returns true if new SSL sessions may be established by this socket.
    648      *
    649      * @return true if the session may be created; false if a session already
    650      *         exists and must be resumed.
    651      */
    652     public boolean getEnableSessionCreation() {
    653         return sslParameters.getEnableSessionCreation();
    654     }
    655 
    656     /**
    657      * Set a flag for the socket to inhibit or to allow the creation of a new
    658      * SSL sessions. If the flag is set to false, and there are no actual
    659      * sessions to resume, then there will be no successful handshaking.
    660      *
    661      * @param flag true if session may be created; false
    662      *            if a session already exists and must be resumed.
    663      */
    664     public void setEnableSessionCreation(boolean flag) {
    665         sslParameters.setEnableSessionCreation(flag);
    666     }
    667 
    668     /**
    669      * Gets all available ciphers from the current OpenSSL library.
    670      * Needed by OpenSSLSocketFactory too.
    671      */
    672     static native String[] nativegetsupportedciphersuites();
    673 
    674     /**
    675      * The names of the cipher suites which could be used by the SSL connection
    676      * are returned.
    677      * @return an array of cipher suite names
    678      */
    679     public String[] getSupportedCipherSuites() {
    680         return nativegetsupportedciphersuites();
    681     }
    682 
    683     static native String[] nativeGetEnabledCipherSuites(int ssl_ctx);
    684 
    685     /**
    686      * The names of the cipher suites that are in use in the actual the SSL
    687      * connection are returned.
    688      *
    689      * @return an array of cipher suite names
    690      */
    691     public String[] getEnabledCipherSuites() {
    692         return nativeGetEnabledCipherSuites(ssl_ctx);
    693     }
    694 
    695     /**
    696      * Calls the SSL_CTX_set_cipher_list(...) OpenSSL function with the passed
    697      * char array.
    698      */
    699     static native void nativeSetEnabledCipherSuites(int ssl_ctx, String controlString);
    700 
    701     private static boolean findSuite(String suite) {
    702         String[] supportedCipherSuites = nativegetsupportedciphersuites();
    703         for(int i = 0; i < supportedCipherSuites.length; i++) {
    704             if (supportedCipherSuites[i].equals(suite)) {
    705                 return true;
    706             }
    707         }
    708         throw new IllegalArgumentException("Protocol " + suite + " is not supported.");
    709     }
    710 
    711     /**
    712      * This method enables the cipher suites listed by
    713      * getSupportedCipherSuites().
    714      *
    715      * @param suites names of all the cipher suites to
    716      *            put on use
    717      * @throws IllegalArgumentException when one or more of the
    718      *             ciphers in array suites are not supported, or when the array
    719      *             is null.
    720      */
    721     public void setEnabledCipherSuites(String[] suites) {
    722         setEnabledCipherSuites(ssl_ctx, suites);
    723     }
    724 
    725     static void setEnabledCipherSuites(int ssl_ctx, String[] suites) {
    726         if (suites == null) {
    727             throw new IllegalArgumentException("Provided parameter is null");
    728         }
    729         String controlString = "";
    730         for (int i = 0; i < suites.length; i++) {
    731             findSuite(suites[i]);
    732             if (i == 0) controlString = suites[i];
    733             else controlString += ":" + suites[i];
    734         }
    735         nativeSetEnabledCipherSuites(ssl_ctx, controlString);
    736     }
    737 
    738     /**
    739      * The names of the protocols' versions that may be used on this SSL
    740      * connection.
    741      * @return an array of protocols names
    742      */
    743     public String[] getSupportedProtocols() {
    744         return supportedProtocols.clone();
    745     }
    746 
    747     /**
    748      * SSL mode of operation with or without back compatibility. See the OpenSSL
    749      * ssl.h header file for more information.
    750      */
    751     static private long SSL_OP_NO_SSLv3 = 0x02000000L;
    752     static private long SSL_OP_NO_TLSv1 = 0x04000000L;
    753 
    754     /**
    755      * The names of the protocols' versions that are in use on this SSL
    756      * connection.
    757      *
    758      * @return an array of protocols names
    759      */
    760     @Override
    761     public String[] getEnabledProtocols() {
    762         ArrayList<String> array = new ArrayList<String>();
    763 
    764         if ((ssl_op_no & SSL_OP_NO_SSLv3) == 0x00000000L) {
    765             array.add(supportedProtocols[1]);
    766         }
    767         if ((ssl_op_no & SSL_OP_NO_TLSv1) == 0x00000000L) {
    768             array.add(supportedProtocols[2]);
    769         }
    770         return array.toArray(new String[array.size()]);
    771     }
    772 
    773     private native void nativesetenabledprotocols(long l);
    774 
    775     /**
    776      * This method enables the protocols' versions listed by
    777      * getSupportedProtocols().
    778      *
    779      * @param protocols The names of all the protocols to put on use
    780      *
    781      * @throws IllegalArgumentException when one or more of the names in the
    782      *             array are not supported, or when the array is null.
    783      */
    784     @Override
    785     public synchronized void setEnabledProtocols(String[] protocols) {
    786 
    787         if (protocols == null) {
    788             throw new IllegalArgumentException("Provided parameter is null");
    789         }
    790 
    791         ssl_op_no  = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
    792 
    793         for(int i = 0; i < protocols.length; i++) {
    794             if (protocols[i].equals("SSLv3"))
    795                 ssl_op_no ^= SSL_OP_NO_SSLv3;
    796             else if (protocols[i].equals("TLSv1"))
    797                 ssl_op_no ^= SSL_OP_NO_TLSv1;
    798             else throw new IllegalArgumentException("Protocol " + protocols[i] +
    799             " is not supported.");
    800         }
    801 
    802         nativesetenabledprotocols(ssl_op_no);
    803     }
    804 
    805     /**
    806      * This method gives true back if the SSL socket is set to client mode.
    807      *
    808      * @return true if the socket should do the handshaking as client.
    809      */
    810     public boolean getUseClientMode() {
    811         return sslParameters.getUseClientMode();
    812     }
    813 
    814     /**
    815      * This method set the actual SSL socket to client mode.
    816      *
    817      * @param mode true if the socket starts in client
    818      *            mode
    819      * @throws IllegalArgumentException if mode changes during
    820      *             handshake.
    821      */
    822     public synchronized void setUseClientMode(boolean mode) {
    823         if (handshakeStarted) {
    824             throw new IllegalArgumentException(
    825             "Could not change the mode after the initial handshake has begun.");
    826         }
    827         sslParameters.setUseClientMode(mode);
    828     }
    829 
    830     /**
    831      * Returns true if the SSL socket requests client's authentication. Relevant
    832      * only for server sockets!
    833      *
    834      * @return true if client authentication is desired, false if not.
    835      */
    836     public boolean getWantClientAuth() {
    837         return sslParameters.getWantClientAuth();
    838     }
    839 
    840     /**
    841      * Returns true if the SSL socket needs client's authentication. Relevant
    842      * only for server sockets!
    843      *
    844      * @return true if client authentication is desired, false if not.
    845      */
    846     public boolean getNeedClientAuth() {
    847         return sslParameters.getNeedClientAuth();
    848     }
    849 
    850     /**
    851      * Sets the SSL socket to use client's authentication. Relevant only for
    852      * server sockets!
    853      *
    854      * @param need true if client authentication is
    855      *            desired, false if not.
    856      */
    857     public void setNeedClientAuth(boolean need) {
    858         sslParameters.setNeedClientAuth(need);
    859     }
    860 
    861     /**
    862      * Sets the SSL socket to use client's authentication. Relevant only for
    863      * server sockets! Notice that in contrast to setNeedClientAuth(..) this
    864      * method will continue the negotiation if the client decide not to send
    865      * authentication credentials.
    866      *
    867      * @param want true if client authentication is
    868      *            desired, false if not.
    869      */
    870     public void setWantClientAuth(boolean want) {
    871         sslParameters.setWantClientAuth(want);
    872     }
    873 
    874     /**
    875      * This method is not supported for SSLSocket implementation.
    876      */
    877     public void sendUrgentData(int data) throws IOException {
    878         throw new SocketException(
    879                 "Method sendUrgentData() is not supported.");
    880     }
    881 
    882     /**
    883      * This method is not supported for SSLSocket implementation.
    884      */
    885     public void setOOBInline(boolean on) throws SocketException {
    886         throw new SocketException(
    887                 "Methods sendUrgentData, setOOBInline are not supported.");
    888     }
    889 
    890     /**
    891      * Set the read timeout on this socket. The SO_TIMEOUT option, is specified
    892      * in milliseconds. The read operation will block indefinitely for a zero
    893      * value.
    894      *
    895      * @param timeout the read timeout value
    896      * @throws SocketException if an error occurs setting the option
    897      */
    898     public synchronized void setSoTimeout(int timeout) throws SocketException {
    899         super.setSoTimeout(timeout);
    900         this.timeout = timeout;
    901     }
    902 
    903     // BEGIN android-added
    904     /**
    905      * Set the handshake timeout on this socket.  This timeout is specified in
    906      * milliseconds and will be used only during the handshake process.
    907      *
    908      * @param timeout the handshake timeout value
    909      */
    910     public synchronized void setHandshakeTimeout(int timeout) throws SocketException {
    911         this.handshakeTimeout = timeout;
    912     }
    913     // END android-added
    914 
    915     private native void nativeinterrupt() throws IOException;
    916     private native void nativeclose() throws IOException;
    917 
    918     /**
    919      * Closes the SSL socket. Once closed, a socket is not available for further
    920      * use anymore under any circumstance. A new socket must be created.
    921      *
    922      * @throws <code>IOException</code> if an I/O error happens during the
    923      *             socket's closure.
    924      */
    925     public void close() throws IOException {
    926         // TODO: Close SSL sockets using a background thread so they close
    927         // gracefully.
    928 
    929         synchronized (handshakeLock) {
    930             if (!handshakeStarted) {
    931                 handshakeStarted = true;
    932 
    933                 synchronized (this) {
    934                     nativefree();
    935 
    936                     if (socket != null) {
    937                         if (autoClose && !socket.isClosed()) socket.close();
    938                     } else {
    939                         if (!super.isClosed()) super.close();
    940                     }
    941                 }
    942 
    943                 return;
    944             }
    945         }
    946 
    947         nativeinterrupt();
    948 
    949         synchronized (this) {
    950             synchronized (writeLock) {
    951                 synchronized (readLock) {
    952 
    953                     IOException pendingException = null;
    954 
    955                     // Shut down the SSL connection, per se.
    956                     try {
    957                         if (handshakeStarted) {
    958                             nativeclose();
    959                         }
    960                     } catch (IOException ex) {
    961                         /*
    962                          * Note the exception at this point, but try to continue
    963                          * to clean the rest of this all up before rethrowing.
    964                          */
    965                         pendingException = ex;
    966                     }
    967 
    968                     /*
    969                      * Even if the above call failed, it is still safe to free
    970                      * the native structs, and we need to do so lest we leak
    971                      * memory.
    972                      */
    973                     nativefree();
    974 
    975                     if (socket != null) {
    976                         if (autoClose && !socket.isClosed())
    977                             socket.close();
    978                     } else {
    979                         if (!super.isClosed())
    980                             super.close();
    981                     }
    982 
    983                     if (pendingException != null) {
    984                         throw pendingException;
    985                     }
    986                 }
    987             }
    988         }
    989     }
    990 
    991     private native void nativefree();
    992 
    993     protected void finalize() throws IOException {
    994         /*
    995          * Just worry about our own state. Notably we do not try and
    996          * close anything. The SocketImpl, either our own
    997          * PlainSocketImpl, or the Socket we are wrapping, will do
    998          * that. This might mean we do not properly SSL_shutdown, but
    999          * if you want to do that, properly close the socket yourself.
   1000          *
   1001          * The reason why we don't try to SSL_shutdown is that there
   1002          * can be a race between finalizers where the PlainSocketImpl
   1003          * finalizer runs first and closes the socket. However, in the
   1004          * meanwhile, the underlying file descriptor could be reused
   1005          * for another purpose. If we call SSL_shutdown after that, the
   1006          * underlying socket BIOs still have the older file descriptor
   1007          * and will write the close notify to some unsuspecting
   1008          * reader.
   1009          */
   1010         updateInstanceCount(-1);
   1011         if (ssl == 0) {
   1012             return;
   1013         }
   1014         nativefree();
   1015     }
   1016 
   1017     /**
   1018      * Verifies an RSA signature. Conceptually, this method doesn't really
   1019      * belong here, but due to its native code being closely tied to OpenSSL
   1020      * (just like the rest of this class), we put it here for the time being.
   1021      * This also solves potential problems with native library initialization.
   1022      *
   1023      * @param message The message to verify
   1024      * @param signature The signature to verify
   1025      * @param algorithm The hash/sign algorithm to use, i.e. "RSA-SHA1"
   1026      * @param key The RSA public key to use
   1027      * @return true if the verification succeeds, false otherwise
   1028      */
   1029     public static boolean verifySignature(byte[] message, byte[] signature, String algorithm, RSAPublicKey key) {
   1030         byte[] modulus = key.getModulus().toByteArray();
   1031         byte[] exponent = key.getPublicExponent().toByteArray();
   1032 
   1033         return nativeverifysignature(message, signature, algorithm, modulus, exponent) == 1;
   1034     }
   1035 
   1036     private static native int nativeverifysignature(byte[] message, byte[] signature,
   1037             String algorithm, byte[] modulus, byte[] exponent);
   1038 }
   1039