blob: 04357174b1067bf0849a1643c818fccf93c6e1ba [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.xnet.provider.jsse;
18
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080019import java.io.IOException;
20import java.io.InputStream;
21import java.io.OutputStream;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080022import java.net.InetAddress;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080023import java.net.Socket;
24import java.net.SocketException;
Brian Carlstrom6df63392010-05-18 11:33:13 -070025import java.security.PrivateKey;
26import java.security.SecureRandom;
Brian Carlstrom12cd1f02010-06-22 23:43:20 -070027import java.security.cert.CertificateEncodingException;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080028import java.security.cert.CertificateException;
29import java.security.cert.X509Certificate;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080030import java.util.ArrayList;
crazybob30da60b2009-07-01 15:30:58 -050031import java.util.concurrent.atomic.AtomicInteger;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080032import java.util.logging.Logger;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080033import javax.net.ssl.HandshakeCompletedEvent;
34import javax.net.ssl.HandshakeCompletedListener;
35import javax.net.ssl.SSLException;
Brian Carlstrombcfb3252010-05-02 11:27:52 -070036import javax.net.ssl.SSLPeerUnverifiedException;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080037import javax.net.ssl.SSLSession;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080038import org.apache.harmony.security.provider.cert.X509CertImpl;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080039
40/**
41 * Implementation of the class OpenSSLSocketImpl
Brian Carlstrom3e24c532010-05-06 00:23:21 -070042 * based on OpenSSL.
Brian Carlstromecaf7592010-03-02 16:55:35 -080043 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080044 * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
Brian Carlstromecaf7592010-03-02 16:55:35 -080045 * later, for example in the package.html or a separate reference document.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080046 */
Brian Carlstromecaf7592010-03-02 16:55:35 -080047public class OpenSSLSocketImpl
48 extends javax.net.ssl.SSLSocket
Brian Carlstrom6df63392010-05-18 11:33:13 -070049 implements NativeCrypto.SSLHandshakeCallbacks {
Brian Carlstromecaf7592010-03-02 16:55:35 -080050 private int sslNativePointer;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080051 private InputStream is;
52 private OutputStream os;
53 private final Object handshakeLock = new Object();
Brian Carlstromecaf7592010-03-02 16:55:35 -080054 private final Object readLock = new Object();
55 private final Object writeLock = new Object();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080056 private SSLParameters sslParameters;
Brian Carlstrombcfb3252010-05-02 11:27:52 -070057 private String[] enabledProtocols;
58 private String[] enabledCipherSuites;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080059 private OpenSSLSessionImpl sslSession;
60 private Socket socket;
61 private boolean autoClose;
62 private boolean handshakeStarted = false;
Brian Carlstrombcfb3252010-05-02 11:27:52 -070063
64 /**
65 * Not set to true until the update from native that tells us the
66 * full handshake is complete, since SSL_do_handshake can return
67 * before the handshake is completely done due to
68 * handshake_cutthrough support.
69 */
70 private boolean handshakeCompleted = false;
71
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080072 private ArrayList<HandshakeCompletedListener> listeners;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080073 private int timeout = 0;
Dan Egnor9d48f972010-02-10 11:48:08 -080074 // BEGIN android-added
75 private int handshakeTimeout = -1; // -1 = same as timeout; 0 = infinite
76 // END android-added
Brian Carlstroma653cca2010-05-18 13:45:26 -070077 private String wrappedHost;
78 private int wrappedPort;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080079
crazybob30da60b2009-07-01 15:30:58 -050080 private static final AtomicInteger instanceCount = new AtomicInteger(0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080081
82 public static int getInstanceCount() {
crazybob30da60b2009-07-01 15:30:58 -050083 return instanceCount.get();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080084 }
85
86 private static void updateInstanceCount(int amount) {
crazybob30da60b2009-07-01 15:30:58 -050087 instanceCount.addAndGet(amount);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080088 }
89
90 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080091 * Class constructor with 1 parameter
92 *
93 * @param sslParameters Parameters for the SSL
94 * context
95 * @throws IOException if network fails
96 */
97 protected OpenSSLSocketImpl(SSLParameters sslParameters) throws IOException {
98 super();
Brian Carlstromecaf7592010-03-02 16:55:35 -080099 init(sslParameters);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800100 }
101
102 /**
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700103 * Create an OpenSSLSocketImpl from an OpenSSLServerSocketImpl
104 *
105 * @param sslParameters Parameters for the SSL
106 * context
107 * @throws IOException if network fails
108 */
109 protected OpenSSLSocketImpl(SSLParameters sslParameters,
110 String[] enabledProtocols,
111 String[] enabledCipherSuites) throws IOException {
112 super();
113 init(sslParameters, enabledProtocols, enabledCipherSuites);
114 }
115
116 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800117 * Class constructor with 3 parameters
118 *
119 * @throws IOException if network fails
120 * @throws java.net.UnknownHostException host not defined
121 */
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700122 protected OpenSSLSocketImpl(String host, int port, SSLParameters sslParameters)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800123 throws IOException {
124 super(host, port);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800125 init(sslParameters);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800126 }
127
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800128 /**
129 * Class constructor with 3 parameters: 1st is InetAddress
130 *
131 * @throws IOException if network fails
132 * @throws java.net.UnknownHostException host not defined
133 */
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700134 protected OpenSSLSocketImpl(InetAddress address, int port, SSLParameters sslParameters)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800135 throws IOException {
136 super(address, port);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800137 init(sslParameters);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800138 }
139
140
141 /**
142 * Class constructor with 5 parameters: 1st is host
143 *
144 * @throws IOException if network fails
145 * @throws java.net.UnknownHostException host not defined
146 */
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700147 protected OpenSSLSocketImpl(String host, int port,
148 InetAddress clientAddress, int clientPort,
149 SSLParameters sslParameters)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800150 throws IOException {
151 super(host, port, clientAddress, clientPort);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800152 init(sslParameters);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800153 }
154
155 /**
156 * Class constructor with 5 parameters: 1st is InetAddress
157 *
158 * @throws IOException if network fails
159 * @throws java.net.UnknownHostException host not defined
160 */
161 protected OpenSSLSocketImpl(InetAddress address, int port,
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700162 InetAddress clientAddress, int clientPort,
163 SSLParameters sslParameters)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800164 throws IOException {
165 super(address, port, clientAddress, clientPort);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800166 init(sslParameters);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800167 }
168
169 /**
170 * Constructor with 5 parameters: 1st is socket. Enhances an existing socket
Brian Carlstroma653cca2010-05-18 13:45:26 -0700171 * with SSL functionality. Invoked via OpenSSLSocketImplWrapper constructor.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800172 *
173 * @throws IOException if network fails
174 */
175 protected OpenSSLSocketImpl(Socket socket, String host, int port,
176 boolean autoClose, SSLParameters sslParameters) throws IOException {
177 super();
178 this.socket = socket;
179 this.timeout = socket.getSoTimeout();
Brian Carlstroma653cca2010-05-18 13:45:26 -0700180 this.wrappedHost = host;
181 this.wrappedPort = port;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800182 this.autoClose = autoClose;
Brian Carlstromecaf7592010-03-02 16:55:35 -0800183 init(sslParameters);
184 }
185
186 /**
187 * Initialize the SSL socket and set the certificates for the
188 * future handshaking.
189 */
190 private void init(SSLParameters sslParameters) throws IOException {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700191 init(sslParameters,
192 NativeCrypto.getSupportedProtocols(),
193 NativeCrypto.getDefaultCipherSuites());
194 }
195
196 /**
197 * Initialize the SSL socket and set the certificates for the
198 * future handshaking.
199 */
200 private void init(SSLParameters sslParameters,
201 String[] enabledProtocols,
202 String[] enabledCipherSuites) throws IOException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800203 this.sslParameters = sslParameters;
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700204 this.enabledProtocols = enabledProtocols;
205 this.enabledCipherSuites = enabledCipherSuites;
Brian Carlstromecaf7592010-03-02 16:55:35 -0800206 updateInstanceCount(1);
207 }
208
209 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800210 * Gets the suitable session reference from the session cache container.
211 *
212 * @return OpenSSLSessionImpl
213 */
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700214 private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800215 if (super.getInetAddress() == null ||
216 super.getInetAddress().getHostAddress() == null ||
217 super.getInetAddress().getHostName() == null) {
218 return null;
219 }
Brian Carlstrom9acacc32010-05-14 11:14:18 -0700220 OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800221 super.getInetAddress().getHostName(),
222 super.getPort());
Brian Carlstrom9acacc32010-05-14 11:14:18 -0700223 if (session == null) {
224 return null;
225 }
226
227 String protocol = session.getProtocol();
228 boolean protocolFound = false;
229 for (String enabledProtocol : enabledProtocols) {
230 if (protocol.equals(enabledProtocol)) {
231 protocolFound = true;
232 break;
233 }
234 }
235 if (!protocolFound) {
236 return null;
237 }
238
239 String cipherSuite = session.getCipherSuite();
240 boolean cipherSuiteFound = false;
241 for (String enabledCipherSuite : enabledCipherSuites) {
242 if (cipherSuite.equals(enabledCipherSuite)) {
243 cipherSuiteFound = true;
244 break;
245 }
246 }
247 if (!cipherSuiteFound) {
248 return null;
249 }
Brian Carlstrom6df63392010-05-18 11:33:13 -0700250
Brian Carlstrom9acacc32010-05-14 11:14:18 -0700251 return session;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800252 }
253
254 /**
255 * Ensures that logger is lazily loaded. The outer class seems to load
256 * before logging is ready.
257 */
258 static class LoggerHolder {
Brian Carlstromecaf7592010-03-02 16:55:35 -0800259 static final Logger logger = Logger.getLogger(OpenSSLSocketImpl.class.getName());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800260 }
261
262 /**
263 * Starts a TLS/SSL handshake on this connection using some native methods
264 * from the OpenSSL library. It can negotiate new encryption keys, change
265 * cipher suites, or initiate a new session. The certificate chain is
266 * verified if the correspondent property in java.Security is set. All
Brian Carlstromecaf7592010-03-02 16:55:35 -0800267 * listeners are notified at the end of the TLS/SSL handshake.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800268 *
269 * @throws <code>IOException</code> if network fails
270 */
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700271 public void startHandshake() throws IOException {
272 startHandshake(true);
273 }
274
275 /**
276 * Perform the handshake
277 * @param full If true, disable handshake cutthrough for a fully synchronous handshake
278 */
279 public synchronized void startHandshake(boolean full) throws IOException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800280 synchronized (handshakeLock) {
281 if (!handshakeStarted) {
282 handshakeStarted = true;
283 } else {
284 return;
285 }
286 }
287
Brian Carlstrom6df63392010-05-18 11:33:13 -0700288 // note that this modifies the global seed, not something specific to the connection
289 final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
290 final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
291 if (secureRandom == null) {
292 NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
293 } else {
294 NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
295 }
296
297 final boolean client = sslParameters.getUseClientMode();
298
299 final int sslCtxNativePointer = (client) ?
300 sslParameters.getClientSessionContext().sslCtxNativePointer :
301 sslParameters.getServerSessionContext().sslCtxNativePointer;
302
303 this.sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
304
305 // setup server certificates and private keys.
306 // clients will receive a call back to request certificates.
307 if (!client) {
308 for (String keyType : NativeCrypto.KEY_TYPES) {
309 setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
310 null,
311 null));
312 }
313 }
314
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700315 NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
316 NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800317
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700318 boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
319 if (!enableSessionCreation) {
320 NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
321 enableSessionCreation);
322 }
323
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700324 AbstractSessionContext sessionContext;
325 OpenSSLSessionImpl session;
326 if (client) {
327 // look for client session to reuse
328 ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
329 sessionContext = clientSessionContext;
330 session = getCachedClientSession(clientSessionContext);
331 if (session != null) {
332 NativeCrypto.SSL_set_session(sslNativePointer, session.sslSessionNativePointer);
333 }
334 } else {
335 sessionContext = sslParameters.getServerSessionContext();
336 session = null;
337 }
338
339 // setup peer certificate verification
340 if (client) {
Brian Carlstrom6df63392010-05-18 11:33:13 -0700341 // TODO support for anonymous cipher would require us to
342 // conditionally use SSL_VERIFY_NONE
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700343 } else {
344 // needing client auth takes priority...
345 if (sslParameters.getNeedClientAuth()) {
346 NativeCrypto.SSL_set_verify(sslNativePointer,
347 NativeCrypto.SSL_VERIFY_PEER|
348 NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
349 NativeCrypto.SSL_VERIFY_CLIENT_ONCE);
350 // ... over just wanting it...
351 } else if (sslParameters.getWantClientAuth()) {
352 NativeCrypto.SSL_set_verify(sslNativePointer,
353 NativeCrypto.SSL_VERIFY_PEER|
354 NativeCrypto.SSL_VERIFY_CLIENT_ONCE);
355 }
356 // ... and it defaults properly so we don't need call SSL_set_verify in the common case.
357 }
358
359 if (client && full) {
360 // we want to do a full synchronous handshake, so turn off cutthrough
Brian Carlstrom6df63392010-05-18 11:33:13 -0700361 NativeCrypto.SSL_clear_mode(sslNativePointer,
362 NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800363 }
364
Brian Carlstromecaf7592010-03-02 16:55:35 -0800365 // BEGIN android-added
366 // Temporarily use a different timeout for the handshake process
367 int savedTimeout = timeout;
368 if (handshakeTimeout >= 0) {
369 setSoTimeout(handshakeTimeout);
370 }
371 // END android-added
372
Brian Carlstromecaf7592010-03-02 16:55:35 -0800373
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700374 Socket socket = this.socket != null ? this.socket : this;
375 int sslSessionNativePointer;
376 try {
Brian Carlstrom6df63392010-05-18 11:33:13 -0700377 sslSessionNativePointer
378 = NativeCrypto.SSL_do_handshake(sslNativePointer, socket, this, timeout, client);
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700379 } catch (CertificateException e) {
380 throw new SSLPeerUnverifiedException(e.getMessage());
381 }
Brian Carlstromf002bdd2010-05-05 13:23:14 -0700382 byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700383 sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
384 if (sslSession != null) {
Brian Carlstrom9acacc32010-05-14 11:14:18 -0700385 sslSession.lastAccessedTime = System.currentTimeMillis();
Brian Carlstromecaf7592010-03-02 16:55:35 -0800386 LoggerHolder.logger.fine("Reused cached session for "
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700387 + getInetAddress() + ".");
Brian Carlstromf002bdd2010-05-05 13:23:14 -0700388 NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800389 } else {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700390 if (!enableSessionCreation) {
391 // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
392 throw new IllegalStateException("SSL Session may not be created");
393 }
394 byte[][] localCertificatesBytes = NativeCrypto.SSL_get_certificate(sslNativePointer);
395 X509Certificate[] localCertificates;
396 if (localCertificatesBytes == null) {
397 localCertificates = null;
Brian Carlstromecaf7592010-03-02 16:55:35 -0800398 } else {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700399 localCertificates = new X509Certificate[localCertificatesBytes.length];
400 for (int i = 0; i < localCertificatesBytes.length; i++) {
401 try {
402 // TODO do not go through PEM decode, DER encode, DER decode
403 localCertificates[i]
404 = new X509CertImpl(
405 javax.security.cert.X509Certificate.getInstance(
406 localCertificatesBytes[i]).getEncoded());
407 } catch (javax.security.cert.CertificateException e) {
408 throw new IOException("Problem decoding local certificate", e);
409 }
410 }
Brian Carlstromecaf7592010-03-02 16:55:35 -0800411 }
412
Brian Carlstroma653cca2010-05-18 13:45:26 -0700413 if (wrappedHost == null) {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700414 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
Brian Carlstromecaf7592010-03-02 16:55:35 -0800415 super.getInetAddress().getHostName(),
416 super.getPort(), sessionContext);
417 } else {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700418 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
Brian Carlstroma653cca2010-05-18 13:45:26 -0700419 wrappedHost, wrappedPort,
Brian Carlstromecaf7592010-03-02 16:55:35 -0800420 sessionContext);
421 }
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700422 // if not, putSession later in handshakeCompleted() callback
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700423 if (handshakeCompleted) {
Brian Carlstromecaf7592010-03-02 16:55:35 -0800424 sessionContext.putSession(sslSession);
Brian Carlstromecaf7592010-03-02 16:55:35 -0800425 }
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700426 LoggerHolder.logger.fine("Created new session for "
427 + getInetAddress().getHostName() + ".");
Brian Carlstromecaf7592010-03-02 16:55:35 -0800428 }
429
430 // BEGIN android-added
431 // Restore the original timeout now that the handshake is complete
432 if (handshakeTimeout >= 0) {
433 setSoTimeout(savedTimeout);
434 }
435 // END android-added
436
Brian Carlstrom0c131a22010-05-20 15:27:31 -0700437 // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700438 if (handshakeCompleted) {
439 notifyHandshakeCompletedListeners();
440 }
441
442 }
443
Brian Carlstrom6df63392010-05-18 11:33:13 -0700444 private void setCertificate (String alias) throws IOException {
445 if (alias == null) {
446 return;
447 }
448
449 PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
Brian Carlstrom12cd1f02010-06-22 23:43:20 -0700450 byte[] privateKeyBytes = privateKey.getEncoded();
Brian Carlstrom6df63392010-05-18 11:33:13 -0700451 NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
452
453 X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
Brian Carlstrom12cd1f02010-06-22 23:43:20 -0700454 byte[][] certificateBytes = new byte[certificates.length][];
455 for (int i = 0; i < certificates.length; i++) {
456 try {
457 certificateBytes[i] = certificates[i].getEncoded();
458 } catch (CertificateEncodingException e) {
459 throw new IOException("Problem encoding certificate " + certificates[i], e);
460 }
Brian Carlstrom6df63392010-05-18 11:33:13 -0700461 }
Brian Carlstrom6df63392010-05-18 11:33:13 -0700462 // TODO SSL_use_certificate only looks at the first certificate in the chain.
463 // It would be better to use a custom version of SSL_CTX_use_certificate_chain_file
464 // to set the whole chain. Note there is no SSL_ equivalent of this SSL_CTX_ function.
465 NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
466
467 // checks the last installed private key and certificate,
468 // so need to do this once per loop iteration
469 NativeCrypto.SSL_check_private_key(sslNativePointer);
470 }
471
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700472 /**
Brian Carlstrom6df63392010-05-18 11:33:13 -0700473 * Implementation of NativeCrypto.SSLHandshakeCallbacks
474 * invoked via JNI from client_cert_cb
475 */
476 public void clientCertificateRequested(String keyType) throws IOException {
477 setCertificate(sslParameters.getKeyManager().chooseClientAlias(new String[] { keyType },
478 null,
479 null));
480 }
481
482 /**
483 * Implementation of NativeCrypto.SSLHandshakeCallbacks
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700484 * invoked via JNI from info_callback
485 */
486 public void handshakeCompleted() {
487 handshakeCompleted = true;
488
489 // If sslSession is null, the handshake was completed during
490 // the call to NativeCrypto.SSL_do_handshake and not during a
491 // later read operation. That means we do not need to fixup
492 // the SSLSession and session cache or notify
493 // HandshakeCompletedListeners, it will be done in
494 // startHandshake.
495 if (sslSession == null) {
496 return;
497 }
498
499 // reset session id from the native pointer and update the
500 // appropriate cache.
501 sslSession.resetId();
502 AbstractSessionContext sessionContext =
503 (sslParameters.getUseClientMode())
504 ? sslParameters.getClientSessionContext()
505 : sslParameters.getServerSessionContext();
506 sessionContext.putSession(sslSession);
507
508 // let listeners know we are finally done
509 notifyHandshakeCompletedListeners();
510 }
511
512 private void notifyHandshakeCompletedListeners() {
513 if (listeners != null && !listeners.isEmpty()) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800514 // notify the listeners
515 HandshakeCompletedEvent event =
516 new HandshakeCompletedEvent(this, sslSession);
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700517 for (HandshakeCompletedListener listener : listeners) {
518 try {
519 listener.handshakeCompleted(event);
520 } catch (RuntimeException e) {
Brian Carlstrome688a412010-05-04 15:40:51 -0700521 // The RI runs the handlers in a separate thread,
522 // which we do not. But we try to preserve their
523 // behavior of logging a problem and not killing
524 // the handshaking thread just because a listener
525 // has a problem.
526 Thread thread = Thread.currentThread();
527 thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700528 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800529 }
530 }
531 }
532
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800533 /**
Brian Carlstrom6df63392010-05-18 11:33:13 -0700534 * Implementation of NativeCrypto.SSLHandshakeCallbacks
Brian Carlstromecaf7592010-03-02 16:55:35 -0800535 *
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700536 * @param bytes An array of certficates in PEM encode bytes
537 * @param authMethod auth algorithm name
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800538 *
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700539 * @throws CertificateException if the certificate is untrusted
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800540 */
541 @SuppressWarnings("unused")
Brian Carlstrom6df63392010-05-18 11:33:13 -0700542 public void verifyCertificateChain(byte[][] bytes, String authMethod)
543 throws CertificateException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800544 try {
Brian Carlstrome688a412010-05-04 15:40:51 -0700545 if (bytes == null || bytes.length == 0) {
546 throw new SSLException("Peer sent no certificate");
547 }
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700548 X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
549 for (int i = 0; i < bytes.length; i++) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800550 peerCertificateChain[i] =
Brian Carlstrom6df63392010-05-18 11:33:13 -0700551 new X509CertImpl(
552 javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded());
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800553 }
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700554 boolean client = sslParameters.getUseClientMode();
555 if (client) {
Brian Carlstrom6df63392010-05-18 11:33:13 -0700556 sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
557 authMethod);
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700558 } else {
Brian Carlstrom6df63392010-05-18 11:33:13 -0700559 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
560 authMethod);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800561 }
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700562
563 } catch (CertificateException e) {
564 throw e;
565 } catch (Exception e) {
566 throw new RuntimeException(e);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800567 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800568 }
569
570 /**
571 * Returns an input stream for this SSL socket using native calls to the
572 * OpenSSL library.
573 *
574 * @return: an input stream for reading bytes from this socket.
575 * @throws: <code>IOException</code> if an I/O error occurs when creating
576 * the input stream, the socket is closed, the socket is not
577 * connected, or the socket input has been shutdown.
578 */
579 public InputStream getInputStream() throws IOException {
580 synchronized(this) {
581 if (is == null) {
582 is = new SSLInputStream();
583 }
584
585 return is;
586 }
587 }
588
589 /**
590 * Returns an output stream for this SSL socket using native calls to the
591 * OpenSSL library.
592 *
593 * @return an output stream for writing bytes to this socket.
594 * @throws <code>IOException</code> if an I/O error occurs when creating
595 * the output stream, or no connection to the socket exists.
596 */
597 public OutputStream getOutputStream() throws IOException {
598 synchronized(this) {
599 if (os == null) {
600 os = new SSLOutputStream();
601 }
602
603 return os;
604 }
605 }
606
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700607 /**
608 * This method is not supported for this SSLSocket implementation
609 * because reading from an SSLSocket may involve writing to the
610 * network.
611 */
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800612 public void shutdownInput() throws IOException {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700613 throw new UnsupportedOperationException();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800614 }
615
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700616 /**
617 * This method is not supported for this SSLSocket implementation
618 * because writing to an SSLSocket may involve reading from the
619 * network.
620 */
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800621 public void shutdownOutput() throws IOException {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700622 throw new UnsupportedOperationException();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800623 }
624
625 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800626 * This inner class provides input data stream functionality
627 * for the OpenSSL native implementation. It is used to
628 * read data received via SSL protocol.
629 */
630 private class SSLInputStream extends InputStream {
631 SSLInputStream() throws IOException {
632 /**
633 /* Note: When startHandshake() throws an exception, no
634 * SSLInputStream object will be created.
635 */
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700636 OpenSSLSocketImpl.this.startHandshake(false);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800637 }
638
639 /**
640 * Reads one byte. If there is no data in the underlying buffer,
641 * this operation can block until the data will be
642 * available.
643 * @return read value.
644 * @throws <code>IOException</code>
645 */
646 public int read() throws IOException {
647 synchronized(readLock) {
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700648 return NativeCrypto.SSL_read_byte(sslNativePointer, timeout);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800649 }
650 }
651
652 /**
653 * Method acts as described in spec for superclass.
654 * @see java.io.InputStream#read(byte[],int,int)
655 */
656 public int read(byte[] b, int off, int len) throws IOException {
657 synchronized(readLock) {
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700658 return NativeCrypto.SSL_read(sslNativePointer, b, off, len, timeout);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800659 }
660 }
661 }
662
663 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800664 * This inner class provides output data stream functionality
665 * for the OpenSSL native implementation. It is used to
666 * write data according to the encryption parameters given in SSL context.
667 */
668 private class SSLOutputStream extends OutputStream {
669 SSLOutputStream() throws IOException {
670 /**
671 /* Note: When startHandshake() throws an exception, no
Brian Carlstromecaf7592010-03-02 16:55:35 -0800672 * SSLOutputStream object will be created.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800673 */
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700674 OpenSSLSocketImpl.this.startHandshake(false);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800675 }
676
677 /**
678 * Method acts as described in spec for superclass.
679 * @see java.io.OutputStream#write(int)
680 */
681 public void write(int b) throws IOException {
682 synchronized(writeLock) {
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700683 NativeCrypto.SSL_write_byte(sslNativePointer, b);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800684 }
685 }
686
687 /**
688 * Method acts as described in spec for superclass.
689 * @see java.io.OutputStream#write(byte[],int,int)
690 */
691 public void write(byte[] b, int start, int len) throws IOException {
692 synchronized(writeLock) {
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700693 NativeCrypto.SSL_write(sslNativePointer, b, start, len);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800694 }
695 }
696 }
697
698
699 /**
700 * The SSL session used by this connection is returned. The SSL session
701 * determines which cipher suite should be used by all connections within
702 * that session and which identities have the session's client and server.
703 * This method starts the SSL handshake.
704 * @return the SSLSession.
705 * @throws <code>IOException</code> if the handshake fails
706 */
707 public SSLSession getSession() {
708 try {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700709 startHandshake(true);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800710 } catch (IOException e) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800711 // return an invalid session with
712 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
713 return SSLSessionImpl.NULL_SESSION;
714 }
715 return sslSession;
716 }
717
718 /**
719 * Registers a listener to be notified that a SSL handshake
720 * was successfully completed on this connection.
721 * @throws <code>IllegalArgumentException</code> if listener is null.
722 */
723 public void addHandshakeCompletedListener(
724 HandshakeCompletedListener listener) {
725 if (listener == null) {
726 throw new IllegalArgumentException("Provided listener is null");
727 }
728 if (listeners == null) {
729 listeners = new ArrayList();
730 }
731 listeners.add(listener);
732 }
733
734 /**
735 * The method removes a registered listener.
736 * @throws IllegalArgumentException if listener is null or not registered
737 */
738 public void removeHandshakeCompletedListener(
739 HandshakeCompletedListener listener) {
740 if (listener == null) {
741 throw new IllegalArgumentException("Provided listener is null");
742 }
743 if (listeners == null) {
744 throw new IllegalArgumentException(
745 "Provided listener is not registered");
746 }
747 if (!listeners.remove(listener)) {
748 throw new IllegalArgumentException(
749 "Provided listener is not registered");
750 }
751 }
752
753 /**
754 * Returns true if new SSL sessions may be established by this socket.
755 *
756 * @return true if the session may be created; false if a session already
757 * exists and must be resumed.
758 */
759 public boolean getEnableSessionCreation() {
760 return sslParameters.getEnableSessionCreation();
761 }
762
763 /**
764 * Set a flag for the socket to inhibit or to allow the creation of a new
765 * SSL sessions. If the flag is set to false, and there are no actual
766 * sessions to resume, then there will be no successful handshaking.
767 *
768 * @param flag true if session may be created; false
769 * if a session already exists and must be resumed.
770 */
771 public void setEnableSessionCreation(boolean flag) {
772 sslParameters.setEnableSessionCreation(flag);
773 }
774
775 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800776 * The names of the cipher suites which could be used by the SSL connection
777 * are returned.
778 * @return an array of cipher suite names
779 */
780 public String[] getSupportedCipherSuites() {
Brian Carlstromecaf7592010-03-02 16:55:35 -0800781 return NativeCrypto.getSupportedCipherSuites();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800782 }
783
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800784 /**
785 * The names of the cipher suites that are in use in the actual the SSL
786 * connection are returned.
787 *
788 * @return an array of cipher suite names
789 */
790 public String[] getEnabledCipherSuites() {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700791 return enabledCipherSuites.clone();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800792 }
793
794 /**
795 * This method enables the cipher suites listed by
796 * getSupportedCipherSuites().
797 *
798 * @param suites names of all the cipher suites to
799 * put on use
800 * @throws IllegalArgumentException when one or more of the
801 * ciphers in array suites are not supported, or when the array
802 * is null.
803 */
804 public void setEnabledCipherSuites(String[] suites) {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700805 enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800806 }
807
808 /**
809 * The names of the protocols' versions that may be used on this SSL
810 * connection.
811 * @return an array of protocols names
812 */
813 public String[] getSupportedProtocols() {
Brian Carlstromecaf7592010-03-02 16:55:35 -0800814 return NativeCrypto.getSupportedProtocols();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800815 }
816
817 /**
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800818 * The names of the protocols' versions that are in use on this SSL
819 * connection.
Brian Carlstromecaf7592010-03-02 16:55:35 -0800820 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800821 * @return an array of protocols names
822 */
823 @Override
824 public String[] getEnabledProtocols() {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700825 return enabledProtocols.clone();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800826 }
827
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800828 /**
829 * This method enables the protocols' versions listed by
830 * getSupportedProtocols().
Brian Carlstromecaf7592010-03-02 16:55:35 -0800831 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800832 * @param protocols The names of all the protocols to put on use
Brian Carlstromecaf7592010-03-02 16:55:35 -0800833 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800834 * @throws IllegalArgumentException when one or more of the names in the
835 * array are not supported, or when the array is null.
836 */
837 @Override
838 public synchronized void setEnabledProtocols(String[] protocols) {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700839 enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800840 }
841
842 /**
843 * This method gives true back if the SSL socket is set to client mode.
844 *
845 * @return true if the socket should do the handshaking as client.
846 */
847 public boolean getUseClientMode() {
848 return sslParameters.getUseClientMode();
849 }
850
851 /**
852 * This method set the actual SSL socket to client mode.
853 *
854 * @param mode true if the socket starts in client
855 * mode
856 * @throws IllegalArgumentException if mode changes during
857 * handshake.
858 */
859 public synchronized void setUseClientMode(boolean mode) {
860 if (handshakeStarted) {
861 throw new IllegalArgumentException(
862 "Could not change the mode after the initial handshake has begun.");
863 }
864 sslParameters.setUseClientMode(mode);
865 }
866
867 /**
868 * Returns true if the SSL socket requests client's authentication. Relevant
869 * only for server sockets!
870 *
871 * @return true if client authentication is desired, false if not.
872 */
873 public boolean getWantClientAuth() {
874 return sslParameters.getWantClientAuth();
875 }
876
877 /**
878 * Returns true if the SSL socket needs client's authentication. Relevant
879 * only for server sockets!
880 *
881 * @return true if client authentication is desired, false if not.
882 */
883 public boolean getNeedClientAuth() {
884 return sslParameters.getNeedClientAuth();
885 }
886
887 /**
888 * Sets the SSL socket to use client's authentication. Relevant only for
889 * server sockets!
890 *
891 * @param need true if client authentication is
892 * desired, false if not.
893 */
894 public void setNeedClientAuth(boolean need) {
895 sslParameters.setNeedClientAuth(need);
896 }
897
898 /**
899 * Sets the SSL socket to use client's authentication. Relevant only for
900 * server sockets! Notice that in contrast to setNeedClientAuth(..) this
901 * method will continue the negotiation if the client decide not to send
902 * authentication credentials.
903 *
904 * @param want true if client authentication is
905 * desired, false if not.
906 */
907 public void setWantClientAuth(boolean want) {
908 sslParameters.setWantClientAuth(want);
909 }
910
911 /**
912 * This method is not supported for SSLSocket implementation.
913 */
914 public void sendUrgentData(int data) throws IOException {
915 throw new SocketException(
916 "Method sendUrgentData() is not supported.");
917 }
918
919 /**
920 * This method is not supported for SSLSocket implementation.
921 */
922 public void setOOBInline(boolean on) throws SocketException {
923 throw new SocketException(
924 "Methods sendUrgentData, setOOBInline are not supported.");
925 }
926
927 /**
928 * Set the read timeout on this socket. The SO_TIMEOUT option, is specified
929 * in milliseconds. The read operation will block indefinitely for a zero
930 * value.
931 *
932 * @param timeout the read timeout value
933 * @throws SocketException if an error occurs setting the option
934 */
935 public synchronized void setSoTimeout(int timeout) throws SocketException {
936 super.setSoTimeout(timeout);
937 this.timeout = timeout;
938 }
939
Dan Egnor9d48f972010-02-10 11:48:08 -0800940 // BEGIN android-added
941 /**
942 * Set the handshake timeout on this socket. This timeout is specified in
943 * milliseconds and will be used only during the handshake process.
944 *
945 * @param timeout the handshake timeout value
946 */
947 public synchronized void setHandshakeTimeout(int timeout) throws SocketException {
948 this.handshakeTimeout = timeout;
949 }
950 // END android-added
951
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800952 /**
953 * Closes the SSL socket. Once closed, a socket is not available for further
954 * use anymore under any circumstance. A new socket must be created.
955 *
956 * @throws <code>IOException</code> if an I/O error happens during the
957 * socket's closure.
958 */
959 public void close() throws IOException {
960 // TODO: Close SSL sockets using a background thread so they close
961 // gracefully.
962
963 synchronized (handshakeLock) {
964 if (!handshakeStarted) {
Brian Carlstrombcfb3252010-05-02 11:27:52 -0700965 // prevent further attemps to start handshake
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800966 handshakeStarted = true;
Brian Carlstromecaf7592010-03-02 16:55:35 -0800967
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800968 synchronized (this) {
Brian Carlstromecaf7592010-03-02 16:55:35 -0800969 free();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800970
971 if (socket != null) {
972 if (autoClose && !socket.isClosed()) socket.close();
973 } else {
974 if (!super.isClosed()) super.close();
975 }
976 }
Brian Carlstromecaf7592010-03-02 16:55:35 -0800977
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800978 return;
979 }
980 }
981
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700982 NativeCrypto.SSL_interrupt(sslNativePointer);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800983
984 synchronized (this) {
985 synchronized (writeLock) {
986 synchronized (readLock) {
987
988 IOException pendingException = null;
989
990 // Shut down the SSL connection, per se.
991 try {
992 if (handshakeStarted) {
Brian Carlstrom3e24c532010-05-06 00:23:21 -0700993 NativeCrypto.SSL_shutdown(sslNativePointer);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800994 }
995 } catch (IOException ex) {
996 /*
997 * Note the exception at this point, but try to continue
998 * to clean the rest of this all up before rethrowing.
999 */
1000 pendingException = ex;
1001 }
1002
1003 /*
1004 * Even if the above call failed, it is still safe to free
1005 * the native structs, and we need to do so lest we leak
1006 * memory.
1007 */
Brian Carlstromecaf7592010-03-02 16:55:35 -08001008 free();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001009
1010 if (socket != null) {
1011 if (autoClose && !socket.isClosed())
1012 socket.close();
1013 } else {
1014 if (!super.isClosed())
1015 super.close();
1016 }
1017
1018 if (pendingException != null) {
1019 throw pendingException;
1020 }
1021 }
1022 }
1023 }
1024 }
1025
Brian Carlstromecaf7592010-03-02 16:55:35 -08001026 private void free() {
1027 if (sslNativePointer == 0) {
1028 return;
1029 }
1030 NativeCrypto.SSL_free(sslNativePointer);
1031 sslNativePointer = 0;
1032 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001033
1034 protected void finalize() throws IOException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001035 /*
Brian Carlstrombcfb3252010-05-02 11:27:52 -07001036 * Just worry about our own state. Notably we do not try and
1037 * close anything. The SocketImpl, either our own
1038 * PlainSocketImpl, or the Socket we are wrapping, will do
1039 * that. This might mean we do not properly SSL_shutdown, but
1040 * if you want to do that, properly close the socket yourself.
1041 *
1042 * The reason why we don't try to SSL_shutdown, is that there
1043 * can be a race between finalizers where the PlainSocketImpl
1044 * finalizer runs first and closes the socket. However, in the
1045 * meanwhile, the underlying file descriptor could be reused
1046 * for another purpose. If we call SSL_shutdown, the
1047 * underlying socket BIOs still have the old file descriptor
1048 * and will write the close notify to some unsuspecting
1049 * reader.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001050 */
Brian Carlstrombcfb3252010-05-02 11:27:52 -07001051 updateInstanceCount(-1);
1052 free();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001053 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001054}