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             conContext.fatal(Alert.HANDSHAKE_FAILURE,
 106                 "Couldn't kickstart handshaking", ioe);
 107         } catch (Exception ex) {     // including RuntimeException
 108             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(
 117                 appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
 118     }
 119 
 120     // @Override
 121     public synchronized SSLEngineResult wrap(
 122         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 123         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 124 
 125         if (conContext.isUnsureMode) {
 126             throw new IllegalStateException(
 127                     "Client/Server mode has not yet been set.");
 128         }
 129 
 130         // See if the handshaker needs to report back some SSLException.
 131         if (conContext.outputRecord.isEmpty()) {
 132             checkTaskThrown();
 133         }   // Otherwise, deliver cached records before throwing task exception.
 134 
 135         // check parameters
 136         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 137 
 138         try {
 139             return writeRecord(
 140                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 141         } catch (SSLProtocolException spe) {
 142             // may be an unexpected handshake message
 143             conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
 144         } catch (IOException ioe) {
 145             conContext.fatal(Alert.INTERNAL_ERROR,
 146                 "problem wrapping app data", ioe);
 147         } catch (Exception ex) {     // including RuntimeException
 148             conContext.fatal(Alert.INTERNAL_ERROR,
 149                 "Fail to wrap application data", ex);
 150         }
 151 
 152         return null;    // make compiler happy
 153     }
 154 
 155     private SSLEngineResult writeRecord(
 156         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 157         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 158 
 159         if (isOutboundDone()) {
 160             return new SSLEngineResult(
 161                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 162         }
 163 
 164         HandshakeContext hc = conContext.handshakeContext;
 165         HandshakeStatus hsStatus = null;
 166         if (!conContext.isNegotiated) {
 167             conContext.kickstart();
 168 
 169             hsStatus = getHandshakeStatus();
 170             if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
 171                 /*
 172                  * For DTLS, if the handshake state is
 173                  * HandshakeStatus.NEED_UNWRAP, a call to SSLEngine.wrap()
 174                  * means that the previous handshake packets (if delivered)
 175                  * get lost, and need retransmit the handshake messages.
 176                  */
 177                 if (!sslContext.isDTLS() || hc == null ||
 178                         !hc.sslConfig.enableRetransmissions ||
 179                         conContext.outputRecord.firstMessage) {
 180 
 181                     return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 182                 }   // otherwise, need retransmission
 183             }
 184         }
 185 
 186         if (hsStatus == null) {
 187             hsStatus = getHandshakeStatus();
 188         }
 189 
 190         /*
 191          * If we have a task outstanding, this *MUST* be done before
 192          * doing any more wrapping, because we could be in the middle
 193          * of receiving a handshake message, for example, a finished
 194          * message which would change the ciphers.
 195          */
 196         if (hsStatus == HandshakeStatus.NEED_TASK) {
 197             return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 198         }
 199 
 200         int dstsRemains = 0;
 201         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 202             dstsRemains += dsts[i].remaining();
 203         }
 204 
 205         // Check destination buffer size.
 206         //
 207         // We can be smarter about using smaller buffer sizes later.  For
 208         // now, force it to be large enough to handle any valid record.
 209         if (dstsRemains < conContext.conSession.getPacketBufferSize()) {
 210             return new SSLEngineResult(
 211                 Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
 212         }
 213 
 214         int srcsRemains = 0;
 215         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 216             srcsRemains += srcs[i].remaining();
 217         }
 218 
 219         Ciphertext ciphertext = null;
 220         try {
 221             // Acquire the buffered to-be-delivered records or retransmissions.
 222             //
 223             // May have buffered records, or need retransmission if handshaking.
 224             if (!conContext.outputRecord.isEmpty() || (hc != null &&
 225                     hc.sslConfig.enableRetransmissions &&
 226                     hc.sslContext.isDTLS() &&
 227                     hsStatus == HandshakeStatus.NEED_UNWRAP)) {
 228                 ciphertext = encode(null, 0, 0,
 229                         dsts, dstsOffset, dstsLength);
 230             }
 231 
 232             if (ciphertext == null && srcsRemains != 0) {
 233                 ciphertext = encode(srcs, srcsOffset, srcsLength,
 234                         dsts, dstsOffset, dstsLength);
 235             }
 236         } catch (IOException ioe) {
 237             if (ioe instanceof SSLException) {
 238                 throw ioe;
 239             } else {
 240                 throw new SSLException("Write problems", ioe);
 241             }
 242         }
 243 
 244         /*
 245          * Check for status.
 246          */
 247         Status status = (isOutboundDone() ? Status.CLOSED : Status.OK);
 248         if (ciphertext != null && ciphertext.handshakeStatus != null) {
 249             hsStatus = ciphertext.handshakeStatus;
 250         } else {
 251             hsStatus = getHandshakeStatus();
 252         }
 253 
 254         int deltaSrcs = srcsRemains;
 255         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 256             deltaSrcs -= srcs[i].remaining();
 257         }
 258 
 259         int deltaDsts = dstsRemains;
 260         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 261             deltaDsts -= dsts[i].remaining();
 262         }
 263 
 264         return new SSLEngineResult(status, hsStatus, deltaSrcs, deltaDsts,
 265                 ciphertext != null ? ciphertext.recordSN : -1L);
 266     }
 267 
 268     private Ciphertext encode(
 269         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 270         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 271 
 272         Ciphertext ciphertext = null;
 273         try {
 274             ciphertext = conContext.outputRecord.encode(
 275                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 276         } catch (SSLHandshakeException she) {
 277             // may be record sequence number overflow
 278             conContext.fatal(Alert.HANDSHAKE_FAILURE, she);
 279         } catch (IOException e) {
 280             conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
 281         }
 282 
 283         if (ciphertext == null) {
 284             return Ciphertext.CIPHERTEXT_NULL;
 285         }
 286 
 287         // Is the handshake completed?
 288         boolean needRetransmission =
 289                 conContext.sslContext.isDTLS() &&
 290                 conContext.handshakeContext != null &&
 291                 conContext.handshakeContext.sslConfig.enableRetransmissions;
 292         HandshakeStatus hsStatus =
 293                 tryToFinishHandshake(ciphertext.contentType);
 294         if (needRetransmission &&
 295                 hsStatus == HandshakeStatus.FINISHED &&
 296                 conContext.sslContext.isDTLS() &&
 297                 ciphertext.handshakeType == SSLHandshake.FINISHED.id) {
 298             // Retransmit the last flight for DTLS.
 299             //
 300             // The application data transactions may begin immediately
 301             // after the last flight.  If the last flight get lost, the
 302             // application data may be discarded accordingly.  As could
 303             // be an issue for some applications.  This impact can be
 304             // mitigated by sending the last fligth twice.
 305             if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 306                 SSLLogger.finest("retransmit the last flight messages");
 307             }
 308 
 309             conContext.outputRecord.launchRetransmission();
 310             hsStatus = HandshakeStatus.NEED_WRAP;
 311         }
 312 
 313         if (hsStatus == null) {
 314             hsStatus = conContext.getHandshakeStatus();
 315         }
 316 
 317         // Is the sequence number is nearly overflow?
 318         if (conContext.outputRecord.seqNumIsHuge()) {
 319             hsStatus = tryKeyUpdate(hsStatus);
 320         }
 321 
 322         // update context status
 323         ciphertext.handshakeStatus = hsStatus;
 324 
 325         return ciphertext;
 326     }
 327 
 328     private HandshakeStatus tryToFinishHandshake(byte contentType) {
 329         HandshakeStatus hsStatus = null;
 330         if ((contentType == ContentType.HANDSHAKE.id) &&
 331                 conContext.outputRecord.isEmpty()) {
 332             if (conContext.handshakeContext == null) {
 333                 hsStatus = HandshakeStatus.FINISHED;
 334             } else if (conContext.handshakeContext.handshakeFinished) {
 335                 hsStatus = conContext.finishHandshake();
 336             }
 337         }   // Otherwise, the followed call to getHSStatus() will help.
 338 
 339         return hsStatus;
 340     }
 341 
 342     /**
 343      * Try renegotiation or key update for sequence number wrap.
 344      *
 345      * Note that in order to maintain the handshake status properly, we check
 346      * the sequence number after the last record reading/writing process.  As
 347      * we request renegotiation or close the connection for wrapped sequence
 348      * number when there is enough sequence number space left to handle a few
 349      * more records, so the sequence number of the last record cannot be
 350      * wrapped.
 351      */
 352     private HandshakeStatus tryKeyUpdate(
 353             HandshakeStatus currentHandshakeStatus) throws IOException {
 354         // Don't bother to kickstart the renegotiation or key update when the
 355         // local is asking for it.
 356         if ((conContext.handshakeContext == null) &&
 357                 !conContext.isClosed() && !conContext.isBroken) {
 358             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 359                 SSLLogger.finest("key update to wrap sequence number");
 360             }
 361             conContext.keyUpdate();
 362             return conContext.getHandshakeStatus();
 363         }
 364 
 365         return currentHandshakeStatus;
 366     }
 367 
 368     private static void checkParams(
 369             ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 370             ByteBuffer[] dsts, int dstsOffset, int dstsLength) {
 371 
 372         if ((srcs == null) || (dsts == null)) {
 373             throw new IllegalArgumentException(
 374                     "source or destination buffer is null");
 375         }
 376 
 377         if ((srcsOffset < 0) || (srcsLength < 0) ||
 378                 (srcsOffset > srcs.length - srcsLength)) {
 379             throw new IndexOutOfBoundsException(
 380                     "index out of bound of the source buffers");
 381         }
 382 
 383         if ((dstsOffset < 0) || (dstsLength < 0) ||
 384                 (dstsOffset > dsts.length - dstsLength)) {
 385             throw new IndexOutOfBoundsException(
 386                     "index out of bound of the destination buffers");
 387         }
 388 
 389         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 390             if (srcs[i] == null) {
 391                 throw new IllegalArgumentException(
 392                         "source buffer[" + i + "] == null");
 393             }
 394         }
 395 
 396         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 397             if (dsts[i] == null) {
 398                 throw new IllegalArgumentException(
 399                         "destination buffer[" + i + "] == null");
 400             }
 401 
 402             /*
 403              * Make sure the destination bufffers are writable.
 404              */
 405             if (dsts[i].isReadOnly()) {
 406                 throw new ReadOnlyBufferException();
 407             }
 408         }
 409     }
 410 
 411     @Override
 412     public synchronized SSLEngineResult unwrap(ByteBuffer src,
 413             ByteBuffer[] dsts, int offset, int length) throws SSLException {
 414         return unwrap(
 415                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
 416     }
 417 
 418     // @Override
 419     public synchronized SSLEngineResult unwrap(
 420         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 421         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 422 
 423         if (conContext.isUnsureMode) {
 424             throw new IllegalStateException(
 425                     "Client/Server mode has not yet been set.");
 426         }
 427 
 428         // See if the handshaker needs to report back some SSLException.
 429         checkTaskThrown();
 430 
 431         // check parameters
 432         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 433 
 434         try {
 435             return readRecord(
 436                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 437         } catch (SSLProtocolException spe) {
 438             // may be an unexpected handshake message
 439             conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 440                     spe.getMessage(), spe);
 441         } catch (IOException ioe) {
 442             /*
 443              * Don't reset position so it looks like we didn't
 444              * consume anything.  We did consume something, and it
 445              * got us into this situation, so report that much back.
 446              * Our days of consuming are now over anyway.
 447              */
 448             conContext.fatal(Alert.INTERNAL_ERROR,
 449                     "problem unwrapping net record", ioe);
 450         } catch (Exception ex) {     // including RuntimeException
 451             conContext.fatal(Alert.INTERNAL_ERROR,
 452                 "Fail to unwrap network record", ex);
 453         }
 454 
 455         return null;    // make compiler happy
 456     }
 457 
 458     private SSLEngineResult readRecord(
 459         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 460         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 461 
 462         /*
 463          * Check if we are closing/closed.
 464          */
 465         if (isInboundDone()) {
 466             return new SSLEngineResult(
 467                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 468         }
 469 
 470         HandshakeStatus hsStatus = null;
 471         if (!conContext.isNegotiated) {
 472             conContext.kickstart();
 473 
 474             /*
 475              * If there's still outbound data to flush, we
 476              * can return without trying to unwrap anything.
 477              */
 478             hsStatus = getHandshakeStatus();
 479             if (hsStatus == HandshakeStatus.NEED_WRAP) {
 480                 return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 481             }
 482         }
 483 
 484         if (hsStatus == null) {
 485             hsStatus = getHandshakeStatus();
 486         }
 487 
 488         /*
 489          * If we have a task outstanding, this *MUST* be done before
 490          * doing any more unwrapping, because we could be in the middle
 491          * of receiving a handshake message, for example, a finished
 492          * message which would change the ciphers.
 493          */
 494         if (hsStatus == HandshakeStatus.NEED_TASK) {
 495             return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 496         }
 497 
 498         if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
 499             Plaintext plainText = null;
 500             try {
 501                 plainText = decode(null, 0, 0,
 502                         dsts, dstsOffset, dstsLength);
 503             } catch (IOException ioe) {
 504                 if (ioe instanceof SSLException) {
 505                     throw ioe;
 506                 } else {
 507                     throw new SSLException("readRecord", ioe);
 508                 }
 509             }
 510 
 511             Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 512             if (plainText.handshakeStatus != null) {
 513                 hsStatus = plainText.handshakeStatus;
 514             } else {
 515                 hsStatus = getHandshakeStatus();
 516             }
 517 
 518             return new SSLEngineResult(
 519                     status, hsStatus, 0, 0, plainText.recordSN);
 520         }
 521 
 522         int srcsRemains = 0;
 523         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 524             srcsRemains += srcs[i].remaining();
 525         }
 526 
 527         if (srcsRemains == 0) {
 528             return new SSLEngineResult(Status.OK, getHandshakeStatus(), 0, 0);
 529         }
 530 
 531         /*
 532          * Check the packet to make sure enough is here.
 533          * This will also indirectly check for 0 len packets.
 534          */
 535         int packetLen = 0;
 536         try {
 537             packetLen = conContext.inputRecord.bytesInCompletePacket(
 538                     srcs, srcsOffset, srcsLength);
 539         } catch (SSLException ssle) {
 540             // Need to discard invalid records for DTLS protocols.
 541             if (sslContext.isDTLS()) {
 542                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 543                     SSLLogger.finest("Discard invalid DTLS records", ssle);
 544                 }
 545 
 546                 // invalid, discard the entire data [section 4.1.2.7, RFC 6347]
 547                 // TODO
 548                 int deltaNet = 0;
 549                 // int deltaNet = netData.remaining();
 550                 // netData.position(netData.limit());
 551 
 552                 Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 553                 if (hsStatus == null) {
 554                     hsStatus = getHandshakeStatus();
 555                 }
 556 
 557                 return new SSLEngineResult(status, hsStatus, deltaNet, 0, -1L);
 558             } else {
 559                 throw ssle;
 560             }
 561         }
 562 
 563         // Is this packet bigger than SSL/TLS normally allows?
 564         if (packetLen > conContext.conSession.getPacketBufferSize()) {
 565             int largestRecordSize = sslContext.isDTLS() ?
 566                     DTLSRecord.maxRecordSize : SSLRecord.maxLargeRecordSize;
 567             if ((packetLen <= largestRecordSize) && !sslContext.isDTLS()) {
 568                 // Expand the expected maximum packet/application buffer
 569                 // sizes.
 570                 //
 571                 // Only apply to SSL/TLS protocols.
 572 
 573                 // Old behavior: shall we honor the System Property
 574                 // "jsse.SSLEngine.acceptLargeFragments" if it is "false"?
 575                 conContext.conSession.expandBufferSizes();
 576             }
 577 
 578             // check the packet again
 579             largestRecordSize = conContext.conSession.getPacketBufferSize();
 580             if (packetLen > largestRecordSize) {
 581                 throw new SSLProtocolException(
 582                         "Input record too big: max = " +
 583                         largestRecordSize + " len = " + packetLen);
 584             }
 585         }
 586 
 587         /*
 588          * Check for OVERFLOW.
 589          *
 590          * Delay enforcing the application buffer free space requirement
 591          * until after the initial handshaking.
 592          */
 593         int dstsRemains = 0;
 594         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 595             dstsRemains += dsts[i].remaining();
 596         }
 597 
 598         if (conContext.isNegotiated) {
 599             int FragLen =
 600                     conContext.inputRecord.estimateFragmentSize(packetLen);
 601             if (FragLen > dstsRemains) {
 602                 return new SSLEngineResult(
 603                         Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
 604             }
 605         }
 606 
 607         // check for UNDERFLOW.
 608         if ((packetLen == -1) || (srcsRemains < packetLen)) {
 609             return new SSLEngineResult(Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
 610         }
 611 
 612         /*
 613          * We're now ready to actually do the read.
 614          */
 615         Plaintext plainText = null;
 616         try {
 617             plainText = decode(srcs, srcsOffset, srcsLength,
 618                             dsts, dstsOffset, dstsLength);
 619         } catch (IOException ioe) {
 620             if (ioe instanceof SSLException) {
 621                 throw ioe;
 622             } else {
 623                 throw new SSLException("readRecord", ioe);
 624             }
 625         }
 626 
 627         /*
 628          * Check the various condition that we could be reporting.
 629          *
 630          * It's *possible* something might have happened between the
 631          * above and now, but it was better to minimally lock "this"
 632          * during the read process.  We'll return the current
 633          * status, which is more representative of the current state.
 634          *
 635          * status above should cover:  FINISHED, NEED_TASK
 636          */
 637         Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 638         if (plainText.handshakeStatus != null) {
 639             hsStatus = plainText.handshakeStatus;
 640         } else {
 641             hsStatus = getHandshakeStatus();
 642         }
 643 
 644         int deltaNet = srcsRemains;
 645         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 646             deltaNet -= srcs[i].remaining();
 647         }
 648 
 649         int deltaApp = dstsRemains;
 650         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 651             deltaApp -= dsts[i].remaining();
 652         }
 653 
 654         return new SSLEngineResult(
 655                 status, hsStatus, deltaNet, deltaApp, plainText.recordSN);
 656     }
 657 
 658     private Plaintext decode(
 659         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 660         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 661 
 662         Plaintext pt = SSLTransport.decode(conContext,
 663                             srcs, srcsOffset, srcsLength,
 664                             dsts, dstsOffset, dstsLength);
 665 
 666         // Is the handshake completed?
 667         if (pt != Plaintext.PLAINTEXT_NULL) {
 668             HandshakeStatus hsStatus = tryToFinishHandshake(pt.contentType);
 669             if (hsStatus == null) {
 670                 pt.handshakeStatus = conContext.getHandshakeStatus();
 671             } else {
 672                 pt.handshakeStatus = hsStatus;
 673             }
 674 
 675             // Is the sequence number is nearly overflow?
 676             if (conContext.inputRecord.seqNumIsHuge()) {
 677                 pt.handshakeStatus =
 678                         tryKeyUpdate(pt.handshakeStatus);
 679             }
 680         }
 681 
 682         return pt;
 683     }
 684 
 685     @Override
 686     public synchronized Runnable getDelegatedTask() {
 687         if (conContext.handshakeContext != null &&
 688                 !conContext.handshakeContext.taskDelegated &&
 689                 !conContext.handshakeContext.delegatedActions.isEmpty()) {
 690             conContext.handshakeContext.taskDelegated = true;
 691             return new DelegatedTask(this);
 692         }
 693 
 694         return null;
 695     }
 696 
 697     @Override
 698     public synchronized void closeInbound() throws SSLException {
 699         conContext.closeInbound();
 700     }
 701 
 702     @Override
 703     public synchronized boolean isInboundDone() {
 704         return conContext.isInboundDone();
 705     }
 706 
 707     @Override
 708     public synchronized void closeOutbound() {
 709         conContext.closeOutbound();
 710     }
 711 
 712     @Override
 713     public synchronized boolean isOutboundDone() {
 714         return conContext.isOutboundDone();
 715     }
 716 
 717     @Override
 718     public String[] getSupportedCipherSuites() {
 719         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 720     }
 721 
 722     @Override
 723     public synchronized String[] getEnabledCipherSuites() {
 724         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
 725     }
 726 
 727     @Override
 728     public synchronized void setEnabledCipherSuites(String[] suites) {
 729         if (suites == null) {
 730             throw new IllegalArgumentException("CipherSuites cannot be null");
 731         }
 732 
 733         conContext.sslConfig.enabledCipherSuites =
 734                 CipherSuite.validValuesOf(suites);
 735     }
 736 
 737     @Override
 738     public String[] getSupportedProtocols() {
 739         return ProtocolVersion.toStringArray(
 740                 sslContext.getSuportedProtocolVersions());
 741     }
 742 
 743     @Override
 744     public synchronized String[] getEnabledProtocols() {
 745         return ProtocolVersion.toStringArray(
 746                 conContext.sslConfig.enabledProtocols);
 747     }
 748 
 749     @Override
 750     public synchronized void setEnabledProtocols(String[] protocols) {
 751         if (protocols == null) {
 752             throw new IllegalArgumentException("Protocols cannot be null");
 753         }
 754 
 755         conContext.sslConfig.enabledProtocols =
 756                 ProtocolVersion.namesOf(protocols);
 757     }
 758 
 759     @Override
 760     public synchronized SSLSession getSession() {
 761         return conContext.conSession;
 762     }
 763 
 764     @Override
 765     public synchronized SSLSession getHandshakeSession() {
 766         return conContext.handshakeContext == null ?
 767                 null : conContext.handshakeContext.handshakeSession;
 768     }
 769 
 770     @Override
 771     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
 772         return conContext.getHandshakeStatus();
 773     }
 774 
 775     @Override
 776     public synchronized void setUseClientMode(boolean mode) {
 777         conContext.setUseClientMode(mode);
 778     }
 779 
 780     @Override
 781     public synchronized boolean getUseClientMode() {
 782         return conContext.sslConfig.isClientMode;
 783     }
 784 
 785     @Override
 786     public synchronized void setNeedClientAuth(boolean need) {
 787         conContext.sslConfig.clientAuthType =
 788                 (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 789                         ClientAuthType.CLIENT_AUTH_NONE);
 790     }
 791 
 792     @Override
 793     public synchronized boolean getNeedClientAuth() {
 794         return (conContext.sslConfig.clientAuthType ==
 795                         ClientAuthType.CLIENT_AUTH_REQUIRED);
 796     }
 797 
 798     @Override
 799     public synchronized void setWantClientAuth(boolean want) {
 800         conContext.sslConfig.clientAuthType =
 801                 (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 802                         ClientAuthType.CLIENT_AUTH_NONE);
 803     }
 804 
 805     @Override
 806     public synchronized boolean getWantClientAuth() {
 807         return (conContext.sslConfig.clientAuthType ==
 808                         ClientAuthType.CLIENT_AUTH_REQUESTED);
 809     }
 810 
 811     @Override
 812     public synchronized void setEnableSessionCreation(boolean flag) {
 813         conContext.sslConfig.enableSessionCreation = flag;
 814     }
 815 
 816     @Override
 817     public synchronized boolean getEnableSessionCreation() {
 818         return conContext.sslConfig.enableSessionCreation;
 819     }
 820 
 821     @Override
 822     public synchronized SSLParameters getSSLParameters() {
 823         return conContext.sslConfig.getSSLParameters();
 824     }
 825 
 826     @Override
 827     public synchronized void setSSLParameters(SSLParameters params) {
 828         conContext.sslConfig.setSSLParameters(params);
 829 
 830         if (conContext.sslConfig.maximumPacketSize != 0) {
 831             conContext.outputRecord.changePacketSize(
 832                     conContext.sslConfig.maximumPacketSize);
 833         }
 834     }
 835 
 836     @Override
 837     public synchronized String getApplicationProtocol() {
 838         return conContext.applicationProtocol;
 839     }
 840 
 841     @Override
 842     public synchronized String getHandshakeApplicationProtocol() {
 843         return conContext.handshakeContext == null ?
 844                 null : conContext.handshakeContext.applicationProtocol;
 845     }
 846 
 847     @Override
 848     public synchronized void setHandshakeApplicationProtocolSelector(
 849             BiFunction<SSLEngine, List<String>, String> selector) {
 850         conContext.sslConfig.engineAPSelector = selector;
 851     }
 852 
 853     @Override
 854     public synchronized BiFunction<SSLEngine, List<String>, String>
 855             getHandshakeApplicationProtocolSelector() {
 856         return conContext.sslConfig.engineAPSelector;
 857     }
 858 
 859     @Override
 860     public boolean useDelegatedTask() {
 861         return true;
 862     }
 863 
 864     private synchronized void checkTaskThrown() throws SSLException {
 865         HandshakeContext hc = conContext.handshakeContext;
 866         if (hc != null && hc.delegatedThrown != null) {
 867             try {
 868                 throw getTaskThrown(hc.delegatedThrown);
 869             } finally {
 870                 hc.delegatedThrown = null;
 871             }
 872         }
 873 
 874         if (conContext.isBroken && conContext.closeReason != null) {
 875             throw getTaskThrown(conContext.closeReason);
 876         }
 877     }
 878 
 879     private static SSLException getTaskThrown(Exception taskThrown) {
 880         String msg = taskThrown.getMessage();
 881 
 882         if (msg == null) {
 883             msg = "Delegated task threw Exception or Error";
 884         }
 885 
 886         if (taskThrown instanceof RuntimeException) {
 887             throw new RuntimeException(msg, taskThrown);
 888         } else if (taskThrown instanceof SSLHandshakeException) {
 889             return (SSLHandshakeException)
 890                 new SSLHandshakeException(msg).initCause(taskThrown);
 891         } else if (taskThrown instanceof SSLKeyException) {
 892             return (SSLKeyException)
 893                 new SSLKeyException(msg).initCause(taskThrown);
 894         } else if (taskThrown instanceof SSLPeerUnverifiedException) {
 895             return (SSLPeerUnverifiedException)
 896                 new SSLPeerUnverifiedException(msg).initCause(taskThrown);
 897         } else if (taskThrown instanceof SSLProtocolException) {
 898             return (SSLProtocolException)
 899                 new SSLProtocolException(msg).initCause(taskThrown);
 900         } else if (taskThrown instanceof SSLException) {
 901             return (SSLException)taskThrown;
 902         } else {
 903             return new SSLException(msg, taskThrown);
 904         }
 905     }
 906 
 907     /**
 908      * Implement a simple task delegator.
 909      */
 910     private static class DelegatedTask implements Runnable {
 911         private final SSLEngineImpl engine;
 912 
 913         DelegatedTask(SSLEngineImpl engineInstance) {
 914             this.engine = engineInstance;
 915         }
 916 
 917         @Override
 918         public void run() {
 919             synchronized (engine) {
 920                 HandshakeContext hc = engine.conContext.handshakeContext;
 921                 if (hc == null || hc.delegatedActions.isEmpty()) {
 922                     return;
 923                 }
 924 
 925                 try {
 926                     AccessController.doPrivileged(
 927                             new DelegatedAction(hc), engine.conContext.acc);
 928                 } catch (PrivilegedActionException pae) {
 929                     // Get the handshake context again in case the
 930                     // handshaking has completed.
 931                     hc = engine.conContext.handshakeContext;
 932                     if (hc != null) {
 933                         hc.delegatedThrown = pae.getException();
 934                     } else if (engine.conContext.closeReason != null) {
 935                         engine.conContext.closeReason =
 936                                 getTaskThrown(pae.getException());
 937                     }
 938                 } catch (RuntimeException rte) {
 939                     // Get the handshake context again in case the
 940                     // handshaking has completed.
 941                     hc = engine.conContext.handshakeContext;
 942                     if (hc != null) {
 943                         hc.delegatedThrown = rte;
 944                     } else if (engine.conContext.closeReason != null) {
 945                         engine.conContext.closeReason = rte;
 946                     }
 947                 }
 948 
 949                 // Get the handshake context again in case the
 950                 // handshaking has completed.
 951                 hc = engine.conContext.handshakeContext;
 952                 if (hc != null) {
 953                     hc.taskDelegated = false;
 954                 }
 955             }
 956         }
 957 
 958         private static class DelegatedAction
 959                 implements PrivilegedExceptionAction<Void> {
 960             final HandshakeContext context;
 961             DelegatedAction(HandshakeContext context) {
 962                 this.context = context;
 963             }
 964 
 965             @Override
 966             public Void run() throws Exception {
 967                 while (!context.delegatedActions.isEmpty()) {
 968                     // Report back the task SSLException
 969                     if (context.delegatedThrown != null) {
 970                         Exception delegatedThrown = context.delegatedThrown;
 971                         context.delegatedThrown = null;
 972                         throw getTaskThrown(delegatedThrown);
 973                     }
 974 
 975                     Map.Entry<Byte, ByteBuffer> me =
 976                             context.delegatedActions.poll();
 977                     if (me != null) {
 978                         context.dispatch(me.getKey(), me.getValue());
 979                     }
 980                 }
 981                 return null;
 982             }
 983         }
 984     }
 985 }