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      */
SSLEngineImpl(SSLContextImpl sslContext)65     SSLEngineImpl(SSLContextImpl sslContext) {
66         this(sslContext, null, -1);
67     }
68 
69     /**
70      * Constructor for an SSLEngine from SSLContext.
71      */
SSLEngineImpl(SSLContextImpl sslContext, String host, int port)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
beginHandshake()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
wrap(ByteBuffer[] appData, int offset, int length, ByteBuffer netData)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
wrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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 
writeRecord( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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 
encode( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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 
tryToFinishHandshake(byte contentType)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      */
tryKeyUpdate( HandshakeStatus currentHandshakeStatus)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 
checkParams( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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
unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length)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
unwrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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 
readRecord( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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 
decode( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)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
getDelegatedTask()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
closeInbound()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
isInboundDone()741     public synchronized boolean isInboundDone() {
742         return conContext.isInboundClosed();
743     }
744 
745     @Override
closeOutbound()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
isOutboundDone()759     public synchronized boolean isOutboundDone() {
760         return conContext.isOutboundDone();
761     }
762 
763     @Override
getSupportedCipherSuites()764     public String[] getSupportedCipherSuites() {
765         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
766     }
767 
768     @Override
getEnabledCipherSuites()769     public synchronized String[] getEnabledCipherSuites() {
770         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
771     }
772 
773     @Override
setEnabledCipherSuites(String[] suites)774     public synchronized void setEnabledCipherSuites(String[] suites) {
775         conContext.sslConfig.enabledCipherSuites =
776                 CipherSuite.validValuesOf(suites);
777     }
778 
779     @Override
getSupportedProtocols()780     public String[] getSupportedProtocols() {
781         return ProtocolVersion.toStringArray(
782                 sslContext.getSupportedProtocolVersions());
783     }
784 
785     @Override
getEnabledProtocols()786     public synchronized String[] getEnabledProtocols() {
787         return ProtocolVersion.toStringArray(
788                 conContext.sslConfig.enabledProtocols);
789     }
790 
791     @Override
setEnabledProtocols(String[] protocols)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
getSession()802     public synchronized SSLSession getSession() {
803         return conContext.conSession;
804     }
805 
806     @Override
getHandshakeSession()807     public synchronized SSLSession getHandshakeSession() {
808         return conContext.handshakeContext == null ?
809                 null : conContext.handshakeContext.handshakeSession;
810     }
811 
812     @Override
getHandshakeStatus()813     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
814         return conContext.getHandshakeStatus();
815     }
816 
817     @Override
setUseClientMode(boolean mode)818     public synchronized void setUseClientMode(boolean mode) {
819         conContext.setUseClientMode(mode);
820     }
821 
822     @Override
getUseClientMode()823     public synchronized boolean getUseClientMode() {
824         return conContext.sslConfig.isClientMode;
825     }
826 
827     @Override
setNeedClientAuth(boolean need)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
getNeedClientAuth()835     public synchronized boolean getNeedClientAuth() {
836         return (conContext.sslConfig.clientAuthType ==
837                         ClientAuthType.CLIENT_AUTH_REQUIRED);
838     }
839 
840     @Override
setWantClientAuth(boolean want)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
getWantClientAuth()848     public synchronized boolean getWantClientAuth() {
849         return (conContext.sslConfig.clientAuthType ==
850                         ClientAuthType.CLIENT_AUTH_REQUESTED);
851     }
852 
853     @Override
setEnableSessionCreation(boolean flag)854     public synchronized void setEnableSessionCreation(boolean flag) {
855         conContext.sslConfig.enableSessionCreation = flag;
856     }
857 
858     @Override
getEnableSessionCreation()859     public synchronized boolean getEnableSessionCreation() {
860         return conContext.sslConfig.enableSessionCreation;
861     }
862 
863     @Override
getSSLParameters()864     public synchronized SSLParameters getSSLParameters() {
865         return conContext.sslConfig.getSSLParameters();
866     }
867 
868     @Override
setSSLParameters(SSLParameters params)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
getApplicationProtocol()879     public synchronized String getApplicationProtocol() {
880         return conContext.applicationProtocol;
881     }
882 
883     @Override
getHandshakeApplicationProtocol()884     public synchronized String getHandshakeApplicationProtocol() {
885         return conContext.handshakeContext == null ?
886                 null : conContext.handshakeContext.applicationProtocol;
887     }
888 
889     @Override
setHandshakeApplicationProtocolSelector( BiFunction<SSLEngine, List<String>, String> selector)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>
getHandshakeApplicationProtocolSelector()897             getHandshakeApplicationProtocolSelector() {
898         return conContext.sslConfig.engineAPSelector;
899     }
900 
901     @Override
useDelegatedTask()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      */
checkTaskThrown()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 
getTaskThrown(Exception taskThrown)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 
DelegatedTask(SSLEngineImpl engineInstance)995         DelegatedTask(SSLEngineImpl engineInstance) {
996             this.engine = engineInstance;
997         }
998 
999         @Override
run()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;
DelegatedAction(HandshakeContext context)1064             DelegatedAction(HandshakeContext context) {
1065                 this.context = context;
1066             }
1067 
1068             @Override
run()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 }
1082