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
17package org.conscrypt;
18
19import org.conscrypt.util.Arrays;
20import dalvik.system.BlockGuard;
21import dalvik.system.CloseGuard;
22import java.io.FileDescriptor;
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.OutputStream;
26import java.net.InetAddress;
27import java.net.Socket;
28import java.net.SocketException;
29import java.security.InvalidKeyException;
30import java.security.PrivateKey;
31import java.security.SecureRandom;
32import java.security.cert.CertificateEncodingException;
33import java.security.cert.CertificateException;
34import java.util.ArrayList;
35import javax.crypto.SecretKey;
36import javax.net.ssl.HandshakeCompletedEvent;
37import javax.net.ssl.HandshakeCompletedListener;
38import javax.net.ssl.SSLException;
39import javax.net.ssl.SSLHandshakeException;
40import javax.net.ssl.SSLParameters;
41import javax.net.ssl.SSLProtocolException;
42import javax.net.ssl.SSLSession;
43import javax.net.ssl.X509KeyManager;
44import javax.net.ssl.X509TrustManager;
45import javax.security.auth.x500.X500Principal;
46
47/**
48 * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
49 * <p>
50 * Extensions to SSLSocket include:
51 * <ul>
52 * <li>handshake timeout
53 * <li>session tickets
54 * <li>Server Name Indication
55 * </ul>
56 */
57public class OpenSSLSocketImpl
58        extends javax.net.ssl.SSLSocket
59        implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser,
60        SSLParametersImpl.PSKCallbacks {
61
62    private static final boolean DBG_STATE = false;
63
64    /**
65     * Protects handshakeStarted and handshakeCompleted.
66     */
67    private final Object stateLock = new Object();
68
69    /**
70     * The {@link OpenSSLSocketImpl} object is constructed, but {@link #startHandshake()}
71     * has not yet been called.
72     */
73    private static final int STATE_NEW = 0;
74
75    /**
76     * {@link #startHandshake()} has been called at least once.
77     */
78    private static final int STATE_HANDSHAKE_STARTED = 1;
79
80    /**
81     * {@link #handshakeCompleted()} has been called, but {@link #startHandshake()} hasn't
82     * returned yet.
83     */
84    private static final int STATE_HANDSHAKE_COMPLETED = 2;
85
86    /**
87     * {@link #startHandshake()} has completed but {@link #handshakeCompleted()} hasn't
88     * been called. This is expected behaviour in cut-through mode, where SSL_do_handshake
89     * returns before the handshake is complete. We can now start writing data to the socket.
90     */
91    private static final int STATE_READY_HANDSHAKE_CUT_THROUGH = 3;
92
93    /**
94     * {@link #startHandshake()} has completed and {@link #handshakeCompleted()} has been
95     * called.
96     */
97    private static final int STATE_READY = 4;
98
99    /**
100     * {@link #close()} has been called at least once.
101     */
102    private static final int STATE_CLOSED = 5;
103
104    // @GuardedBy("stateLock");
105    private int state = STATE_NEW;
106
107    /**
108     * Protected by synchronizing on stateLock. Starts as 0, set by
109     * startHandshake, reset to 0 on close.
110     */
111    // @GuardedBy("stateLock");
112    private long sslNativePointer;
113
114    /**
115     * Protected by synchronizing on stateLock. Starts as null, set by
116     * getInputStream.
117     */
118    // @GuardedBy("stateLock");
119    private SSLInputStream is;
120
121    /**
122     * Protected by synchronizing on stateLock. Starts as null, set by
123     * getInputStream.
124     */
125    // @GuardedBy("stateLock");
126    private SSLOutputStream os;
127
128    private final Socket socket;
129    private final boolean autoClose;
130    private String wrappedHost;
131    private final int wrappedPort;
132    private final SSLParametersImpl sslParameters;
133    private final CloseGuard guard = CloseGuard.get();
134
135    private ArrayList<HandshakeCompletedListener> listeners;
136
137    /**
138     * Private key for the TLS Channel ID extension. This field is client-side
139     * only. Set during startHandshake.
140     */
141    OpenSSLKey channelIdPrivateKey;
142
143    /** Set during startHandshake. */
144    private OpenSSLSessionImpl sslSession;
145
146    /** Used during handshake callbacks. */
147    private OpenSSLSessionImpl handshakeSession;
148
149    /**
150     * Local cache of timeout to avoid getsockopt on every read and
151     * write for non-wrapped sockets. Note that
152     * OpenSSLSocketImplWrapper overrides setSoTimeout and
153     * getSoTimeout to delegate to the wrapped socket.
154     */
155    private int readTimeoutMilliseconds = 0;
156    private int writeTimeoutMilliseconds = 0;
157
158    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
159
160    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
161        this.socket = this;
162        this.wrappedHost = null;
163        this.wrappedPort = -1;
164        this.autoClose = false;
165        this.sslParameters = sslParameters;
166    }
167
168    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
169            throws IOException {
170        super(host, port);
171        this.socket = this;
172        this.wrappedHost = null;
173        this.wrappedPort = -1;
174        this.autoClose = false;
175        this.sslParameters = sslParameters;
176    }
177
178    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
179            throws IOException {
180        super(address, port);
181        this.socket = this;
182        this.wrappedHost = null;
183        this.wrappedPort = -1;
184        this.autoClose = false;
185        this.sslParameters = sslParameters;
186    }
187
188
189    protected OpenSSLSocketImpl(String host, int port,
190                                InetAddress clientAddress, int clientPort,
191                                SSLParametersImpl sslParameters) throws IOException {
192        super(host, port, clientAddress, clientPort);
193        this.socket = this;
194        this.wrappedHost = null;
195        this.wrappedPort = -1;
196        this.autoClose = false;
197        this.sslParameters = sslParameters;
198    }
199
200    protected OpenSSLSocketImpl(InetAddress address, int port,
201                                InetAddress clientAddress, int clientPort,
202                                SSLParametersImpl sslParameters) throws IOException {
203        super(address, port, clientAddress, clientPort);
204        this.socket = this;
205        this.wrappedHost = null;
206        this.wrappedPort = -1;
207        this.autoClose = false;
208        this.sslParameters = sslParameters;
209    }
210
211    /**
212     * Create an SSL socket that wraps another socket. Invoked by
213     * OpenSSLSocketImplWrapper constructor.
214     */
215    protected OpenSSLSocketImpl(Socket socket, String host, int port,
216            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
217        this.socket = socket;
218        this.wrappedHost = host;
219        this.wrappedPort = port;
220        this.autoClose = autoClose;
221        this.sslParameters = sslParameters;
222
223        // this.timeout is not set intentionally.
224        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
225        // to wrapped socket
226    }
227
228    private void checkOpen() throws SocketException {
229        if (isClosed()) {
230            throw new SocketException("Socket is closed");
231        }
232    }
233
234    /**
235     * Starts a TLS/SSL handshake on this connection using some native methods
236     * from the OpenSSL library. It can negotiate new encryption keys, change
237     * cipher suites, or initiate a new session. The certificate chain is
238     * verified if the correspondent property in java.Security is set. All
239     * listeners are notified at the end of the TLS/SSL handshake.
240     */
241    @Override
242    public void startHandshake() throws IOException {
243        checkOpen();
244        synchronized (stateLock) {
245            if (state == STATE_NEW) {
246                state = STATE_HANDSHAKE_STARTED;
247            } else {
248                // We've either started the handshake already or have been closed.
249                // Do nothing in both cases.
250                return;
251            }
252        }
253
254        // note that this modifies the global seed, not something specific to the connection
255        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
256        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
257        if (secureRandom == null) {
258            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
259        } else {
260            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
261        }
262
263        final boolean client = sslParameters.getUseClientMode();
264
265        sslNativePointer = 0;
266        boolean releaseResources = true;
267        try {
268            final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
269            final long sslCtxNativePointer = sessionContext.sslCtxNativePointer;
270            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
271            guard.open("close");
272
273            boolean enableSessionCreation = getEnableSessionCreation();
274            if (!enableSessionCreation) {
275                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
276                        enableSessionCreation);
277            }
278
279            final OpenSSLSessionImpl sessionToReuse = sslParameters.getSessionToReuse(
280                    sslNativePointer, getPeerHostName(), getPeerPort());
281            sslParameters.setSSLParameters(sslCtxNativePointer, sslNativePointer, this, this,
282                    getPeerHostName());
283            sslParameters.setCertificateValidation(sslNativePointer);
284            sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
285
286            // Temporarily use a different timeout for the handshake process
287            int savedReadTimeoutMilliseconds = getSoTimeout();
288            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
289            if (handshakeTimeoutMilliseconds >= 0) {
290                setSoTimeout(handshakeTimeoutMilliseconds);
291                setSoWriteTimeout(handshakeTimeoutMilliseconds);
292            }
293
294            synchronized (stateLock) {
295                if (state == STATE_CLOSED) {
296                    return;
297                }
298            }
299
300            long sslSessionNativePointer;
301            try {
302                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
303                        Platform.getFileDescriptor(socket), this, getSoTimeout(), client,
304                        sslParameters.npnProtocols, client ? null : sslParameters.alpnProtocols);
305            } catch (CertificateException e) {
306                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
307                wrapper.initCause(e);
308                throw wrapper;
309            } catch (SSLException e) {
310                // Swallow this exception if it's thrown as the result of an interruption.
311                //
312                // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake
313                // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ
314                // (or WANT_WRITE). Catching that exception here doesn't seem much worse than
315                // changing the native code to return a "special" native pointer value when that
316                // happens.
317                synchronized (stateLock) {
318                    if (state == STATE_CLOSED) {
319                        return;
320                    }
321                }
322
323                // Write CCS errors to EventLog
324                String message = e.getMessage();
325                // Must match error string of SSL_R_UNEXPECTED_CCS
326                if (message.contains("unexpected CCS")) {
327                    String logMessage = String.format("ssl_unexpected_ccs: host=%s",
328                            getPeerHostName());
329                    Platform.logEvent(logMessage);
330                }
331
332                throw e;
333            }
334
335            boolean handshakeCompleted = false;
336            synchronized (stateLock) {
337                if (state == STATE_HANDSHAKE_COMPLETED) {
338                    handshakeCompleted = true;
339                } else if (state == STATE_CLOSED) {
340                    return;
341                }
342            }
343
344            sslSession = sslParameters.setupSession(sslSessionNativePointer, sslNativePointer,
345                    sessionToReuse, getPeerHostName(), getPeerPort(), handshakeCompleted);
346
347            // Restore the original timeout now that the handshake is complete
348            if (handshakeTimeoutMilliseconds >= 0) {
349                setSoTimeout(savedReadTimeoutMilliseconds);
350                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
351            }
352
353            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
354            if (handshakeCompleted) {
355                notifyHandshakeCompletedListeners();
356            }
357
358            synchronized (stateLock) {
359                releaseResources = (state == STATE_CLOSED);
360
361                if (state == STATE_HANDSHAKE_STARTED) {
362                    state = STATE_READY_HANDSHAKE_CUT_THROUGH;
363                } else if (state == STATE_HANDSHAKE_COMPLETED) {
364                    state = STATE_READY;
365                }
366
367                if (!releaseResources) {
368                    // Unblock threads that are waiting for our state to transition
369                    // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
370                    stateLock.notifyAll();
371                }
372            }
373        } catch (SSLProtocolException e) {
374            throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed")
375                    .initCause(e);
376        } finally {
377            // on exceptional exit, treat the socket as closed
378            if (releaseResources) {
379                synchronized (stateLock) {
380                    // Mark the socket as closed since we might have reached this as
381                    // a result on an exception thrown by the handshake process.
382                    //
383                    // The state will already be set to closed if we reach this as a result of
384                    // an early return or an interruption due to a concurrent call to close().
385                    state = STATE_CLOSED;
386                    stateLock.notifyAll();
387                }
388
389                try {
390                    shutdownAndFreeSslNative();
391                } catch (IOException ignored) {
392
393                }
394            }
395        }
396    }
397
398    String getPeerHostName() {
399        if (wrappedHost != null) {
400            return wrappedHost;
401        }
402        InetAddress inetAddress = super.getInetAddress();
403        if (inetAddress != null) {
404            return inetAddress.getHostName();
405        }
406        return null;
407    }
408
409    int getPeerPort() {
410        return wrappedHost == null ? super.getPort() : wrappedPort;
411    }
412
413    @Override
414    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
415    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
416            throws CertificateEncodingException, SSLException {
417        sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals,
418                sslNativePointer, this);
419    }
420
421    @Override
422    @SuppressWarnings("unused") // used by native psk_client_callback
423    public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
424        return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
425    }
426
427    @Override
428    @SuppressWarnings("unused") // used by native psk_server_callback
429    public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
430        return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
431    }
432
433    @Override
434    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
435    public void onSSLStateChange(long sslSessionNativePtr, int type, int val) {
436        if (type != NativeCrypto.SSL_CB_HANDSHAKE_DONE) {
437            return;
438        }
439
440        synchronized (stateLock) {
441            if (state == STATE_HANDSHAKE_STARTED) {
442                // If sslSession is null, the handshake was completed during
443                // the call to NativeCrypto.SSL_do_handshake and not during a
444                // later read operation. That means we do not need to fix up
445                // the SSLSession and session cache or notify
446                // HandshakeCompletedListeners, it will be done in
447                // startHandshake.
448
449                state = STATE_HANDSHAKE_COMPLETED;
450                return;
451            } else if (state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
452                // We've returned from startHandshake, which means we've set a sslSession etc.
453                // we need to fix them up, which we'll do outside this lock.
454            } else if (state == STATE_CLOSED) {
455                // Someone called "close" but the handshake hasn't been interrupted yet.
456                return;
457            }
458        }
459
460        // reset session id from the native pointer and update the
461        // appropriate cache.
462        sslSession.resetId();
463        AbstractSessionContext sessionContext =
464            (sslParameters.getUseClientMode())
465            ? sslParameters.getClientSessionContext()
466                : sslParameters.getServerSessionContext();
467        sessionContext.putSession(sslSession);
468
469        // let listeners know we are finally done
470        notifyHandshakeCompletedListeners();
471
472        synchronized (stateLock) {
473            // Now that we've fixed up our state, we can tell waiting threads that
474            // we're ready.
475            state = STATE_READY;
476            // Notify all threads waiting for the handshake to complete.
477            stateLock.notifyAll();
478        }
479    }
480
481    private void notifyHandshakeCompletedListeners() {
482        if (listeners != null && !listeners.isEmpty()) {
483            // notify the listeners
484            HandshakeCompletedEvent event =
485                new HandshakeCompletedEvent(this, sslSession);
486            for (HandshakeCompletedListener listener : listeners) {
487                try {
488                    listener.handshakeCompleted(event);
489                } catch (RuntimeException e) {
490                    // The RI runs the handlers in a separate thread,
491                    // which we do not. But we try to preserve their
492                    // behavior of logging a problem and not killing
493                    // the handshaking thread just because a listener
494                    // has a problem.
495                    Thread thread = Thread.currentThread();
496                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
497                }
498            }
499        }
500    }
501
502    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
503    @Override
504    public void verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)
505            throws CertificateException {
506        try {
507            X509TrustManager x509tm = sslParameters.getX509TrustManager();
508            if (x509tm == null) {
509                throw new CertificateException("No X.509 TrustManager");
510            }
511            if (certRefs == null || certRefs.length == 0) {
512                throw new SSLException("Peer sent no certificate");
513            }
514            OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length];
515            for (int i = 0; i < certRefs.length; i++) {
516                peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]);
517            }
518
519            // Used for verifyCertificateChain callback
520            handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain,
521                    getPeerHostName(), getPeerPort(), null);
522
523            boolean client = sslParameters.getUseClientMode();
524            if (client) {
525                Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, getPeerHostName());
526            } else {
527                String authType = peerCertChain[0].getPublicKey().getAlgorithm();
528                x509tm.checkClientTrusted(peerCertChain, authType);
529            }
530        } catch (CertificateException e) {
531            throw e;
532        } catch (Exception e) {
533            throw new CertificateException(e);
534        } finally {
535            // Clear this before notifying handshake completed listeners
536            handshakeSession = null;
537        }
538    }
539
540    @Override
541    public InputStream getInputStream() throws IOException {
542        checkOpen();
543
544        InputStream returnVal;
545        synchronized (stateLock) {
546            if (state == STATE_CLOSED) {
547                throw new SocketException("Socket is closed.");
548            }
549
550            if (is == null) {
551                is = new SSLInputStream();
552            }
553
554            returnVal = is;
555        }
556
557        // Block waiting for a handshake without a lock held. It's possible that the socket
558        // is closed at this point. If that happens, we'll still return the input stream but
559        // all reads on it will throw.
560        waitForHandshake();
561        return returnVal;
562    }
563
564    @Override
565    public OutputStream getOutputStream() throws IOException {
566        checkOpen();
567
568        OutputStream returnVal;
569        synchronized (stateLock) {
570            if (state == STATE_CLOSED) {
571                throw new SocketException("Socket is closed.");
572            }
573
574            if (os == null) {
575                os = new SSLOutputStream();
576            }
577
578            returnVal = os;
579        }
580
581        // Block waiting for a handshake without a lock held. It's possible that the socket
582        // is closed at this point. If that happens, we'll still return the output stream but
583        // all writes on it will throw.
584        waitForHandshake();
585        return returnVal;
586    }
587
588    private void assertReadableOrWriteableState() {
589        if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
590            return;
591        }
592
593        throw new AssertionError("Invalid state: " + state);
594    }
595
596
597    private void waitForHandshake() throws IOException {
598        startHandshake();
599
600        synchronized (stateLock) {
601            while (state != STATE_READY &&
602                    state != STATE_READY_HANDSHAKE_CUT_THROUGH &&
603                    state != STATE_CLOSED) {
604                try {
605                    stateLock.wait();
606                } catch (InterruptedException e) {
607                    Thread.currentThread().interrupt();
608                    IOException ioe = new IOException("Interrupted waiting for handshake");
609                    ioe.initCause(e);
610
611                    throw ioe;
612                }
613            }
614
615            if (state == STATE_CLOSED) {
616                throw new SocketException("Socket is closed");
617            }
618        }
619    }
620
621    /**
622     * This inner class provides input data stream functionality
623     * for the OpenSSL native implementation. It is used to
624     * read data received via SSL protocol.
625     */
626    private class SSLInputStream extends InputStream {
627        /**
628         * OpenSSL only lets one thread read at a time, so this is used to
629         * make sure we serialize callers of SSL_read. Thread is already
630         * expected to have completed handshaking.
631         */
632        private final Object readLock = new Object();
633
634        SSLInputStream() {
635        }
636
637        /**
638         * Reads one byte. If there is no data in the underlying buffer,
639         * this operation can block until the data will be
640         * available.
641         * @return read value.
642         * @throws IOException
643         */
644        @Override
645        public int read() throws IOException {
646            byte[] buffer = new byte[1];
647            int result = read(buffer, 0, 1);
648            return (result != -1) ? buffer[0] & 0xff : -1;
649        }
650
651        /**
652         * Method acts as described in spec for superclass.
653         * @see java.io.InputStream#read(byte[],int,int)
654         */
655        @Override
656        public int read(byte[] buf, int offset, int byteCount) throws IOException {
657            BlockGuard.getThreadPolicy().onNetwork();
658
659            checkOpen();
660            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
661            if (byteCount == 0) {
662                return 0;
663            }
664
665            synchronized (readLock) {
666                synchronized (stateLock) {
667                    if (state == STATE_CLOSED) {
668                        throw new SocketException("socket is closed");
669                    }
670
671                    if (DBG_STATE) assertReadableOrWriteableState();
672                }
673
674                return NativeCrypto.SSL_read(sslNativePointer, Platform.getFileDescriptor(socket),
675                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
676            }
677        }
678
679        public void awaitPendingOps() {
680            if (DBG_STATE) {
681                synchronized (stateLock) {
682                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
683                }
684            }
685
686            synchronized (readLock) { }
687        }
688    }
689
690    /**
691     * This inner class provides output data stream functionality
692     * for the OpenSSL native implementation. It is used to
693     * write data according to the encryption parameters given in SSL context.
694     */
695    private class SSLOutputStream extends OutputStream {
696
697        /**
698         * OpenSSL only lets one thread write at a time, so this is used
699         * to make sure we serialize callers of SSL_write. Thread is
700         * already expected to have completed handshaking.
701         */
702        private final Object writeLock = new Object();
703
704        SSLOutputStream() {
705        }
706
707        /**
708         * Method acts as described in spec for superclass.
709         * @see java.io.OutputStream#write(int)
710         */
711        @Override
712        public void write(int oneByte) throws IOException {
713            byte[] buffer = new byte[1];
714            buffer[0] = (byte) (oneByte & 0xff);
715            write(buffer);
716        }
717
718        /**
719         * Method acts as described in spec for superclass.
720         * @see java.io.OutputStream#write(byte[],int,int)
721         */
722        @Override
723        public void write(byte[] buf, int offset, int byteCount) throws IOException {
724            BlockGuard.getThreadPolicy().onNetwork();
725            checkOpen();
726            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
727            if (byteCount == 0) {
728                return;
729            }
730
731            synchronized (writeLock) {
732                synchronized (stateLock) {
733                    if (state == STATE_CLOSED) {
734                        throw new SocketException("socket is closed");
735                    }
736
737                    if (DBG_STATE) assertReadableOrWriteableState();
738                }
739
740                NativeCrypto.SSL_write(sslNativePointer, Platform.getFileDescriptor(socket),
741                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
742            }
743        }
744
745
746        public void awaitPendingOps() {
747            if (DBG_STATE) {
748                synchronized (stateLock) {
749                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
750                }
751            }
752
753            synchronized (writeLock) { }
754        }
755    }
756
757
758    @Override
759    public SSLSession getSession() {
760        if (sslSession == null) {
761            try {
762                waitForHandshake();
763            } catch (IOException e) {
764                // return an invalid session with
765                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
766                return SSLNullSession.getNullSession();
767            }
768        }
769        return sslSession;
770    }
771
772    @Override
773    public void addHandshakeCompletedListener(
774            HandshakeCompletedListener listener) {
775        if (listener == null) {
776            throw new IllegalArgumentException("Provided listener is null");
777        }
778        if (listeners == null) {
779            listeners = new ArrayList<HandshakeCompletedListener>();
780        }
781        listeners.add(listener);
782    }
783
784    @Override
785    public void removeHandshakeCompletedListener(
786            HandshakeCompletedListener listener) {
787        if (listener == null) {
788            throw new IllegalArgumentException("Provided listener is null");
789        }
790        if (listeners == null) {
791            throw new IllegalArgumentException(
792                    "Provided listener is not registered");
793        }
794        if (!listeners.remove(listener)) {
795            throw new IllegalArgumentException(
796                    "Provided listener is not registered");
797        }
798    }
799
800    @Override
801    public boolean getEnableSessionCreation() {
802        return sslParameters.getEnableSessionCreation();
803    }
804
805    @Override
806    public void setEnableSessionCreation(boolean flag) {
807        sslParameters.setEnableSessionCreation(flag);
808    }
809
810    @Override
811    public String[] getSupportedCipherSuites() {
812        return NativeCrypto.getSupportedCipherSuites();
813    }
814
815    @Override
816    public String[] getEnabledCipherSuites() {
817        return sslParameters.getEnabledCipherSuites();
818    }
819
820    @Override
821    public void setEnabledCipherSuites(String[] suites) {
822        sslParameters.setEnabledCipherSuites(suites);
823    }
824
825    @Override
826    public String[] getSupportedProtocols() {
827        return NativeCrypto.getSupportedProtocols();
828    }
829
830    @Override
831    public String[] getEnabledProtocols() {
832        return sslParameters.getEnabledProtocols();
833    }
834
835    @Override
836    public void setEnabledProtocols(String[] protocols) {
837        sslParameters.setEnabledProtocols(protocols);
838    }
839
840    /**
841     * This method enables session ticket support.
842     *
843     * @param useSessionTickets True to enable session tickets
844     */
845    public void setUseSessionTickets(boolean useSessionTickets) {
846        sslParameters.useSessionTickets = useSessionTickets;
847    }
848
849    /**
850     * This method enables Server Name Indication
851     *
852     * @param hostname the desired SNI hostname, or null to disable
853     */
854    public void setHostname(String hostname) {
855        sslParameters.setUseSni(hostname != null);
856        wrappedHost = hostname;
857    }
858
859    /**
860     * Enables/disables TLS Channel ID for this server socket.
861     *
862     * <p>This method needs to be invoked before the handshake starts.
863     *
864     * @throws IllegalStateException if this is a client socket or if the handshake has already
865     *         started.
866
867     */
868    public void setChannelIdEnabled(boolean enabled) {
869        if (getUseClientMode()) {
870            throw new IllegalStateException("Client mode");
871        }
872
873        synchronized (stateLock) {
874            if (state != STATE_NEW) {
875                throw new IllegalStateException(
876                        "Could not enable/disable Channel ID after the initial handshake has"
877                                + " begun.");
878            }
879        }
880        sslParameters.channelIdEnabled = enabled;
881    }
882
883    /**
884     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
885     * handshake completes.
886     *
887     * @return channel ID or {@code null} if not available.
888     *
889     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
890     *         completed.
891     * @throws SSLException if channel ID is available but could not be obtained.
892     */
893    public byte[] getChannelId() throws SSLException {
894        if (getUseClientMode()) {
895            throw new IllegalStateException("Client mode");
896        }
897
898        synchronized (stateLock) {
899            if (state != STATE_READY) {
900                throw new IllegalStateException(
901                        "Channel ID is only available after handshake completes");
902            }
903        }
904        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
905    }
906
907    /**
908     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
909     *
910     * <p>This method needs to be invoked before the handshake starts.
911     *
912     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
913     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
914     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
915     *
916     * @throws IllegalStateException if this is a server socket or if the handshake has already
917     *         started.
918     */
919    public void setChannelIdPrivateKey(PrivateKey privateKey) {
920        if (!getUseClientMode()) {
921            throw new IllegalStateException("Server mode");
922        }
923
924        synchronized (stateLock) {
925            if (state != STATE_NEW) {
926                throw new IllegalStateException(
927                        "Could not change Channel ID private key after the initial handshake has"
928                                + " begun.");
929            }
930        }
931
932        if (privateKey == null) {
933            sslParameters.channelIdEnabled = false;
934            channelIdPrivateKey = null;
935        } else {
936            sslParameters.channelIdEnabled = true;
937            try {
938                channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
939            } catch (InvalidKeyException e) {
940                // Will have error in startHandshake
941            }
942        }
943    }
944
945    @Override
946    public boolean getUseClientMode() {
947        return sslParameters.getUseClientMode();
948    }
949
950    @Override
951    public void setUseClientMode(boolean mode) {
952        synchronized (stateLock) {
953            if (state != STATE_NEW) {
954                throw new IllegalArgumentException(
955                        "Could not change the mode after the initial handshake has begun.");
956            }
957        }
958        sslParameters.setUseClientMode(mode);
959    }
960
961    @Override
962    public boolean getWantClientAuth() {
963        return sslParameters.getWantClientAuth();
964    }
965
966    @Override
967    public boolean getNeedClientAuth() {
968        return sslParameters.getNeedClientAuth();
969    }
970
971    @Override
972    public void setNeedClientAuth(boolean need) {
973        sslParameters.setNeedClientAuth(need);
974    }
975
976    @Override
977    public void setWantClientAuth(boolean want) {
978        sslParameters.setWantClientAuth(want);
979    }
980
981    @Override
982    public void sendUrgentData(int data) throws IOException {
983        throw new SocketException("Method sendUrgentData() is not supported.");
984    }
985
986    @Override
987    public void setOOBInline(boolean on) throws SocketException {
988        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
989    }
990
991    @Override
992    public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
993        super.setSoTimeout(readTimeoutMilliseconds);
994        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
995    }
996
997    @Override
998    public int getSoTimeout() throws SocketException {
999        return readTimeoutMilliseconds;
1000    }
1001
1002    /**
1003     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1004     */
1005    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
1006        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
1007
1008        Platform.setSocketTimeout(this, writeTimeoutMilliseconds);
1009    }
1010
1011    /**
1012     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1013     */
1014    public int getSoWriteTimeout() throws SocketException {
1015        return writeTimeoutMilliseconds;
1016    }
1017
1018    /**
1019     * Set the handshake timeout on this socket.  This timeout is specified in
1020     * milliseconds and will be used only during the handshake process.
1021     */
1022    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
1023        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
1024    }
1025
1026    @Override
1027    public void close() throws IOException {
1028        // TODO: Close SSL sockets using a background thread so they close gracefully.
1029
1030        SSLInputStream sslInputStream = null;
1031        SSLOutputStream sslOutputStream = null;
1032
1033        synchronized (stateLock) {
1034            if (state == STATE_CLOSED) {
1035                // close() has already been called, so do nothing and return.
1036                return;
1037            }
1038
1039            int oldState = state;
1040            state = STATE_CLOSED;
1041
1042            if (oldState == STATE_NEW) {
1043                // The handshake hasn't been started yet, so there's no OpenSSL related
1044                // state to clean up. We still need to close the underlying socket if
1045                // we're wrapping it and were asked to autoClose.
1046                closeUnderlyingSocket();
1047
1048                stateLock.notifyAll();
1049                return;
1050            }
1051
1052            if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) {
1053                // If we're in these states, we still haven't returned from startHandshake.
1054                // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then
1055                // set the state to STATE_CLOSED. startHandshake will handle all cleanup
1056                // after SSL_do_handshake returns, so we don't have anything to do here.
1057                NativeCrypto.SSL_interrupt(sslNativePointer);
1058
1059                stateLock.notifyAll();
1060                return;
1061            }
1062
1063            stateLock.notifyAll();
1064            // We've already returned from startHandshake, so we potentially have
1065            // input and output streams to clean up.
1066            sslInputStream = is;
1067            sslOutputStream = os;
1068        }
1069
1070        // Don't bother interrupting unless we have something to interrupt.
1071        if (sslInputStream != null || sslOutputStream != null) {
1072            NativeCrypto.SSL_interrupt(sslNativePointer);
1073        }
1074
1075        // Wait for the input and output streams to finish any reads they have in
1076        // progress. If there are no reads in progress at this point, future reads will
1077        // throw because state == STATE_CLOSED
1078        if (sslInputStream != null) {
1079            sslInputStream.awaitPendingOps();
1080        }
1081        if (sslOutputStream != null) {
1082            sslOutputStream.awaitPendingOps();
1083        }
1084
1085        shutdownAndFreeSslNative();
1086    }
1087
1088    private void shutdownAndFreeSslNative() throws IOException {
1089        try {
1090            BlockGuard.getThreadPolicy().onNetwork();
1091            NativeCrypto.SSL_shutdown(sslNativePointer, Platform.getFileDescriptor(socket),
1092                    this);
1093        } catch (IOException ignored) {
1094            /*
1095            * Note that although close() can throw
1096            * IOException, the RI does not throw if there
1097            * is problem sending a "close notify" which
1098            * can happen if the underlying socket is closed.
1099            */
1100        } finally {
1101            free();
1102            closeUnderlyingSocket();
1103        }
1104    }
1105
1106    private void closeUnderlyingSocket() throws IOException {
1107        if (socket != this) {
1108            if (autoClose && !socket.isClosed()) {
1109                socket.close();
1110            }
1111        } else {
1112            if (!super.isClosed()) {
1113                super.close();
1114            }
1115        }
1116    }
1117
1118    private void free() {
1119        if (sslNativePointer == 0) {
1120            return;
1121        }
1122        NativeCrypto.SSL_free(sslNativePointer);
1123        sslNativePointer = 0;
1124        guard.close();
1125    }
1126
1127    @Override
1128    protected void finalize() throws Throwable {
1129        try {
1130            /*
1131             * Just worry about our own state. Notably we do not try and
1132             * close anything. The SocketImpl, either our own
1133             * PlainSocketImpl, or the Socket we are wrapping, will do
1134             * that. This might mean we do not properly SSL_shutdown, but
1135             * if you want to do that, properly close the socket yourself.
1136             *
1137             * The reason why we don't try to SSL_shutdown, is that there
1138             * can be a race between finalizers where the PlainSocketImpl
1139             * finalizer runs first and closes the socket. However, in the
1140             * meanwhile, the underlying file descriptor could be reused
1141             * for another purpose. If we call SSL_shutdown, the
1142             * underlying socket BIOs still have the old file descriptor
1143             * and will write the close notify to some unsuspecting
1144             * reader.
1145             */
1146            if (guard != null) {
1147                guard.warnIfOpen();
1148            }
1149            free();
1150        } finally {
1151            super.finalize();
1152        }
1153    }
1154
1155    /* @Override */
1156    public FileDescriptor getFileDescriptor$() {
1157        if (socket == this) {
1158            return Platform.getFileDescriptorFromSSLSocket(this);
1159        } else {
1160            return Platform.getFileDescriptor(socket);
1161        }
1162    }
1163
1164    /**
1165     * Returns the protocol agreed upon by client and server, or null if no
1166     * protocol was agreed upon.
1167     */
1168    public byte[] getNpnSelectedProtocol() {
1169        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1170    }
1171
1172    /**
1173     * Returns the protocol agreed upon by client and server, or {@code null} if
1174     * no protocol was agreed upon.
1175     */
1176    public byte[] getAlpnSelectedProtocol() {
1177        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
1178    }
1179
1180    /**
1181     * Sets the list of protocols this peer is interested in. If null no
1182     * protocols will be used.
1183     *
1184     * @param npnProtocols a non-empty array of protocol names. From
1185     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1186     *     strings. The length byte itself is not included in the length. A byte
1187     *     string of length 0 is invalid. No byte string may be truncated.".
1188     */
1189    public void setNpnProtocols(byte[] npnProtocols) {
1190        if (npnProtocols != null && npnProtocols.length == 0) {
1191            throw new IllegalArgumentException("npnProtocols.length == 0");
1192        }
1193        sslParameters.npnProtocols = npnProtocols;
1194    }
1195
1196    /**
1197     * Sets the list of protocols this peer is interested in. If the list is
1198     * {@code null}, no protocols will be used.
1199     *
1200     * @param alpnProtocols a non-empty array of protocol names. From
1201     *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1202     *            strings. The length byte itself is not included in the length.
1203     *            A byte string of length 0 is invalid. No byte string may be
1204     *            truncated.".
1205     */
1206    public void setAlpnProtocols(byte[] alpnProtocols) {
1207        if (alpnProtocols != null && alpnProtocols.length == 0) {
1208            throw new IllegalArgumentException("alpnProtocols.length == 0");
1209        }
1210        sslParameters.alpnProtocols = alpnProtocols;
1211    }
1212
1213    @Override
1214    public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
1215        return keyManager.chooseServerAlias(keyType, null, this);
1216    }
1217
1218    @Override
1219    public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
1220            String[] keyTypes) {
1221        return keyManager.chooseClientAlias(keyTypes, null, this);
1222    }
1223
1224    @Override
1225    public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
1226        return keyManager.chooseServerKeyIdentityHint(this);
1227    }
1228
1229    @Override
1230    public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
1231        return keyManager.chooseClientKeyIdentity(identityHint, this);
1232    }
1233
1234    @Override
1235    public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
1236        return keyManager.getKey(identityHint, identity, this);
1237    }
1238}
1239