1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.nio.ReadOnlyBufferException;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedActionException;
  33 import java.security.PrivilegedExceptionAction;
  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.function.BiFunction;
  37 import javax.net.ssl.SSLEngine;
  38 import javax.net.ssl.SSLEngineResult;
  39 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  40 import javax.net.ssl.SSLEngineResult.Status;
  41 import javax.net.ssl.SSLException;
  42 import javax.net.ssl.SSLHandshakeException;
  43 import javax.net.ssl.SSLKeyException;
  44 import javax.net.ssl.SSLParameters;
  45 import javax.net.ssl.SSLPeerUnverifiedException;
  46 import javax.net.ssl.SSLProtocolException;
  47 import javax.net.ssl.SSLSession;
  48 
  49 /**
  50  * Implementation of an non-blocking SSLEngine.
  51  *
  52  * @author Brad Wetmore
  53  */
  54 final class SSLEngineImpl extends SSLEngine implements SSLTransport {
  55     private final SSLContextImpl        sslContext;
  56     final TransportContext              conContext;
  57 
  58     /**
  59      * Constructor for an SSLEngine from SSLContext, without
  60      * host/port hints.
  61      *
  62      * This Engine will not be able to cache sessions, but must renegotiate
  63      * everything by hand.
  64      */
  65     SSLEngineImpl(SSLContextImpl sslContext) {
  66         this(sslContext, null, -1);
  67     }
  68 
  69     /**
  70      * Constructor for an SSLEngine from SSLContext.
  71      */
  72     SSLEngineImpl(SSLContextImpl sslContext,
  73             String host, int port) {
  74         super(host, port);
  75         this.sslContext = sslContext;
  76         HandshakeHash handshakeHash = new HandshakeHash();
  77         if (sslContext.isDTLS()) {
  78             this.conContext = new TransportContext(sslContext, this,
  79                     new DTLSInputRecord(handshakeHash),
  80                     new DTLSOutputRecord(handshakeHash));
  81         } else {
  82             this.conContext = new TransportContext(sslContext, this,
  83                     new SSLEngineInputRecord(handshakeHash),
  84                     new SSLEngineOutputRecord(handshakeHash));
  85         }
  86 
  87         // Server name indication is a connection scope extension.
  88         if (host != null) {
  89             this.conContext.sslConfig.serverNames =
  90                     Utilities.addToSNIServerNameList(
  91                             conContext.sslConfig.serverNames, host);
  92         }
  93     }
  94 
  95     @Override
  96     public synchronized void beginHandshake() throws SSLException {
  97         if (conContext.isUnsureMode) {
  98             throw new IllegalStateException(
  99                     "Client/Server mode has not yet been set.");
 100         }
 101 
 102         try {
 103             conContext.kickstart();
 104         } catch (IOException ioe) {
 105             throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
 106                 "Couldn't kickstart handshaking", ioe);
 107         } catch (Exception ex) {     // including RuntimeException
 108             throw conContext.fatal(Alert.INTERNAL_ERROR,
 109                 "Fail to begin handshake", ex);
 110         }
 111     }
 112 
 113     @Override
 114     public synchronized SSLEngineResult wrap(ByteBuffer[] appData,
 115             int offset, int length, ByteBuffer netData) throws SSLException {
 116         return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
 117     }
 118 
 119     // @Override
 120     public synchronized SSLEngineResult wrap(
 121         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 122         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 123 
 124         if (conContext.isUnsureMode) {
 125             throw new IllegalStateException(
 126                     "Client/Server mode has not yet been set.");
 127         }
 128 
 129         // See if the handshaker needs to report back some SSLException.
 130         checkTaskThrown();
 131 
 132         // check parameters
 133         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 134 
 135         try {
 136             return writeRecord(
 137                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 138         } catch (SSLProtocolException spe) {
 139             // may be an unexpected handshake message
 140             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
 141         } catch (IOException ioe) {
 142             throw conContext.fatal(Alert.INTERNAL_ERROR,
 143                 "problem wrapping app data", ioe);
 144         } catch (Exception ex) {     // including RuntimeException
 145             throw conContext.fatal(Alert.INTERNAL_ERROR,
 146                 "Fail to wrap application data", ex);
 147         }
 148     }
 149 
 150     private SSLEngineResult writeRecord(
 151         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 152         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 153 
 154         // May need to deliver cached records.
 155         if (isOutboundDone()) {
 156             return new SSLEngineResult(
 157                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 158         }
 159 
 160         HandshakeContext hc = conContext.handshakeContext;
 161         HandshakeStatus hsStatus = null;
 162         if (!conContext.isNegotiated && !conContext.isBroken &&
 163                 !conContext.isInboundClosed() &&
 164                 !conContext.isOutboundClosed()) {
 165             conContext.kickstart();
 166 
 167             hsStatus = getHandshakeStatus();
 168             if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
 169                 /*
 170                  * For DTLS, if the handshake state is
 171                  * HandshakeStatus.NEED_UNWRAP, a call to SSLEngine.wrap()
 172                  * means that the previous handshake packets (if delivered)
 173                  * get lost, and need retransmit the handshake messages.
 174                  */
 175                 if (!sslContext.isDTLS() || hc == null ||
 176                         !hc.sslConfig.enableRetransmissions ||
 177                         conContext.outputRecord.firstMessage) {
 178 
 179                     return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 180                 }   // otherwise, need retransmission
 181             }
 182         }
 183 
 184         if (hsStatus == null) {
 185             hsStatus = getHandshakeStatus();
 186         }
 187 
 188         /*
 189          * If we have a task outstanding, this *MUST* be done before
 190          * doing any more wrapping, because we could be in the middle
 191          * of receiving a handshake message, for example, a finished
 192          * message which would change the ciphers.
 193          */
 194         if (hsStatus == HandshakeStatus.NEED_TASK) {
 195             return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 196         }
 197 
 198         int dstsRemains = 0;
 199         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 200             dstsRemains += dsts[i].remaining();
 201         }
 202 
 203         // Check destination buffer size.
 204         //
 205         // We can be smarter about using smaller buffer sizes later.  For
 206         // now, force it to be large enough to handle any valid record.
 207         if (dstsRemains < conContext.conSession.getPacketBufferSize()) {
 208             return new SSLEngineResult(
 209                 Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
 210         }
 211 
 212         int srcsRemains = 0;
 213         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 214             srcsRemains += srcs[i].remaining();
 215         }
 216 
 217         Ciphertext ciphertext = null;
 218         try {
 219             // Acquire the buffered to-be-delivered records or retransmissions.
 220             //
 221             // May have buffered records, or need retransmission if handshaking.
 222             if (!conContext.outputRecord.isEmpty() || (hc != null &&
 223                     hc.sslConfig.enableRetransmissions &&
 224                     hc.sslContext.isDTLS() &&
 225                     hsStatus == HandshakeStatus.NEED_UNWRAP)) {
 226                 ciphertext = encode(null, 0, 0,
 227                         dsts, dstsOffset, dstsLength);
 228             }
 229 
 230             if (ciphertext == null && srcsRemains != 0) {
 231                 ciphertext = encode(srcs, srcsOffset, srcsLength,
 232                         dsts, dstsOffset, dstsLength);
 233             }
 234         } catch (IOException ioe) {
 235             if (ioe instanceof SSLException) {
 236                 throw ioe;
 237             } else {
 238                 throw new SSLException("Write problems", ioe);
 239             }
 240         }
 241 
 242         /*
 243          * Check for status.
 244          */
 245         Status status = (isOutboundDone() ? Status.CLOSED : Status.OK);
 246         if (ciphertext != null && ciphertext.handshakeStatus != null) {
 247             hsStatus = ciphertext.handshakeStatus;
 248         } else {
 249             hsStatus = getHandshakeStatus();
 250             if (ciphertext == null && !conContext.isNegotiated &&
 251                     conContext.isInboundClosed() &&
 252                     hsStatus == HandshakeStatus.NEED_WRAP) {
 253                 // Even the outboud is open, no futher data could be wrapped as:
 254                 //     1. the outbound is empty
 255                 //     2. no negotiated connection
 256                 //     3. the inbound has closed, cannot complete the handshake
 257                 //
 258                 // Mark the engine as closed if the handshake status is
 259                 // NEED_WRAP. Otherwise, it could lead to dead loops in
 260                 // applications.
 261                 status = Status.CLOSED;
 262             }
 263         }
 264 
 265         int deltaSrcs = srcsRemains;
 266         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 267             deltaSrcs -= srcs[i].remaining();
 268         }
 269 
 270         int deltaDsts = dstsRemains;
 271         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 272             deltaDsts -= dsts[i].remaining();
 273         }
 274 
 275         return new SSLEngineResult(status, hsStatus, deltaSrcs, deltaDsts,
 276                 ciphertext != null ? ciphertext.recordSN : -1L);
 277     }
 278 
 279     private Ciphertext encode(
 280         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 281         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 282 
 283         Ciphertext ciphertext = null;
 284         try {
 285             ciphertext = conContext.outputRecord.encode(
 286                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 287         } catch (SSLHandshakeException she) {
 288             // may be record sequence number overflow
 289             throw conContext.fatal(Alert.HANDSHAKE_FAILURE, she);
 290         } catch (IOException e) {
 291             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
 292         }
 293 
 294         if (ciphertext == null) {
 295             return null;
 296         }
 297 
 298         // Is the handshake completed?
 299         boolean needRetransmission =
 300                 conContext.sslContext.isDTLS() &&
 301                 conContext.handshakeContext != null &&
 302                 conContext.handshakeContext.sslConfig.enableRetransmissions;
 303         HandshakeStatus hsStatus =
 304                 tryToFinishHandshake(ciphertext.contentType);
 305         if (needRetransmission &&
 306                 hsStatus == HandshakeStatus.FINISHED &&
 307                 conContext.sslContext.isDTLS() &&
 308                 ciphertext.handshakeType == SSLHandshake.FINISHED.id) {
 309             // Retransmit the last flight for DTLS.
 310             //
 311             // The application data transactions may begin immediately
 312             // after the last flight.  If the last flight get lost, the
 313             // application data may be discarded accordingly.  As could
 314             // be an issue for some applications.  This impact can be
 315             // mitigated by sending the last fligth twice.
 316             if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 317                 SSLLogger.finest("retransmit the last flight messages");
 318             }
 319 
 320             conContext.outputRecord.launchRetransmission();
 321             hsStatus = HandshakeStatus.NEED_WRAP;
 322         }
 323 
 324         if (hsStatus == null) {
 325             hsStatus = conContext.getHandshakeStatus();
 326         }
 327 
 328         // Is the sequence number is nearly overflow?
 329         if (conContext.outputRecord.seqNumIsHuge() ||
 330                 conContext.outputRecord.writeCipher.atKeyLimit()) {
 331             hsStatus = tryKeyUpdate(hsStatus);
 332         }
 333 
 334         // update context status
 335         ciphertext.handshakeStatus = hsStatus;
 336 
 337         return ciphertext;
 338     }
 339 
 340     private HandshakeStatus tryToFinishHandshake(byte contentType) {
 341         HandshakeStatus hsStatus = null;
 342         if ((contentType == ContentType.HANDSHAKE.id) &&
 343                 conContext.outputRecord.isEmpty()) {
 344             if (conContext.handshakeContext == null) {
 345                 hsStatus = HandshakeStatus.FINISHED;
 346             } else if (conContext.isPostHandshakeContext()) {
 347                 // unlikely, but just in case.
 348                 hsStatus = conContext.finishPostHandshake();
 349             } else if (conContext.handshakeContext.handshakeFinished) {
 350                 hsStatus = conContext.finishHandshake();
 351             }
 352         }   // Otherwise, the followed call to getHSStatus() will help.
 353 
 354         return hsStatus;
 355     }
 356 
 357     /**
 358      * Try key update for sequence number wrap or key usage limit.
 359      *
 360      * Note that in order to maintain the handshake status properly, we check
 361      * the sequence number and key usage limit after the last record
 362      * reading/writing process.
 363      *
 364      * As we request renegotiation or close the connection for wrapped sequence
 365      * number when there is enough sequence number space left to handle a few
 366      * more records, so the sequence number of the last record cannot be
 367      * wrapped.
 368      */
 369     private HandshakeStatus tryKeyUpdate(
 370             HandshakeStatus currentHandshakeStatus) throws IOException {
 371         // Don't bother to kickstart if handshaking is in progress, or if the
 372         // connection is not duplex-open.
 373         if ((conContext.handshakeContext == null) &&
 374                 !conContext.isOutboundClosed() &&
 375                 !conContext.isInboundClosed() &&
 376                 !conContext.isBroken) {
 377             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 378                 SSLLogger.finest("trigger key update");
 379             }
 380             beginHandshake();
 381             return conContext.getHandshakeStatus();
 382         }
 383 
 384         return currentHandshakeStatus;
 385     }
 386 
 387     private static void checkParams(
 388             ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 389             ByteBuffer[] dsts, int dstsOffset, int dstsLength) {
 390 
 391         if ((srcs == null) || (dsts == null)) {
 392             throw new IllegalArgumentException(
 393                     "source or destination buffer is null");
 394         }
 395 
 396         if ((dstsOffset < 0) || (dstsLength < 0) ||
 397                 (dstsOffset > dsts.length - dstsLength)) {
 398             throw new IndexOutOfBoundsException(
 399                     "index out of bound of the destination buffers");
 400         }
 401 
 402         if ((srcsOffset < 0) || (srcsLength < 0) ||
 403                 (srcsOffset > srcs.length - srcsLength)) {
 404             throw new IndexOutOfBoundsException(
 405                     "index out of bound of the source buffers");
 406         }
 407 
 408         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 409             if (dsts[i] == null) {
 410                 throw new IllegalArgumentException(
 411                         "destination buffer[" + i + "] == null");
 412             }
 413 
 414             /*
 415              * Make sure the destination bufffers are writable.
 416              */
 417             if (dsts[i].isReadOnly()) {
 418                 throw new ReadOnlyBufferException();
 419             }
 420         }
 421 
 422         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 423             if (srcs[i] == null) {
 424                 throw new IllegalArgumentException(
 425                         "source buffer[" + i + "] == null");
 426             }
 427         }
 428     }
 429 
 430     @Override
 431     public synchronized SSLEngineResult unwrap(ByteBuffer src,
 432             ByteBuffer[] dsts, int offset, int length) throws SSLException {
 433         return unwrap(
 434                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
 435     }
 436 
 437     // @Override
 438     public synchronized SSLEngineResult unwrap(
 439         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 440         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 441 
 442         if (conContext.isUnsureMode) {
 443             throw new IllegalStateException(
 444                     "Client/Server mode has not yet been set.");
 445         }
 446 
 447         // See if the handshaker needs to report back some SSLException.
 448         checkTaskThrown();
 449 
 450         // check parameters
 451         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 452 
 453         try {
 454             return readRecord(
 455                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 456         } catch (SSLProtocolException spe) {
 457             // may be an unexpected handshake message
 458             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 459                     spe.getMessage(), spe);
 460         } catch (IOException ioe) {
 461             /*
 462              * Don't reset position so it looks like we didn't
 463              * consume anything.  We did consume something, and it
 464              * got us into this situation, so report that much back.
 465              * Our days of consuming are now over anyway.
 466              */
 467             throw conContext.fatal(Alert.INTERNAL_ERROR,
 468                     "problem unwrapping net record", ioe);
 469         } catch (Exception ex) {     // including RuntimeException
 470             throw conContext.fatal(Alert.INTERNAL_ERROR,
 471                 "Fail to unwrap network record", ex);
 472         }
 473     }
 474 
 475     private SSLEngineResult readRecord(
 476         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 477         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 478 
 479         /*
 480          * Check if we are closing/closed.
 481          */
 482         if (isInboundDone()) {
 483             return new SSLEngineResult(
 484                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 485         }
 486 
 487         HandshakeStatus hsStatus = null;
 488         if (!conContext.isNegotiated && !conContext.isBroken &&
 489                 !conContext.isInboundClosed() &&
 490                 !conContext.isOutboundClosed()) {
 491             conContext.kickstart();
 492 
 493             /*
 494              * If there's still outbound data to flush, we
 495              * can return without trying to unwrap anything.
 496              */
 497             hsStatus = getHandshakeStatus();
 498             if (hsStatus == HandshakeStatus.NEED_WRAP) {
 499                 return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 500             }
 501         }
 502 
 503         if (hsStatus == null) {
 504             hsStatus = getHandshakeStatus();
 505         }
 506 
 507         /*
 508          * If we have a task outstanding, this *MUST* be done before
 509          * doing any more unwrapping, because we could be in the middle
 510          * of receiving a handshake message, for example, a finished
 511          * message which would change the ciphers.
 512          */
 513         if (hsStatus == HandshakeStatus.NEED_TASK) {
 514             return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 515         }
 516 
 517         if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
 518             Plaintext plainText = null;
 519             try {
 520                 plainText = decode(null, 0, 0,
 521                         dsts, dstsOffset, dstsLength);
 522             } catch (IOException ioe) {
 523                 if (ioe instanceof SSLException) {
 524                     throw ioe;
 525                 } else {
 526                     throw new SSLException("readRecord", ioe);
 527                 }
 528             }
 529 
 530             Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 531             if (plainText.handshakeStatus != null) {
 532                 hsStatus = plainText.handshakeStatus;
 533             } else {
 534                 hsStatus = getHandshakeStatus();
 535             }
 536 
 537             return new SSLEngineResult(
 538                     status, hsStatus, 0, 0, plainText.recordSN);
 539         }
 540 
 541         int srcsRemains = 0;
 542         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 543             srcsRemains += srcs[i].remaining();
 544         }
 545 
 546         if (srcsRemains == 0) {
 547             return new SSLEngineResult(
 548                 Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
 549         }
 550 
 551         /*
 552          * Check the packet to make sure enough is here.
 553          * This will also indirectly check for 0 len packets.
 554          */
 555         int packetLen = 0;
 556         try {
 557             packetLen = conContext.inputRecord.bytesInCompletePacket(
 558                     srcs, srcsOffset, srcsLength);
 559         } catch (SSLException ssle) {
 560             // Need to discard invalid records for DTLS protocols.
 561             if (sslContext.isDTLS()) {
 562                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 563                     SSLLogger.finest("Discard invalid DTLS records", ssle);
 564                 }
 565 
 566                 // invalid, discard the entire data [section 4.1.2.7, RFC 6347]
 567                 int deltaNet = 0;
 568                 // int deltaNet = netData.remaining();
 569                 // netData.position(netData.limit());
 570 
 571                 Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 572                 if (hsStatus == null) {
 573                     hsStatus = getHandshakeStatus();
 574                 }
 575 
 576                 return new SSLEngineResult(status, hsStatus, deltaNet, 0, -1L);
 577             } else {
 578                 throw ssle;
 579             }
 580         }
 581 
 582         // Is this packet bigger than SSL/TLS normally allows?
 583         if (packetLen > conContext.conSession.getPacketBufferSize()) {
 584             int largestRecordSize = sslContext.isDTLS() ?
 585                     DTLSRecord.maxRecordSize : SSLRecord.maxLargeRecordSize;
 586             if ((packetLen <= largestRecordSize) && !sslContext.isDTLS()) {
 587                 // Expand the expected maximum packet/application buffer
 588                 // sizes.
 589                 //
 590                 // Only apply to SSL/TLS protocols.
 591 
 592                 // Old behavior: shall we honor the System Property
 593                 // "jsse.SSLEngine.acceptLargeFragments" if it is "false"?
 594                 conContext.conSession.expandBufferSizes();
 595             }
 596 
 597             // check the packet again
 598             largestRecordSize = conContext.conSession.getPacketBufferSize();
 599             if (packetLen > largestRecordSize) {
 600                 throw new SSLProtocolException(
 601                         "Input record too big: max = " +
 602                         largestRecordSize + " len = " + packetLen);
 603             }
 604         }
 605 
 606         /*
 607          * Check for OVERFLOW.
 608          *
 609          * Delay enforcing the application buffer free space requirement
 610          * until after the initial handshaking.
 611          */
 612         int dstsRemains = 0;
 613         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 614             dstsRemains += dsts[i].remaining();
 615         }
 616 
 617         if (conContext.isNegotiated) {
 618             int FragLen =
 619                     conContext.inputRecord.estimateFragmentSize(packetLen);
 620             if (FragLen > dstsRemains) {
 621                 return new SSLEngineResult(
 622                         Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
 623             }
 624         }
 625 
 626         // check for UNDERFLOW.
 627         if ((packetLen == -1) || (srcsRemains < packetLen)) {
 628             return new SSLEngineResult(Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
 629         }
 630 
 631         /*
 632          * We're now ready to actually do the read.
 633          */
 634         Plaintext plainText = null;
 635         try {
 636             plainText = decode(srcs, srcsOffset, srcsLength,
 637                             dsts, dstsOffset, dstsLength);
 638         } catch (IOException ioe) {
 639             if (ioe instanceof SSLException) {
 640                 throw ioe;
 641             } else {
 642                 throw new SSLException("readRecord", ioe);
 643             }
 644         }
 645 
 646         /*
 647          * Check the various condition that we could be reporting.
 648          *
 649          * It's *possible* something might have happened between the
 650          * above and now, but it was better to minimally lock "this"
 651          * during the read process.  We'll return the current
 652          * status, which is more representative of the current state.
 653          *
 654          * status above should cover:  FINISHED, NEED_TASK
 655          */
 656         Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 657         if (plainText.handshakeStatus != null) {
 658             hsStatus = plainText.handshakeStatus;
 659         } else {
 660             hsStatus = getHandshakeStatus();
 661         }
 662 
 663         int deltaNet = srcsRemains;
 664         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 665             deltaNet -= srcs[i].remaining();
 666         }
 667 
 668         int deltaApp = dstsRemains;
 669         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 670             deltaApp -= dsts[i].remaining();
 671         }
 672 
 673         return new SSLEngineResult(
 674                 status, hsStatus, deltaNet, deltaApp, plainText.recordSN);
 675     }
 676 
 677     private Plaintext decode(
 678         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 679         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 680 
 681         Plaintext pt = SSLTransport.decode(conContext,
 682                             srcs, srcsOffset, srcsLength,
 683                             dsts, dstsOffset, dstsLength);
 684 
 685         // Is the handshake completed?
 686         if (pt != Plaintext.PLAINTEXT_NULL) {
 687             HandshakeStatus hsStatus = tryToFinishHandshake(pt.contentType);
 688             if (hsStatus == null) {
 689                 pt.handshakeStatus = conContext.getHandshakeStatus();
 690             } else {
 691                 pt.handshakeStatus = hsStatus;
 692             }
 693 
 694             // Is the sequence number is nearly overflow?
 695             if (conContext.inputRecord.seqNumIsHuge() ||
 696                     conContext.inputRecord.readCipher.atKeyLimit()) {
 697                 pt.handshakeStatus =
 698                         tryKeyUpdate(pt.handshakeStatus);
 699             }
 700         }
 701 
 702         return pt;
 703     }
 704 
 705     @Override
 706     public synchronized Runnable getDelegatedTask() {
 707         if (conContext.handshakeContext != null && // PRE or POST handshake
 708                 !conContext.handshakeContext.taskDelegated &&
 709                 !conContext.handshakeContext.delegatedActions.isEmpty()) {
 710             conContext.handshakeContext.taskDelegated = true;
 711             return new DelegatedTask(this);
 712         }
 713 
 714         return null;
 715     }
 716 
 717     @Override
 718     public synchronized void closeInbound() throws SSLException {
 719         if (isInboundDone()) {
 720             return;
 721         }
 722 
 723         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 724             SSLLogger.finest("Closing inbound of SSLEngine");
 725         }
 726 
 727         // Is it ready to close inbound?
 728         //
 729         // No need to throw exception if the initial handshake is not started.
 730         if (!conContext.isInputCloseNotified &&
 731             (conContext.isNegotiated || conContext.handshakeContext != null)) {
 732 
 733             throw conContext.fatal(Alert.INTERNAL_ERROR,
 734                     "closing inbound before receiving peer's close_notify");
 735         }
 736 
 737         conContext.closeInbound();
 738     }
 739 
 740     @Override
 741     public synchronized boolean isInboundDone() {
 742         return conContext.isInboundClosed();
 743     }
 744 
 745     @Override
 746     public synchronized void closeOutbound() {
 747         if (conContext.isOutboundClosed()) {
 748             return;
 749         }
 750 
 751         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 752             SSLLogger.finest("Closing outbound of SSLEngine");
 753         }
 754 
 755         conContext.closeOutbound();
 756     }
 757 
 758     @Override
 759     public synchronized boolean isOutboundDone() {
 760         return conContext.isOutboundDone();
 761     }
 762 
 763     @Override
 764     public String[] getSupportedCipherSuites() {
 765         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 766     }
 767 
 768     @Override
 769     public synchronized String[] getEnabledCipherSuites() {
 770         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
 771     }
 772 
 773     @Override
 774     public synchronized void setEnabledCipherSuites(String[] suites) {
 775         conContext.sslConfig.enabledCipherSuites =
 776                 CipherSuite.validValuesOf(suites);
 777     }
 778 
 779     @Override
 780     public String[] getSupportedProtocols() {
 781         return ProtocolVersion.toStringArray(
 782                 sslContext.getSupportedProtocolVersions());
 783     }
 784 
 785     @Override
 786     public synchronized String[] getEnabledProtocols() {
 787         return ProtocolVersion.toStringArray(
 788                 conContext.sslConfig.enabledProtocols);
 789     }
 790 
 791     @Override
 792     public synchronized void setEnabledProtocols(String[] protocols) {
 793         if (protocols == null) {
 794             throw new IllegalArgumentException("Protocols cannot be null");
 795         }
 796 
 797         conContext.sslConfig.enabledProtocols =
 798                 ProtocolVersion.namesOf(protocols);
 799     }
 800 
 801     @Override
 802     public synchronized SSLSession getSession() {
 803         return conContext.conSession;
 804     }
 805 
 806     @Override
 807     public synchronized SSLSession getHandshakeSession() {
 808         return conContext.handshakeContext == null ?
 809                 null : conContext.handshakeContext.handshakeSession;
 810     }
 811 
 812     @Override
 813     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
 814         return conContext.getHandshakeStatus();
 815     }
 816 
 817     @Override
 818     public synchronized void setUseClientMode(boolean mode) {
 819         conContext.setUseClientMode(mode);
 820     }
 821 
 822     @Override
 823     public synchronized boolean getUseClientMode() {
 824         return conContext.sslConfig.isClientMode;
 825     }
 826 
 827     @Override
 828     public synchronized void setNeedClientAuth(boolean need) {
 829         conContext.sslConfig.clientAuthType =
 830                 (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 831                         ClientAuthType.CLIENT_AUTH_NONE);
 832     }
 833 
 834     @Override
 835     public synchronized boolean getNeedClientAuth() {
 836         return (conContext.sslConfig.clientAuthType ==
 837                         ClientAuthType.CLIENT_AUTH_REQUIRED);
 838     }
 839 
 840     @Override
 841     public synchronized void setWantClientAuth(boolean want) {
 842         conContext.sslConfig.clientAuthType =
 843                 (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 844                         ClientAuthType.CLIENT_AUTH_NONE);
 845     }
 846 
 847     @Override
 848     public synchronized boolean getWantClientAuth() {
 849         return (conContext.sslConfig.clientAuthType ==
 850                         ClientAuthType.CLIENT_AUTH_REQUESTED);
 851     }
 852 
 853     @Override
 854     public synchronized void setEnableSessionCreation(boolean flag) {
 855         conContext.sslConfig.enableSessionCreation = flag;
 856     }
 857 
 858     @Override
 859     public synchronized boolean getEnableSessionCreation() {
 860         return conContext.sslConfig.enableSessionCreation;
 861     }
 862 
 863     @Override
 864     public synchronized SSLParameters getSSLParameters() {
 865         return conContext.sslConfig.getSSLParameters();
 866     }
 867 
 868     @Override
 869     public synchronized void setSSLParameters(SSLParameters params) {
 870         conContext.sslConfig.setSSLParameters(params);
 871 
 872         if (conContext.sslConfig.maximumPacketSize != 0) {
 873             conContext.outputRecord.changePacketSize(
 874                     conContext.sslConfig.maximumPacketSize);
 875         }
 876     }
 877 
 878     @Override
 879     public synchronized String getApplicationProtocol() {
 880         return conContext.applicationProtocol;
 881     }
 882 
 883     @Override
 884     public synchronized String getHandshakeApplicationProtocol() {
 885         return conContext.handshakeContext == null ?
 886                 null : conContext.handshakeContext.applicationProtocol;
 887     }
 888 
 889     @Override
 890     public synchronized void setHandshakeApplicationProtocolSelector(
 891             BiFunction<SSLEngine, List<String>, String> selector) {
 892         conContext.sslConfig.engineAPSelector = selector;
 893     }
 894 
 895     @Override
 896     public synchronized BiFunction<SSLEngine, List<String>, String>
 897             getHandshakeApplicationProtocolSelector() {
 898         return conContext.sslConfig.engineAPSelector;
 899     }
 900 
 901     @Override
 902     public boolean useDelegatedTask() {
 903         return true;
 904     }
 905 
 906     /*
 907      * Depending on whether the error was just a warning and the
 908      * handshaker wasn't closed, or fatal and the handshaker is now
 909      * null, report back the Exception that happened in the delegated
 910      * task(s).
 911      */
 912     private synchronized void checkTaskThrown() throws SSLException {
 913 
 914         Exception exc = null;
 915 
 916         // First check the handshake context.
 917         HandshakeContext hc = conContext.handshakeContext;
 918         if ((hc != null) && (hc.delegatedThrown != null)) {
 919             exc = hc.delegatedThrown;
 920             hc.delegatedThrown = null;
 921         }
 922 
 923         /*
 924          * hc.delegatedThrown and conContext.delegatedThrown are most likely
 925          * the same, but it's possible we could have had a non-fatal
 926          * exception and thus the new HandshakeContext is still valid
 927          * (alert warning).  If so, then we may have a secondary exception
 928          * waiting to be reported from the TransportContext, so we will
 929          * need to clear that on a successive call.  Otherwise, clear it now.
 930          */
 931         if (conContext.delegatedThrown != null) {
 932             if (exc != null) {
 933                 // hc object comparison
 934                 if (conContext.delegatedThrown == exc) {
 935                     // clear if/only if both are the same
 936                     conContext.delegatedThrown = null;
 937                 } // otherwise report the hc delegatedThrown
 938             } else {
 939                 // Nothing waiting in HandshakeContext, but one is in the
 940                 // TransportContext.
 941                 exc = conContext.delegatedThrown;
 942                 conContext.delegatedThrown = null;
 943             }
 944         }
 945 
 946         // Anything to report?
 947         if (exc == null) {
 948             return;
 949         }
 950 
 951         // If it wasn't a RuntimeException/SSLException, need to wrap it.
 952         if (exc instanceof SSLException) {
 953             throw (SSLException)exc;
 954         } else if (exc instanceof RuntimeException) {
 955             throw (RuntimeException)exc;
 956         } else {
 957             throw getTaskThrown(exc);
 958         }
 959     }
 960 
 961     private static SSLException getTaskThrown(Exception taskThrown) {
 962         String msg = taskThrown.getMessage();
 963 
 964         if (msg == null) {
 965             msg = "Delegated task threw Exception or Error";
 966         }
 967 
 968         if (taskThrown instanceof RuntimeException) {
 969             throw new RuntimeException(msg, taskThrown);
 970         } else if (taskThrown instanceof SSLHandshakeException) {
 971             return (SSLHandshakeException)
 972                 new SSLHandshakeException(msg).initCause(taskThrown);
 973         } else if (taskThrown instanceof SSLKeyException) {
 974             return (SSLKeyException)
 975                 new SSLKeyException(msg).initCause(taskThrown);
 976         } else if (taskThrown instanceof SSLPeerUnverifiedException) {
 977             return (SSLPeerUnverifiedException)
 978                 new SSLPeerUnverifiedException(msg).initCause(taskThrown);
 979         } else if (taskThrown instanceof SSLProtocolException) {
 980             return (SSLProtocolException)
 981                 new SSLProtocolException(msg).initCause(taskThrown);
 982         } else if (taskThrown instanceof SSLException) {
 983             return (SSLException)taskThrown;
 984         } else {
 985             return new SSLException(msg, taskThrown);
 986         }
 987     }
 988 
 989     /**
 990      * Implement a simple task delegator.
 991      */
 992     private static class DelegatedTask implements Runnable {
 993         private final SSLEngineImpl engine;
 994 
 995         DelegatedTask(SSLEngineImpl engineInstance) {
 996             this.engine = engineInstance;
 997         }
 998 
 999         @Override
1000         public void run() {
1001             synchronized (engine) {
1002                 HandshakeContext hc = engine.conContext.handshakeContext;
1003                 if (hc == null || hc.delegatedActions.isEmpty()) {
1004                     return;
1005                 }
1006 
1007                 try {
1008                     AccessController.doPrivileged(
1009                             new DelegatedAction(hc), engine.conContext.acc);
1010                 } catch (PrivilegedActionException pae) {
1011                     // Get the handshake context again in case the
1012                     // handshaking has completed.
1013                     Exception reportedException = pae.getException();
1014 
1015                     // Report to both the TransportContext...
1016                     if (engine.conContext.delegatedThrown == null) {
1017                         engine.conContext.delegatedThrown = reportedException;
1018                     }
1019 
1020                     // ...and the HandshakeContext in case condition
1021                     // wasn't fatal and the handshakeContext is still
1022                     // around.
1023                     hc = engine.conContext.handshakeContext;
1024                     if (hc != null) {
1025                         hc.delegatedThrown = reportedException;
1026                     } else if (engine.conContext.closeReason != null) {
1027                         // Update the reason in case there was a previous.
1028                         engine.conContext.closeReason =
1029                                 getTaskThrown(reportedException);
1030                     }
1031                 } catch (RuntimeException rte) {
1032                     // Get the handshake context again in case the
1033                     // handshaking has completed.
1034 
1035                     // Report to both the TransportContext...
1036                     if (engine.conContext.delegatedThrown == null) {
1037                         engine.conContext.delegatedThrown = rte;
1038                     }
1039 
1040                     // ...and the HandshakeContext in case condition
1041                     // wasn't fatal and the handshakeContext is still
1042                     // around.
1043                     hc = engine.conContext.handshakeContext;
1044                     if (hc != null) {
1045                         hc.delegatedThrown = rte;
1046                     } else if (engine.conContext.closeReason != null) {
1047                         // Update the reason in case there was a previous.
1048                         engine.conContext.closeReason = rte;
1049                     }
1050                 }
1051 
1052                 // Get the handshake context again in case the
1053                 // handshaking has completed.
1054                 hc = engine.conContext.handshakeContext;
1055                 if (hc != null) {
1056                     hc.taskDelegated = false;
1057                 }
1058             }
1059         }
1060 
1061         private static class DelegatedAction
1062                 implements PrivilegedExceptionAction<Void> {
1063             final HandshakeContext context;
1064             DelegatedAction(HandshakeContext context) {
1065                 this.context = context;
1066             }
1067 
1068             @Override
1069             public Void run() throws Exception {
1070                 while (!context.delegatedActions.isEmpty()) {
1071                     Map.Entry<Byte, ByteBuffer> me =
1072                             context.delegatedActions.poll();
1073                     if (me != null) {
1074                         context.dispatch(me.getKey(), me.getValue());
1075                     }
1076                 }
1077                 return null;
1078             }
1079         }
1080     }
1081 }