• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.conscrypt;
18 
19 import org.conscrypt.util.Arrays;
20 import dalvik.system.BlockGuard;
21 import dalvik.system.CloseGuard;
22 import java.io.FileDescriptor;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.net.InetAddress;
27 import java.net.Socket;
28 import java.net.SocketException;
29 import java.security.InvalidKeyException;
30 import java.security.PrivateKey;
31 import java.security.SecureRandom;
32 import java.security.cert.CertificateEncodingException;
33 import java.security.cert.CertificateException;
34 import java.util.ArrayList;
35 import javax.crypto.SecretKey;
36 import javax.net.ssl.HandshakeCompletedEvent;
37 import javax.net.ssl.HandshakeCompletedListener;
38 import javax.net.ssl.SSLException;
39 import javax.net.ssl.SSLHandshakeException;
40 import javax.net.ssl.SSLParameters;
41 import javax.net.ssl.SSLProtocolException;
42 import javax.net.ssl.SSLSession;
43 import javax.net.ssl.X509KeyManager;
44 import javax.net.ssl.X509TrustManager;
45 import 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  */
57 public 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 
OpenSSLSocketImpl(SSLParametersImpl sslParameters)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 
OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)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 
OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)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 
OpenSSLSocketImpl(String host, int port, InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)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 
OpenSSLSocketImpl(InetAddress address, int port, InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters)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      */
OpenSSLSocketImpl(Socket socket, String host, int port, boolean autoClose, SSLParametersImpl sslParameters)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 
checkOpen()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
startHandshake()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 
getPeerHostName()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 
getPeerPort()409     int getPeerPort() {
410         return wrappedHost == null ? super.getPort() : wrappedPort;
411     }
412 
413     @Override
414     @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)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
clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key)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
serverPSKKeyRequested(String identityHint, String identity, byte[] key)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
onSSLStateChange(long sslSessionNativePtr, int type, int val)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 
notifyHandshakeCompletedListeners()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
verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)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
getInputStream()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
getOutputStream()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 
assertReadableOrWriteableState()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 
waitForHandshake()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 
SSLInputStream()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
read()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
read(byte[] buf, int offset, int byteCount)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 
awaitPendingOps()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 
SSLOutputStream()704         SSLOutputStream() {
705         }
706 
707         /**
708          * Method acts as described in spec for superclass.
709          * @see java.io.OutputStream#write(int)
710          */
711         @Override
write(int oneByte)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
write(byte[] buf, int offset, int byteCount)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 
awaitPendingOps()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
getSession()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
addHandshakeCompletedListener( HandshakeCompletedListener listener)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
removeHandshakeCompletedListener( HandshakeCompletedListener listener)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
getEnableSessionCreation()801     public boolean getEnableSessionCreation() {
802         return sslParameters.getEnableSessionCreation();
803     }
804 
805     @Override
setEnableSessionCreation(boolean flag)806     public void setEnableSessionCreation(boolean flag) {
807         sslParameters.setEnableSessionCreation(flag);
808     }
809 
810     @Override
getSupportedCipherSuites()811     public String[] getSupportedCipherSuites() {
812         return NativeCrypto.getSupportedCipherSuites();
813     }
814 
815     @Override
getEnabledCipherSuites()816     public String[] getEnabledCipherSuites() {
817         return sslParameters.getEnabledCipherSuites();
818     }
819 
820     @Override
setEnabledCipherSuites(String[] suites)821     public void setEnabledCipherSuites(String[] suites) {
822         sslParameters.setEnabledCipherSuites(suites);
823     }
824 
825     @Override
getSupportedProtocols()826     public String[] getSupportedProtocols() {
827         return NativeCrypto.getSupportedProtocols();
828     }
829 
830     @Override
getEnabledProtocols()831     public String[] getEnabledProtocols() {
832         return sslParameters.getEnabledProtocols();
833     }
834 
835     @Override
setEnabledProtocols(String[] protocols)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      */
setUseSessionTickets(boolean useSessionTickets)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      */
setHostname(String hostname)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      */
setChannelIdEnabled(boolean enabled)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      */
getChannelId()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      */
setChannelIdPrivateKey(PrivateKey privateKey)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
getUseClientMode()946     public boolean getUseClientMode() {
947         return sslParameters.getUseClientMode();
948     }
949 
950     @Override
setUseClientMode(boolean mode)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
getWantClientAuth()962     public boolean getWantClientAuth() {
963         return sslParameters.getWantClientAuth();
964     }
965 
966     @Override
getNeedClientAuth()967     public boolean getNeedClientAuth() {
968         return sslParameters.getNeedClientAuth();
969     }
970 
971     @Override
setNeedClientAuth(boolean need)972     public void setNeedClientAuth(boolean need) {
973         sslParameters.setNeedClientAuth(need);
974     }
975 
976     @Override
setWantClientAuth(boolean want)977     public void setWantClientAuth(boolean want) {
978         sslParameters.setWantClientAuth(want);
979     }
980 
981     @Override
sendUrgentData(int data)982     public void sendUrgentData(int data) throws IOException {
983         throw new SocketException("Method sendUrgentData() is not supported.");
984     }
985 
986     @Override
setOOBInline(boolean on)987     public void setOOBInline(boolean on) throws SocketException {
988         throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
989     }
990 
991     @Override
setSoTimeout(int readTimeoutMilliseconds)992     public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
993         super.setSoTimeout(readTimeoutMilliseconds);
994         this.readTimeoutMilliseconds = readTimeoutMilliseconds;
995     }
996 
997     @Override
getSoTimeout()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      */
setSoWriteTimeout(int writeTimeoutMilliseconds)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      */
getSoWriteTimeout()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      */
setHandshakeTimeout(int handshakeTimeoutMilliseconds)1022     public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
1023         this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
1024     }
1025 
1026     @Override
close()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 
shutdownAndFreeSslNative()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 
closeUnderlyingSocket()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 
free()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
finalize()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 */
getFileDescriptor$()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      */
getNpnSelectedProtocol()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      */
getAlpnSelectedProtocol()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      */
setNpnProtocols(byte[] npnProtocols)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      */
setAlpnProtocols(byte[] alpnProtocols)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
chooseServerAlias(X509KeyManager keyManager, String keyType)1214     public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
1215         return keyManager.chooseServerAlias(keyType, null, this);
1216     }
1217 
1218     @Override
chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes)1219     public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
1220             String[] keyTypes) {
1221         return keyManager.chooseClientAlias(keyTypes, null, this);
1222     }
1223 
1224     @Override
chooseServerPSKIdentityHint(PSKKeyManager keyManager)1225     public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
1226         return keyManager.chooseServerKeyIdentityHint(this);
1227     }
1228 
1229     @Override
chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint)1230     public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
1231         return keyManager.chooseClientKeyIdentity(identityHint, this);
1232     }
1233 
1234     @Override
getPSKKey(PSKKeyManager keyManager, String identityHint, String identity)1235     public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
1236         return keyManager.getKey(identityHint, identity, this);
1237     }
1238 }
1239