1 module hunt.net.secure.conscrypt.ConscryptEngine; 2 3 // dfmt off 4 version(WITH_HUNT_SECURITY): 5 // dfmt on 6 7 import hunt.net.secure.conscrypt.ApplicationProtocolSelectorAdapter; 8 import hunt.net.secure.conscrypt.ApplicationProtocolSelector; 9 import hunt.net.secure.conscrypt.AbstractConscryptEngine; 10 import hunt.net.secure.conscrypt.AbstractSessionContext; 11 import hunt.net.secure.conscrypt.ActiveSession; 12 import hunt.net.secure.conscrypt.AllocatedBuffer; 13 import hunt.net.secure.conscrypt.ClientSessionContext; 14 import hunt.net.secure.conscrypt.ConscryptSession; 15 import hunt.net.secure.conscrypt.NativeCrypto; 16 import hunt.net.secure.conscrypt.NativeSsl; 17 import hunt.net.secure.conscrypt.NativeSslSession; 18 import hunt.net.secure.conscrypt.OpenSSLKey; 19 import hunt.net.secure.conscrypt.PeerInfoProvider; 20 import hunt.net.secure.conscrypt.SessionSnapshot; 21 import hunt.net.secure.conscrypt.SSLParametersImpl; 22 import hunt.net.secure.conscrypt.SSLNullSession; 23 import hunt.net.secure.conscrypt.SSLUtils; 24 25 26 // import hunt.net.ssl.KeyManager; 27 // import hunt.net.ssl.X509KeyManager; 28 // import hunt.net.ssl.X509TrustManager; 29 30 // import hunt.security.Key; 31 // import hunt.security.cert.X509Certificate; 32 // import hunt.security.x500.X500Principal; 33 34 import hunt.collection; 35 import hunt.net.Exceptions; 36 37 import hunt.net.ssl.SSLEngine; 38 import hunt.net.ssl.SSLEngineResult; 39 import hunt.net.ssl.SSLSession; 40 41 import hunt.Exceptions; 42 import hunt.text.Common; 43 44 import hunt.logging; 45 46 import deimos.openssl.ssl; 47 48 import std.algorithm; 49 import std.conv; 50 import std.format; 51 52 53 /** 54 * Implements the {@link SSLEngine} API using OpenSSL's non-blocking interfaces. 55 , 56 SSLParametersImpl.AliasChooser, 57 SSLParametersImpl.PSKCallbacks 58 */ 59 final class ConscryptEngine : AbstractConscryptEngine , SSLHandshakeCallbacks { 60 private __gshared SSLEngineResult NEED_UNWRAP_OK; 61 private __gshared SSLEngineResult NEED_UNWRAP_CLOSED; 62 private __gshared SSLEngineResult NEED_WRAP_OK; 63 private __gshared SSLEngineResult NEED_WRAP_CLOSED; 64 private __gshared SSLEngineResult CLOSED_NOT_HANDSHAKING; 65 private __gshared ByteBuffer EMPTY; 66 67 shared static this() 68 { 69 NEED_UNWRAP_OK = new SSLEngineResult(SSLEngineResult.Status.OK, HandshakeStatus.NEED_UNWRAP, 0, 0); 70 NEED_UNWRAP_CLOSED = new SSLEngineResult(SSLEngineResult.Status.CLOSED, HandshakeStatus.NEED_UNWRAP, 0, 0); 71 NEED_WRAP_OK = new SSLEngineResult(SSLEngineResult.Status.OK, HandshakeStatus.NEED_WRAP, 0, 0); 72 NEED_WRAP_CLOSED = new SSLEngineResult(SSLEngineResult.Status.CLOSED, HandshakeStatus.NEED_WRAP, 0, 0); 73 CLOSED_NOT_HANDSHAKING = new SSLEngineResult(SSLEngineResult.Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING, 0, 0); 74 EMPTY = new HeapByteBuffer(0, 0); // ByteBuffer.allocateDirect(0); 75 } 76 77 private static BufferAllocator defaultBufferAllocator = null; 78 79 private SSLParametersImpl sslParameters; 80 private BufferAllocator bufferAllocator; 81 82 /** 83 * A lazy-created direct buffer used as a bridge between heap buffers provided by the 84 * application and JNI. This avoids the overhead of calling JNI with heap buffers. 85 * Used only when no {@link #bufferAllocator} has been provided. 86 */ 87 private ByteBuffer lazyDirectBuffer; 88 89 /** 90 * Hostname used with the TLS extension SNI hostname. 91 */ 92 private string peerHostname; 93 94 // @GuardedBy("ssl"); 95 private int state = EngineStates.STATE_NEW; 96 private bool handshakeFinished; 97 98 /** 99 * Wrapper around the underlying SSL object. 100 */ 101 private NativeSsl ssl; 102 103 /** 104 * The BIO used for reading/writing encrypted bytes. 105 */ 106 // @GuardedBy("ssl"); 107 private BioWrapper networkBio; 108 109 /** 110 * Set during startHandshake. 111 */ 112 private ActiveSession activeSession; 113 114 /** 115 * A snapshot of the active session when the engine was closed. 116 */ 117 private SessionSnapshot closedSession; 118 119 /** 120 * The session object exposed externally from this class. 121 */ 122 private SSLSession externalSession; 123 124 /** 125 * Private key for the TLS Channel ID extension. This field is client-side only. Set during 126 * startHandshake. 127 */ 128 // private OpenSSLKey channelIdPrivateKey; 129 130 private int _maxSealOverhead; 131 132 /** 133 * Called by the engine when the TLS handshake has completed. 134 */ 135 private HandshakeListener handshakeListener; 136 137 private ByteBuffer[] singleSrcBuffer; 138 private ByteBuffer[] singleDstBuffer; 139 private PeerInfoProvider peerInfoProvider; 140 141 private SSLException handshakeException; 142 143 this(SSLParametersImpl sslParameters) { 144 this.sslParameters = sslParameters; 145 peerInfoProvider = PeerInfoProvider.nullProvider(); 146 this.ssl = newSsl(sslParameters, this); 147 singleSrcBuffer = new ByteBuffer[1]; 148 singleDstBuffer = new ByteBuffer[1]; 149 bufferAllocator = defaultBufferAllocator; 150 this.networkBio = ssl.newBio(); 151 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 152 externalSession = this.provideSession(); 153 154 setUseClientMode(sslParameters.getUseClientMode()); 155 156 // externalSession = Platform.wrapSSLSession(new ExternalSession(new Provider() { 157 // override 158 // ConscryptSession provideSession() { 159 // return ConscryptEngine.this.provideSession(); 160 // } 161 // })); 162 } 163 164 this(string host, int port, SSLParametersImpl sslParameters) { 165 this.sslParameters = sslParameters; 166 this.peerInfoProvider = PeerInfoProvider.forHostAndPort(host, port); 167 this.ssl = newSsl(sslParameters, this); 168 this.networkBio = ssl.newBio(); 169 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 170 setUseClientMode(sslParameters.getUseClientMode()); 171 } 172 173 // this(SSLParametersImpl sslParameters, PeerInfoProvider peerInfoProvider) { 174 // this.sslParameters = sslParameters; 175 // this.peerInfoProvider = checkNotNull(peerInfoProvider, "peerInfoProvider"); 176 // this.ssl = newSsl(sslParameters, this); 177 // this.networkBio = ssl.newBio(); 178 // activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 179 // } 180 181 private static NativeSsl newSsl(SSLParametersImpl sslParameters, ConscryptEngine engine) { 182 try { 183 return NativeSsl.newInstance(sslParameters, engine); 184 } catch (SSLException e) { 185 throw new RuntimeException(e); 186 } 187 } 188 189 /** 190 * Configures the default {@link BufferAllocator} to be used by all future 191 * {@link SSLEngine} instances from this provider. 192 */ 193 // static void setDefaultBufferAllocator(BufferAllocator bufferAllocator) { 194 // defaultBufferAllocator = bufferAllocator; 195 // } 196 197 // override 198 // void setBufferAllocator(BufferAllocator bufferAllocator) { 199 // synchronized (ssl) { 200 // if (isHandshakeStarted()) { 201 // throw new IllegalStateException( 202 // "Could not set buffer allocator after the initial handshake has begun."); 203 // } 204 // this.bufferAllocator = bufferAllocator; 205 // } 206 // } 207 208 /** 209 * Returns the maximum overhead, in bytes, of sealing a record with SSL. 210 */ 211 override 212 int maxSealOverhead() { 213 return _maxSealOverhead; 214 } 215 216 // /** 217 // * Enables/disables TLS Channel ID for this server engine. 218 // * 219 // * <p>This method needs to be invoked before the handshake starts. 220 // * 221 // * @throws IllegalStateException if this is a client engine or if the handshake has already 222 // * started. 223 // */ 224 // override 225 // void setChannelIdEnabled(bool enabled) { 226 // synchronized (ssl) { 227 // if (getUseClientMode()) { 228 // throw new IllegalStateException("Not allowed in client mode"); 229 // } 230 // if (isHandshakeStarted()) { 231 // throw new IllegalStateException( 232 // "Could not enable/disable Channel ID after the initial handshake has begun."); 233 // } 234 // sslParameters.channelIdEnabled = enabled; 235 // } 236 // } 237 238 // /** 239 // * Gets the TLS Channel ID for this server engine. Channel ID is only available once the 240 // * handshake completes. 241 // * 242 // * @return channel ID or {@code null} if not available. 243 // * 244 // * @throws IllegalStateException if this is a client engine or if the handshake has not yet 245 // * completed. 246 // * @throws SSLException if channel ID is available but could not be obtained. 247 // */ 248 // override 249 // byte[] getChannelId() { 250 // synchronized (ssl) { 251 // if (getUseClientMode()) { 252 // throw new IllegalStateException("Not allowed in client mode"); 253 // } 254 255 // if (isHandshakeStarted()) { 256 // throw new IllegalStateException( 257 // "Channel ID is only available after handshake completes"); 258 // } 259 // return ssl.getTlsChannelId(); 260 // } 261 // } 262 263 /** 264 * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client engine. 265 * 266 * <p>This method needs to be invoked before the handshake starts. 267 * 268 * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables 269 * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST 270 * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1). 271 * 272 * @throws IllegalStateException if this is a server engine or if the handshake has already 273 * started. 274 */ 275 // override 276 // void setChannelIdPrivateKey(PrivateKey privateKey) { 277 // implementationMissing(false); 278 // // if (!getUseClientMode()) { 279 // // throw new IllegalStateException("Not allowed in server mode"); 280 // // } 281 282 // // synchronized (ssl) { 283 // // if (isHandshakeStarted()) { 284 // // throw new IllegalStateException("Could not change Channel ID private key " 285 // // ~ "after the initial handshake has begun."); 286 // // } 287 288 // // if (privateKey is null) { 289 // // sslParameters.channelIdEnabled = false; 290 // // channelIdPrivateKey = null; 291 // // return; 292 // // } 293 294 // // sslParameters.channelIdEnabled = true; 295 // // try { 296 // // ECParameterSpec ecParams = null; 297 // // if (privateKey instanceof ECKey) { 298 // // ecParams = ((ECKey) privateKey).getParams(); 299 // // } 300 // // if (ecParams is null) { 301 // // // Assume this is a P-256 key, as specified in the contract of this method. 302 // // ecParams = 303 // // OpenSSLECGroupContext.getCurveByName("prime256v1").getECParameterSpec(); 304 // // } 305 // // channelIdPrivateKey = 306 // // OpenSSLKey.fromECPrivateKeyForTLSStackOnly(privateKey, ecParams); 307 // // } catch (InvalidKeyException e) { 308 // // // Will have error in startHandshake 309 // // } 310 // // } 311 // } 312 313 /** 314 * Sets the listener for the completion of the TLS handshake. 315 */ 316 override 317 void setHandshakeListener(HandshakeListener handshakeListener) { 318 synchronized (ssl) { 319 if (isHandshakeStarted()) { 320 throw new IllegalStateException( 321 "Handshake listener must be set before starting the handshake."); 322 } 323 this.handshakeListener = handshakeListener; 324 } 325 } 326 327 private bool isHandshakeStarted() { 328 switch (state) { 329 case EngineStates.STATE_NEW: 330 case EngineStates.STATE_MODE_SET: 331 return false; 332 default: 333 return true; 334 } 335 } 336 337 /** 338 * This method enables Server Name Indication (SNI) and overrides the {@link PeerInfoProvider} 339 * supplied during engine creation. If the hostname is not a valid SNI hostname, the SNI 340 * extension will be omitted from the handshake. 341 */ 342 override 343 void setHostname(string hostname) { 344 sslParameters.setUseSni(hostname !is null); 345 this.peerHostname = hostname; 346 } 347 348 /** 349 * Returns the hostname from {@link #setHostname(string)} or supplied by the 350 * {@link PeerInfoProvider} upon creation. No DNS resolution is attempted before 351 * returning the hostname. 352 */ 353 override 354 string getHostname() { 355 return peerHostname !is null ? peerHostname : peerInfoProvider.getHostname(); 356 } 357 358 override 359 string getPeerHost() { 360 return peerHostname !is null ? peerHostname : peerInfoProvider.getHostnameOrIP(); 361 } 362 363 override 364 int getPeerPort() { 365 return peerInfoProvider.getPort(); 366 } 367 368 override 369 void beginHandshake() { 370 synchronized (ssl) { 371 beginHandshakeInternal(); 372 } 373 } 374 375 private void beginHandshakeInternal() { 376 switch (state) { 377 case EngineStates.STATE_NEW: { 378 throw new IllegalStateException("Client/server mode must be set before handshake"); 379 } 380 case EngineStates.STATE_MODE_SET: { 381 // We know what mode to handshake in but have not started the handshake, proceed 382 break; 383 } 384 case EngineStates.STATE_CLOSED_INBOUND: 385 case EngineStates.STATE_CLOSED_OUTBOUND: 386 case EngineStates.STATE_CLOSED: 387 throw new IllegalStateException("Engine has already been closed"); 388 default: 389 // We've already started the handshake, just return 390 return; 391 } 392 393 transitionTo(EngineStates.STATE_HANDSHAKE_STARTED); 394 395 bool releaseResources = true; 396 try { 397 // Prepare the SSL object for the handshake. 398 ssl.initialize(getHostname()); // , channelIdPrivateKey 399 400 // For clients, offer to resume a previously cached session to avoid the 401 // full TLS handshake. 402 if (getUseClientMode()) { 403 NativeSslSession cachedSession = clientSessionContext().getCachedSession( 404 getHostname(), getPeerPort(), sslParameters); 405 if (cachedSession !is null) { 406 cachedSession.offerToResume(ssl); 407 } 408 } 409 410 _maxSealOverhead = ssl.getMaxSealOverhead(); 411 handshake(); 412 releaseResources = false; 413 } catch (IOException e) { 414 // Write CCS errors to EventLog 415 string message = e.msg; 416 // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c) 417 if (message.canFind("unexpected CCS")) { 418 errorf("ssl_unexpected_ccs: host=%s", getPeerHost()); 419 } 420 throw SSLUtils.toSSLHandshakeException(e); 421 } finally { 422 if (releaseResources) { 423 closeAndFreeResources(); 424 } 425 } 426 } 427 428 override 429 void closeInbound() { 430 synchronized (ssl) { 431 if (state == EngineStates.STATE_CLOSED || state == EngineStates.STATE_CLOSED_INBOUND) { 432 return; 433 } 434 if (isOutboundDone()) { 435 transitionTo(EngineStates.STATE_CLOSED); 436 } else { 437 transitionTo(EngineStates.STATE_CLOSED_INBOUND); 438 } 439 } 440 } 441 442 override 443 void closeOutbound() { 444 synchronized (ssl) { 445 if (state == EngineStates.STATE_CLOSED || state == EngineStates.STATE_CLOSED_OUTBOUND) { 446 return; 447 } 448 if (isHandshakeStarted()) { 449 sendSSLShutdown(); 450 if (isInboundDone()) { 451 closeAndFreeResources(); 452 } else { 453 transitionTo(EngineStates.STATE_CLOSED_OUTBOUND); 454 } 455 } else { 456 // Never started the handshake. Just close now. 457 closeAndFreeResources(); 458 } 459 } 460 } 461 462 // override 463 // Runnable getDelegatedTask() { 464 // // This implementation doesn't use any delegated tasks. 465 // return null; 466 // } 467 468 override 469 string[] getEnabledCipherSuites() { 470 return sslParameters.getEnabledCipherSuites(); 471 } 472 473 override 474 string[] getEnabledProtocols() { 475 return sslParameters.getEnabledProtocols(); 476 } 477 478 override 479 bool getEnableSessionCreation() { 480 return sslParameters.getEnableSessionCreation(); 481 } 482 483 // override 484 // SSLParameters getSSLParameters() { 485 // SSLParameters params = super.getSSLParameters(); 486 // Platform.getSSLParameters(params, sslParameters, this); 487 // return params; 488 // } 489 490 // override 491 // void setSSLParameters(SSLParameters p) { 492 // super.setSSLParameters(p); 493 // Platform.setSSLParameters(p, sslParameters, this); 494 // } 495 496 override 497 HandshakeStatus getHandshakeStatus() { 498 synchronized (ssl) { 499 return getHandshakeStatusInternal(); 500 } 501 } 502 503 private HandshakeStatus getHandshakeStatusInternal() { 504 if (handshakeFinished) { 505 return HandshakeStatus.NOT_HANDSHAKING; 506 } 507 switch (state) { 508 case EngineStates.STATE_HANDSHAKE_STARTED: 509 return pendingStatus(pendingOutboundEncryptedBytes()); 510 case EngineStates.STATE_HANDSHAKE_COMPLETED: 511 return HandshakeStatus.NEED_WRAP; 512 case EngineStates.STATE_NEW: 513 case EngineStates.STATE_MODE_SET: 514 case EngineStates.STATE_CLOSED: 515 case EngineStates.STATE_CLOSED_INBOUND: 516 case EngineStates.STATE_CLOSED_OUTBOUND: 517 case EngineStates.STATE_READY: 518 case EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH: 519 return HandshakeStatus.NOT_HANDSHAKING; 520 default: 521 break; 522 } 523 throw new IllegalStateException("Unexpected engine state: " ~ state.to!string()); 524 } 525 526 private int pendingOutboundEncryptedBytes() { 527 return networkBio.getPendingWrittenBytes(); 528 } 529 530 private int pendingInboundCleartextBytes() { 531 return ssl.getPendingReadableBytes(); 532 } 533 534 private static HandshakeStatus pendingStatus(int pendingOutboundBytes) { 535 // Depending on if there is something left in the BIO we need to WRAP or UNWRAP 536 return pendingOutboundBytes > 0 ? HandshakeStatus.NEED_WRAP : HandshakeStatus.NEED_UNWRAP; 537 } 538 539 override 540 bool getNeedClientAuth() { 541 return sslParameters.getNeedClientAuth(); 542 } 543 544 /** 545 * Work-around to allow this method to be called on older versions of Android. 546 */ 547 override 548 SSLSession handshakeSession() { 549 implementationMissing(false); 550 return null; 551 // synchronized (ssl) { 552 // if (state == EngineStates.STATE_HANDSHAKE_STARTED) { 553 // return Platform.wrapSSLSession(new ExternalSession(new Provider() { 554 // override 555 // ConscryptSession provideSession() { 556 // return ConscryptEngine.this.provideHandshakeSession(); 557 // } 558 // })); 559 // } 560 // return null; 561 // } 562 } 563 564 override 565 SSLSession getSession() { 566 return externalSession; 567 } 568 569 private ConscryptSession provideSession() { 570 synchronized (ssl) { 571 if (state == EngineStates.STATE_CLOSED) { 572 return closedSession !is null ? closedSession : SSLNullSession.getNullSession(); 573 } 574 if (state < EngineStates.STATE_HANDSHAKE_COMPLETED) { 575 // Return an invalid session with invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 576 return SSLNullSession.getNullSession(); 577 } 578 return activeSession; 579 } 580 } 581 582 private ConscryptSession provideHandshakeSession() { 583 synchronized (ssl) { 584 return state == EngineStates.STATE_HANDSHAKE_STARTED ? activeSession 585 : SSLNullSession.getNullSession(); 586 } 587 } 588 589 override 590 string[] getSupportedCipherSuites() { 591 return NativeCrypto.getSupportedCipherSuites(); 592 } 593 594 override 595 string[] getSupportedProtocols() { 596 return NativeCrypto.getSupportedProtocols(); 597 } 598 599 override 600 bool getUseClientMode() { 601 return sslParameters.getUseClientMode(); 602 } 603 604 override 605 bool getWantClientAuth() { 606 return sslParameters.getWantClientAuth(); 607 } 608 609 override 610 bool isInboundDone() { 611 synchronized (ssl) { 612 return state == EngineStates.STATE_CLOSED || state == EngineStates.STATE_CLOSED_INBOUND 613 || ssl.wasShutdownReceived(); 614 } 615 } 616 617 override 618 bool isOutboundDone() { 619 synchronized (ssl) { 620 return state == EngineStates.STATE_CLOSED || state == EngineStates.STATE_CLOSED_OUTBOUND || ssl.wasShutdownSent(); 621 } 622 } 623 624 override 625 void setEnabledCipherSuites(string[] suites) { 626 sslParameters.setEnabledCipherSuites(suites); 627 } 628 629 override 630 void setEnabledProtocols(string[] protocols) { 631 sslParameters.setEnabledProtocols(protocols); 632 } 633 634 override 635 void setEnableSessionCreation(bool flag) { 636 sslParameters.setEnableSessionCreation(flag); 637 } 638 639 override 640 void setNeedClientAuth(bool need) { 641 sslParameters.setNeedClientAuth(need); 642 } 643 644 override 645 void setUseClientMode(bool mode) { 646 synchronized (ssl) { 647 if (isHandshakeStarted()) { 648 throw new IllegalArgumentException( 649 "Can not change mode after handshake: state == " ~ state.to!string()); 650 } 651 transitionTo(EngineStates.STATE_MODE_SET); 652 sslParameters.setUseClientMode(mode); 653 } 654 } 655 656 override 657 void setWantClientAuth(bool want) { 658 sslParameters.setWantClientAuth(want); 659 } 660 661 override 662 SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) { 663 // synchronized (ssl) { 664 try { 665 return unwrap(makeSingleSrcBuffer(src), makeSingleDstBuffer(dst)); 666 } finally { 667 resetSingleSrcBuffer(); 668 resetSingleDstBuffer(); 669 } 670 // } 671 } 672 673 override 674 SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) { 675 // synchronized (ssl) { 676 try { 677 return unwrap(makeSingleSrcBuffer(src), dsts); 678 } finally { 679 resetSingleSrcBuffer(); 680 } 681 // } 682 } 683 684 override 685 SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, 686 int length) { 687 synchronized (ssl) { 688 try { 689 return unwrap(makeSingleSrcBuffer(src), 0, 1, dsts, offset, length); 690 } finally { 691 resetSingleSrcBuffer(); 692 } 693 } 694 } 695 696 override 697 SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dsts) { 698 assert(srcs !is null, "srcs is null"); 699 assert(dsts !is null, "dsts is null"); 700 return unwrap(srcs, 0, cast(int)srcs.length, dsts, 0, cast(int)dsts.length); 701 } 702 703 override 704 SSLEngineResult unwrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, 705 ByteBuffer[] dsts, int dstsOffset, int dstsLength) { 706 assert(srcs !is null, "srcs is null"); 707 assert(dsts !is null, "dsts is null"); 708 // infof("srcsOffset=%d", srcsOffset); 709 710 checkPositionIndexes(srcsOffset, srcsOffset + srcsLength, cast(int)srcs.length); 711 checkPositionIndexes(dstsOffset, dstsOffset + dstsLength, cast(int)dsts.length); 712 713 // Determine the output capacity. 714 int dstLength = calcDstsLength(dsts, dstsOffset, dstsLength); 715 int endOffset = dstsOffset + dstsLength; 716 717 int srcsEndOffset = srcsOffset + srcsLength; 718 long srcLength = calcSrcsLength(srcs, srcsOffset, srcsEndOffset); 719 720 synchronized (ssl) { 721 switch (state) { 722 case EngineStates.STATE_MODE_SET: 723 // Begin the handshake implicitly. 724 beginHandshakeInternal(); 725 break; 726 case EngineStates.STATE_CLOSED_INBOUND: 727 case EngineStates.STATE_CLOSED: 728 // If the inbound direction is closed. we can't send anymore. 729 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, getHandshakeStatusInternal(), 0, 0); 730 case EngineStates.STATE_NEW: 731 throw new IllegalStateException( 732 "Client/server mode must be set before calling unwrap"); 733 default: 734 break; 735 } 736 737 HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; 738 if (!handshakeFinished) { 739 handshakeStatus = handshake(); 740 version(HUNT_DEBUG_MORE) trace("handshakeStatus=", handshakeStatus); 741 if (handshakeStatus == HandshakeStatus.NEED_WRAP) { 742 return NEED_WRAP_OK; 743 } 744 if (state == EngineStates.STATE_CLOSED) { 745 return NEED_WRAP_CLOSED; 746 } 747 // NEED_UNWRAP - just fall through to perform the unwrap. 748 } 749 750 // Consume any source data. Skip this if there are unread cleartext data. 751 bool noCleartextDataAvailable = pendingInboundCleartextBytes() <= 0; 752 // tracef("srcLength=%d, noCleartextDataAvailable=%s", srcLength, noCleartextDataAvailable); 753 int lenRemaining = 0; 754 if (srcLength > 0 && noCleartextDataAvailable) { 755 if (srcLength < SSL3_RT_HEADER_LENGTH) { 756 // Need to be able to read a full TLS header. 757 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0); 758 } 759 760 int packetLength = SSLUtils.getEncryptedPacketLength(srcs, srcsOffset); 761 762 version(HUNT_DEBUG_MORE) { 763 tracef("srcLength=%d, srcsOffset=%d packetLength=%d", srcLength, srcsOffset, packetLength); 764 } 765 766 767 if (packetLength < 0) { 768 throw new SSLException("Unable to parse TLS packet header"); 769 } 770 771 if (srcLength < packetLength) { 772 // We either have not enough data to read the packet header or not enough for 773 // reading the whole packet. 774 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0); 775 } 776 777 // Limit the amount of data to be read to a single packet. 778 lenRemaining = packetLength; 779 } else if (noCleartextDataAvailable) { 780 // No pending data and nothing provided as input. Need more data. 781 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0); 782 } 783 784 // tracef("lenRemaining=%d, srcsOffset=%d, srcsEndOffset=%d", lenRemaining, srcsOffset, srcsEndOffset); 785 786 // Write all of the encrypted source data to the networkBio 787 int bytesConsumed = 0; 788 if (lenRemaining > 0 && srcsOffset < srcsEndOffset) { 789 do { 790 ByteBuffer src = srcs[srcsOffset]; 791 int remaining = src.remaining(); 792 if (remaining == 0) { 793 // We must skip empty buffers as BIO_write will return 0 if asked to 794 // write something with length 0. 795 srcsOffset++; 796 continue; 797 } 798 799 // Write the source encrypted data to the networkBio. 800 int written = writeEncryptedData(src, min(lenRemaining, remaining)); 801 if (written > 0) { 802 bytesConsumed += written; 803 lenRemaining -= written; 804 if (lenRemaining == 0) { 805 // A whole packet has been consumed. 806 break; 807 } 808 809 if (written == remaining) { 810 srcsOffset++; 811 } else { 812 // We were not able to write everything into the BIO so break the 813 // write loop as otherwise we will produce an error on the next 814 // write attempt, which will trigger a SSL.clearError() later. 815 break; 816 } 817 } else { 818 // BIO_write returned a negative or zero number, this means we could not 819 // complete the write operation and should retry later. 820 // We ignore BIO_* errors here as we use in memory BIO anyway and will 821 // do another SSL_* call later on in which we will produce an exception 822 // in case of an error 823 NativeCrypto.SSL_clear_error(); 824 break; 825 } 826 } while (srcsOffset < srcsEndOffset); 827 } 828 829 // Now read any available plaintext data. 830 int bytesProduced = 0; 831 try { 832 if (dstLength > 0) { 833 // Write decrypted data to dsts buffers 834 for (int idx = dstsOffset; idx < endOffset; ++idx) { 835 ByteBuffer dst = dsts[idx]; 836 if (!dst.hasRemaining()) { 837 continue; 838 } 839 840 int bytesRead = readPlaintextData(dst); 841 if (bytesRead > 0) { 842 bytesProduced += bytesRead; 843 if (dst.hasRemaining()) { 844 // We haven't filled this buffer fully, break out of the loop 845 // and determine the correct response status below. 846 break; 847 } 848 } else { 849 switch (bytesRead) { 850 case -SSL_ERROR_WANT_READ: 851 case -SSL_ERROR_WANT_WRITE: { 852 return newResult(bytesConsumed, bytesProduced, handshakeStatus); 853 } 854 case -SSL_ERROR_ZERO_RETURN: { 855 // We received a close_notify from the peer, so mark the 856 // inbound direction as closed and shut down the SSL object 857 closeInbound(); 858 sendSSLShutdown(); 859 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, 860 pendingOutboundEncryptedBytes() > 0 861 ? HandshakeStatus.NEED_WRAP : HandshakeStatus.NOT_HANDSHAKING, 862 bytesConsumed, bytesProduced); 863 } 864 default: { 865 // Should never get here. 866 sendSSLShutdown(); 867 throw newSslExceptionWithMessage("SSL_read"); 868 } 869 } 870 } 871 } 872 } else { 873 // If the capacity of all destination buffers is 0 we need to trigger a SSL_read 874 // anyway to ensure everything is flushed in the BIO pair and so we can detect 875 // it in the pendingInboundCleartextBytes() call. 876 readPlaintextData(EMPTY); 877 } 878 } catch (SSLException e) { 879 if (pendingOutboundEncryptedBytes() > 0) { 880 // We need to flush any pending bytes to the remote endpoint in case 881 // there is an alert that needs to be propagated. 882 if (!handshakeFinished && handshakeException is null) { 883 // Save the handshake exception. We will re-throw during the next 884 // handshake. 885 handshakeException = e; 886 } 887 return new SSLEngineResult(SSLEngineResult.Status.OK, HandshakeStatus.NEED_WRAP, bytesConsumed, bytesProduced); 888 } 889 890 // Nothing to write, just shutdown and throw the exception. 891 sendSSLShutdown(); 892 throw convertException(e); 893 } catch (InterruptedIOException e) { 894 return newResult(bytesConsumed, bytesProduced, handshakeStatus); 895 } catch (EOFException e) { 896 closeAll(); 897 throw convertException(e); 898 } catch (IOException e) { 899 sendSSLShutdown(); 900 throw convertException(e); 901 } 902 903 // There won't be any application data until we're done handshaking. 904 // We first check handshakeFinished to eliminate the overhead of extra JNI call if 905 // possible. 906 int pendingCleartextBytes = handshakeFinished ? pendingInboundCleartextBytes() : 0; 907 if (pendingCleartextBytes > 0) { 908 // We filled all buffers but there is still some data pending in the BIO buffer, 909 // return BUFFER_OVERFLOW. 910 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, 911 mayFinishHandshake(handshakeStatus == HandshakeStatus.FINISHED 912 ? handshakeStatus 913 : getHandshakeStatusInternal()), 914 bytesConsumed, bytesProduced); 915 } 916 917 return newResult(bytesConsumed, bytesProduced, handshakeStatus); 918 } 919 } 920 921 private static int calcDstsLength(ByteBuffer[] dsts, int dstsOffset, int dstsLength) { 922 int capacity = 0; 923 for (int i = 0; i < dsts.length; i++) { 924 ByteBuffer dst = dsts[i]; 925 assert(dst !is null, format("dsts[%d] is null", i)); 926 if (dst.isReadOnly()) { 927 throw new ReadOnlyBufferException(""); 928 } 929 if (i >= dstsOffset && i < dstsOffset + dstsLength) { 930 capacity += dst.remaining(); 931 } 932 } 933 return capacity; 934 } 935 936 private static long calcSrcsLength(ByteBuffer[] srcs, int srcsOffset, int srcsEndOffset) { 937 long len = 0; 938 for (int i = srcsOffset; i < srcsEndOffset; i++) { 939 ByteBuffer src = srcs[i]; 940 if (src is null) { 941 throw new IllegalArgumentException("srcs[" ~ i.to!string() ~ "] is null"); 942 } 943 len += src.remaining(); 944 } 945 return len; 946 } 947 948 949 // private HandshakeStatus handshake() { 950 // // try { 951 // return doHandshake(); 952 // // } catch (Exception e) { 953 // // throw SSLUtils.toSSLHandshakeException(e); 954 // // } 955 // } 956 957 private HandshakeStatus handshake() { 958 // Only actually perform the handshake if we haven't already just completed it 959 // via BIO operations. 960 try { 961 // First, check to see if we already have a pending alert that needs to be written. 962 if (handshakeException !is null) { 963 if (pendingOutboundEncryptedBytes() > 0) { 964 // Need to finish writing the alert to the remote peer. 965 return HandshakeStatus.NEED_WRAP; 966 } 967 968 // We've finished writing the alert, just throw the exception. 969 SSLException e = handshakeException; 970 handshakeException = null; 971 throw e; 972 } 973 974 int ssl_error_code = ssl.doHandshake(); 975 switch (ssl_error_code) { 976 case SSL_ERROR_WANT_READ: 977 return pendingStatus(pendingOutboundEncryptedBytes()); 978 case SSL_ERROR_WANT_WRITE: { 979 return HandshakeStatus.NEED_WRAP; 980 } 981 default: { 982 // SSL_ERROR_NONE. 983 } 984 } 985 } catch (SSLException e) { 986 if (pendingOutboundEncryptedBytes() > 0) { 987 // Delay throwing the exception since we appear to have an outbound alert 988 // that needs to be written to the remote endpoint. 989 handshakeException = e; 990 return HandshakeStatus.NEED_WRAP; 991 } 992 993 // There is no pending alert to write - just shutdown and throw. 994 sendSSLShutdown(); 995 throw e; 996 } catch (IOException e) { 997 sendSSLShutdown(); 998 throw e; 999 } 1000 1001 // The handshake has completed successfully... 1002 version(HUNT_DEBUG_MORE) trace("The handshake is completing..."); 1003 1004 // Update the session from the current state of the SSL object. 1005 activeSession.onPeerCertificateAvailable(getPeerHost(), getPeerPort()); 1006 1007 finishHandshake(); 1008 return HandshakeStatus.FINISHED; 1009 } 1010 1011 private void finishHandshake() { 1012 version(HUNT_DEBUG) info("Handshake finish."); 1013 handshakeFinished = true; 1014 // Notify the listener, if provided. 1015 if (handshakeListener !is null) { 1016 handshakeListener(); 1017 } 1018 } 1019 1020 /** 1021 * Write plaintext data to the OpenSSL internal BIO 1022 * 1023 * Calling this function with src.remaining == 0 is undefined. 1024 */ 1025 private int writePlaintextData(ByteBuffer src, int len) { 1026 try { 1027 int pos = src.position(); 1028 int sslWrote; 1029 if (src.isDirect()) { 1030 sslWrote = writePlaintextDataDirect(src, pos, len); 1031 } else { 1032 sslWrote = writePlaintextDataHeap(src, pos, len); 1033 } 1034 if (sslWrote > 0) { 1035 src.position(pos + sslWrote); 1036 } 1037 return sslWrote; 1038 } catch (Exception e) { 1039 throw convertException(e); 1040 } 1041 } 1042 1043 private int writePlaintextDataDirect(ByteBuffer src, int pos, int len) { 1044 return ssl.writeDirectByteBuffer(directByteBufferAddress(src, pos), len); 1045 } 1046 1047 private int writePlaintextDataHeap(ByteBuffer src, int pos, int len) { 1048 AllocatedBuffer allocatedBuffer = null; 1049 try { 1050 ByteBuffer buffer; 1051 if (bufferAllocator !is null) { 1052 allocatedBuffer = bufferAllocator.allocateDirectBuffer(len); 1053 buffer = allocatedBuffer.nioBuffer(); 1054 } else { 1055 // We don't have a buffer allocator, but we don't want to send a heap 1056 // buffer to JNI. So lazy-create a direct buffer that we will use from now 1057 // on to copy plaintext data. 1058 buffer = getOrCreateLazyDirectBuffer(); 1059 } 1060 1061 // Copy the data to the direct buffer. 1062 int limit = src.limit(); 1063 int bytesToWrite = min(len, buffer.remaining()); 1064 src.limit(pos + bytesToWrite); 1065 buffer.put(src); 1066 buffer.flip(); 1067 // Restore the original position and limit. 1068 src.limit(limit); 1069 src.position(pos); 1070 1071 return writePlaintextDataDirect(buffer, 0, bytesToWrite); 1072 } finally { 1073 if (allocatedBuffer !is null) { 1074 // Release the buffer back to the pool. 1075 allocatedBuffer.release(); 1076 } 1077 } 1078 } 1079 1080 /** 1081 * Read plaintext data from the OpenSSL internal BIO 1082 */ 1083 private int readPlaintextData(ByteBuffer dst) { 1084 try { 1085 int pos = dst.position(); 1086 int limit = dst.limit(); 1087 int len = min(SSL3_RT_MAX_PACKET_SIZE, limit - pos); 1088 if (dst.isDirect()) { 1089 int bytesRead = readPlaintextDataDirect(dst, pos, len); 1090 if (bytesRead > 0) { 1091 dst.position(pos + bytesRead); 1092 } 1093 return bytesRead; 1094 } 1095 1096 // The heap method updates the dst position automatically. 1097 return readPlaintextDataHeap(dst, len); 1098 } catch (CertificateException e) { 1099 throw convertException(e); 1100 } 1101 } 1102 1103 private int readPlaintextDataDirect(ByteBuffer dst, int pos, int len) { 1104 return ssl.readDirectByteBuffer(directByteBufferAddress(dst, pos), len); 1105 // tracef("bbbbbbbbbbb=>%s", dst.toString()); 1106 // int r = ssl.readDirectByteBuffer(directByteBufferAddress(dst, pos), len); 1107 // byte[] bf = dst.array(); 1108 // if(bf.length>16) 1109 // tracef("ccccccccccccc=>%s, %(%02X %)", dst.toString(), bf[0..16]); 1110 // else 1111 // tracef("ccccccccccccc=>%s, %(%02X %)", dst.toString(), bf[0..$]); 1112 1113 // return r; 1114 } 1115 1116 private int readPlaintextDataHeap(ByteBuffer dst, int len) { 1117 AllocatedBuffer allocatedBuffer = null; 1118 try { 1119 ByteBuffer buffer; 1120 if (bufferAllocator !is null) { 1121 allocatedBuffer = bufferAllocator.allocateDirectBuffer(len); 1122 buffer = allocatedBuffer.nioBuffer(); 1123 } else { 1124 // We don't have a buffer allocator, but we don't want to send a heap 1125 // buffer to JNI. So lazy-create a direct buffer that we will use from now 1126 // on to copy plaintext data. 1127 buffer = getOrCreateLazyDirectBuffer(); 1128 } 1129 1130 byte[] bf = buffer.array(); 1131 // if(bf.length>16) 1132 // tracef("aaaaaaaaa=>%s, %(%02X %)", buffer.toString(), bf[0..16]); 1133 // else 1134 // tracef("aaaaaaaaa=>%s, %(%02X %)", buffer.toString(), bf[0..$]); 1135 1136 // Read the data to the direct buffer. 1137 int bytesToRead = min(len, buffer.remaining()); 1138 int bytesRead = readPlaintextDataDirect(buffer, 0, bytesToRead); 1139 1140 // if(bf.length>16) 1141 // tracef("ccccccccccccc=>bytesRead=%d, %s, %(%02X %)", bytesRead, buffer.toString(), bf[0..16]); 1142 1143 if (bytesRead > 0) { 1144 // Copy the data to the heap buffer. 1145 buffer.position(bytesRead); 1146 buffer.flip(); 1147 // tracef("ccccccccc, dst=> %s", dst.toString()); 1148 dst.put(buffer); 1149 // tracef("ddddddddd, dst=> %s", dst.toString()); 1150 } 1151 1152 return bytesRead; 1153 } finally { 1154 if (allocatedBuffer !is null) { 1155 // Release the buffer back to the pool. 1156 allocatedBuffer.release(); 1157 } 1158 } 1159 } 1160 1161 private SSLException convertException(Throwable e) { 1162 if (typeid(e) == typeid(SSLHandshakeException) || !handshakeFinished) { 1163 return SSLUtils.toSSLHandshakeException(e); 1164 } 1165 return SSLUtils.toSSLException(e); 1166 } 1167 1168 /** 1169 * Write encrypted data to the OpenSSL network BIO. 1170 */ 1171 private int writeEncryptedData(ByteBuffer src, int len) { 1172 try { 1173 int pos = src.position(); 1174 int bytesWritten; 1175 if (src.isDirect()) { 1176 bytesWritten = writeEncryptedDataDirect(src, pos, len); 1177 } else { 1178 bytesWritten = writeEncryptedDataHeap(src, pos, len); 1179 } 1180 1181 if (bytesWritten > 0) { 1182 src.position(pos + bytesWritten); 1183 } 1184 1185 return bytesWritten; 1186 } catch (Exception e) { 1187 throw new SSLException("", e); 1188 } 1189 } 1190 1191 private int writeEncryptedDataDirect(ByteBuffer src, int pos, int len) { 1192 return networkBio.writeDirectByteBuffer(directByteBufferAddress(src, pos), len); 1193 } 1194 1195 private int writeEncryptedDataHeap(ByteBuffer src, int pos, int len) { 1196 AllocatedBuffer allocatedBuffer = null; 1197 try { 1198 ByteBuffer buffer; 1199 if (bufferAllocator !is null) { 1200 allocatedBuffer = bufferAllocator.allocateDirectBuffer(len); 1201 buffer = allocatedBuffer.nioBuffer(); 1202 } else { 1203 // We don't have a buffer allocator, but we don't want to send a heap 1204 // buffer to JNI. So lazy-create a direct buffer that we will use from now 1205 // on to copy encrypted packets. 1206 buffer = getOrCreateLazyDirectBuffer(); 1207 } 1208 1209 int limit = src.limit(); 1210 int bytesToCopy = min(min(limit - pos, len), buffer.remaining()); 1211 src.limit(pos + bytesToCopy); 1212 buffer.put(src); 1213 // Restore the original limit. 1214 src.limit(limit); 1215 1216 // Reset the original position on the source buffer. 1217 src.position(pos); 1218 1219 int bytesWritten = writeEncryptedDataDirect(buffer, 0, bytesToCopy); 1220 1221 // Restore the original position. 1222 src.position(pos); 1223 1224 return bytesWritten; 1225 } finally { 1226 if (allocatedBuffer !is null) { 1227 // Release the buffer back to the pool. 1228 allocatedBuffer.release(); 1229 } 1230 } 1231 } 1232 1233 private ByteBuffer getOrCreateLazyDirectBuffer() { 1234 if (lazyDirectBuffer is null) { 1235 int capacity = max(SSL3_RT_MAX_PLAIN_LENGTH, SSL3_RT_MAX_PACKET_SIZE); 1236 lazyDirectBuffer = new HeapByteBuffer(capacity, capacity); 1237 // lazyDirectBuffer = ByteBuffer.allocateDirect( 1238 // max(SSL3_RT_MAX_PLAIN_LENGTH, SSL3_RT_MAX_PACKET_SIZE)); 1239 } 1240 lazyDirectBuffer.clear(); 1241 return lazyDirectBuffer; 1242 } 1243 1244 private long directByteBufferAddress(ByteBuffer directBuffer, int pos) { 1245 byte[] buffer = directBuffer.array(); 1246 // tracef("xxxxxxxxxxxxx=>%s, pos=%d", buffer.ptr, pos); 1247 return cast(long)cast(void*)(buffer.ptr + pos); 1248 } 1249 1250 private SSLEngineResult readPendingBytesFromBIO(ByteBuffer dst, int bytesConsumed, 1251 int bytesProduced, HandshakeStatus status) { 1252 try { 1253 // Check to see if the engine wrote data into the network BIO 1254 int pendingNet = pendingOutboundEncryptedBytes(); 1255 if (pendingNet > 0) { 1256 // Do we have enough room in dst to write encrypted data? 1257 int capacity = dst.remaining(); 1258 if (capacity < pendingNet) { 1259 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, 1260 mayFinishHandshake( status == HandshakeStatus.FINISHED ? 1261 status : getHandshakeStatus(pendingNet)), 1262 bytesConsumed, bytesProduced); 1263 } 1264 1265 // Write the pending data from the network BIO into the dst buffer 1266 int produced = readEncryptedData(dst, pendingNet); 1267 1268 if (produced <= 0) { 1269 warning("Can't read encrypted data."); 1270 // We ignore BIO_* errors here as we use in memory BIO anyway and will do 1271 // another SSL_* call later on in which we will produce an exception in 1272 // case of an error 1273 NativeCrypto.SSL_clear_error(); 1274 } else { 1275 bytesProduced += produced; 1276 pendingNet -= produced; 1277 } 1278 1279 return new SSLEngineResult(getEngineStatus(), 1280 mayFinishHandshake( status == HandshakeStatus.FINISHED ? 1281 status : getHandshakeStatus(pendingNet)), 1282 bytesConsumed, bytesProduced); 1283 } 1284 return null; 1285 } catch (Exception e) { 1286 throw convertException(e); 1287 } 1288 } 1289 1290 /** 1291 * Read encrypted data from the OpenSSL network BIO 1292 */ 1293 private int readEncryptedData(ByteBuffer dst, int pending) { 1294 try { 1295 int bytesRead = 0; 1296 int pos = dst.position(); 1297 if (dst.remaining() >= pending) { 1298 int limit = dst.limit(); 1299 int len = min(pending, limit - pos); 1300 if (dst.isDirect()) { 1301 bytesRead = readEncryptedDataDirect(dst, pos, len); 1302 // Need to update the position on the dst buffer. 1303 if (bytesRead > 0) { 1304 dst.position(pos + bytesRead); 1305 } 1306 } else { 1307 // The heap method will update the position on the dst buffer automatically. 1308 bytesRead = readEncryptedDataHeap(dst, len); 1309 } 1310 } 1311 1312 return bytesRead; 1313 } catch (Exception e) { 1314 throw convertException(e); 1315 } 1316 } 1317 1318 private int readEncryptedDataDirect(ByteBuffer dst, int pos, int len) { 1319 return networkBio.readDirectByteBuffer(directByteBufferAddress(dst, pos), len); 1320 } 1321 1322 private int readEncryptedDataHeap(ByteBuffer dst, int len) { 1323 AllocatedBuffer allocatedBuffer = null; 1324 try { 1325 ByteBuffer buffer; 1326 if (bufferAllocator !is null) { 1327 allocatedBuffer = bufferAllocator.allocateDirectBuffer(len); 1328 buffer = allocatedBuffer.nioBuffer(); 1329 } else { 1330 // We don't have a buffer allocator, but we don't want to send a heap 1331 // buffer to JNI. So lazy-create a direct buffer that we will use from now 1332 // on to copy encrypted packets. 1333 buffer = getOrCreateLazyDirectBuffer(); 1334 } 1335 1336 version(HUNT_DEBUG_MORE) trace(BufferUtils.toSummaryString(buffer)); 1337 1338 int bytesToRead = min(len, buffer.remaining()); 1339 int bytesRead = readEncryptedDataDirect(buffer, 0, bytesToRead); 1340 1341 // byte[] temp = buffer.array(); 1342 // tracef("%(%02X %)", temp[0..len]); 1343 version(HUNT_DEBUG_MORE) { 1344 tracef("read encrypted data: %d / %d bytes", bytesRead, bytesToRead); 1345 } 1346 1347 if (bytesRead > 0) { 1348 buffer.position(bytesRead); 1349 buffer.flip(); 1350 dst.put(buffer); 1351 version(HUNT_DEBUG_MORE) trace(BufferUtils.toSummaryString(dst)); 1352 } 1353 1354 return bytesRead; 1355 } finally { 1356 if (allocatedBuffer !is null) { 1357 // Release the buffer back to the pool. 1358 allocatedBuffer.release(); 1359 } 1360 } 1361 } 1362 1363 private HandshakeStatus mayFinishHandshake(HandshakeStatus status) { 1364 if (!handshakeFinished && status == HandshakeStatus.NOT_HANDSHAKING) { 1365 // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call 1366 // SSL_do_handshake() again 1367 return handshake(); 1368 } 1369 return status; 1370 } 1371 1372 private HandshakeStatus getHandshakeStatus(int pending) { 1373 // Check if we are in the initial handshake phase or shutdown phase 1374 return !handshakeFinished ? pendingStatus(pending) : HandshakeStatus.NOT_HANDSHAKING; 1375 } 1376 1377 private SSLEngineResult.Status getEngineStatus() { 1378 switch (state) { 1379 case EngineStates.STATE_CLOSED_INBOUND: 1380 case EngineStates.STATE_CLOSED_OUTBOUND: 1381 case EngineStates.STATE_CLOSED: 1382 return SSLEngineResult.Status.CLOSED; 1383 default: 1384 return SSLEngineResult.Status.OK; 1385 } 1386 } 1387 1388 private void closeAll() { 1389 closeOutbound(); 1390 closeInbound(); 1391 } 1392 1393 private SSLException newSslExceptionWithMessage(string err) { 1394 if (!handshakeFinished) { 1395 return new SSLException(err); 1396 } 1397 return new SSLHandshakeException(err); 1398 } 1399 1400 private SSLEngineResult newResult(int bytesConsumed, int bytesProduced, 1401 HandshakeStatus status) { 1402 return new SSLEngineResult(getEngineStatus(), 1403 mayFinishHandshake(status == HandshakeStatus.FINISHED ? status : getHandshakeStatusInternal()), 1404 bytesConsumed, bytesProduced); 1405 } 1406 1407 alias wrap = SSLEngine.wrap; 1408 1409 override 1410 SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) { 1411 synchronized (ssl) { 1412 try { 1413 return wrap(makeSingleSrcBuffer(src), dst); 1414 } finally { 1415 resetSingleSrcBuffer(); 1416 } 1417 } 1418 } 1419 1420 private static string badPositionIndexes(int start, int end, int size) { 1421 if (start < 0 || start > size) { 1422 return badPositionIndex(start, size, "start index"); 1423 } 1424 if (end < 0 || end > size) { 1425 return badPositionIndex(end, size, "end index"); 1426 } 1427 // end < start 1428 return format("end index (%s) must not be less than start index (%s)", end, start); 1429 } 1430 1431 private static string badPositionIndex(int index, int size, string desc) { 1432 if (index < 0) { 1433 return format("%s (%s) must not be negative", desc, index); 1434 } else if (size < 0) { 1435 throw new IllegalArgumentException("negative size: " ~ size.to!string()); 1436 } else { // index > size 1437 return format("%s (%s) must not be greater than size (%s)", desc, index, size); 1438 } 1439 } 1440 1441 /** 1442 * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list 1443 * or string of size {@code size}, and are in order. A position index may range from zero to 1444 * {@code size}, inclusive. 1445 * 1446 * @param start a user-supplied index identifying a starting position in an array, list or string 1447 * @param end a user-supplied index identifying a ending position in an array, list or string 1448 * @param size the size of that array, list or string 1449 * @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size}, 1450 * or if {@code end} is less than {@code start} 1451 * @throws IllegalArgumentException if {@code size} is negative 1452 */ 1453 static void checkPositionIndexes(int start, int end, int size) { 1454 // Carefully optimized for execution by hotspot (explanatory comment above) 1455 if (start < 0 || end < start || end > size) { 1456 throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); 1457 } 1458 } 1459 1460 override 1461 SSLEngineResult wrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer dst) 1462 { 1463 assert(srcs !is null, "srcs is null"); 1464 assert(dst !is null, "dst is null"); 1465 checkPositionIndexes(srcsOffset, srcsOffset + srcsLength, cast(int)srcs.length); 1466 if (dst.isReadOnly()) { 1467 throw new ReadOnlyBufferException(""); 1468 } 1469 1470 synchronized (ssl) { 1471 switch (state) { 1472 case EngineStates.STATE_MODE_SET: 1473 // Begin the handshake implicitly. 1474 beginHandshakeInternal(); 1475 break; 1476 case EngineStates.STATE_CLOSED_OUTBOUND: 1477 case EngineStates.STATE_CLOSED: 1478 // We may have pending encrypted bytes from a close_notify alert, so 1479 // try to read them out 1480 SSLEngineResult pendingNetResult = 1481 readPendingBytesFromBIO(dst, 0, 0, HandshakeStatus.NOT_HANDSHAKING); 1482 if (pendingNetResult !is null) { 1483 return pendingNetResult; 1484 } 1485 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, getHandshakeStatusInternal(), 0, 0); 1486 case EngineStates.STATE_NEW: 1487 throw new IllegalStateException( 1488 "Client/server mode must be set before calling wrap"); 1489 default: 1490 break; 1491 } 1492 1493 // If we haven't completed the handshake yet, just let the caller know. 1494 HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; 1495 // Prepare OpenSSL to work in server mode and receive handshake 1496 if (!handshakeFinished) { 1497 handshakeStatus = handshake(); 1498 if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) { 1499 return NEED_UNWRAP_OK; 1500 } 1501 1502 if (state == EngineStates.STATE_CLOSED) { 1503 return NEED_UNWRAP_CLOSED; 1504 } 1505 // NEED_WRAP - just fall through to perform the wrap. 1506 } 1507 1508 int srcsLen = 0; 1509 int endOffset = srcsOffset + srcsLength; 1510 for (int i = srcsOffset; i < endOffset; ++i) { 1511 ByteBuffer src = srcs[i]; 1512 if (src is null) { 1513 throw new IllegalArgumentException("srcs[" ~ i.to!string() ~ "] is null"); 1514 } 1515 if (srcsLen == SSL3_RT_MAX_PLAIN_LENGTH) { 1516 continue; 1517 } 1518 1519 srcsLen += src.remaining(); 1520 if (srcsLen > SSL3_RT_MAX_PLAIN_LENGTH || srcsLen < 0) { 1521 // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to 1522 // MAX_PLAINTEXT_LENGTH. 1523 // This also help us to guard against overflow. 1524 // We not break out here as we still need to check for null entries in srcs[]. 1525 srcsLen = SSL3_RT_MAX_PLAIN_LENGTH; 1526 } 1527 } 1528 1529 if (dst.remaining() < SSLUtils.calculateOutNetBufSize(srcsLen)) { 1530 return new SSLEngineResult( 1531 SSLEngineResult.Status.BUFFER_OVERFLOW, getHandshakeStatusInternal(), 0, 0); 1532 } 1533 1534 int bytesProduced = 0; 1535 int bytesConsumed = 0; 1536 loop: 1537 for (int i = srcsOffset; i < endOffset; ++i) { 1538 ByteBuffer src = srcs[i]; 1539 assert(src !is null, format("srcs[%d] is null", i)); 1540 while (src.hasRemaining()) { 1541 SSLEngineResult pendingNetResult; 1542 // Write plaintext application data to the SSL engine 1543 int result = writePlaintextData(src, min(src.remaining(), SSL3_RT_MAX_PLAIN_LENGTH - bytesConsumed)); 1544 if (result > 0) { 1545 bytesConsumed += result; 1546 1547 pendingNetResult = readPendingBytesFromBIO( 1548 dst, bytesConsumed, bytesProduced, handshakeStatus); 1549 if (pendingNetResult !is null) { 1550 if (pendingNetResult.getStatus() != SSLEngineResult.Status.OK) { 1551 return pendingNetResult; 1552 } 1553 bytesProduced = pendingNetResult.bytesProduced(); 1554 } 1555 if (bytesConsumed == SSL3_RT_MAX_PLAIN_LENGTH) { 1556 // If we consumed the maximum amount of bytes for the plaintext length 1557 // break out of the loop and start to fill the dst buffer. 1558 break loop; 1559 } 1560 } else { 1561 int sslError = ssl.getError(result); 1562 switch (sslError) { 1563 case SSL_ERROR_ZERO_RETURN: 1564 // This means the connection was shutdown correctly, close inbound 1565 // and outbound 1566 closeAll(); 1567 pendingNetResult = readPendingBytesFromBIO( 1568 dst, bytesConsumed, bytesProduced, handshakeStatus); 1569 return pendingNetResult !is null ? pendingNetResult 1570 : CLOSED_NOT_HANDSHAKING; 1571 case SSL_ERROR_WANT_READ: 1572 // If there is no pending data to read from BIO we should go back to 1573 // event loop and try 1574 // to read more data [1]. It is also possible that event loop will 1575 // detect the socket 1576 // has been closed. [1] 1577 // https://www.openssl.org/docs/manmaster/ssl/SSL_write.html 1578 pendingNetResult = readPendingBytesFromBIO( 1579 dst, bytesConsumed, bytesProduced, handshakeStatus); 1580 return pendingNetResult !is null 1581 ? pendingNetResult 1582 : new SSLEngineResult(getEngineStatus(), HandshakeStatus.NEED_UNWRAP, 1583 bytesConsumed, bytesProduced); 1584 case SSL_ERROR_WANT_WRITE: 1585 // SSL_ERROR_WANT_WRITE typically means that the underlying 1586 // transport is not writable 1587 // and we should set the "want write" flag on the selector and try 1588 // again when the 1589 // underlying transport is writable [1]. However we are not directly 1590 // writing to the 1591 // underlying transport and instead writing to a BIO buffer. The 1592 // OpenSsl documentation 1593 // says we should do the following [1]: 1594 // 1595 // "When using a buffering BIO, like a BIO pair, data must be 1596 // written into or retrieved 1597 // out of the BIO before being able to continue." 1598 // 1599 // So we attempt to drain the BIO buffer below, but if there is no 1600 // data this condition 1601 // is undefined and we assume their is a fatal error with the 1602 // openssl engine and close. 1603 // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html 1604 pendingNetResult = readPendingBytesFromBIO( 1605 dst, bytesConsumed, bytesProduced, handshakeStatus); 1606 return pendingNetResult !is null ? pendingNetResult 1607 : NEED_WRAP_CLOSED; 1608 default: 1609 // Everything else is considered as error 1610 sendSSLShutdown(); 1611 throw newSslExceptionWithMessage("SSL_write"); 1612 } 1613 } 1614 } 1615 } 1616 // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not checked 1617 // if the srcs was 1618 // empty, or only contained empty buffers. 1619 if (bytesConsumed == 0) { 1620 SSLEngineResult pendingNetResult = 1621 readPendingBytesFromBIO(dst, 0, bytesProduced, handshakeStatus); 1622 if (pendingNetResult !is null) { 1623 return pendingNetResult; 1624 } 1625 } 1626 1627 // return new SSLEngineResult(OK, getHandshakeStatusInternal(), bytesConsumed, 1628 // bytesProduced); 1629 return newResult(bytesConsumed, bytesProduced, handshakeStatus); 1630 } 1631 } 1632 1633 override 1634 int clientPSKKeyRequested(string identityHint, byte[] identity, byte[] key) { 1635 return ssl.clientPSKKeyRequested(identityHint, identity, key); 1636 } 1637 1638 override 1639 int serverPSKKeyRequested(string identityHint, string identity, byte[] key) { 1640 return ssl.serverPSKKeyRequested(identityHint, identity, key); 1641 } 1642 1643 override 1644 void onSSLStateChange(int type, int val) { 1645 synchronized (ssl) { 1646 switch (type) { 1647 case SSL_CB_HANDSHAKE_START: { 1648 // For clients, this will allow the NEED_UNWRAP status to be 1649 // returned. 1650 transitionTo(EngineStates.STATE_HANDSHAKE_STARTED); 1651 break; 1652 } 1653 case SSL_CB_HANDSHAKE_DONE: { 1654 if (state != EngineStates.STATE_HANDSHAKE_STARTED 1655 && state != EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH) { 1656 throw new IllegalStateException("Completed handshake while in mode " ~ state.to!string()); 1657 } 1658 transitionTo(EngineStates.STATE_HANDSHAKE_COMPLETED); 1659 break; 1660 } 1661 default: 1662 // Ignore 1663 } 1664 } 1665 } 1666 1667 override 1668 void onNewSessionEstablished(long sslSessionNativePtr) { 1669 1670 implementationMissing(false); 1671 // try { 1672 // // Increment the reference count to "take ownership" of the session resource. 1673 // NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr); 1674 1675 // // Create a native reference which will release the SSL_SESSION in its finalizer. 1676 // // This constructor will only throw if the native pointer passed in is NULL, which 1677 // // BoringSSL guarantees will not happen. 1678 // NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr); 1679 1680 // NativeSslSession nativeSession = NativeSslSession.newInstance(ref, activeSession); 1681 1682 // // Cache the newly established session. 1683 // AbstractSessionContext ctx = sessionContext(); 1684 // ctx.cacheSession(nativeSession); 1685 // } catch (Exception ignored) { 1686 // // Ignore. 1687 // } 1688 } 1689 1690 override 1691 long serverSessionRequested(byte[] id) { 1692 // TODO(nathanmittler): Implement server-side caching for TLS < 1.3 1693 return 0; 1694 } 1695 1696 override 1697 void verifyCertificateChain(byte[][] certChain, string authMethod) { 1698 implementationMissing(false); 1699 // try { 1700 // if (certChain is null || certChain.length == 0) { 1701 // throw new CertificateException("Peer sent no certificate"); 1702 // } 1703 // X509Certificate[] peerCertChain = SSLUtils.decodeX509CertificateChain(certChain); 1704 1705 // X509TrustManager x509tm = sslParameters.getX509TrustManager(); 1706 // if (x509tm is null) { 1707 // throw new CertificateException("No X.509 TrustManager"); 1708 // } 1709 1710 // // Update the peer information on the session. 1711 // activeSession.onPeerCertificatesReceived(getPeerHost(), getPeerPort(), peerCertChain); 1712 1713 // if (getUseClientMode()) { 1714 // Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this); 1715 // } else { 1716 // string authType = peerCertChain[0].getPublicKey().getAlgorithm(); 1717 // Platform.checkClientTrusted(x509tm, peerCertChain, authType, this); 1718 // } 1719 // } catch (CertificateException e) { 1720 // throw e; 1721 // } catch (Exception e) { 1722 // throw new CertificateException(e); 1723 // } 1724 } 1725 1726 override 1727 void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) { 1728 ssl.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals); 1729 } 1730 1731 private void sendSSLShutdown() { 1732 try { 1733 ssl.shutdown(); 1734 } catch (IOException ignored) { 1735 // TODO: The RI ignores close failures in SSLSocket, but need to 1736 // investigate whether it does for SSLEngine. 1737 } 1738 } 1739 1740 private void closeAndFreeResources() { 1741 transitionTo(EngineStates.STATE_CLOSED); 1742 if (!ssl.isClosed()) { 1743 ssl.close(); 1744 networkBio.close(); 1745 } 1746 } 1747 1748 // override 1749 // protected void finalize() throws Throwable { 1750 // try { 1751 // transitionTo(STATE_CLOSED); 1752 // } finally { 1753 // super.finalize(); 1754 // } 1755 // } 1756 1757 // override string chooseServerAlias(X509KeyManager keyManager, string keyType) { 1758 // // X509ExtendedKeyManager ekm = cast(X509ExtendedKeyManager) keyManager; 1759 // // if (ekm is null) { 1760 // // return keyManager.chooseServerAlias(keyType, null, null); 1761 // // } else { 1762 // // return ekm.chooseEngineServerAlias(keyType, null, this); 1763 // // } 1764 // implementationMissing(false); 1765 // return ""; 1766 // } 1767 1768 // override string chooseClientAlias(X509KeyManager keyManager, 1769 // X500Principal[] issuers, string[] keyTypes) { 1770 1771 // implementationMissing(false); 1772 // return ""; 1773 // // X509ExtendedKeyManager ekm = cast(X509ExtendedKeyManager) keyManager; 1774 // // if (ekm is null) { 1775 // // return keyManager.chooseClientAlias(keyTypes, issuers, null); 1776 // // } else { 1777 // // return ekm.chooseEngineClientAlias(keyTypes, issuers, this); 1778 // // } 1779 // } 1780 1781 // override 1782 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1783 // string chooseServerPSKIdentityHint(PSKKeyManager keyManager) { 1784 // return keyManager.chooseServerKeyIdentityHint(this); 1785 // } 1786 1787 // override 1788 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1789 // string chooseClientPSKIdentity(PSKKeyManager keyManager, string identityHint) { 1790 // return keyManager.chooseClientKeyIdentity(identityHint, this); 1791 // } 1792 1793 // override 1794 // @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1795 // SecretKey getPSKKey(PSKKeyManager keyManager, string identityHint, string identity) { 1796 // return keyManager.getKey(identityHint, identity, this); 1797 // } 1798 1799 /** 1800 * This method enables session ticket support. 1801 * 1802 * @param useSessionTickets True to enable session tickets 1803 */ 1804 override 1805 void setUseSessionTickets(bool useSessionTickets) { 1806 sslParameters.setUseSessionTickets(useSessionTickets); 1807 } 1808 1809 override 1810 string[] getApplicationProtocols() { 1811 return sslParameters.getApplicationProtocols(); 1812 } 1813 1814 override 1815 void setApplicationProtocols(string[] protocols) { 1816 sslParameters.setApplicationProtocols(protocols); 1817 } 1818 1819 override 1820 void setApplicationProtocolSelector(ApplicationProtocolSelector selector) { 1821 setApplicationProtocolSelector( 1822 selector is null ? null : new ApplicationProtocolSelectorAdapter(this, selector)); 1823 } 1824 1825 // override 1826 // byte[] getTlsUnique() { 1827 // return ssl.getTlsUnique(); 1828 // } 1829 1830 // override 1831 // void setTokenBindingParams(int... params) { 1832 // synchronized (ssl) { 1833 // if (isHandshakeStarted()) { 1834 // throw new IllegalStateException( 1835 // "Cannot set token binding params after handshake has started."); 1836 // } 1837 // } 1838 // ssl.setTokenBindingParams(params); 1839 // }; 1840 1841 // override 1842 // int getTokenBindingParams() { 1843 // return ssl.getTokenBindingParams(); 1844 // } 1845 1846 // override 1847 // byte[] exportKeyingMaterial(string label, byte[] context, int length) { 1848 // synchronized (ssl) { 1849 // if (state < STATE_HANDSHAKE_COMPLETED || state == STATE_CLOSED) { 1850 // return null; 1851 // } 1852 // } 1853 // return ssl.exportKeyingMaterial(label, context, length); 1854 // } 1855 1856 void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter adapter) { 1857 sslParameters.setApplicationProtocolSelector(adapter); 1858 } 1859 1860 override 1861 string getApplicationProtocol() { 1862 return SSLUtils.toProtocolString(ssl.getApplicationProtocol()); 1863 } 1864 1865 override 1866 string getHandshakeApplicationProtocol() { 1867 synchronized (ssl) { 1868 return state == EngineStates.STATE_HANDSHAKE_STARTED ? getApplicationProtocol() : null; 1869 } 1870 } 1871 1872 private ByteBuffer[] makeSingleSrcBuffer(ByteBuffer src) { 1873 singleSrcBuffer[0] = src; 1874 return singleSrcBuffer; 1875 } 1876 1877 private void resetSingleSrcBuffer() { 1878 singleSrcBuffer[0] = null; 1879 } 1880 1881 private ByteBuffer[] makeSingleDstBuffer(ByteBuffer src) { 1882 singleDstBuffer[0] = src; 1883 return singleDstBuffer; 1884 } 1885 1886 private void resetSingleDstBuffer() { 1887 singleDstBuffer[0] = null; 1888 } 1889 1890 private ClientSessionContext clientSessionContext() { 1891 return sslParameters.getClientSessionContext(); 1892 } 1893 1894 private AbstractSessionContext sessionContext() { 1895 return sslParameters.getSessionContext(); 1896 } 1897 1898 private void transitionTo(int newState) { 1899 switch (newState) { 1900 case EngineStates.STATE_HANDSHAKE_STARTED: { 1901 handshakeFinished = false; 1902 break; 1903 } 1904 case EngineStates.STATE_CLOSED: { 1905 if (!ssl.isClosed() && state >= EngineStates.STATE_HANDSHAKE_STARTED && 1906 state < EngineStates.STATE_CLOSED ) { 1907 closedSession = new SessionSnapshot(activeSession); 1908 } 1909 break; 1910 } 1911 default: { 1912 break; 1913 } 1914 } 1915 1916 // Update the state 1917 this.state = newState; 1918 } 1919 }