108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/* 208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License. 608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at 708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * 1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and 1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License. 1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 193e46e4ee56c8e37158f46941dedd5b436d724baaKenny Rootimport org.conscrypt.util.Arrays; 20ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrickimport dalvik.system.BlockGuard; 21fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport dalvik.system.CloseGuard; 220648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkeyimport java.io.FileDescriptor; 2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException; 2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream; 2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream; 2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress; 2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket; 2808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException; 291ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Rootimport java.security.InvalidKeyException; 3098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey; 3198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom; 321f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException; 3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException; 3408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList; 3501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubinimport javax.crypto.SecretKey; 3608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent; 3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener; 3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException; 39edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException; 40d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLParameters; 418765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException; 4208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession; 438d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubinimport javax.net.ssl.X509KeyManager; 44fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager; 4598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal; 468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/** 480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL. 490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p> 500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include: 510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul> 520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout 530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets 540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication 550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul> 5608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 57f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl 58f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom extends javax.net.ssl.SSLSocket 5901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser, 6001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin SSLParametersImpl.PSKCallbacks { 6190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom 628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final boolean DBG_STATE = false; 638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 6569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom * Protects handshakeStarted and handshakeCompleted. 6669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private final Object stateLock = new Object(); 6869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 6969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * The {@link OpenSSLSocketImpl} object is constructed, but {@link #startHandshake()} 718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * has not yet been called. 7269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_NEW = 0; 7469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 7569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * {@link #startHandshake()} has been called at least once. 7769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_HANDSHAKE_STARTED = 1; 7969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 8069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * {@link #handshakeCompleted()} has been called, but {@link #startHandshake()} hasn't 828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * returned yet. 8369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_HANDSHAKE_COMPLETED = 2; 858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath /** 878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * {@link #startHandshake()} has completed but {@link #handshakeCompleted()} hasn't 888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * been called. This is expected behaviour in cut-through mode, where SSL_do_handshake 898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * returns before the handshake is complete. We can now start writing data to the socket. 908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath */ 918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_READY_HANDSHAKE_CUT_THROUGH = 3; 9269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 9369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * {@link #startHandshake()} has completed and {@link #handshakeCompleted()} has been 958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * called. 9669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_READY = 4; 9869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 9969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 1008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * {@link #close()} has been called at least once. 10169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 1028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private static final int STATE_CLOSED = 5; 1038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 1048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // @GuardedBy("stateLock"); 1058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private int state = STATE_NEW; 10669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 10769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 1088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * Protected by synchronizing on stateLock. Starts as 0, set by 1098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * startHandshake, reset to 0 on close. 11069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 1118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // @GuardedBy("stateLock"); 1128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private long sslNativePointer; 11369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 11469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** 1158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * Protected by synchronizing on stateLock. Starts as null, set by 1168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * getInputStream. 11769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom */ 1188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // @GuardedBy("stateLock"); 1198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private SSLInputStream is; 1208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 1218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath /** 1228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * Protected by synchronizing on stateLock. Starts as null, set by 1238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * getInputStream. 1248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath */ 1258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // @GuardedBy("stateLock"); 1268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private SSLOutputStream os; 12769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 12869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom private final Socket socket; 12969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom private final boolean autoClose; 130dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root 131dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root /** 132dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * The peer's DNS hostname if it was supplied during creation. 133dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root */ 134dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root private String peerHostname; 135dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root 136dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root /** 137dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * The DNS hostname from reverse lookup on the socket. Should never be used 138dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * for Server Name Indication (SNI). 139dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root */ 140dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root private String resolvedHostname; 141dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root 142dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root /** 143dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * The peer's port if it was supplied during creation. Should only be set if 144dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * {@link #peerHostname} is also set. 145dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root */ 146dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root private final int peerPort; 147dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root 14869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom private final SSLParametersImpl sslParameters; 14969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom private final CloseGuard guard = CloseGuard.get(); 15069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 1513c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root private ArrayList<HandshakeCompletedListener> listeners; 1522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 1532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom /** 1543c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root * Private key for the TLS Channel ID extension. This field is client-side 1553c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root * only. Set during startHandshake. 1562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom */ 1573c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root OpenSSLKey channelIdPrivateKey; 15869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom 15969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom /** Set during startHandshake. */ 16069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom private OpenSSLSessionImpl sslSession; 1612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 162d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root /** Used during handshake callbacks. */ 163d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root private OpenSSLSessionImpl handshakeSession; 164d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 16572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom /** 16672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom * Local cache of timeout to avoid getsockopt on every read and 16772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom * write for non-wrapped sockets. Note that 16872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom * OpenSSLSocketImplWrapper overrides setSoTimeout and 16972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom * getSoTimeout to delegate to the wrapped socket. 17072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom */ 171fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom private int readTimeoutMilliseconds = 0; 172fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom private int writeTimeoutMilliseconds = 0; 17372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom 17472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite 17508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 176cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException { 17790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom this.socket = this; 178dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = null; 179dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = -1; 18069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.autoClose = false; 18169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 18208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 18308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 184dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root protected OpenSSLSocketImpl(String hostname, int port, SSLParametersImpl sslParameters) 18590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom throws IOException { 186dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root super(hostname, port); 18790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom this.socket = this; 188dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = hostname; 189dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = port; 19069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.autoClose = false; 19169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 194cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters) 19590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom throws IOException { 19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project super(address, port); 19790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom this.socket = this; 198dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = null; 199dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = -1; 20069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.autoClose = false; 20169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 20208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 20308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 20408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 205dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root protected OpenSSLSocketImpl(String hostname, int port, 206c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom InetAddress clientAddress, int clientPort, 2075006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson SSLParametersImpl sslParameters) throws IOException { 208dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root super(hostname, port, clientAddress, clientPort); 20990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom this.socket = this; 210dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = hostname; 211dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = port; 21269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.autoClose = false; 21369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 21408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 21508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 21608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project protected OpenSSLSocketImpl(InetAddress address, int port, 217c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom InetAddress clientAddress, int clientPort, 2185006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson SSLParametersImpl sslParameters) throws IOException { 21908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project super(address, port, clientAddress, clientPort); 22090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom this.socket = this; 221dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = null; 222dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = -1; 22369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.autoClose = false; 22469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 22508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 22608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 22708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 2285006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson * Create an SSL socket that wraps another socket. Invoked by 2295006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson * OpenSSLSocketImplWrapper constructor. 23008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 231dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root protected OpenSSLSocketImpl(Socket socket, String hostname, int port, 232cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom boolean autoClose, SSLParametersImpl sslParameters) throws IOException { 23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project this.socket = socket; 234dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerHostname = hostname; 235dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root this.peerPort = port; 23608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project this.autoClose = autoClose; 23769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom this.sslParameters = sslParameters; 23872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom 23972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom // this.timeout is not set intentionally. 24072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout 24172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom // to wrapped socket 242f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom } 243f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 244a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom private void checkOpen() throws SocketException { 245a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom if (isClosed()) { 246a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom throw new SocketException("Socket is closed"); 247a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom } 248a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom } 249a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom 250a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom /** 251d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson * Starts a TLS/SSL handshake on this connection using some native methods 252d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson * from the OpenSSL library. It can negotiate new encryption keys, change 253d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson * cipher suites, or initiate a new session. The certificate chain is 254d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson * verified if the correspondent property in java.Security is set. All 255d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson * listeners are notified at the end of the TLS/SSL handshake. 2562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom */ 257f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 258f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void startHandshake() throws IOException { 2598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath checkOpen(); 2608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 2618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_NEW) { 2628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_HANDSHAKE_STARTED; 26308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } else { 2648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // We've either started the handshake already or have been closed. 2658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Do nothing in both cases. 26608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return; 26708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 26808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 27098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom // note that this modifies the global seed, not something specific to the connection 27198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES; 27298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom final SecureRandom secureRandom = sslParameters.getSecureRandomMember(); 27398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom if (secureRandom == null) { 27498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes); 27598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom } else { 27698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes)); 27798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom } 27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom 27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom final boolean client = sslParameters.getUseClientMode(); 28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom 2818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath sslNativePointer = 0; 2828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath boolean releaseResources = true; 283fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom try { 2843c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root final AbstractSessionContext sessionContext = sslParameters.getSessionContext(); 2853c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root final long sslCtxNativePointer = sessionContext.sslCtxNativePointer; 286fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer); 287fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom guard.open("close"); 28898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom 2893c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root boolean enableSessionCreation = getEnableSessionCreation(); 290fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom if (!enableSessionCreation) { 291fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, 2923c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root enableSessionCreation); 2932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 2942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 2953c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root final OpenSSLSessionImpl sessionToReuse = sslParameters.getSessionToReuse( 296dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root sslNativePointer, getHostname(), getPort()); 29701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin sslParameters.setSSLParameters(sslCtxNativePointer, sslNativePointer, this, this, 298dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root peerHostname); 2993c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.setCertificateValidation(sslNativePointer); 3003c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey); 301f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 302fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom // Temporarily use a different timeout for the handshake process 303fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom int savedReadTimeoutMilliseconds = getSoTimeout(); 304fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom int savedWriteTimeoutMilliseconds = getSoWriteTimeout(); 305fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom if (handshakeTimeoutMilliseconds >= 0) { 306fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom setSoTimeout(handshakeTimeoutMilliseconds); 307fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom setSoWriteTimeout(handshakeTimeoutMilliseconds); 308fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom } 3092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 3108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 3118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 3128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 3138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3167dd8d0b433cf8212538aaaf8726f5222abf035ddMatteo Franchin long sslSessionNativePointer; 317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom try { 318a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer, 3193e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root Platform.getFileDescriptor(socket), this, getSoTimeout(), client, 3203c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.npnProtocols, client ? null : sslParameters.alpnProtocols); 321fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom } catch (CertificateException e) { 322d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage()); 323d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom wrapper.initCause(e); 324d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom throw wrapper; 3258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } catch (SSLException e) { 3268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Swallow this exception if it's thrown as the result of an interruption. 3278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // 3288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake 3298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ 3308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // (or WANT_WRITE). Catching that exception here doesn't seem much worse than 3318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // changing the native code to return a "special" native pointer value when that 3328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // happens. 3338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 3348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 3358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 3368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3392e1be9d876e8c5554f91afee914641f323eebd4crich cannings // Write CCS errors to EventLog 3402e1be9d876e8c5554f91afee914641f323eebd4crich cannings String message = e.getMessage(); 3412e1be9d876e8c5554f91afee914641f323eebd4crich cannings // Must match error string of SSL_R_UNEXPECTED_CCS 3422e1be9d876e8c5554f91afee914641f323eebd4crich cannings if (message.contains("unexpected CCS")) { 3432e1be9d876e8c5554f91afee914641f323eebd4crich cannings String logMessage = String.format("ssl_unexpected_ccs: host=%s", 344dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root getHostname()); 3452e1be9d876e8c5554f91afee914641f323eebd4crich cannings Platform.logEvent(logMessage); 3462e1be9d876e8c5554f91afee914641f323eebd4crich cannings } 3472e1be9d876e8c5554f91afee914641f323eebd4crich cannings 3488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw e; 3492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 3508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath boolean handshakeCompleted = false; 3528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 3538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_HANDSHAKE_COMPLETED) { 3548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath handshakeCompleted = true; 3558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } else if (state == STATE_CLOSED) { 3568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 3578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3600dd7db8b85dfd8ad5d16d239432b9852450dc78fKenny Root sslSession = sslParameters.setupSession(sslSessionNativePointer, sslNativePointer, 361dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root sessionToReuse, getHostname(), getPort(), handshakeCompleted); 362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom 363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom // Restore the original timeout now that the handshake is complete 364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom if (handshakeTimeoutMilliseconds >= 0) { 365fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom setSoTimeout(savedReadTimeoutMilliseconds); 366fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom setSoWriteTimeout(savedWriteTimeoutMilliseconds); 367331900211d05cd282141a3a50cb1db626f418b2cDan Egnor } 36808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback 370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom if (handshakeCompleted) { 371fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom notifyHandshakeCompletedListeners(); 372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom } 373f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 3748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 3758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath releaseResources = (state == STATE_CLOSED); 3768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_HANDSHAKE_STARTED) { 3788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_READY_HANDSHAKE_CUT_THROUGH; 3798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } else if (state == STATE_HANDSHAKE_COMPLETED) { 3808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_READY; 3818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 3838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (!releaseResources) { 3848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Unblock threads that are waiting for our state to transition 3858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH. 3868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 3878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 3898765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom } catch (SSLProtocolException e) { 3903e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed") 3913e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root .initCause(e); 392fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom } finally { 393aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom // on exceptional exit, treat the socket as closed 3948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (releaseResources) { 3958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 3968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Mark the socket as closed since we might have reached this as 3978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // a result on an exception thrown by the handshake process. 3988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // 3998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // The state will already be set to closed if we reach this as a result of 4008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // an early return or an interruption due to a concurrent call to close(). 4018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_CLOSED; 4028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 4038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 4048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 4058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath try { 4068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath shutdownAndFreeSslNative(); 4078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } catch (IOException ignored) { 4088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 4098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 410fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom } 41108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 412e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom } 4133ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root 414dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root /** 415dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * Returns the hostname that was supplied during socket creation or tries to 416dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * look up the hostname via the supplied socket address if possible. This 417dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * may result in the return of a IP address and should not be used for 418dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root * Server Name Indication (SNI). 419dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root */ 420dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root private String getHostname() { 421dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root if (peerHostname != null) { 422dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root return peerHostname; 4238ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom } 424dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root if (resolvedHostname == null) { 425dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root InetAddress inetAddress = super.getInetAddress(); 426dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root if (inetAddress != null) { 427dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root resolvedHostname = inetAddress.getHostName(); 428dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root } 4298ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom } 430dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root return resolvedHostname; 4313967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson } 4323967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson 433dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root @Override 434dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root public int getPort() { 435131640979c0ba3f18581cee9bf5c925ec8a7372bNarayan Kamath return peerPort == -1 ? super.getPort() : peerPort; 4363967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson } 4373967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson 438f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 4395006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb 44098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) 441f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom throws CertificateEncodingException, SSLException { 4423c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals, 4433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslNativePointer, this); 44498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom } 44598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom 446f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 44701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @SuppressWarnings("unused") // used by native psk_client_callback 44801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) { 44901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this); 45001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin } 45101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin 45201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @Override 45301cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @SuppressWarnings("unused") // used by native psk_server_callback 45401cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) { 45501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this); 45601cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin } 45701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin 45801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @Override 4595006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback 460f878e438660d93f8689b864165230492e7a412d4Kenny Root public void onSSLStateChange(long sslSessionNativePtr, int type, int val) { 461f878e438660d93f8689b864165230492e7a412d4Kenny Root if (type != NativeCrypto.SSL_CB_HANDSHAKE_DONE) { 462f878e438660d93f8689b864165230492e7a412d4Kenny Root return; 463f878e438660d93f8689b864165230492e7a412d4Kenny Root } 464f878e438660d93f8689b864165230492e7a412d4Kenny Root 4658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 4668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_HANDSHAKE_STARTED) { 4678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // If sslSession is null, the handshake was completed during 4688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // the call to NativeCrypto.SSL_do_handshake and not during a 4698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // later read operation. That means we do not need to fix up 4708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // the SSLSession and session cache or notify 4718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // HandshakeCompletedListeners, it will be done in 4728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // startHandshake. 4738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 4748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_HANDSHAKE_COMPLETED; 4758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 4768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } else if (state == STATE_READY_HANDSHAKE_CUT_THROUGH) { 4778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // We've returned from startHandshake, which means we've set a sslSession etc. 4788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // we need to fix them up, which we'll do outside this lock. 4798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } else if (state == STATE_CLOSED) { 4808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Someone called "close" but the handshake hasn't been interrupted yet. 4818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 4828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 4832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 48408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 4852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom // reset session id from the native pointer and update the 4862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom // appropriate cache. 4872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom sslSession.resetId(); 4882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom AbstractSessionContext sessionContext = 4892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom (sslParameters.getUseClientMode()) 4902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom ? sslParameters.getClientSessionContext() 4912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom : sslParameters.getServerSessionContext(); 49208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project sessionContext.putSession(sslSession); 4932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 4942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom // let listeners know we are finally done 4952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom notifyHandshakeCompletedListeners(); 4968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 4978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 4988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Now that we've fixed up our state, we can tell waiting threads that 4998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // we're ready. 5008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_READY; 5018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Notify all threads waiting for the handshake to complete. 5028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 5038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 5042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 5052828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 5062828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom private void notifyHandshakeCompletedListeners() { 5072828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom if (listeners != null && !listeners.isEmpty()) { 5082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom // notify the listeners 5092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom HandshakeCompletedEvent event = 5102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom new HandshakeCompletedEvent(this, sslSession); 5112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom for (HandshakeCompletedListener listener : listeners) { 5122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom try { 5132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom listener.handshakeCompleted(event); 5142828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } catch (RuntimeException e) { 515371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom // The RI runs the handlers in a separate thread, 516371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom // which we do not. But we try to preserve their 517371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom // behavior of logging a problem and not killing 518371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom // the handshaking thread just because a listener 519371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom // has a problem. 520371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom Thread thread = Thread.currentThread(); 521371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom thread.getUncaughtExceptionHandler().uncaughtException(thread, e); 5222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 5232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 5242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } 52508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 52608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 5275006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks 528f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 529d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root public void verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod) 53098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom throws CertificateException { 53108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project try { 5328d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin X509TrustManager x509tm = sslParameters.getX509TrustManager(); 5338d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin if (x509tm == null) { 5348d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin throw new CertificateException("No X.509 TrustManager"); 5358d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin } 5360e9746b7b132058651155b33f219c7789997985bKenny Root if (certRefs == null || certRefs.length == 0) { 537371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom throw new SSLException("Peer sent no certificate"); 538371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom } 5390e9746b7b132058651155b33f219c7789997985bKenny Root OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length]; 5400e9746b7b132058651155b33f219c7789997985bKenny Root for (int i = 0; i < certRefs.length; i++) { 5410e9746b7b132058651155b33f219c7789997985bKenny Root peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]); 54208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 543d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 544d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root // Used for verifyCertificateChain callback 545d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain, 546dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root getHostname(), getPort(), null); 547d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 5482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom boolean client = sslParameters.getUseClientMode(); 5492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom if (client) { 550dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, getHostname()); 5512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } else { 5520e9746b7b132058651155b33f219c7789997985bKenny Root String authType = peerCertChain[0].getPublicKey().getAlgorithm(); 553b860016f415dfc5655dcee45f70e8871a2e3edfeBrian Carlstrom x509tm.checkClientTrusted(peerCertChain, authType); 55408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 5552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } catch (CertificateException e) { 5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom throw e; 5572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom } catch (Exception e) { 5589400b50da5ca8f1e796f5b158063db0aefb58441Brian Carlstrom throw new CertificateException(e); 559d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root } finally { 560d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root // Clear this before notifying handshake completed listeners 561d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root handshakeSession = null; 56208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 56308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 56408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 565f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 566f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public InputStream getInputStream() throws IOException { 567a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom checkOpen(); 5688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 5698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath InputStream returnVal; 5708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 5718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 5728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new SocketException("Socket is closed."); 5738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 5748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 57508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (is == null) { 57608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project is = new SSLInputStream(); 57708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 57808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 5798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath returnVal = is; 58008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 5818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 5828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Block waiting for a handshake without a lock held. It's possible that the socket 5838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // is closed at this point. If that happens, we'll still return the input stream but 5848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // all reads on it will throw. 5858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath waitForHandshake(); 5868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return returnVal; 58708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 58808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 589f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 590f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public OutputStream getOutputStream() throws IOException { 591a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom checkOpen(); 5928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 5938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath OutputStream returnVal; 5948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 5958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 5968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new SocketException("Socket is closed."); 5978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 5988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 59908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (os == null) { 60008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project os = new SSLOutputStream(); 60108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 60208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 6038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath returnVal = os; 6048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Block waiting for a handshake without a lock held. It's possible that the socket 6078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // is closed at this point. If that happens, we'll still return the output stream but 6088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // all writes on it will throw. 6098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath waitForHandshake(); 6108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return returnVal; 6118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private void assertReadableOrWriteableState() { 6148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) { 6158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 6168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new AssertionError("Invalid state: " + state); 6198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private void waitForHandshake() throws IOException { 6238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath startHandshake(); 6248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 6268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath while (state != STATE_READY && 6278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state != STATE_READY_HANDSHAKE_CUT_THROUGH && 6288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state != STATE_CLOSED) { 6298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath try { 6308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.wait(); 6318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } catch (InterruptedException e) { 6328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath Thread.currentThread().interrupt(); 6338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath IOException ioe = new IOException("Interrupted waiting for handshake"); 6348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath ioe.initCause(e); 6358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw ioe; 6378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6408db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 6418db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new SocketException("Socket is closed"); 6428db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 6462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom /** 64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * This inner class provides input data stream functionality 64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * for the OpenSSL native implementation. It is used to 64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * read data received via SSL protocol. 65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project private class SSLInputStream extends InputStream { 6528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath /** 6538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * OpenSSL only lets one thread read at a time, so this is used to 6548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * make sure we serialize callers of SSL_read. Thread is already 6558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * expected to have completed handshaking. 6568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath */ 6578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private final Object readLock = new Object(); 6588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath SSLInputStream() { 66008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 66208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 66308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Reads one byte. If there is no data in the underlying buffer, 66408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * this operation can block until the data will be 66508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * available. 66608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @return read value. 6670e9746b7b132058651155b33f219c7789997985bKenny Root * @throws IOException 66808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 6690b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom @Override 67008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project public int read() throws IOException { 6713e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root byte[] buffer = new byte[1]; 6723e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root int result = read(buffer, 0, 1); 6733e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root return (result != -1) ? buffer[0] & 0xff : -1; 67408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 67508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Method acts as described in spec for superclass. 67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @see java.io.InputStream#read(byte[],int,int) 67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 6800b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom @Override 68197e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes public int read(byte[] buf, int offset, int byteCount) throws IOException { 682ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick BlockGuard.getThreadPolicy().onNetwork(); 6838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath checkOpen(); 6858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 6868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (byteCount == 0) { 6878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return 0; 6888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 690f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom synchronized (readLock) { 6918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 6928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 6938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new SocketException("socket is closed"); 6948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 6958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (DBG_STATE) assertReadableOrWriteableState(); 6977b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom } 6988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 6993e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root return NativeCrypto.SSL_read(sslNativePointer, Platform.getFileDescriptor(socket), 700a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout()); 70108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 70208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 7038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath public void awaitPendingOps() { 7058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (DBG_STATE) { 7068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 7078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_CLOSED) throw new AssertionError("State is: " + state); 7088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (readLock) { } 7128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 71308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 71508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 71608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * This inner class provides output data stream functionality 71708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * for the OpenSSL native implementation. It is used to 71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * write data according to the encryption parameters given in SSL context. 71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 72008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project private class SSLOutputStream extends OutputStream { 7218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath /** 7238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * OpenSSL only lets one thread write at a time, so this is used 7248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * to make sure we serialize callers of SSL_write. Thread is 7258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * already expected to have completed handshaking. 7268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath */ 7278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private final Object writeLock = new Object(); 7288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath SSLOutputStream() { 73008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 73108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 73208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 73308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Method acts as described in spec for superclass. 73408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @see java.io.OutputStream#write(int) 73508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 7360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom @Override 7375c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom public void write(int oneByte) throws IOException { 7383e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root byte[] buffer = new byte[1]; 7393e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root buffer[0] = (byte) (oneByte & 0xff); 7403e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root write(buffer); 74108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 74208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 74308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Method acts as described in spec for superclass. 74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * @see java.io.OutputStream#write(byte[],int,int) 74608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 7470b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom @Override 74897e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes public void write(byte[] buf, int offset, int byteCount) throws IOException { 749ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick BlockGuard.getThreadPolicy().onNetwork(); 7508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath checkOpen(); 7518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 7528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (byteCount == 0) { 7538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 7548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 756f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom synchronized (writeLock) { 7578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 7588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 7598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new SocketException("socket is closed"); 7608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (DBG_STATE) assertReadableOrWriteableState(); 7637b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom } 7648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7653e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root NativeCrypto.SSL_write(sslNativePointer, Platform.getFileDescriptor(socket), 766fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds); 76708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 7698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath public void awaitPendingOps() { 7728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (DBG_STATE) { 7738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 7748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_CLOSED) throw new AssertionError("State is: " + state); 7758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 7778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 7788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (writeLock) { } 7798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 78008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 783f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 784f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public SSLSession getSession() { 785e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom if (sslSession == null) { 786e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom try { 7878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath waitForHandshake(); 788e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom } catch (IOException e) { 789e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom // return an invalid session with 790e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 791f111f6235d016ce54ab95a2c634a400efe29f24bKenny Root return SSLNullSession.getNullSession(); 792e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom } 79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return sslSession; 79508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 79608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 797d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 798f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void addHandshakeCompletedListener( 79908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project HandshakeCompletedListener listener) { 80008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (listener == null) { 80108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project throw new IllegalArgumentException("Provided listener is null"); 80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 80308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (listeners == null) { 8045006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson listeners = new ArrayList<HandshakeCompletedListener>(); 80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project listeners.add(listener); 80708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 80808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 809f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 810f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void removeHandshakeCompletedListener( 81108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project HandshakeCompletedListener listener) { 81208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (listener == null) { 81308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project throw new IllegalArgumentException("Provided listener is null"); 81408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 81508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (listeners == null) { 81608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project throw new IllegalArgumentException( 81708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project "Provided listener is not registered"); 81808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 81908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (!listeners.remove(listener)) { 82008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project throw new IllegalArgumentException( 82108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project "Provided listener is not registered"); 82208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 82308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 82408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 825f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 826f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public boolean getEnableSessionCreation() { 82708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return sslParameters.getEnableSessionCreation(); 82808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 82908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 830f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 831f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setEnableSessionCreation(boolean flag) { 83208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project sslParameters.setEnableSessionCreation(flag); 83308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 83408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 835f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 836f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public String[] getSupportedCipherSuites() { 837f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom return NativeCrypto.getSupportedCipherSuites(); 83808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 83908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 840f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 841f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public String[] getEnabledCipherSuites() { 842f878e438660d93f8689b864165230492e7a412d4Kenny Root return sslParameters.getEnabledCipherSuites(); 84308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 84408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 845f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 846f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setEnabledCipherSuites(String[] suites) { 847f878e438660d93f8689b864165230492e7a412d4Kenny Root sslParameters.setEnabledCipherSuites(suites); 84808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 84908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 850f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 851f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public String[] getSupportedProtocols() { 852f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom return NativeCrypto.getSupportedProtocols(); 85308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 85408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 855f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 856f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public String[] getEnabledProtocols() { 857ae2ecac00779167b0381c48da7c612567d1c646fAlex Klyubin return sslParameters.getEnabledProtocols(); 85808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 860f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 861f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setEnabledProtocols(String[] protocols) { 862ae2ecac00779167b0381c48da7c612567d1c646fAlex Klyubin sslParameters.setEnabledProtocols(protocols); 86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 86508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 8660b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * This method enables session ticket support. 8670b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * 8680b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * @param useSessionTickets True to enable session tickets 8690b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom */ 8700b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom public void setUseSessionTickets(boolean useSessionTickets) { 8713c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.useSessionTickets = useSessionTickets; 8720b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom } 8730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom 8740b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom /** 8750b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * This method enables Server Name Indication 8760b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * 8770b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * @param hostname the desired SNI hostname, or null to disable 8780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom */ 8790b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom public void setHostname(String hostname) { 8803c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.setUseSni(hostname != null); 881dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root peerHostname = hostname; 8820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom } 8830b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom 884577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin /** 885577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * Enables/disables TLS Channel ID for this server socket. 886577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 887577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * <p>This method needs to be invoked before the handshake starts. 888577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 889577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @throws IllegalStateException if this is a client socket or if the handshake has already 890577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * started. 891577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin 892577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin */ 893577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin public void setChannelIdEnabled(boolean enabled) { 894577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin if (getUseClientMode()) { 895577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin throw new IllegalStateException("Client mode"); 896577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 8978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 8988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 8998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_NEW) { 9008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new IllegalStateException( 9018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath "Could not enable/disable Channel ID after the initial handshake has" 9028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath + " begun."); 9038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 904577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 9053c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.channelIdEnabled = enabled; 906577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 907577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin 908577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin /** 909577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * Gets the TLS Channel ID for this server socket. Channel ID is only available once the 910577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * handshake completes. 911577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 912577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @return channel ID or {@code null} if not available. 913577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 914577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @throws IllegalStateException if this is a client socket or if the handshake has not yet 915577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * completed. 916577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @throws SSLException if channel ID is available but could not be obtained. 917577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin */ 918577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin public byte[] getChannelId() throws SSLException { 919577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin if (getUseClientMode()) { 920577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin throw new IllegalStateException("Client mode"); 921577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 9228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 9238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 9248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_READY) { 9258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new IllegalStateException( 9268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath "Channel ID is only available after handshake completes"); 9278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 928577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 929577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer); 930577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 931577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin 932577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin /** 933577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket. 934577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 935577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * <p>This method needs to be invoked before the handshake starts. 936577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 937577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables 9384022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST 939577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1). 940577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * 941577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * @throws IllegalStateException if this is a server socket or if the handshake has already 942577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin * started. 943577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin */ 9444022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin public void setChannelIdPrivateKey(PrivateKey privateKey) { 945577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin if (!getUseClientMode()) { 946577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin throw new IllegalStateException("Server mode"); 947577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 9488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 9498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 9508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_NEW) { 9518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new IllegalStateException( 9528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath "Could not change Channel ID private key after the initial handshake has" 9538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath + " begun."); 9548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 955577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 9568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 9571ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root if (privateKey == null) { 9583c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.channelIdEnabled = false; 9593c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root channelIdPrivateKey = null; 9601ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root } else { 9613c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.channelIdEnabled = true; 9621ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root try { 9633c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey); 9641ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root } catch (InvalidKeyException e) { 9651ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root // Will have error in startHandshake 9661ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root } 9671ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root } 968577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin } 969577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin 970f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 971f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public boolean getUseClientMode() { 97208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return sslParameters.getUseClientMode(); 97308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 97408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 975f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 976f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setUseClientMode(boolean mode) { 9778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 9788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state != STATE_NEW) { 9798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath throw new IllegalArgumentException( 9808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath "Could not change the mode after the initial handshake has begun."); 9818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 98208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 98308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project sslParameters.setUseClientMode(mode); 98408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 98508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 986f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 987f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public boolean getWantClientAuth() { 98808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return sslParameters.getWantClientAuth(); 98908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 99008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 991f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 992f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public boolean getNeedClientAuth() { 99308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return sslParameters.getNeedClientAuth(); 99408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 99508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 996f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 997f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setNeedClientAuth(boolean need) { 99808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project sslParameters.setNeedClientAuth(need); 99908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 100008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1001f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1002f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setWantClientAuth(boolean want) { 100308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project sslParameters.setWantClientAuth(want); 100408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 100508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1006f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1007f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void sendUrgentData(int data) throws IOException { 10085006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson throw new SocketException("Method sendUrgentData() is not supported."); 100908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 101008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1011f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1012f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setOOBInline(boolean on) throws SocketException { 10135006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson throw new SocketException("Methods sendUrgentData, setOOBInline are not supported."); 101408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 101508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1016f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1017f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException { 1018fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom super.setSoTimeout(readTimeoutMilliseconds); 1019fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom this.readTimeoutMilliseconds = readTimeoutMilliseconds; 102072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom } 102172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom 1022f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1023f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public int getSoTimeout() throws SocketException { 1024fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom return readTimeoutMilliseconds; 1025fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom } 1026fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom 1027fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom /** 1028fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom * Note write timeouts are not part of the javax.net.ssl.SSLSocket API 1029fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom */ 1030fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException { 1031fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom this.writeTimeoutMilliseconds = writeTimeoutMilliseconds; 1032fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom 1033dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root Platform.setSocketWriteTimeout(this, writeTimeoutMilliseconds); 1034fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom } 1035fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom 1036fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom /** 1037fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom * Note write timeouts are not part of the javax.net.ssl.SSLSocket API 1038fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom */ 1039fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom public int getSoWriteTimeout() throws SocketException { 1040fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom return writeTimeoutMilliseconds; 104108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 104208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1043331900211d05cd282141a3a50cb1db626f418b2cDan Egnor /** 1044331900211d05cd282141a3a50cb1db626f418b2cDan Egnor * Set the handshake timeout on this socket. This timeout is specified in 1045331900211d05cd282141a3a50cb1db626f418b2cDan Egnor * milliseconds and will be used only during the handshake process. 1046331900211d05cd282141a3a50cb1db626f418b2cDan Egnor */ 1047fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException { 1048fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds; 1049331900211d05cd282141a3a50cb1db626f418b2cDan Egnor } 1050331900211d05cd282141a3a50cb1db626f418b2cDan Egnor 1051f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1052f06338c01394610174fe2b3532beac56d61d9e26Kenny Root public void close() throws IOException { 10535006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson // TODO: Close SSL sockets using a background thread so they close gracefully. 105408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 10558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath SSLInputStream sslInputStream = null; 10568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath SSLOutputStream sslOutputStream = null; 1057f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 10588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath synchronized (stateLock) { 10598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (state == STATE_CLOSED) { 10608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // close() has already been called, so do nothing and return. 10618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 10628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 106308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 10648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath int oldState = state; 10658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath state = STATE_CLOSED; 10668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 10678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (oldState == STATE_NEW) { 10688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // The handshake hasn't been started yet, so there's no OpenSSL related 10698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // state to clean up. We still need to close the underlying socket if 10708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // we're wrapping it and were asked to autoClose. 10718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath closeUnderlyingSocket(); 1072f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 10738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 107408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project return; 107508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 107608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 10778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) { 10788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // If we're in these states, we still haven't returned from startHandshake. 10798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then 10808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // set the state to STATE_CLOSED. startHandshake will handle all cleanup 10818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // after SSL_do_handshake returns, so we don't have anything to do here. 10828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath NativeCrypto.SSL_interrupt(sslNativePointer); 108308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 10848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 10858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath return; 10868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 10878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 10888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath stateLock.notifyAll(); 10898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // We've already returned from startHandshake, so we potentially have 10908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // input and output streams to clean up. 10918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath sslInputStream = is; 10928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath sslOutputStream = os; 10938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 10948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 10958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Don't bother interrupting unless we have something to interrupt. 10968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (sslInputStream != null || sslOutputStream != null) { 1097fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom NativeCrypto.SSL_interrupt(sslNativePointer); 10988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 10998b352156f879e7b36d223d3f65b8de46b7dc4dcfBrian Carlstrom 11008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // Wait for the input and output streams to finish any reads they have in 11018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // progress. If there are no reads in progress at this point, future reads will 11028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath // throw because state == STATE_CLOSED 11038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (sslInputStream != null) { 11048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath sslInputStream.awaitPendingOps(); 11058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (sslOutputStream != null) { 11078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath sslOutputStream.awaitPendingOps(); 11088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 11108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath shutdownAndFreeSslNative(); 11118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 11138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private void shutdownAndFreeSslNative() throws IOException { 11148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath try { 11158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath BlockGuard.getThreadPolicy().onNetwork(); 11163e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root NativeCrypto.SSL_shutdown(sslNativePointer, Platform.getFileDescriptor(socket), 11178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath this); 11188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } catch (IOException ignored) { 11198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath /* 11208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * Note that although close() can throw 11218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * IOException, the RI does not throw if there 11228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * is problem sending a "close notify" which 11238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath * can happen if the underlying socket is closed. 11248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath */ 11258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } finally { 11268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath free(); 11278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath closeUnderlyingSocket(); 11288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath 11318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath private void closeUnderlyingSocket() throws IOException { 11328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (socket != this) { 11338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (autoClose && !socket.isClosed()) { 11348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath socket.close(); 11358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } 11368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath } else { 11378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath if (!super.isClosed()) { 11388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath super.close(); 113908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 114008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 114108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 114208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1143f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom private void free() { 1144f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom if (sslNativePointer == 0) { 1145f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom return; 1146f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom } 1147f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom NativeCrypto.SSL_free(sslNativePointer); 1148f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom sslNativePointer = 0; 1149fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom guard.close(); 1150f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom } 115108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1152f06338c01394610174fe2b3532beac56d61d9e26Kenny Root @Override 1153f06338c01394610174fe2b3532beac56d61d9e26Kenny Root protected void finalize() throws Throwable { 11541990574e420184f3ad43400171f624dad44700d8Brian Carlstrom try { 11551990574e420184f3ad43400171f624dad44700d8Brian Carlstrom /* 11561990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * Just worry about our own state. Notably we do not try and 11571990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * close anything. The SocketImpl, either our own 11581990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * PlainSocketImpl, or the Socket we are wrapping, will do 11591990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * that. This might mean we do not properly SSL_shutdown, but 11601990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * if you want to do that, properly close the socket yourself. 11611990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * 11621990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * The reason why we don't try to SSL_shutdown, is that there 11631990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * can be a race between finalizers where the PlainSocketImpl 11641990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * finalizer runs first and closes the socket. However, in the 11651990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * meanwhile, the underlying file descriptor could be reused 11661990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * for another purpose. If we call SSL_shutdown, the 11671990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * underlying socket BIOs still have the old file descriptor 11681990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * and will write the close notify to some unsuspecting 11691990574e420184f3ad43400171f624dad44700d8Brian Carlstrom * reader. 11701990574e420184f3ad43400171f624dad44700d8Brian Carlstrom */ 1171f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom if (guard != null) { 1172f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom guard.warnIfOpen(); 1173f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom } 11741990574e420184f3ad43400171f624dad44700d8Brian Carlstrom free(); 11751990574e420184f3ad43400171f624dad44700d8Brian Carlstrom } finally { 11761990574e420184f3ad43400171f624dad44700d8Brian Carlstrom super.finalize(); 11771990574e420184f3ad43400171f624dad44700d8Brian Carlstrom } 117808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 11790648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey 11803e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root /* @Override */ 11810648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey public FileDescriptor getFileDescriptor$() { 11820648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey if (socket == this) { 11833e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root return Platform.getFileDescriptorFromSSLSocket(this); 11840648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey } else { 11853e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root return Platform.getFileDescriptor(socket); 11860648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey } 11870648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey } 1188721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson 1189721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson /** 1190721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson * Returns the protocol agreed upon by client and server, or null if no 1191721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson * protocol was agreed upon. 1192721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson */ 1193721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson public byte[] getNpnSelectedProtocol() { 1194263808a68e1538db41196065830107991e9f974aJesse Wilson return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer); 1195721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson } 1196721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson 1197721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson /** 11986fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * Returns the protocol agreed upon by client and server, or {@code null} if 11996fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * no protocol was agreed upon. 12006fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root */ 12016fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root public byte[] getAlpnSelectedProtocol() { 12026fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer); 12036fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root } 12046fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root 12056fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root /** 1206721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson * Sets the list of protocols this peer is interested in. If null no 1207721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson * protocols will be used. 1208721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson * 1209d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson * @param npnProtocols a non-empty array of protocol names. From 1210d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson * SSL_select_next_proto, "vector of 8-bit, length prefixed byte 1211d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson * strings. The length byte itself is not included in the length. A byte 1212d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson * string of length 0 is invalid. No byte string may be truncated.". 1213721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson */ 1214721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson public void setNpnProtocols(byte[] npnProtocols) { 1215d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson if (npnProtocols != null && npnProtocols.length == 0) { 1216d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson throw new IllegalArgumentException("npnProtocols.length == 0"); 1217d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson } 12183c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.npnProtocols = npnProtocols; 1219721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson } 12206fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root 12216fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root /** 12226fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * Sets the list of protocols this peer is interested in. If the list is 12236fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * {@code null}, no protocols will be used. 12246fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * 12256fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * @param alpnProtocols a non-empty array of protocol names. From 12266fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * SSL_select_next_proto, "vector of 8-bit, length prefixed byte 12276fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * strings. The length byte itself is not included in the length. 12286fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * A byte string of length 0 is invalid. No byte string may be 12296fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root * truncated.". 12306fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root */ 12316fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root public void setAlpnProtocols(byte[] alpnProtocols) { 12326fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root if (alpnProtocols != null && alpnProtocols.length == 0) { 12336fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root throw new IllegalArgumentException("alpnProtocols.length == 0"); 12346fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root } 12353c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root sslParameters.alpnProtocols = alpnProtocols; 12362d089e18deae231149737cad6ce00f1e137a7199Alex Klyubin } 1237d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root 1238d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root @Override 12393c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root public String chooseServerAlias(X509KeyManager keyManager, String keyType) { 12403c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root return keyManager.chooseServerAlias(keyType, null, this); 12413c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root } 12423c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root 12433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root @Override 12443c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, 12453c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root String[] keyTypes) { 12463c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root return keyManager.chooseClientAlias(keyTypes, null, this); 12473c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root } 124801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin 124901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @Override 125001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) { 125101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin return keyManager.chooseServerKeyIdentityHint(this); 125201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin } 125301cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin 125401cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @Override 125501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) { 125601cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin return keyManager.chooseClientKeyIdentity(identityHint, this); 125701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin } 125801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin 125901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin @Override 126001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) { 126101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin return keyManager.getKey(identityHint, identity, this); 126201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin } 126308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project} 1264