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