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