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