1 /* 2 * Copyright (C) 2017 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 static org.conscrypt.NativeConstants.SSL_RECEIVED_SHUTDOWN; 20 import static org.conscrypt.NativeConstants.SSL_SENT_SHUTDOWN; 21 22 import java.io.FileDescriptor; 23 import java.io.IOException; 24 import java.io.UnsupportedEncodingException; 25 import java.net.SocketTimeoutException; 26 import java.security.InvalidKeyException; 27 import java.security.PrivateKey; 28 import java.security.PublicKey; 29 import java.security.cert.CertificateEncodingException; 30 import java.security.cert.CertificateException; 31 import java.security.cert.X509Certificate; 32 import java.util.HashSet; 33 import java.util.Set; 34 import javax.crypto.SecretKey; 35 import javax.net.ssl.SSLException; 36 import javax.net.ssl.SSLHandshakeException; 37 import javax.net.ssl.X509KeyManager; 38 import javax.net.ssl.X509TrustManager; 39 import javax.security.auth.x500.X500Principal; 40 import org.conscrypt.NativeCrypto.SSLHandshakeCallbacks; 41 import org.conscrypt.SSLParametersImpl.AliasChooser; 42 import org.conscrypt.SSLParametersImpl.PSKCallbacks; 43 44 /** 45 * A utility wrapper that abstracts operations on the underlying native SSL instance. 46 */ 47 final class SslWrapper { 48 private final SSLParametersImpl parameters; 49 private final SSLHandshakeCallbacks handshakeCallbacks; 50 private final AliasChooser aliasChooser; 51 private final PSKCallbacks pskCallbacks; 52 private long ssl; 53 newInstance(SSLParametersImpl parameters, SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser, PSKCallbacks pskCallbacks)54 static SslWrapper newInstance(SSLParametersImpl parameters, 55 SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser, 56 PSKCallbacks pskCallbacks) throws SSLException { 57 long ctx = parameters.getSessionContext().sslCtxNativePointer; 58 long ssl = NativeCrypto.SSL_new(ctx); 59 return new SslWrapper(ssl, parameters, handshakeCallbacks, chooser, pskCallbacks); 60 } 61 SslWrapper(long ssl, SSLParametersImpl parameters, SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser, PSKCallbacks pskCallbacks)62 private SslWrapper(long ssl, SSLParametersImpl parameters, 63 SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser, 64 PSKCallbacks pskCallbacks) { 65 this.ssl = ssl; 66 this.parameters = parameters; 67 this.handshakeCallbacks = handshakeCallbacks; 68 this.aliasChooser = aliasChooser; 69 this.pskCallbacks = pskCallbacks; 70 } 71 ssl()72 long ssl() { 73 return ssl; 74 } 75 newBio()76 BioWrapper newBio() { 77 try { 78 return new BioWrapper(); 79 } catch (SSLException e) { 80 throw new RuntimeException(e); 81 } 82 } 83 offerToResumeSession(long sslSessionNativePointer)84 void offerToResumeSession(long sslSessionNativePointer) throws SSLException { 85 NativeCrypto.SSL_set_session(ssl, sslSessionNativePointer); 86 } 87 getSessionId()88 byte[] getSessionId() { 89 return NativeCrypto.SSL_session_id(ssl); 90 } 91 getTime()92 long getTime() { 93 return NativeCrypto.SSL_get_time(ssl); 94 } 95 getTimeout()96 long getTimeout() { 97 return NativeCrypto.SSL_get_timeout(ssl); 98 } 99 setTimeout(long millis)100 void setTimeout(long millis) { 101 NativeCrypto.SSL_set_timeout(ssl, millis); 102 } 103 getCipherSuite()104 String getCipherSuite() { 105 return NativeCrypto.cipherSuiteToJava(NativeCrypto.SSL_get_current_cipher(ssl)); 106 } 107 getLocalCertificates()108 OpenSSLX509Certificate[] getLocalCertificates() { 109 return OpenSSLX509Certificate.createCertChain(NativeCrypto.SSL_get_certificate(ssl)); 110 } 111 getPeerCertificates()112 OpenSSLX509Certificate[] getPeerCertificates() { 113 return OpenSSLX509Certificate.createCertChain(NativeCrypto.SSL_get_peer_cert_chain(ssl)); 114 } 115 getPeerCertificateOcspData()116 byte[] getPeerCertificateOcspData() { 117 return NativeCrypto.SSL_get_ocsp_response(ssl); 118 } 119 getPeerTlsSctData()120 byte[] getPeerTlsSctData() { 121 return NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl); 122 } 123 124 /** 125 * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(String, byte[], byte[]) 126 */ 127 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package clientPSKKeyRequested(String identityHint, byte[] identityBytesOut, byte[] key)128 int clientPSKKeyRequested(String identityHint, byte[] identityBytesOut, byte[] key) { 129 PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 130 if (pskKeyManager == null) { 131 return 0; 132 } 133 134 String identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint); 135 // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut 136 byte[] identityBytes; 137 if (identity == null) { 138 identity = ""; 139 identityBytes = EmptyArray.BYTE; 140 } else if (identity.isEmpty()) { 141 identityBytes = EmptyArray.BYTE; 142 } else { 143 try { 144 identityBytes = identity.getBytes("UTF-8"); 145 } catch (UnsupportedEncodingException e) { 146 throw new RuntimeException("UTF-8 encoding not supported", e); 147 } 148 } 149 if (identityBytes.length + 1 > identityBytesOut.length) { 150 // Insufficient space in the output buffer 151 return 0; 152 } 153 if (identityBytes.length > 0) { 154 System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length); 155 } 156 identityBytesOut[identityBytes.length] = 0; 157 158 SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity); 159 byte[] secretKeyBytes = secretKey.getEncoded(); 160 if (secretKeyBytes == null) { 161 return 0; 162 } else if (secretKeyBytes.length > key.length) { 163 // Insufficient space in the output buffer 164 return 0; 165 } 166 System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length); 167 return secretKeyBytes.length; 168 } 169 170 /** 171 * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(String, String, byte[]) 172 */ 173 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package serverPSKKeyRequested(String identityHint, String identity, byte[] key)174 int serverPSKKeyRequested(String identityHint, String identity, byte[] key) { 175 PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 176 if (pskKeyManager == null) { 177 return 0; 178 } 179 SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity); 180 byte[] secretKeyBytes = secretKey.getEncoded(); 181 if (secretKeyBytes == null) { 182 return 0; 183 } else if (secretKeyBytes.length > key.length) { 184 return 0; 185 } 186 System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length); 187 return secretKeyBytes.length; 188 } 189 chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)190 void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) 191 throws SSLException, CertificateEncodingException { 192 Set<String> keyTypesSet = SSLUtils.getSupportedClientKeyTypes(keyTypeBytes); 193 String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]); 194 195 X500Principal[] issuers; 196 if (asn1DerEncodedPrincipals == null) { 197 issuers = null; 198 } else { 199 issuers = new X500Principal[asn1DerEncodedPrincipals.length]; 200 for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { 201 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); 202 } 203 } 204 X509KeyManager keyManager = parameters.getX509KeyManager(); 205 String alias = (keyManager != null) 206 ? aliasChooser.chooseClientAlias(keyManager, issuers, keyTypes) 207 : null; 208 setCertificate(alias); 209 } 210 setCertificate(String alias)211 void setCertificate(String alias) throws CertificateEncodingException, SSLException { 212 if (alias == null) { 213 return; 214 } 215 X509KeyManager keyManager = parameters.getX509KeyManager(); 216 if (keyManager == null) { 217 return; 218 } 219 PrivateKey privateKey = keyManager.getPrivateKey(alias); 220 if (privateKey == null) { 221 return; 222 } 223 X509Certificate[] certificates = keyManager.getCertificateChain(alias); 224 if (certificates == null) { 225 return; 226 } 227 PublicKey publicKey = (certificates.length > 0) ? certificates[0].getPublicKey() : null; 228 229 /* 230 * Make sure we keep a reference to the OpenSSLX509Certificate by using 231 * this array. Otherwise, if they're not OpenSSLX509Certificate 232 * instances originally, they may be garbage collected before we 233 * complete our JNI calls. 234 */ 235 OpenSSLX509Certificate[] openSslCerts = new OpenSSLX509Certificate[certificates.length]; 236 long[] x509refs = new long[certificates.length]; 237 for (int i = 0; i < certificates.length; i++) { 238 OpenSSLX509Certificate openSslCert = 239 OpenSSLX509Certificate.fromCertificate(certificates[i]); 240 openSslCerts[i] = openSslCert; 241 x509refs[i] = openSslCert.getContext(); 242 } 243 244 // Note that OpenSSL says to use SSL_use_certificate before 245 // SSL_use_PrivateKey. 246 NativeCrypto.SSL_use_certificate(ssl, x509refs); 247 248 final OpenSSLKey key; 249 try { 250 key = OpenSSLKey.fromPrivateKeyForTLSStackOnly(privateKey, publicKey); 251 NativeCrypto.SSL_use_PrivateKey(ssl, key.getNativeRef()); 252 } catch (InvalidKeyException e) { 253 throw new SSLException(e); 254 } 255 256 // We may not have access to all the information to check the private key 257 // if it's a wrapped platform key, so skip this check. 258 if (!key.isWrapped()) { 259 // Makes sure the set PrivateKey and X509Certificate refer to the same 260 // key by comparing the public values. 261 NativeCrypto.SSL_check_private_key(ssl); 262 } 263 } 264 getVersion()265 String getVersion() { 266 return NativeCrypto.SSL_get_version(ssl); 267 } 268 isReused()269 boolean isReused() { 270 return NativeCrypto.SSL_session_reused(ssl); 271 } 272 getRequestedServerName()273 String getRequestedServerName() { 274 return NativeCrypto.SSL_get_servername(ssl); 275 } 276 getTlsChannelId()277 byte[] getTlsChannelId() throws SSLException { 278 return NativeCrypto.SSL_get_tls_channel_id(ssl); 279 } 280 initialize(String hostname, OpenSSLKey channelIdPrivateKey)281 void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException { 282 boolean enableSessionCreation = parameters.getEnableSessionCreation(); 283 if (!enableSessionCreation) { 284 NativeCrypto.SSL_set_session_creation_enabled(ssl, false); 285 } 286 287 // Allow servers to trigger renegotiation. Some inadvisable server 288 // configurations cause them to attempt to renegotiate during 289 // certain protocols. 290 NativeCrypto.SSL_accept_renegotiations(ssl); 291 292 if (isClient()) { 293 NativeCrypto.SSL_set_connect_state(ssl); 294 295 // Configure OCSP and CT extensions for client 296 NativeCrypto.SSL_enable_ocsp_stapling(ssl); 297 if (parameters.isCTVerificationEnabled(hostname)) { 298 NativeCrypto.SSL_enable_signed_cert_timestamps(ssl); 299 } 300 } else { 301 NativeCrypto.SSL_set_accept_state(ssl); 302 303 // Configure OCSP for server 304 if (parameters.getOCSPResponse() != null) { 305 NativeCrypto.SSL_enable_ocsp_stapling(ssl); 306 } 307 } 308 309 if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) { 310 throw new SSLHandshakeException("No enabled protocols; " 311 + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3 312 + " is no longer supported and was filtered from the list"); 313 } 314 NativeCrypto.SSL_configure_alpn(ssl, isClient(), parameters.alpnProtocols); 315 NativeCrypto.setEnabledProtocols(ssl, parameters.enabledProtocols); 316 NativeCrypto.setEnabledCipherSuites(ssl, parameters.enabledCipherSuites); 317 318 // setup server certificates and private keys. 319 // clients will receive a call back to request certificates. 320 if (!isClient()) { 321 Set<String> keyTypes = new HashSet<String>(); 322 for (long sslCipherNativePointer : NativeCrypto.SSL_get_ciphers(ssl)) { 323 String keyType = SSLUtils.getServerX509KeyType(sslCipherNativePointer); 324 if (keyType != null) { 325 keyTypes.add(keyType); 326 } 327 } 328 X509KeyManager keyManager = parameters.getX509KeyManager(); 329 if (keyManager != null) { 330 for (String keyType : keyTypes) { 331 try { 332 setCertificate(aliasChooser.chooseServerAlias(keyManager, keyType)); 333 } catch (CertificateEncodingException e) { 334 throw new IOException(e); 335 } 336 } 337 } 338 339 NativeCrypto.SSL_set_options(ssl, NativeConstants.SSL_OP_CIPHER_SERVER_PREFERENCE); 340 341 if (parameters.sctExtension != null) { 342 NativeCrypto.SSL_set_signed_cert_timestamp_list(ssl, parameters.sctExtension); 343 } 344 345 if (parameters.ocspResponse != null) { 346 NativeCrypto.SSL_set_ocsp_response(ssl, parameters.ocspResponse); 347 } 348 } 349 350 enablePSKKeyManagerIfRequested(); 351 352 if (parameters.useSessionTickets) { 353 NativeCrypto.SSL_clear_options(ssl, NativeConstants.SSL_OP_NO_TICKET); 354 } else { 355 NativeCrypto.SSL_set_options( 356 ssl, NativeCrypto.SSL_get_options(ssl) | NativeConstants.SSL_OP_NO_TICKET); 357 } 358 359 if (parameters.getUseSni() && AddressUtils.isValidSniHostname(hostname)) { 360 NativeCrypto.SSL_set_tlsext_host_name(ssl, hostname); 361 } 362 363 // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites 364 // with TLSv1 and SSLv3). 365 NativeCrypto.SSL_set_mode(ssl, NativeConstants.SSL_MODE_CBC_RECORD_SPLITTING); 366 367 setCertificateValidation(ssl); 368 setTlsChannelId(channelIdPrivateKey); 369 } 370 371 // TODO(nathanmittler): Remove once after we switch to the engine socket. doHandshake(FileDescriptor fd, int timeoutMillis)372 void doHandshake(FileDescriptor fd, int timeoutMillis) 373 throws CertificateException, SocketTimeoutException, SSLException { 374 NativeCrypto.SSL_do_handshake(ssl, fd, handshakeCallbacks, timeoutMillis); 375 } 376 doHandshake()377 int doHandshake() throws IOException { 378 return NativeCrypto.ENGINE_SSL_do_handshake(ssl, handshakeCallbacks); 379 } 380 381 // TODO(nathanmittler): Remove once after we switch to the engine socket. read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)382 int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 383 throws IOException { 384 return NativeCrypto.SSL_read(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); 385 } 386 387 // TODO(nathanmittler): Remove once after we switch to the engine socket. write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis)388 void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 389 throws IOException { 390 NativeCrypto.SSL_write(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); 391 } 392 393 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package enablePSKKeyManagerIfRequested()394 private void enablePSKKeyManagerIfRequested() throws SSLException { 395 // Enable Pre-Shared Key (PSK) key exchange if requested 396 PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 397 if (pskKeyManager != null) { 398 boolean pskEnabled = false; 399 for (String enabledCipherSuite : parameters.enabledCipherSuites) { 400 if ((enabledCipherSuite != null) && (enabledCipherSuite.contains("PSK"))) { 401 pskEnabled = true; 402 break; 403 } 404 } 405 if (pskEnabled) { 406 if (isClient()) { 407 NativeCrypto.set_SSL_psk_client_callback_enabled(ssl, true); 408 } else { 409 NativeCrypto.set_SSL_psk_server_callback_enabled(ssl, true); 410 String identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager); 411 NativeCrypto.SSL_use_psk_identity_hint(ssl, identityHint); 412 } 413 } 414 } 415 } 416 setTlsChannelId(OpenSSLKey channelIdPrivateKey)417 private void setTlsChannelId(OpenSSLKey channelIdPrivateKey) throws SSLException { 418 if (!parameters.channelIdEnabled) { 419 return; 420 } 421 422 if (parameters.getUseClientMode()) { 423 // Client-side TLS Channel ID 424 if (channelIdPrivateKey == null) { 425 throw new SSLHandshakeException("Invalid TLS channel ID key specified"); 426 } 427 NativeCrypto.SSL_set1_tls_channel_id(ssl, channelIdPrivateKey.getNativeRef()); 428 } else { 429 // Server-side TLS Channel ID 430 NativeCrypto.SSL_enable_tls_channel_id(ssl); 431 } 432 } 433 setCertificateValidation(long sslNativePointer)434 private void setCertificateValidation(long sslNativePointer) throws SSLException { 435 // setup peer certificate verification 436 if (!isClient()) { 437 // needing client auth takes priority... 438 boolean certRequested; 439 if (parameters.getNeedClientAuth()) { 440 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER 441 | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT); 442 certRequested = true; 443 // ... over just wanting it... 444 } else if (parameters.getWantClientAuth()) { 445 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_PEER); 446 certRequested = true; 447 // ... and we must disable verification if we don't want client auth. 448 } else { 449 NativeCrypto.SSL_set_verify(sslNativePointer, NativeCrypto.SSL_VERIFY_NONE); 450 certRequested = false; 451 } 452 453 if (certRequested) { 454 X509TrustManager trustManager = parameters.getX509TrustManager(); 455 X509Certificate[] issuers = trustManager.getAcceptedIssuers(); 456 if (issuers != null && issuers.length != 0) { 457 byte[][] issuersBytes; 458 try { 459 issuersBytes = SSLUtils.encodeIssuerX509Principals(issuers); 460 } catch (CertificateEncodingException e) { 461 throw new SSLException("Problem encoding principals", e); 462 } 463 NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes); 464 } 465 } 466 } 467 } 468 interrupt()469 void interrupt() { 470 NativeCrypto.SSL_interrupt(ssl); 471 } 472 473 // TODO(nathanmittler): Remove once after we switch to the engine socket. shutdown(FileDescriptor fd)474 void shutdown(FileDescriptor fd) throws IOException { 475 NativeCrypto.SSL_shutdown(ssl, fd, handshakeCallbacks); 476 } 477 shutdown()478 void shutdown() throws IOException { 479 NativeCrypto.ENGINE_SSL_shutdown(ssl, handshakeCallbacks); 480 } 481 wasShutdownReceived()482 boolean wasShutdownReceived() { 483 return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) != 0; 484 } 485 wasShutdownSent()486 boolean wasShutdownSent() { 487 return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN) != 0; 488 } 489 readDirectByteBuffer(long destAddress, int destLength)490 int readDirectByteBuffer(long destAddress, int destLength) 491 throws IOException, CertificateException { 492 return NativeCrypto.ENGINE_SSL_read_direct( 493 ssl, destAddress, destLength, handshakeCallbacks); 494 } 495 readArray(byte[] destJava, int destOffset, int destLength)496 int readArray(byte[] destJava, int destOffset, int destLength) 497 throws IOException, CertificateException { 498 return NativeCrypto.ENGINE_SSL_read_heap( 499 ssl, destJava, destOffset, destLength, handshakeCallbacks); 500 } 501 writeDirectByteBuffer(long sourceAddress, int sourceLength)502 int writeDirectByteBuffer(long sourceAddress, int sourceLength) throws IOException { 503 return NativeCrypto.ENGINE_SSL_write_direct( 504 ssl, sourceAddress, sourceLength, handshakeCallbacks); 505 } 506 writeArray(byte[] sourceJava, int sourceOffset, int sourceLength)507 int writeArray(byte[] sourceJava, int sourceOffset, int sourceLength) throws IOException { 508 return NativeCrypto.ENGINE_SSL_write_heap( 509 ssl, sourceJava, sourceOffset, sourceLength, handshakeCallbacks); 510 } 511 getPendingReadableBytes()512 int getPendingReadableBytes() { 513 return NativeCrypto.SSL_pending_readable_bytes(ssl); 514 } 515 getMaxSealOverhead()516 int getMaxSealOverhead() { 517 return NativeCrypto.SSL_max_seal_overhead(ssl); 518 } 519 close()520 void close() { 521 NativeCrypto.SSL_free(ssl); 522 ssl = 0L; 523 } 524 isClosed()525 boolean isClosed() { 526 return ssl == 0L; 527 } 528 getError(int result)529 int getError(int result) { 530 return NativeCrypto.SSL_get_error(ssl, result); 531 } 532 getAlpnSelectedProtocol()533 byte[] getAlpnSelectedProtocol() { 534 return NativeCrypto.SSL_get0_alpn_selected(ssl); 535 } 536 isClient()537 private boolean isClient() { 538 return parameters.getUseClientMode(); 539 } 540 541 /** 542 * A utility wrapper that abstracts operations on the underlying native BIO instance. 543 */ 544 final class BioWrapper { 545 private long bio; 546 BioWrapper()547 private BioWrapper() throws SSLException { 548 this.bio = NativeCrypto.SSL_BIO_new(ssl); 549 } 550 getPendingWrittenBytes()551 int getPendingWrittenBytes() { 552 return NativeCrypto.SSL_pending_written_bytes_in_BIO(bio); 553 } 554 writeDirectByteBuffer(long address, int length)555 int writeDirectByteBuffer(long address, int length) throws IOException { 556 return NativeCrypto.ENGINE_SSL_write_BIO_direct( 557 ssl, bio, address, length, handshakeCallbacks); 558 } 559 writeArray(byte[] sourceJava, int sourceOffset, int sourceLength)560 int writeArray(byte[] sourceJava, int sourceOffset, int sourceLength) throws IOException { 561 return NativeCrypto.ENGINE_SSL_write_BIO_heap( 562 ssl, bio, sourceJava, sourceOffset, sourceLength, handshakeCallbacks); 563 } 564 readDirectByteBuffer(long destAddress, int destLength)565 int readDirectByteBuffer(long destAddress, int destLength) throws IOException { 566 return NativeCrypto.ENGINE_SSL_read_BIO_direct( 567 ssl, bio, destAddress, destLength, handshakeCallbacks); 568 } 569 readArray(byte[] destJava, int destOffset, int destLength)570 int readArray(byte[] destJava, int destOffset, int destLength) throws IOException { 571 return NativeCrypto.ENGINE_SSL_read_BIO_heap( 572 ssl, bio, destJava, destOffset, destLength, handshakeCallbacks); 573 } 574 close()575 void close() { 576 NativeCrypto.BIO_free_all(bio); 577 bio = 0L; 578 } 579 } 580 } 581