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