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         }
 251 
 252         int deltaSrcs = srcsRemains;
 253         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 254             deltaSrcs -= srcs[i].remaining();
 255         }
 256 
 257         int deltaDsts = dstsRemains;
 258         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 259             deltaDsts -= dsts[i].remaining();
 260         }
 261 
 262         return new SSLEngineResult(status, hsStatus, deltaSrcs, deltaDsts,
 263                 ciphertext != null ? ciphertext.recordSN : -1L);
 264     }
 265 
 266     private Ciphertext encode(
 267         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 268         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 269 
 270         Ciphertext ciphertext = null;
 271         try {
 272             ciphertext = conContext.outputRecord.encode(
 273                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 274         } catch (SSLHandshakeException she) {
 275             // may be record sequence number overflow
 276             throw conContext.fatal(Alert.HANDSHAKE_FAILURE, she);
 277         } catch (IOException e) {
 278             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
 279         }
 280 
 281         if (ciphertext == null) {
 282             return Ciphertext.CIPHERTEXT_NULL;
 283         }
 284 
 285         // Is the handshake completed?
 286         boolean needRetransmission =
 287                 conContext.sslContext.isDTLS() &&
 288                 conContext.handshakeContext != null &&
 289                 conContext.handshakeContext.sslConfig.enableRetransmissions;
 290         HandshakeStatus hsStatus =
 291                 tryToFinishHandshake(ciphertext.contentType);
 292         if (needRetransmission &&
 293                 hsStatus == HandshakeStatus.FINISHED &&
 294                 conContext.sslContext.isDTLS() &&
 295                 ciphertext.handshakeType == SSLHandshake.FINISHED.id) {
 296             // Retransmit the last flight for DTLS.
 297             //
 298             // The application data transactions may begin immediately
 299             // after the last flight.  If the last flight get lost, the
 300             // application data may be discarded accordingly.  As could
 301             // be an issue for some applications.  This impact can be
 302             // mitigated by sending the last fligth twice.
 303             if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 304                 SSLLogger.finest("retransmit the last flight messages");
 305             }
 306 
 307             conContext.outputRecord.launchRetransmission();
 308             hsStatus = HandshakeStatus.NEED_WRAP;
 309         }
 310 
 311         if (hsStatus == null) {
 312             hsStatus = conContext.getHandshakeStatus();
 313         }
 314 
 315         // Is the sequence number is nearly overflow?
 316         if (conContext.outputRecord.seqNumIsHuge() ||
 317                 conContext.outputRecord.writeCipher.atKeyLimit()) {
 318             hsStatus = tryKeyUpdate(hsStatus);
 319         }
 320 
 321         // update context status
 322         ciphertext.handshakeStatus = hsStatus;
 323 
 324         return ciphertext;
 325     }
 326 
 327     private HandshakeStatus tryToFinishHandshake(byte contentType) {
 328         HandshakeStatus hsStatus = null;
 329         if ((contentType == ContentType.HANDSHAKE.id) &&
 330                 conContext.outputRecord.isEmpty()) {
 331             if (conContext.handshakeContext == null) {
 332                 hsStatus = HandshakeStatus.FINISHED;
 333             } else if (conContext.isPostHandshakeContext()) {
 334                 // unlikely, but just in case.
 335                 hsStatus = conContext.finishPostHandshake();
 336             } else if (conContext.handshakeContext.handshakeFinished) {
 337                 hsStatus = conContext.finishHandshake();
 338             }
 339         }   // Otherwise, the followed call to getHSStatus() will help.
 340 
 341         return hsStatus;
 342     }
 343 
 344     /**
 345      * Try key update for sequence number wrap or key usage limit.
 346      *
 347      * Note that in order to maintain the handshake status properly, we check
 348      * the sequence number and key usage limit after the last record
 349      * reading/writing process.
 350      *
 351      * As we request renegotiation or close the connection for wrapped sequence
 352      * number when there is enough sequence number space left to handle a few
 353      * more records, so the sequence number of the last record cannot be
 354      * wrapped.
 355      */
 356     private HandshakeStatus tryKeyUpdate(
 357             HandshakeStatus currentHandshakeStatus) throws IOException {
 358         // Don't bother to kickstart if handshaking is in progress, or if the
 359         // connection is not duplex-open.
 360         if ((conContext.handshakeContext == null) &&
 361                 !conContext.isOutboundClosed() &&
 362                 !conContext.isInboundClosed() &&
 363                 !conContext.isBroken) {
 364             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 365                 SSLLogger.finest("trigger key update");
 366             }
 367             beginHandshake();
 368             return conContext.getHandshakeStatus();
 369         }
 370 
 371         return currentHandshakeStatus;
 372     }
 373 
 374     private static void checkParams(
 375             ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 376             ByteBuffer[] dsts, int dstsOffset, int dstsLength) {
 377 
 378         if ((srcs == null) || (dsts == null)) {
 379             throw new IllegalArgumentException(
 380                     "source or destination buffer is null");
 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         if ((srcsOffset < 0) || (srcsLength < 0) ||
 390                 (srcsOffset > srcs.length - srcsLength)) {
 391             throw new IndexOutOfBoundsException(
 392                     "index out of bound of the source buffers");
 393         }
 394 
 395         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 396             if (dsts[i] == null) {
 397                 throw new IllegalArgumentException(
 398                         "destination buffer[" + i + "] == null");
 399             }
 400 
 401             /*
 402              * Make sure the destination bufffers are writable.
 403              */
 404             if (dsts[i].isReadOnly()) {
 405                 throw new ReadOnlyBufferException();
 406             }
 407         }
 408 
 409         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 410             if (srcs[i] == null) {
 411                 throw new IllegalArgumentException(
 412                         "source buffer[" + i + "] == null");
 413             }
 414         }
 415     }
 416 
 417     @Override
 418     public synchronized SSLEngineResult unwrap(ByteBuffer src,
 419             ByteBuffer[] dsts, int offset, int length) throws SSLException {
 420         return unwrap(
 421                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
 422     }
 423 
 424     // @Override
 425     public synchronized SSLEngineResult unwrap(
 426         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 427         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 428 
 429         if (conContext.isUnsureMode) {
 430             throw new IllegalStateException(
 431                     "Client/Server mode has not yet been set.");
 432         }
 433 
 434         // See if the handshaker needs to report back some SSLException.
 435         checkTaskThrown();
 436 
 437         // check parameters
 438         checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 439 
 440         try {
 441             return readRecord(
 442                 srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
 443         } catch (SSLProtocolException spe) {
 444             // may be an unexpected handshake message
 445             throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 446                     spe.getMessage(), spe);
 447         } catch (IOException ioe) {
 448             /*
 449              * Don't reset position so it looks like we didn't
 450              * consume anything.  We did consume something, and it
 451              * got us into this situation, so report that much back.
 452              * Our days of consuming are now over anyway.
 453              */
 454             throw conContext.fatal(Alert.INTERNAL_ERROR,
 455                     "problem unwrapping net record", ioe);
 456         } catch (Exception ex) {     // including RuntimeException
 457             throw conContext.fatal(Alert.INTERNAL_ERROR,
 458                 "Fail to unwrap network record", ex);
 459         }
 460     }
 461 
 462     private SSLEngineResult readRecord(
 463         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 464         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 465 
 466         /*
 467          * Check if we are closing/closed.
 468          */
 469         if (isInboundDone()) {
 470             return new SSLEngineResult(
 471                     Status.CLOSED, getHandshakeStatus(), 0, 0);
 472         }
 473 
 474         HandshakeStatus hsStatus = null;
 475         if (!conContext.isNegotiated && !conContext.isBroken &&
 476                 !conContext.isInboundClosed() &&
 477                 !conContext.isOutboundClosed()) {
 478             conContext.kickstart();
 479 
 480             /*
 481              * If there's still outbound data to flush, we
 482              * can return without trying to unwrap anything.
 483              */
 484             hsStatus = getHandshakeStatus();
 485             if (hsStatus == HandshakeStatus.NEED_WRAP) {
 486                 return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 487             }
 488         }
 489 
 490         if (hsStatus == null) {
 491             hsStatus = getHandshakeStatus();
 492         }
 493 
 494         /*
 495          * If we have a task outstanding, this *MUST* be done before
 496          * doing any more unwrapping, because we could be in the middle
 497          * of receiving a handshake message, for example, a finished
 498          * message which would change the ciphers.
 499          */
 500         if (hsStatus == HandshakeStatus.NEED_TASK) {
 501             return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
 502         }
 503 
 504         if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
 505             Plaintext plainText = null;
 506             try {
 507                 plainText = decode(null, 0, 0,
 508                         dsts, dstsOffset, dstsLength);
 509             } catch (IOException ioe) {
 510                 if (ioe instanceof SSLException) {
 511                     throw ioe;
 512                 } else {
 513                     throw new SSLException("readRecord", ioe);
 514                 }
 515             }
 516 
 517             Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 518             if (plainText.handshakeStatus != null) {
 519                 hsStatus = plainText.handshakeStatus;
 520             } else {
 521                 hsStatus = getHandshakeStatus();
 522             }
 523 
 524             return new SSLEngineResult(
 525                     status, hsStatus, 0, 0, plainText.recordSN);
 526         }
 527 
 528         int srcsRemains = 0;
 529         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 530             srcsRemains += srcs[i].remaining();
 531         }
 532 
 533         if (srcsRemains == 0) {
 534             return new SSLEngineResult(
 535                 Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
 536         }
 537 
 538         /*
 539          * Check the packet to make sure enough is here.
 540          * This will also indirectly check for 0 len packets.
 541          */
 542         int packetLen = 0;
 543         try {
 544             packetLen = conContext.inputRecord.bytesInCompletePacket(
 545                     srcs, srcsOffset, srcsLength);
 546         } catch (SSLException ssle) {
 547             // Need to discard invalid records for DTLS protocols.
 548             if (sslContext.isDTLS()) {
 549                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
 550                     SSLLogger.finest("Discard invalid DTLS records", ssle);
 551                 }
 552 
 553                 // invalid, discard the entire data [section 4.1.2.7, RFC 6347]
 554                 int deltaNet = 0;
 555                 // int deltaNet = netData.remaining();
 556                 // netData.position(netData.limit());
 557 
 558                 Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 559                 if (hsStatus == null) {
 560                     hsStatus = getHandshakeStatus();
 561                 }
 562 
 563                 return new SSLEngineResult(status, hsStatus, deltaNet, 0, -1L);
 564             } else {
 565                 throw ssle;
 566             }
 567         }
 568 
 569         // Is this packet bigger than SSL/TLS normally allows?
 570         if (packetLen > conContext.conSession.getPacketBufferSize()) {
 571             int largestRecordSize = sslContext.isDTLS() ?
 572                     DTLSRecord.maxRecordSize : SSLRecord.maxLargeRecordSize;
 573             if ((packetLen <= largestRecordSize) && !sslContext.isDTLS()) {
 574                 // Expand the expected maximum packet/application buffer
 575                 // sizes.
 576                 //
 577                 // Only apply to SSL/TLS protocols.
 578 
 579                 // Old behavior: shall we honor the System Property
 580                 // "jsse.SSLEngine.acceptLargeFragments" if it is "false"?
 581                 conContext.conSession.expandBufferSizes();
 582             }
 583 
 584             // check the packet again
 585             largestRecordSize = conContext.conSession.getPacketBufferSize();
 586             if (packetLen > largestRecordSize) {
 587                 throw new SSLProtocolException(
 588                         "Input record too big: max = " +
 589                         largestRecordSize + " len = " + packetLen);
 590             }
 591         }
 592 
 593         /*
 594          * Check for OVERFLOW.
 595          *
 596          * Delay enforcing the application buffer free space requirement
 597          * until after the initial handshaking.
 598          */
 599         int dstsRemains = 0;
 600         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 601             dstsRemains += dsts[i].remaining();
 602         }
 603 
 604         if (conContext.isNegotiated) {
 605             int FragLen =
 606                     conContext.inputRecord.estimateFragmentSize(packetLen);
 607             if (FragLen > dstsRemains) {
 608                 return new SSLEngineResult(
 609                         Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
 610             }
 611         }
 612 
 613         // check for UNDERFLOW.
 614         if ((packetLen == -1) || (srcsRemains < packetLen)) {
 615             return new SSLEngineResult(Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
 616         }
 617 
 618         /*
 619          * We're now ready to actually do the read.
 620          */
 621         Plaintext plainText = null;
 622         try {
 623             plainText = decode(srcs, srcsOffset, srcsLength,
 624                             dsts, dstsOffset, dstsLength);
 625         } catch (IOException ioe) {
 626             if (ioe instanceof SSLException) {
 627                 throw ioe;
 628             } else {
 629                 throw new SSLException("readRecord", ioe);
 630             }
 631         }
 632 
 633         /*
 634          * Check the various condition that we could be reporting.
 635          *
 636          * It's *possible* something might have happened between the
 637          * above and now, but it was better to minimally lock "this"
 638          * during the read process.  We'll return the current
 639          * status, which is more representative of the current state.
 640          *
 641          * status above should cover:  FINISHED, NEED_TASK
 642          */
 643         Status status = (isInboundDone() ? Status.CLOSED : Status.OK);
 644         if (plainText.handshakeStatus != null) {
 645             hsStatus = plainText.handshakeStatus;
 646         } else {
 647             hsStatus = getHandshakeStatus();
 648         }
 649 
 650         int deltaNet = srcsRemains;
 651         for (int i = srcsOffset; i < srcsOffset + srcsLength; i++) {
 652             deltaNet -= srcs[i].remaining();
 653         }
 654 
 655         int deltaApp = dstsRemains;
 656         for (int i = dstsOffset; i < dstsOffset + dstsLength; i++) {
 657             deltaApp -= dsts[i].remaining();
 658         }
 659 
 660         return new SSLEngineResult(
 661                 status, hsStatus, deltaNet, deltaApp, plainText.recordSN);
 662     }
 663 
 664     private Plaintext decode(
 665         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 666         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 667 
 668         Plaintext pt = SSLTransport.decode(conContext,
 669                             srcs, srcsOffset, srcsLength,
 670                             dsts, dstsOffset, dstsLength);
 671 
 672         // Is the handshake completed?
 673         if (pt != Plaintext.PLAINTEXT_NULL) {
 674             HandshakeStatus hsStatus = tryToFinishHandshake(pt.contentType);
 675             if (hsStatus == null) {
 676                 pt.handshakeStatus = conContext.getHandshakeStatus();
 677             } else {
 678                 pt.handshakeStatus = hsStatus;
 679             }
 680 
 681             // Is the sequence number is nearly overflow?
 682             if (conContext.inputRecord.seqNumIsHuge() ||
 683                     conContext.inputRecord.readCipher.atKeyLimit()) {
 684                 pt.handshakeStatus =
 685                         tryKeyUpdate(pt.handshakeStatus);
 686             }
 687         }
 688 
 689         return pt;
 690     }
 691 
 692     @Override
 693     public synchronized Runnable getDelegatedTask() {
 694         if (conContext.handshakeContext != null && // PRE or POST handshake
 695                 !conContext.handshakeContext.taskDelegated &&
 696                 !conContext.handshakeContext.delegatedActions.isEmpty()) {
 697             conContext.handshakeContext.taskDelegated = true;
 698             return new DelegatedTask(this);
 699         }
 700 
 701         return null;
 702     }
 703 
 704     @Override
 705     public synchronized void closeInbound() throws SSLException {
 706         if (isInboundDone()) {
 707             return;
 708         }
 709 
 710         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 711             SSLLogger.finest("Closing inbound of SSLEngine");
 712         }
 713 
 714         // Is it ready to close inbound?
 715         //
 716         // No need to throw exception if the initial handshake is not started.
 717         if (!conContext.isInputCloseNotified &&
 718             (conContext.isNegotiated || conContext.handshakeContext != null)) {
 719 
 720             throw conContext.fatal(Alert.INTERNAL_ERROR,
 721                     "closing inbound before receiving peer's close_notify");
 722         }
 723 
 724         conContext.closeInbound();
 725     }
 726 
 727     @Override
 728     public synchronized boolean isInboundDone() {
 729         return conContext.isInboundClosed();
 730     }
 731 
 732     @Override
 733     public synchronized void closeOutbound() {
 734         if (conContext.isOutboundClosed()) {
 735             return;
 736         }
 737 
 738         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 739             SSLLogger.finest("Closing outbound of SSLEngine");
 740         }
 741 
 742         conContext.closeOutbound();
 743     }
 744 
 745     @Override
 746     public synchronized boolean isOutboundDone() {
 747         return conContext.isOutboundDone();
 748     }
 749 
 750     @Override
 751     public String[] getSupportedCipherSuites() {
 752         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 753     }
 754 
 755     @Override
 756     public synchronized String[] getEnabledCipherSuites() {
 757         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
 758     }
 759 
 760     @Override
 761     public synchronized void setEnabledCipherSuites(String[] suites) {
 762         conContext.sslConfig.enabledCipherSuites =
 763                 CipherSuite.validValuesOf(suites);
 764     }
 765 
 766     @Override
 767     public String[] getSupportedProtocols() {
 768         return ProtocolVersion.toStringArray(
 769                 sslContext.getSupportedProtocolVersions());
 770     }
 771 
 772     @Override
 773     public synchronized String[] getEnabledProtocols() {
 774         return ProtocolVersion.toStringArray(
 775                 conContext.sslConfig.enabledProtocols);
 776     }
 777 
 778     @Override
 779     public synchronized void setEnabledProtocols(String[] protocols) {
 780         if (protocols == null) {
 781             throw new IllegalArgumentException("Protocols cannot be null");
 782         }
 783 
 784         conContext.sslConfig.enabledProtocols =
 785                 ProtocolVersion.namesOf(protocols);
 786     }
 787 
 788     @Override
 789     public synchronized SSLSession getSession() {
 790         return conContext.conSession;
 791     }
 792 
 793     @Override
 794     public synchronized SSLSession getHandshakeSession() {
 795         return conContext.handshakeContext == null ?
 796                 null : conContext.handshakeContext.handshakeSession;
 797     }
 798 
 799     @Override
 800     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
 801         return conContext.getHandshakeStatus();
 802     }
 803 
 804     @Override
 805     public synchronized void setUseClientMode(boolean mode) {
 806         conContext.setUseClientMode(mode);
 807     }
 808 
 809     @Override
 810     public synchronized boolean getUseClientMode() {
 811         return conContext.sslConfig.isClientMode;
 812     }
 813 
 814     @Override
 815     public synchronized void setNeedClientAuth(boolean need) {
 816         conContext.sslConfig.clientAuthType =
 817                 (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 818                         ClientAuthType.CLIENT_AUTH_NONE);
 819     }
 820 
 821     @Override
 822     public synchronized boolean getNeedClientAuth() {
 823         return (conContext.sslConfig.clientAuthType ==
 824                         ClientAuthType.CLIENT_AUTH_REQUIRED);
 825     }
 826 
 827     @Override
 828     public synchronized void setWantClientAuth(boolean want) {
 829         conContext.sslConfig.clientAuthType =
 830                 (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 831                         ClientAuthType.CLIENT_AUTH_NONE);
 832     }
 833 
 834     @Override
 835     public synchronized boolean getWantClientAuth() {
 836         return (conContext.sslConfig.clientAuthType ==
 837                         ClientAuthType.CLIENT_AUTH_REQUESTED);
 838     }
 839 
 840     @Override
 841     public synchronized void setEnableSessionCreation(boolean flag) {
 842         conContext.sslConfig.enableSessionCreation = flag;
 843     }
 844 
 845     @Override
 846     public synchronized boolean getEnableSessionCreation() {
 847         return conContext.sslConfig.enableSessionCreation;
 848     }
 849 
 850     @Override
 851     public synchronized SSLParameters getSSLParameters() {
 852         return conContext.sslConfig.getSSLParameters();
 853     }
 854 
 855     @Override
 856     public synchronized void setSSLParameters(SSLParameters params) {
 857         conContext.sslConfig.setSSLParameters(params);
 858 
 859         if (conContext.sslConfig.maximumPacketSize != 0) {
 860             conContext.outputRecord.changePacketSize(
 861                     conContext.sslConfig.maximumPacketSize);
 862         }
 863     }
 864 
 865     @Override
 866     public synchronized String getApplicationProtocol() {
 867         return conContext.applicationProtocol;
 868     }
 869 
 870     @Override
 871     public synchronized String getHandshakeApplicationProtocol() {
 872         return conContext.handshakeContext == null ?
 873                 null : conContext.handshakeContext.applicationProtocol;
 874     }
 875 
 876     @Override
 877     public synchronized void setHandshakeApplicationProtocolSelector(
 878             BiFunction<SSLEngine, List<String>, String> selector) {
 879         conContext.sslConfig.engineAPSelector = selector;
 880     }
 881 
 882     @Override
 883     public synchronized BiFunction<SSLEngine, List<String>, String>
 884             getHandshakeApplicationProtocolSelector() {
 885         return conContext.sslConfig.engineAPSelector;
 886     }
 887 
 888     @Override
 889     public boolean useDelegatedTask() {
 890         return true;
 891     }
 892 
 893     /*
 894      * Depending on whether the error was just a warning and the
 895      * handshaker wasn't closed, or fatal and the handshaker is now
 896      * null, report back the Exception that happened in the delegated
 897      * task(s).
 898      */
 899     private synchronized void checkTaskThrown() throws SSLException {
 900 
 901         Exception exc = null;
 902 
 903         // First check the handshake context.
 904         HandshakeContext hc = conContext.handshakeContext;
 905         if ((hc != null) && (hc.delegatedThrown != null)) {
 906             exc = hc.delegatedThrown;
 907             hc.delegatedThrown = null;
 908         }
 909 
 910         /*
 911          * hc.delegatedThrown and conContext.delegatedThrown are most likely
 912          * the same, but it's possible we could have had a non-fatal
 913          * exception and thus the new HandshakeContext is still valid
 914          * (alert warning).  If so, then we may have a secondary exception
 915          * waiting to be reported from the TransportContext, so we will
 916          * need to clear that on a successive call.  Otherwise, clear it now.
 917          */
 918         if (conContext.delegatedThrown != null) {
 919             if (exc != null) {
 920                 // hc object comparison
 921                 if (conContext.delegatedThrown == exc) {
 922                     // clear if/only if both are the same
 923                     conContext.delegatedThrown = null;
 924                 } // otherwise report the hc delegatedThrown
 925             } else {
 926                 // Nothing waiting in HandshakeContext, but one is in the
 927                 // TransportContext.
 928                 exc = conContext.delegatedThrown;
 929                 conContext.delegatedThrown = null;
 930             }
 931         }
 932 
 933         // Anything to report?
 934         if (exc == null) {
 935             return;
 936         }
 937 
 938         // If it wasn't a RuntimeException/SSLException, need to wrap it.
 939         if (exc instanceof SSLException) {
 940             throw (SSLException)exc;
 941         } else if (exc instanceof RuntimeException) {
 942             throw (RuntimeException)exc;
 943         } else {
 944             throw getTaskThrown(exc);
 945         }
 946     }
 947 
 948     private static SSLException getTaskThrown(Exception taskThrown) {
 949         String msg = taskThrown.getMessage();
 950 
 951         if (msg == null) {
 952             msg = "Delegated task threw Exception or Error";
 953         }
 954 
 955         if (taskThrown instanceof RuntimeException) {
 956             throw new RuntimeException(msg, taskThrown);
 957         } else if (taskThrown instanceof SSLHandshakeException) {
 958             return (SSLHandshakeException)
 959                 new SSLHandshakeException(msg).initCause(taskThrown);
 960         } else if (taskThrown instanceof SSLKeyException) {
 961             return (SSLKeyException)
 962                 new SSLKeyException(msg).initCause(taskThrown);
 963         } else if (taskThrown instanceof SSLPeerUnverifiedException) {
 964             return (SSLPeerUnverifiedException)
 965                 new SSLPeerUnverifiedException(msg).initCause(taskThrown);
 966         } else if (taskThrown instanceof SSLProtocolException) {
 967             return (SSLProtocolException)
 968                 new SSLProtocolException(msg).initCause(taskThrown);
 969         } else if (taskThrown instanceof SSLException) {
 970             return (SSLException)taskThrown;
 971         } else {
 972             return new SSLException(msg, taskThrown);
 973         }
 974     }
 975 
 976     /**
 977      * Implement a simple task delegator.
 978      */
 979     private static class DelegatedTask implements Runnable {
 980         private final SSLEngineImpl engine;
 981 
 982         DelegatedTask(SSLEngineImpl engineInstance) {
 983             this.engine = engineInstance;
 984         }
 985 
 986         @Override
 987         public void run() {
 988             synchronized (engine) {
 989                 HandshakeContext hc = engine.conContext.handshakeContext;
 990                 if (hc == null || hc.delegatedActions.isEmpty()) {
 991                     return;
 992                 }
 993 
 994                 try {
 995                     AccessController.doPrivileged(
 996                             new DelegatedAction(hc), engine.conContext.acc);
 997                 } catch (PrivilegedActionException pae) {
 998                     // Get the handshake context again in case the
 999                     // handshaking has completed.
1000                     Exception reportedException = pae.getException();
1001 
1002                     // Report to both the TransportContext...
1003                     if (engine.conContext.delegatedThrown == null) {
1004                         engine.conContext.delegatedThrown = reportedException;
1005                     }
1006 
1007                     // ...and the HandshakeContext in case condition
1008                     // wasn't fatal and the handshakeContext is still
1009                     // around.
1010                     hc = engine.conContext.handshakeContext;
1011                     if (hc != null) {
1012                         hc.delegatedThrown = reportedException;
1013                     } else if (engine.conContext.closeReason != null) {
1014                         // Update the reason in case there was a previous.
1015                         engine.conContext.closeReason =
1016                                 getTaskThrown(reportedException);
1017                     }
1018                 } catch (RuntimeException rte) {
1019                     // Get the handshake context again in case the
1020                     // handshaking has completed.
1021 
1022                     // Report to both the TransportContext...
1023                     if (engine.conContext.delegatedThrown == null) {
1024                         engine.conContext.delegatedThrown = rte;
1025                     }
1026 
1027                     // ...and the HandshakeContext in case condition
1028                     // wasn't fatal and the handshakeContext is still
1029                     // around.
1030                     hc = engine.conContext.handshakeContext;
1031                     if (hc != null) {
1032                         hc.delegatedThrown = rte;
1033                     } else if (engine.conContext.closeReason != null) {
1034                         // Update the reason in case there was a previous.
1035                         engine.conContext.closeReason = rte;
1036                     }
1037                 }
1038 
1039                 // Get the handshake context again in case the
1040                 // handshaking has completed.
1041                 hc = engine.conContext.handshakeContext;
1042                 if (hc != null) {
1043                     hc.taskDelegated = false;
1044                 }
1045             }
1046         }
1047 
1048         private static class DelegatedAction
1049                 implements PrivilegedExceptionAction<Void> {
1050             final HandshakeContext context;
1051             DelegatedAction(HandshakeContext context) {
1052                 this.context = context;
1053             }
1054 
1055             @Override
1056             public Void run() throws Exception {
1057                 while (!context.delegatedActions.isEmpty()) {
1058                     Map.Entry<Byte, ByteBuffer> me =
1059                             context.delegatedActions.poll();
1060                     if (me != null) {
1061                         context.dispatch(me.getKey(), me.getValue());
1062                     }
1063                 }
1064                 return null;
1065             }
1066         }
1067     }
1068 }