• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 import java.io.*;
42 import java.nio.*;
43 import java.nio.channels.*;
44 import javax.net.ssl.*;
45 import javax.net.ssl.SSLEngineResult.*;
46 
47 /**
48  * A helper class which performs I/O using the SSLEngine API.
49  * <P>
50  * Each connection has a SocketChannel and a SSLEngine that is
51  * used through the lifetime of the Channel.  We allocate byte buffers
52  * for use as the outbound and inbound network buffers.
53  *
54  * <PRE>
55  *               Application Data
56  *               src      requestBB
57  *                |           ^
58  *                |     |     |
59  *                v     |     |
60  *           +----+-----|-----+----+
61  *           |          |          |
62  *           |       SSL|Engine    |
63  *   wrap()  |          |          |  unwrap()
64  *           | OUTBOUND | INBOUND  |
65  *           |          |          |
66  *           +----+-----|-----+----+
67  *                |     |     ^
68  *                |     |     |
69  *                v           |
70  *            outNetBB     inNetBB
71  *                   Net data
72  * </PRE>
73  *
74  * These buffers handle all of the intermediary data for the SSL
75  * connection.  To make things easy, we'll require outNetBB be
76  * completely flushed before trying to wrap any more data, but we
77  * could certainly remove that restriction by using larger buffers.
78  * <P>
79  * There are many, many ways to handle compute and I/O strategies.
80  * What follows is a relatively simple one.  The reader is encouraged
81  * to develop the strategy that best fits the application.
82  * <P>
83  * In most of the non-blocking operations in this class, we let the
84  * Selector tell us when we're ready to attempt an I/O operation (by the
85  * application repeatedly calling our methods).  Another option would be
86  * to attempt the operation and return from the method when no forward
87  * progress can be made.
88  * <P>
89  * There's lots of room for enhancements and improvement in this example.
90  * <P>
91  * We're checking for SSL/TLS end-of-stream truncation attacks via
92  * sslEngine.closeInbound().  When you reach the end of a input stream
93  * via a read() returning -1 or an IOException, we call
94  * sslEngine.closeInbound() to signal to the sslEngine that no more
95  * input will be available.  If the peer's close_notify message has not
96  * yet been received, this could indicate a trucation attack, in which
97  * an attacker is trying to prematurely close the connection.   The
98  * closeInbound() will throw an exception if this condition were
99  * present.
100  *
101  * @author Brad R. Wetmore
102  * @author Mark Reinhold
103  */
104 class ChannelIOSecure extends ChannelIO {
105 
106     private SSLEngine sslEngine = null;
107 
108     private int appBBSize;
109     private int netBBSize;
110 
111     /*
112      * All I/O goes through these buffers.
113      * <P>
114      * It might be nice to use a cache of ByteBuffers so we're
115      * not alloc/dealloc'ing ByteBuffer's for each new SSLEngine.
116      * <P>
117      * We use our superclass' requestBB for our application input buffer.
118      * Outbound application data is supplied to us by our callers.
119      */
120     private ByteBuffer inNetBB;
121     private ByteBuffer outNetBB;
122 
123     /*
124      * An empty ByteBuffer for use when one isn't available, say
125      * as a source buffer during initial handshake wraps or for close
126      * operations.
127      */
128     private static ByteBuffer hsBB = ByteBuffer.allocate(0);
129 
130     /*
131      * The FileChannel we're currently transferTo'ing (reading).
132      */
133     private ByteBuffer fileChannelBB = null;
134 
135     /*
136      * During our initial handshake, keep track of the next
137      * SSLEngine operation that needs to occur:
138      *
139      *     NEED_WRAP/NEED_UNWRAP
140      *
141      * Once the initial handshake has completed, we can short circuit
142      * handshake checks with initialHSComplete.
143      */
144     private HandshakeStatus initialHSStatus;
145     private boolean initialHSComplete;
146 
147     /*
148      * We have received the shutdown request by our caller, and have
149      * closed our outbound side.
150      */
151     private boolean shutdown = false;
152 
153     /*
154      * Constructor for a secure ChannelIO variant.
155      */
ChannelIOSecure(SocketChannel sc, boolean blocking, SSLContext sslc)156     protected ChannelIOSecure(SocketChannel sc, boolean blocking,
157             SSLContext sslc) throws IOException {
158         super(sc, blocking);
159 
160         /*
161          * We're a server, so no need to use host/port variant.
162          *
163          * The first call for a server is a NEED_UNWRAP.
164          */
165         sslEngine = sslc.createSSLEngine();
166         sslEngine.setUseClientMode(false);
167         initialHSStatus = HandshakeStatus.NEED_UNWRAP;
168         initialHSComplete = false;
169 
170         // Create a buffer using the normal expected packet size we'll
171         // be getting.  This may change, depending on the peer's
172         // SSL implementation.
173         netBBSize = sslEngine.getSession().getPacketBufferSize();
174         inNetBB = ByteBuffer.allocate(netBBSize);
175         outNetBB = ByteBuffer.allocate(netBBSize);
176         outNetBB.position(0);
177         outNetBB.limit(0);
178     }
179 
180     /*
181      * Static factory method for creating a secure ChannelIO object.
182      * <P>
183      * We need to allocate different sized application data buffers
184      * based on whether we're secure or not.  We can't determine
185      * this until our sslEngine is created.
186      */
getInstance(SocketChannel sc, boolean blocking, SSLContext sslc)187     static ChannelIOSecure getInstance(SocketChannel sc, boolean blocking,
188             SSLContext sslc) throws IOException {
189 
190         ChannelIOSecure cio = new ChannelIOSecure(sc, blocking, sslc);
191 
192         // Create a buffer using the normal expected application size we'll
193         // be getting.  This may change, depending on the peer's
194         // SSL implementation.
195         cio.appBBSize = cio.sslEngine.getSession().getApplicationBufferSize();
196         cio.requestBB = ByteBuffer.allocate(cio.appBBSize);
197 
198         return cio;
199     }
200 
201     /*
202      * Calls up to the superclass to adjust the buffer size
203      * by an appropriate increment.
204      */
resizeRequestBB()205     protected void resizeRequestBB() {
206         resizeRequestBB(appBBSize);
207     }
208 
209     /*
210      * Adjust the inbount network buffer to an appropriate size.
211      */
resizeResponseBB()212     private void resizeResponseBB() {
213         ByteBuffer bb = ByteBuffer.allocate(netBBSize);
214         inNetBB.flip();
215         bb.put(inNetBB);
216         inNetBB = bb;
217     }
218 
219     /*
220      * Writes bb to the SocketChannel.
221      * <P>
222      * Returns true when the ByteBuffer has no remaining data.
223      */
tryFlush(ByteBuffer bb)224     private boolean tryFlush(ByteBuffer bb) throws IOException {
225         super.write(bb);
226         return !bb.hasRemaining();
227     }
228 
229     /*
230      * Perform any handshaking processing.
231      * <P>
232      * This variant is for Servers without SelectionKeys (e.g.
233      * blocking).
234      */
doHandshake()235     boolean doHandshake() throws IOException {
236         return doHandshake(null);
237     }
238 
239     /*
240      * Perform any handshaking processing.
241      * <P>
242      * If a SelectionKey is passed, register for selectable
243      * operations.
244      * <P>
245      * In the blocking case, our caller will keep calling us until
246      * we finish the handshake.  Our reads/writes will block as expected.
247      * <P>
248      * In the non-blocking case, we just received the selection notification
249      * that this channel is ready for whatever the operation is, so give
250      * it a try.
251      * <P>
252      * return:
253      *          true when handshake is done.
254      *          false while handshake is in progress
255      */
doHandshake(SelectionKey sk)256     boolean doHandshake(SelectionKey sk) throws IOException {
257 
258         SSLEngineResult result;
259 
260         if (initialHSComplete) {
261             return initialHSComplete;
262         }
263 
264         /*
265          * Flush out the outgoing buffer, if there's anything left in
266          * it.
267          */
268         if (outNetBB.hasRemaining()) {
269 
270             if (!tryFlush(outNetBB)) {
271                 return false;
272             }
273 
274             // See if we need to switch from write to read mode.
275 
276             switch (initialHSStatus) {
277 
278             /*
279              * Is this the last buffer?
280              */
281             case FINISHED:
282                 initialHSComplete = true;
283                 // Fall-through to reregister need for a Read.
284 
285             case NEED_UNWRAP:
286                 if (sk != null) {
287                     sk.interestOps(SelectionKey.OP_READ);
288                 }
289                 break;
290             }
291 
292             return initialHSComplete;
293         }
294 
295 
296         switch (initialHSStatus) {
297 
298         case NEED_UNWRAP:
299             if (sc.read(inNetBB) == -1) {
300                 sslEngine.closeInbound();
301                 return initialHSComplete;
302             }
303 
304 needIO:
305             while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
306                 resizeRequestBB();    // expected room for unwrap
307                 inNetBB.flip();
308                 result = sslEngine.unwrap(inNetBB, requestBB);
309                 inNetBB.compact();
310 
311                 initialHSStatus = result.getHandshakeStatus();
312 
313                 switch (result.getStatus()) {
314 
315                 case OK:
316                     switch (initialHSStatus) {
317                     case NOT_HANDSHAKING:
318                         throw new IOException(
319                             "Not handshaking during initial handshake");
320 
321                     case NEED_TASK:
322                         initialHSStatus = doTasks();
323                         break;
324 
325                     case FINISHED:
326                         initialHSComplete = true;
327                         break needIO;
328                     }
329 
330                     break;
331 
332                 case BUFFER_UNDERFLOW:
333                     // Resize buffer if needed.
334                     netBBSize = sslEngine.getSession().getPacketBufferSize();
335                     if (netBBSize > inNetBB.capacity()) {
336                         resizeResponseBB();
337                     }
338 
339                     /*
340                      * Need to go reread the Channel for more data.
341                      */
342                     if (sk != null) {
343                         sk.interestOps(SelectionKey.OP_READ);
344                     }
345                     break needIO;
346 
347                 case BUFFER_OVERFLOW:
348                     // Reset the application buffer size.
349                     appBBSize =
350                         sslEngine.getSession().getApplicationBufferSize();
351                     break;
352 
353                 default: //CLOSED:
354                     throw new IOException("Received" + result.getStatus() +
355                         "during initial handshaking");
356                 }
357             }  // "needIO" block.
358 
359             /*
360              * Just transitioned from read to write.
361              */
362             if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
363                 break;
364             }
365 
366             // Fall through and fill the write buffers.
367 
368         case NEED_WRAP:
369             /*
370              * The flush above guarantees the out buffer to be empty
371              */
372             outNetBB.clear();
373             result = sslEngine.wrap(hsBB, outNetBB);
374             outNetBB.flip();
375 
376             initialHSStatus = result.getHandshakeStatus();
377 
378             switch (result.getStatus()) {
379             case OK:
380 
381                 if (initialHSStatus == HandshakeStatus.NEED_TASK) {
382                     initialHSStatus = doTasks();
383                 }
384 
385                 if (sk != null) {
386                     sk.interestOps(SelectionKey.OP_WRITE);
387                 }
388 
389                 break;
390 
391             default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED:
392                 throw new IOException("Received" + result.getStatus() +
393                         "during initial handshaking");
394             }
395             break;
396 
397         default: // NOT_HANDSHAKING/NEED_TASK/FINISHED
398             throw new RuntimeException("Invalid Handshaking State" +
399                     initialHSStatus);
400         } // switch
401 
402         return initialHSComplete;
403     }
404 
405     /*
406      * Do all the outstanding handshake tasks in the current Thread.
407      */
doTasks()408     private SSLEngineResult.HandshakeStatus doTasks() {
409 
410         Runnable runnable;
411 
412         /*
413          * We could run this in a separate thread, but
414          * do in the current for now.
415          */
416         while ((runnable = sslEngine.getDelegatedTask()) != null) {
417             runnable.run();
418         }
419         return sslEngine.getHandshakeStatus();
420     }
421 
422     /*
423      * Read the channel for more information, then unwrap the
424      * (hopefully application) data we get.
425      * <P>
426      * If we run out of data, we'll return to our caller (possibly using
427      * a Selector) to get notification that more is available.
428      * <P>
429      * Each call to this method will perform at most one underlying read().
430      */
read()431     int read() throws IOException {
432         SSLEngineResult result;
433 
434         if (!initialHSComplete) {
435             throw new IllegalStateException();
436         }
437 
438         int pos = requestBB.position();
439 
440         if (sc.read(inNetBB) == -1) {
441             sslEngine.closeInbound();  // probably throws exception
442             return -1;
443         }
444 
445         do {
446             resizeRequestBB();    // expected room for unwrap
447             inNetBB.flip();
448             result = sslEngine.unwrap(inNetBB, requestBB);
449             inNetBB.compact();
450 
451             /*
452              * Could check here for a renegotation, but we're only
453              * doing a simple read/write, and won't have enough state
454              * transitions to do a complete handshake, so ignore that
455              * possibility.
456              */
457             switch (result.getStatus()) {
458 
459             case BUFFER_OVERFLOW:
460                 // Reset the application buffer size.
461                 appBBSize = sslEngine.getSession().getApplicationBufferSize();
462                 break;
463 
464             case BUFFER_UNDERFLOW:
465                 // Resize buffer if needed.
466                 netBBSize = sslEngine.getSession().getPacketBufferSize();
467                 if (netBBSize > inNetBB.capacity()) {
468                     resizeResponseBB();
469 
470                     break; // break, next read will support larger buffer.
471                 }
472             case OK:
473                 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
474                     doTasks();
475                 }
476                 break;
477 
478             default:
479                 throw new IOException("sslEngine error during data read: " +
480                     result.getStatus());
481             }
482         } while ((inNetBB.position() != 0) &&
483             result.getStatus() != Status.BUFFER_UNDERFLOW);
484 
485         return (requestBB.position() - pos);
486     }
487 
488     /*
489      * Try to write out as much as possible from the src buffer.
490      */
write(ByteBuffer src)491     int write(ByteBuffer src) throws IOException {
492 
493         if (!initialHSComplete) {
494             throw new IllegalStateException();
495         }
496 
497         return doWrite(src);
498     }
499 
500     /*
501      * Try to flush out any existing outbound data, then try to wrap
502      * anything new contained in the src buffer.
503      * <P>
504      * Return the number of bytes actually consumed from the buffer,
505      * but the data may actually be still sitting in the output buffer,
506      * waiting to be flushed.
507      */
doWrite(ByteBuffer src)508     private int doWrite(ByteBuffer src) throws IOException {
509         int retValue = 0;
510 
511         if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) {
512             return retValue;
513         }
514 
515         /*
516          * The data buffer is empty, we can reuse the entire buffer.
517          */
518         outNetBB.clear();
519 
520         SSLEngineResult result = sslEngine.wrap(src, outNetBB);
521         retValue = result.bytesConsumed();
522 
523         outNetBB.flip();
524 
525         switch (result.getStatus()) {
526 
527         case OK:
528             if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
529                 doTasks();
530             }
531             break;
532 
533         default:
534             throw new IOException("sslEngine error during data write: " +
535                 result.getStatus());
536         }
537 
538         /*
539          * Try to flush the data, regardless of whether or not
540          * it's been selected.  Odds of a write buffer being full
541          * is less than a read buffer being empty.
542          */
543         if (outNetBB.hasRemaining()) {
544             tryFlush(outNetBB);
545         }
546 
547         return retValue;
548     }
549 
550     /*
551      * Perform a FileChannel.TransferTo on the socket channel.
552      * <P>
553      * We have to copy the data into an intermediary app ByteBuffer
554      * first, then send it through the SSLEngine.
555      * <P>
556      * We return the number of bytes actually read out of the
557      * filechannel.  However, the data may actually be stuck
558      * in the fileChannelBB or the outNetBB.  The caller
559      * is responsible for making sure to call dataFlush()
560      * before shutting down.
561      */
transferTo(FileChannel fc, long pos, long len)562     long transferTo(FileChannel fc, long pos, long len) throws IOException {
563 
564         if (!initialHSComplete) {
565             throw new IllegalStateException();
566         }
567 
568         if (fileChannelBB == null) {
569             fileChannelBB = ByteBuffer.allocate(appBBSize);
570             fileChannelBB.limit(0);
571         }
572 
573         fileChannelBB.compact();
574         int fileRead = fc.read(fileChannelBB);
575         fileChannelBB.flip();
576 
577         /*
578          * We ignore the return value here, we return the
579          * number of bytes actually consumed from the the file.
580          * We'll flush the output buffer before we start shutting down.
581          */
582         doWrite(fileChannelBB);
583 
584         return fileRead;
585     }
586 
587     /*
588      * Flush any remaining data.
589      * <P>
590      * Return true when the fileChannelBB and outNetBB are empty.
591      */
dataFlush()592     boolean dataFlush() throws IOException {
593         boolean fileFlushed = true;
594 
595         if ((fileChannelBB != null) && fileChannelBB.hasRemaining()) {
596             doWrite(fileChannelBB);
597             fileFlushed = !fileChannelBB.hasRemaining();
598         } else if (outNetBB.hasRemaining()) {
599             tryFlush(outNetBB);
600         }
601 
602         return (fileFlushed && !outNetBB.hasRemaining());
603     }
604 
605     /*
606      * Begin the shutdown process.
607      * <P>
608      * Close out the SSLEngine if not already done so, then
609      * wrap our outgoing close_notify message and try to send it on.
610      * <P>
611      * Return true when we're done passing the shutdown messsages.
612      */
shutdown()613     boolean shutdown() throws IOException {
614 
615         if (!shutdown) {
616             sslEngine.closeOutbound();
617             shutdown = true;
618         }
619 
620         if (outNetBB.hasRemaining() && tryFlush(outNetBB)) {
621             return false;
622         }
623 
624         /*
625          * By RFC 2616, we can "fire and forget" our close_notify
626          * message, so that's what we'll do here.
627          */
628         outNetBB.clear();
629         SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB);
630         if (result.getStatus() != Status.CLOSED) {
631             throw new SSLException("Improper close state");
632         }
633         outNetBB.flip();
634 
635         /*
636          * We won't wait for a select here, but if this doesn't work,
637          * we'll cycle back through on the next select.
638          */
639         if (outNetBB.hasRemaining()) {
640             tryFlush(outNetBB);
641         }
642 
643         return (!outNetBB.hasRemaining() &&
644                 (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
645     }
646 
647     /*
648      * close() is not overridden
649      */
650 }
651