1 module hunt.net.secure.conscrypt.NativeSsl; 2 3 // dfmt off 4 version(WITH_HUNT_SECURITY): 5 // dfmt on 6 7 import hunt.net.Exceptions; 8 import hunt.net.KeyCertOptions; 9 import hunt.net.secure.conscrypt.AbstractSessionContext; 10 import hunt.net.secure.conscrypt.AddressUtils; 11 import hunt.net.secure.conscrypt.NativeCrypto; 12 import hunt.net.secure.conscrypt.OpenSSLKey; 13 import hunt.net.secure.conscrypt.SSLParametersImpl; 14 import hunt.net.secure.conscrypt.SSLUtils; 15 16 // import hunt.net.ssl.X509KeyManager; 17 18 // import hunt.security.cert.X509Certificate; 19 // import hunt.security.Key; 20 // import hunt.security.x500.X500Principal; 21 22 import hunt.collection; 23 import hunt.logging; 24 import hunt.Exceptions; 25 26 import std.array; 27 import std.container.array; 28 29 import deimos.openssl.ssl; 30 31 32 /** 33 * A utility wrapper that abstracts operations on the underlying native SSL instance. 34 */ 35 final class NativeSsl { 36 private SSLParametersImpl parameters; 37 private SSLHandshakeCallbacks handshakeCallbacks; 38 // private AliasChooser aliasChooser; 39 // private PSKCallbacks pskCallbacks; 40 // private X509Certificate[] localCertificates; 41 // private ReadWriteLock lock = new ReentrantReadWriteLock(); 42 private long ssl; 43 44 // private this(long ssl, SSLParametersImpl parameters, 45 // SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser, 46 // PSKCallbacks pskCallbacks) { 47 // this.ssl = ssl; 48 // this.parameters = parameters; 49 // this.handshakeCallbacks = handshakeCallbacks; 50 // this.aliasChooser = aliasChooser; 51 // this.pskCallbacks = pskCallbacks; 52 // } 53 private this(long ssl, SSLParametersImpl parameters, 54 SSLHandshakeCallbacks handshakeCallbacks) { 55 this.ssl = ssl; 56 this.parameters = parameters; 57 this.handshakeCallbacks = handshakeCallbacks; 58 } 59 60 static NativeSsl newInstance(SSLParametersImpl parameters, 61 SSLHandshakeCallbacks handshakeCallbacks) { 62 63 AbstractSessionContext ctx = parameters.getSessionContext(); 64 version(HUNT_NET_DEBUG) warning("UseClientMode: ", parameters.getUseClientMode()); 65 66 // KeyCertOptions certOptions = parameters.getKeyCertOptions(); 67 68 // string caFile = certOptions.getCaFile(); 69 // if(!caFile.empty()) { 70 // ctx.useCaCertificate(caFile, certOptions.getCaPassword()); 71 // } 72 73 // string certFile = certOptions.getCertFile(); 74 // string keyFile = certOptions.getKeyFile(); 75 // if(!certFile.empty() && !keyFile.empty()) { 76 // ctx.useCertificate(certFile, keyFile, certOptions.getCertPassword(), certOptions.getKeyPassword()); 77 // } 78 79 long ssl_ctx = ctx.sslCtxNativePointer; 80 long ssl = NativeCrypto.SSL_new(ssl_ctx); 81 82 return new NativeSsl(ssl, parameters, handshakeCallbacks); // , chooser, pskCallbacks 83 } 84 85 BioWrapper newBio() { 86 try { 87 return new BioWrapper(this); 88 } catch (SSLException e) { 89 throw new RuntimeException(e); 90 } 91 } 92 93 void offerToResumeSession(long sslSessionNativePointer) { 94 NativeCrypto.SSL_set_session(ssl, sslSessionNativePointer); 95 } 96 97 byte[] getSessionId() { 98 return NativeCrypto.SSL_session_id(ssl); 99 } 100 101 long getTime() { 102 return NativeCrypto.SSL_get_time(ssl); 103 } 104 105 long getTimeout() { 106 return NativeCrypto.SSL_get_timeout(ssl); 107 } 108 109 void setTimeout(long millis) { 110 NativeCrypto.SSL_set_timeout(ssl, millis); 111 } 112 113 string getCipherSuite() { 114 return NativeCrypto.cipherSuiteToJava(NativeCrypto.SSL_get_current_cipher(ssl)); 115 } 116 117 // X509Certificate[] getPeerCertificates() { 118 // ubyte[][] encoded = null; 119 // version(Have_boringssl) encoded = NativeCrypto.SSL_get0_peer_certificates(ssl); 120 121 // return encoded is null ? null : SSLUtils.decodeX509CertificateChain(encoded); 122 // } 123 124 // X509Certificate[] getLocalCertificates() { 125 // return localCertificates; 126 // } 127 128 byte[] getPeerCertificateOcspData() { 129 return NativeCrypto.SSL_get_ocsp_response(ssl); 130 } 131 132 // byte[] getTlsUnique() { 133 // return NativeCrypto.SSL_get_tls_unique(ssl); 134 // } 135 136 // void setTokenBindingParams(int... params) { 137 // NativeCrypto.SSL_set_token_binding_params(ssl, params); 138 // } 139 140 // int getTokenBindingParams() { 141 // return NativeCrypto.SSL_get_token_binding_params(ssl); 142 // } 143 144 // byte[] exportKeyingMaterial(string label, byte[] context, int length) { 145 // if (label is null) { 146 // throw new NullPointerException("Label is null"); 147 // } 148 // byte[] labelBytes = label.getBytes(Charset.forName("US-ASCII")); 149 // return NativeCrypto.SSL_export_keying_material(ssl, labelBytes, context, length); 150 // } 151 152 byte[] getPeerTlsSctData() { 153 return NativeCrypto.SSL_get_signed_cert_timestamp_list(ssl); 154 } 155 156 /** 157 * @see NativeCrypto.SSLHandshakeCallbacks#clientPSKKeyRequested(string, byte[], byte[]) 158 */ 159 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 160 int clientPSKKeyRequested(string identityHint, byte[] identityBytesOut, byte[] key) { 161 162 implementationMissing(false); 163 return 0; 164 // PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 165 // if (pskKeyManager is null) { 166 // return 0; 167 // } 168 169 // string identity = pskCallbacks.chooseClientPSKIdentity(pskKeyManager, identityHint); 170 // // Store identity in NULL-terminated modified UTF-8 representation into ientityBytesOut 171 // byte[] identityBytes; 172 // if (identity is null) { 173 // identity = ""; 174 // identityBytes = EmptyArray.BYTE; 175 // } else if (identity.isEmpty()) { 176 // identityBytes = EmptyArray.BYTE; 177 // } else { 178 // try { 179 // identityBytes = identity.getBytes("UTF-8"); 180 // } catch (UnsupportedEncodingException e) { 181 // throw new RuntimeException("UTF-8 encoding not supported", e); 182 // } 183 // } 184 // if (identityBytes.length + 1 > identityBytesOut.length) { 185 // // Insufficient space in the output buffer 186 // return 0; 187 // } 188 // if (identityBytes.length > 0) { 189 // System.arraycopy(identityBytes, 0, identityBytesOut, 0, identityBytes.length); 190 // } 191 // identityBytesOut[identityBytes.length] = 0; 192 193 // SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity); 194 // byte[] secretKeyBytes = secretKey.getEncoded(); 195 // if (secretKeyBytes is null) { 196 // return 0; 197 // } else if (secretKeyBytes.length > key.length) { 198 // // Insufficient space in the output buffer 199 // return 0; 200 // } 201 // System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length); 202 // return secretKeyBytes.length; 203 } 204 205 /** 206 * @see NativeCrypto.SSLHandshakeCallbacks#serverPSKKeyRequested(string, string, byte[]) 207 */ 208 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 209 int serverPSKKeyRequested(string identityHint, string identity, byte[] key) { 210 211 implementationMissing(false); 212 return 0; 213 // PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 214 // if (pskKeyManager is null) { 215 // return 0; 216 // } 217 // SecretKey secretKey = pskCallbacks.getPSKKey(pskKeyManager, identityHint, identity); 218 // byte[] secretKeyBytes = secretKey.getEncoded(); 219 // if (secretKeyBytes is null) { 220 // return 0; 221 // } else if (secretKeyBytes.length > key.length) { 222 // return 0; 223 // } 224 // System.arraycopy(secretKeyBytes, 0, key, 0, secretKeyBytes.length); 225 // return secretKeyBytes.length; 226 } 227 228 void chooseClientCertificate(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) { 229 230 implementationMissing(false); 231 // Set<string> keyTypesSet = SSLUtils.getSupportedClientKeyTypes(keyTypeBytes); 232 // string[] keyTypes = keyTypesSet.toArray(new string[keyTypesSet.size()]); 233 234 // X500Principal[] issuers; 235 // if (asn1DerEncodedPrincipals is null) { 236 // issuers = null; 237 // } else { 238 // issuers = new X500Principal[asn1DerEncodedPrincipals.length]; 239 // for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { 240 // issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); 241 // } 242 // } 243 // X509KeyManager keyManager = parameters.getX509KeyManager(); 244 // string name = (keyManager !is null) 245 // ? aliasChooser.chooseClientAlias(keyManager, issuers, keyTypes) 246 // : null; 247 // setCertificate(name); 248 } 249 250 // void setCertificate(string name) { 251 // if (name.empty) { 252 // warning("The certificate name is empty"); 253 // return; 254 // } 255 // tracef("Certificate: %s", name); 256 // X509KeyManager keyManager = parameters.getX509KeyManager(); 257 // if (keyManager is null) { 258 // return; 259 // } 260 // PrivateKey privateKey = keyManager.getPrivateKey(name); 261 // if (privateKey is null) { 262 // return; 263 // } 264 // localCertificates = keyManager.getCertificateChain(name); 265 // if (localCertificates is null) { 266 // return; 267 // } 268 // size_t numLocalCerts = localCertificates.length; 269 // PublicKey publicKey = (numLocalCerts > 0) ? localCertificates[0].getPublicKey() : null; 270 271 // // Encode the local certificates. 272 // byte[][] encodedLocalCerts = new byte[][numLocalCerts]; 273 // for (size_t i = 0; i < numLocalCerts; ++i) { 274 // encodedLocalCerts[i] = localCertificates[i].getEncoded(); 275 // } 276 277 // // Convert the key so we can access a native reference. 278 // OpenSSLKey key; 279 // try { 280 // key = OpenSSLKey.fromPrivateKeyForTLSStackOnly(privateKey, publicKey); 281 // } catch (InvalidKeyException e) { 282 // throw new SSLException(e.msg); 283 // } 284 285 // // Set the local certs and private key. 286 // version(Have_boringssl) NativeCrypto.setLocalCertsAndPrivateKey(ssl, encodedLocalCerts, key.getNativeRef()); 287 // version(Have_hunt_openssl) { 288 // implementationMissing(false); 289 // } 290 // } 291 292 string getVersion() { 293 return NativeCrypto.SSL_get_version(ssl); 294 } 295 296 string getRequestedServerName() { 297 return NativeCrypto.SSL_get_servername(ssl); 298 } 299 300 byte[] getTlsChannelId() { 301 return NativeCrypto.SSL_get_tls_channel_id(ssl); 302 } 303 304 void initialize(string hostname) { // , OpenSSLKey channelIdPrivateKey 305 version(HUNT_NET_DEBUG) tracef("host: %s", hostname); 306 307 bool enableSessionCreation = parameters.getEnableSessionCreation(); 308 if (!enableSessionCreation) { 309 NativeCrypto.SSL_set_session_creation_enabled(ssl, false); 310 } 311 312 // Allow servers to trigger renegotiation. Some inadvisable server 313 // configurations cause them to attempt to renegotiate during 314 // certain protocols. 315 NativeCrypto.SSL_accept_renegotiations(ssl); 316 317 if (isClient()) { 318 version(HUNT_DEBUG) trace("Initializing TLS client..."); 319 NativeCrypto.SSL_set_connect_state(ssl); 320 321 // Configure OCSP and CT extensions for client 322 version(Have_boringssl) { 323 NativeCrypto.SSL_enable_ocsp_stapling(ssl); 324 if (parameters.isCTVerificationEnabled(hostname)) 325 NativeCrypto.SSL_enable_signed_cert_timestamps(ssl); 326 } 327 } else { 328 version(HUNT_DEBUG) trace("Initializing TLS server..."); 329 NativeCrypto.SSL_set_accept_state(ssl); 330 331 // Configure OCSP for server 332 if (parameters.getOCSPResponse() !is null) { 333 version(Have_boringssl) NativeCrypto.SSL_enable_ocsp_stapling(ssl); 334 } 335 } 336 337 if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) { 338 throw new SSLHandshakeException("No enabled protocols; " 339 ~ NativeCrypto.OBSOLETE_PROTOCOL_SSLV3 340 ~ " is no longer supported and was filtered from the list"); 341 } 342 // NativeCrypto.setEnabledProtocols(ssl, parameters.enabledProtocols); 343 // NativeCrypto.setEnabledCipherSuites(ssl, parameters.enabledCipherSuites); 344 345 if (parameters.applicationProtocols.length > 0) { 346 NativeCrypto.setApplicationProtocols(ssl, isClient(), parameters.applicationProtocols); 347 } 348 if (!isClient() && parameters.applicationProtocolSelector !is null) { 349 NativeCrypto.setApplicationProtocolSelector(ssl, parameters.applicationProtocolSelector); 350 } 351 352 // setup server certificates and private keys. 353 // clients will receive a call back to request certificates. 354 if (!isClient()) { 355 Array!string keyTypes; 356 foreach (long sslCipherNativePointer ; NativeCrypto.SSL_get_ciphers(ssl)) { 357 string keyType = SSLUtils.getServerX509KeyType(sslCipherNativePointer); 358 if (!keyType.empty()) 359 keyTypes.insertBack(keyType); 360 } 361 362 // X509KeyManager keyManager = parameters.getX509KeyManager(); 363 // if (keyManager !is null) { 364 // foreach (string keyType ; keyTypes) { 365 // try { 366 // setCertificate(aliasChooser.chooseServerAlias(keyManager, keyType)); 367 // } catch (CertificateEncodingException e) { 368 // throw new IOException(e.msg); 369 // } 370 // } 371 // } else { 372 // warning("keyManager is null"); 373 // } 374 375 NativeCrypto.SSL_set_options(ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); 376 377 if (parameters.sctExtension !is null) { 378 NativeCrypto.SSL_set_signed_cert_timestamp_list(ssl, parameters.sctExtension); 379 } 380 381 if (parameters.ocspResponse !is null) { 382 NativeCrypto.SSL_set_ocsp_response(ssl, parameters.ocspResponse); 383 } 384 } 385 386 // FIXME: Needing refactor or cleanup -@zxp at 8/3/2018, 11:32:59 AM 387 // 388 // enablePSKKeyManagerIfRequested(); 389 390 if (parameters.useSessionTickets) { 391 NativeCrypto.SSL_clear_options(ssl, SSL_OP_NO_TICKET); 392 } else { 393 NativeCrypto.SSL_set_options( 394 ssl, NativeCrypto.SSL_get_options(ssl) | SSL_OP_NO_TICKET); 395 } 396 397 if (parameters.getUseSni() && AddressUtils.isValidSniHostname(hostname)) { 398 NativeCrypto.SSL_set_tlsext_host_name(ssl, hostname); 399 } 400 401 // BEAST attack mitigation (1/n-1 record splitting for CBC cipher suites 402 // with TLSv1 and SSLv3). 403 version(Have_boringssl) NativeCrypto.SSL_set_mode(ssl, SSL_MODE_CBC_RECORD_SPLITTING); 404 405 setCertificateValidation(); 406 // TODO: Tasks pending completion -@zhangxueping at 2019-12-17T14:56:02+08:00 407 // 408 // warning("channelIdEnabled: ", parameters.channelIdEnabled); 409 // if (parameters.channelIdEnabled) { 410 // setTlsChannelId(channelIdPrivateKey); 411 // } 412 } 413 414 // // TODO(nathanmittler): Remove once after we switch to the engine socket. 415 // void doHandshake(FileDescriptor fd, int timeoutMillis) 416 // throws CertificateException, IOException { 417 // lock.readLock().lock(); 418 // try { 419 // if (isClosed() || fd is null || !fd.valid()) { 420 // throw new SocketException("Socket is closed"); 421 // } 422 // NativeCrypto.SSL_do_handshake(ssl, fd, handshakeCallbacks, timeoutMillis); 423 // } finally { 424 // lock.readLock().unlock(); 425 // } 426 // } 427 428 int doHandshake() { 429 // lock.readLock().lock(); 430 try { 431 return NativeCrypto.ENGINE_SSL_do_handshake(ssl, handshakeCallbacks); 432 } catch(Exception ex) { 433 warning(ex.msg); 434 return 0; 435 } finally { 436 // lock.readLock().unlock(); 437 438 } 439 } 440 441 // // TODO(nathanmittler): Remove once after we switch to the engine socket. 442 // int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 443 // { 444 // lock.readLock().lock(); 445 // try { 446 // if (isClosed() || fd is null || !fd.valid()) { 447 // throw new SocketException("Socket is closed"); 448 // } 449 // return NativeCrypto 450 // .SSL_read(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); 451 // } finally { 452 // lock.readLock().unlock(); 453 // } 454 // } 455 456 // // TODO(nathanmittler): Remove once after we switch to the engine socket. 457 // void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) 458 // { 459 // lock.readLock().lock(); 460 // try { 461 // if (isClosed() || fd is null || !fd.valid()) { 462 // throw new SocketException("Socket is closed"); 463 // } 464 // NativeCrypto 465 // .SSL_write(ssl, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); 466 // } finally { 467 // lock.readLock().unlock(); 468 // } 469 // } 470 471 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 472 // private void enablePSKKeyManagerIfRequested() { 473 // // Enable Pre-Shared Key (PSK) key exchange if requested 474 // PSKKeyManager pskKeyManager = parameters.getPSKKeyManager(); 475 // if (pskKeyManager !is null) { 476 // bool pskEnabled = false; 477 // for (string enabledCipherSuite : parameters.enabledCipherSuites) { 478 // if ((enabledCipherSuite !is null) && (enabledCipherSuite.contains("PSK"))) { 479 // pskEnabled = true; 480 // break; 481 // } 482 // } 483 // if (pskEnabled) { 484 // if (isClient()) { 485 // NativeCrypto.set_SSL_psk_client_callback_enabled(ssl, true); 486 // } else { 487 // NativeCrypto.set_SSL_psk_server_callback_enabled(ssl, true); 488 // string identityHint = pskCallbacks.chooseServerPSKIdentityHint(pskKeyManager); 489 // NativeCrypto.SSL_use_psk_identity_hint(ssl, identityHint); 490 // } 491 // } 492 // } 493 // } 494 495 // private void setTlsChannelId(OpenSSLKey channelIdPrivateKey) { 496 497 // if (parameters.getUseClientMode()) { 498 // // Client-side TLS Channel ID 499 // if (channelIdPrivateKey is null) { 500 // throw new SSLHandshakeException("Invalid TLS channel ID key specified"); 501 // } 502 // NativeCrypto.SSL_set1_tls_channel_id(ssl, channelIdPrivateKey.getNativeRef()); 503 // } else { 504 // // Server-side TLS Channel ID 505 // NativeCrypto.SSL_enable_tls_channel_id(ssl); 506 // } 507 // } 508 509 private void setCertificateValidation() { 510 // https://stackoverflow.com/questions/40165088/when-to-call-ssl-set-verify-vs-ssl-ctx-set-verify 511 // https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_verify.html 512 // setup peer certificate verification 513 version(HUNT_NET_DEBUG) warningf("Setup peer certificate verification: isClient=%s", isClient()); 514 515 if (isClient()) { 516 KeyCertOptions certOptions = parameters.getKeyCertOptions(); 517 if(certOptions !is null) { 518 string caFile = certOptions.getCaFile(); 519 if(!caFile.empty()) { 520 NativeCrypto.SSL_set_verify(ssl, SSL_VERIFY_PEER); 521 AbstractSessionContext ctx = parameters.getSessionContext(); 522 ctx.useCaCertificate(caFile, certOptions.getCaPassword()); 523 } 524 525 string certFile = certOptions.getCertFile(); 526 string keyFile = certOptions.getKeyFile(); 527 if(!certFile.empty() && !keyFile.empty()) { 528 NativeCrypto.SSL_use_certificate_file(ssl, certFile); 529 NativeCrypto.SSL_use_PrivateKey_file(ssl, keyFile); 530 // TODO: enable password 531 532 if(!NativeCrypto.SSL_check_private_key(ssl)) { 533 warningf("Private key (%s) does not match the certificate public key: %s", keyFile, certFile); 534 } 535 } 536 } 537 538 } else { 539 // TODO: Tasks pending completion -@zxp at 8/8/2019, 6:34:06 PM 540 // 541 // needing client auth takes priority... 542 bool certRequested; 543 if (parameters.getNeedClientAuth()) { 544 NativeCrypto.SSL_set_verify(ssl, SSL_VERIFY_PEER 545 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); 546 certRequested = true; 547 // ... over just wanting it... 548 } else if (parameters.getWantClientAuth()) { 549 NativeCrypto.SSL_set_verify(ssl, SSL_VERIFY_PEER); 550 certRequested = true; 551 // ... and we must disable verification if we don't want client auth. 552 } else { 553 NativeCrypto.SSL_set_verify(ssl, SSL_VERIFY_NONE); 554 certRequested = false; 555 } 556 557 version(HUNT_NET_DEBUG) warningf("certRequested: %s", certRequested); 558 559 if (certRequested) { 560 // X509TrustManager trustManager = parameters.getX509TrustManager(); 561 // X509Certificate[] issuers = trustManager.getAcceptedIssuers(); 562 // if (issuers !is null && issuers.length != 0) { 563 // byte[][] issuersBytes; 564 // try { 565 // issuersBytes = SSLUtils.encodeSubjectX509Principals(issuers); 566 // } catch (CertificateEncodingException e) { 567 // throw new SSLException("Problem encoding principals", e); 568 // } 569 // NativeCrypto.SSL_set_client_CA_list(ssl, issuersBytes); 570 // } 571 } 572 573 } 574 } 575 576 // void interrupt() { 577 // NativeCrypto.SSL_interrupt(ssl); 578 // } 579 580 // // TODO(nathanmittler): Remove once after we switch to the engine socket. 581 // void shutdown(FileDescriptor fd) { 582 // NativeCrypto.SSL_shutdown(ssl, fd, handshakeCallbacks); 583 // } 584 585 void shutdown() { 586 NativeCrypto.ENGINE_SSL_shutdown(ssl, handshakeCallbacks); 587 } 588 589 bool wasShutdownReceived() { 590 return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) != 0; 591 } 592 593 bool wasShutdownSent() { 594 return (NativeCrypto.SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN) != 0; 595 } 596 597 int readDirectByteBuffer(long destAddress, int destLength) { 598 // lock.readLock().lock(); 599 try { 600 return NativeCrypto.ENGINE_SSL_read_direct( 601 ssl, destAddress, destLength, handshakeCallbacks); 602 } finally { 603 // lock.readLock().unlock(); 604 } 605 } 606 607 int writeDirectByteBuffer(long sourceAddress, int sourceLength) { 608 // lock.readLock().lock(); 609 try { 610 return NativeCrypto.ENGINE_SSL_write_direct( 611 ssl, sourceAddress, sourceLength, handshakeCallbacks); 612 } finally { 613 // lock.readLock().unlock(); 614 } 615 } 616 617 // void forceRead() { 618 // lock.readLock().lock(); 619 // try { 620 // NativeCrypto.ENGINE_SSL_force_read(ssl, handshakeCallbacks); 621 // } finally { 622 // lock.readLock().unlock(); 623 // } 624 // } 625 626 int getPendingReadableBytes() { 627 return NativeCrypto.SSL_pending_readable_bytes(ssl); 628 } 629 630 int getMaxSealOverhead() { 631 version(Have_boringssl) return NativeCrypto.SSL_max_seal_overhead(ssl); 632 version(Have_hunt_openssl) { 633 // implementationMissing(false); 634 return 0; 635 } 636 } 637 638 void close() { 639 // lock.writeLock().lock(); 640 try { 641 if (!isClosed()) { 642 long toFree = ssl; 643 ssl = 0L; 644 NativeCrypto.SSL_free(toFree); 645 } 646 } finally { 647 // lock.writeLock().unlock(); 648 } 649 } 650 651 bool isClosed() { 652 return ssl == 0L; 653 } 654 655 int getError(int result) { 656 return NativeCrypto.SSL_get_error(ssl, result); 657 } 658 659 byte[] getApplicationProtocol() { 660 return NativeCrypto.getApplicationProtocol(ssl); 661 } 662 663 private bool isClient() { 664 return parameters.getUseClientMode(); 665 } 666 667 // protected void finalize() { 668 // try { 669 // close(); 670 // } finally { 671 // // super.finalize(); 672 // } 673 // } 674 } 675 676 677 /** 678 * A utility wrapper that abstracts operations on the underlying native BIO instance. 679 */ 680 class BioWrapper { 681 private long bio; 682 private NativeSsl nativeSsl; 683 684 private this(NativeSsl nativeSsl) { 685 this.nativeSsl = nativeSsl; 686 this.bio = NativeCrypto.SSL_BIO_new(nativeSsl.ssl); 687 } 688 689 int getPendingWrittenBytes() { 690 if (bio != 0) { 691 return NativeCrypto.SSL_pending_written_bytes_in_BIO(bio); 692 } else { 693 return 0; 694 } 695 } 696 697 int writeDirectByteBuffer(long address, int length) { 698 return NativeCrypto.ENGINE_SSL_write_BIO_direct( 699 nativeSsl.ssl, bio, address, length, nativeSsl.handshakeCallbacks); 700 } 701 702 int readDirectByteBuffer(long destAddress, int destLength) { 703 return NativeCrypto.ENGINE_SSL_read_BIO_direct( 704 nativeSsl.ssl, bio, destAddress, destLength, nativeSsl.handshakeCallbacks); 705 } 706 707 void close() { 708 long toFree = bio; 709 bio = 0L; 710 NativeCrypto.BIO_free_all(toFree); 711 } 712 }