View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.filter.ssl;
21  
22  import java.net.InetSocketAddress;
23  import java.nio.ByteBuffer;
24  import java.util.Queue;
25  import java.util.concurrent.ConcurrentLinkedQueue;
26  import java.util.concurrent.atomic.AtomicInteger;
27  import java.util.concurrent.locks.ReentrantLock;
28  
29  import javax.net.ssl.SSLEngine;
30  import javax.net.ssl.SSLEngineResult;
31  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
32  import javax.net.ssl.SSLEngineResult.Status;
33  import javax.net.ssl.SSLException;
34  import javax.net.ssl.SSLHandshakeException;
35  
36  import org.apache.mina.core.RuntimeIoException;
37  import org.apache.mina.core.buffer.IoBuffer;
38  import org.apache.mina.core.filterchain.IoFilter.NextFilter;
39  import org.apache.mina.core.filterchain.IoFilterEvent;
40  import org.apache.mina.core.future.DefaultWriteFuture;
41  import org.apache.mina.core.future.WriteFuture;
42  import org.apache.mina.core.session.IoEventType;
43  import org.apache.mina.core.session.IoSession;
44  import org.apache.mina.core.write.DefaultWriteRequest;
45  import org.apache.mina.core.write.WriteRequest;
46  import org.apache.mina.core.write.WriteRequestQueue;
47  import org.apache.mina.filter.ssl.SslFilter.EncryptedWriteRequest;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  /**
52   * A helper class using the SSLEngine API to decrypt/encrypt data.
53   * <p/>
54   * Each connection has a SSLEngine that is used through the lifetime of the connection.
55   * We allocate buffers for use as the outbound and inbound network buffers.
56   * These buffers handle all of the intermediary data for the SSL connection. To make things easy,
57   * we'll require outNetBuffer be completely flushed before trying to wrap any more data.
58   * <p/>
59   * This class is not to be used by any client, it's closely associated with the SSL Filter.
60   * None of its methods are public as they should not be used by any other class but from
61   * the SslFilter class, in the same package
62   *
63   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
64   */
65  /** No qualifier*/
66  class SslHandler {
67      /** A logger for this class */
68      private static final Logger LOGGER = LoggerFactory.getLogger(SslHandler.class);
69  
70      /** The SSL Filter which has created this handler */
71      private final SslFilter sslFilter;
72  
73      /** The current session */
74      private final IoSession session;
75  
76      private final Queue<IoFilterEvent> preHandshakeEventQueue = new ConcurrentLinkedQueue<>();
77  
78      private final Queue<IoFilterEvent> filterWriteEventQueue = new ConcurrentLinkedQueue<>();
79  
80      /** A queue used to stack all the incoming data until the SSL session is established */
81      private final Queue<IoFilterEvent> messageReceivedEventQueue = new ConcurrentLinkedQueue<>();
82  
83      private SSLEngine sslEngine;
84  
85      /**
86       * Encrypted data from the net
87       */
88      private IoBuffer inNetBuffer;
89  
90      /**
91       * Encrypted data to be written to the net
92       */
93      private IoBuffer outNetBuffer;
94  
95      /**
96       * Application cleartext data to be read by application
97       */
98      private IoBuffer appBuffer;
99  
100     /**
101      * Empty buffer used during initial handshake and close operations
102      */
103     private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
104 
105     private SSLEngineResult.HandshakeStatus handshakeStatus;
106 
107     /**
108      * A flag set to true when the first SSL handshake has been completed
109      * This is used to avoid sending a notification to the application handler
110      * when we switch to a SECURE or UNSECURE session.
111      */
112     private boolean firstSSLNegociation;
113 
114     /** A flag set to true when a SSL Handshake has been completed */
115     private boolean handshakeComplete;
116 
117     /** A flag used to indicate to the SslFilter that the buffer
118      * it will write is already encrypted (this will be the case
119      * for data being produced during the handshake). */
120     private boolean writingEncryptedData;
121 
122     /**
123      * Create a new SSL Handler, and initialize it.
124      *
125      * @param sslContext
126      * @throws SSLException
127      */
128     /* no qualifier */SslHandler(SslFilter sslFilter, IoSession session) {
129         this.sslFilter = sslFilter;
130         this.session = session;
131     }
132 
133     /**
134      * Initialize the SSL handshake.
135      *
136      * @throws SSLException If the underlying SSLEngine handshake initialization failed
137      */
138     /* no qualifier */void init() throws SSLException {
139         if (sslEngine != null) {
140             // We already have a SSL engine created, no need to create a new one
141             return;
142         }
143 
144         if (LOGGER.isDebugEnabled()) {
145             LOGGER.debug("{} Initializing the SSL Handler", sslFilter.getSessionInfo(session));
146         }
147 
148         InetSocketAddress peer = (InetSocketAddress) session.getAttribute(SslFilter.PEER_ADDRESS);
149 
150         // Create the SSL engine here
151         if (peer == null) {
152             sslEngine = sslFilter.sslContext.createSSLEngine();
153         } else {
154             sslEngine = sslFilter.sslContext.createSSLEngine(peer.getHostName(), peer.getPort());
155         }
156 
157         // Initialize the engine in client mode if necessary
158         sslEngine.setUseClientMode(sslFilter.isUseClientMode());
159 
160         // Initialize the different SslEngine modes
161         if (!sslEngine.getUseClientMode()) {
162             // Those parameters are only valid when in server mode
163             if (sslFilter.isWantClientAuth()) {
164                 sslEngine.setWantClientAuth(true);
165             }
166 
167             if (sslFilter.isNeedClientAuth()) {
168                 sslEngine.setNeedClientAuth(true);
169             }
170         }
171 
172         // Set the cipher suite to use by this SslEngine instance
173         if (sslFilter.getEnabledCipherSuites() != null) {
174             sslEngine.setEnabledCipherSuites(sslFilter.getEnabledCipherSuites());
175         }
176 
177         // Set the list of enabled protocols
178         if (sslFilter.getEnabledProtocols() != null) {
179             sslEngine.setEnabledProtocols(sslFilter.getEnabledProtocols());
180         }
181 
182         // TODO : we may not need to call this method...
183         // However, if we don't call it here, the tests are failing. Why?
184         handshakeStatus = sslEngine.getHandshakeStatus();
185 
186         // Default value
187         writingEncryptedData = false;
188 
189         // We haven't yet started a SSL negotiation
190         // set the flags accordingly
191         firstSSLNegociation = true;
192         handshakeComplete = false;
193 
194         if (LOGGER.isDebugEnabled()) {
195             LOGGER.debug("{} SSL Handler Initialization done.", sslFilter.getSessionInfo(session));
196         }
197     }
198     
199 
200     /**
201      * Release allocated buffers.
202      */
203     /* no qualifier */void destroy() {
204         if (sslEngine == null) {
205             return;
206         }
207 
208         // Close inbound and flush all remaining data if available.
209         try {
210             sslEngine.closeInbound();
211         } catch (SSLException e) {
212             if (LOGGER.isDebugEnabled()) {
213                 LOGGER.debug("Unexpected exception from SSLEngine.closeInbound().", e);
214             }
215         }
216 
217         if (outNetBuffer != null) {
218             outNetBuffer.capacity(sslEngine.getSession().getPacketBufferSize());
219         } else {
220             createOutNetBuffer(0);
221         }
222         try {
223             do {
224                 outNetBuffer.clear();
225             } while (sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()).bytesProduced() > 0);
226         } catch (SSLException e) {
227             // Ignore.
228         } finally {
229             outNetBuffer.free();
230             outNetBuffer = null;
231         }
232 
233         sslEngine.closeOutbound();
234         sslEngine = null;
235 
236         preHandshakeEventQueue.clear();
237     }
238 
239     /**
240      * @return The SSL filter which has created this handler
241      */
242     /* no qualifier */SslFilter getSslFilter() {
243         return sslFilter;
244     }
245 
246     /* no qualifier */IoSession getSession() {
247         return session;
248     }
249 
250     /**
251      * Check if we are writing encrypted data.
252      */
253     /* no qualifier */boolean isWritingEncryptedData() {
254         return writingEncryptedData;
255     }
256 
257     /**
258      * Check if handshake is completed.
259      */
260     /* no qualifier */boolean isHandshakeComplete() {
261         return handshakeComplete;
262     }
263 
264     /**
265      * Check if handshake is on going.
266      */
267     /* no qualifier */boolean notHandshaking() {
268         return handshakeStatus == HandshakeStatus.FINISHED || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING;
269     }
270 
271     /* no qualifier */boolean isInboundDone() {
272         return sslEngine == null || sslEngine.isInboundDone();
273     }
274 
275     /* no qualifier */boolean isOutboundDone() {
276         return sslEngine == null || sslEngine.isOutboundDone();
277     }
278 
279     /**
280      * Check if there is any need to complete handshake.
281      */
282     /* no qualifier */boolean needToCompleteHandshake() {
283         return handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !isInboundDone();
284     }
285 
286     /* no qualifier */void schedulePreHandshakeWriteRequest(NextFilter nextFilter, WriteRequest writeRequest) {
287         preHandshakeEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
288     }
289 
290     /* no qualifier */void flushPreHandshakeEvents() throws SSLException {
291         IoFilterEvent scheduledWrite;
292 
293         while ((scheduledWrite = preHandshakeEventQueue.poll()) != null) {
294             sslFilter
295             .filterWrite(scheduledWrite.getNextFilter(), session, (WriteRequest) scheduledWrite.getParameter());
296         }
297     }
298 
299     /* no qualifier */void scheduleFilterWrite(NextFilter nextFilter, WriteRequest writeRequest) {
300         filterWriteEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
301     }
302 
303     /* no qualifier */void flushFilterWrite() {
304         // Fire events only when the lock is available for this handler.
305         IoFilterEvent event;
306     
307         // We need synchronization here inevitably because filterWrite can be
308         // called simultaneously and cause 'bad record MAC' integrity error.
309         while ((event = filterWriteEventQueue.poll()) != null) {
310             NextFilter nextFilter = event.getNextFilter();
311             nextFilter.filterWrite(session, (WriteRequest) event.getParameter());
312         }
313     }
314 
315     /**
316      * Push the newly received data into a queue, waiting for the SSL session
317      * to be fully established
318      *
319      * @param nextFilter The next filter to call
320      * @param message The incoming data
321      */
322     /* no qualifier */void scheduleMessageReceived(NextFilter nextFilter, Object message) {
323         messageReceivedEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.MESSAGE_RECEIVED, session, message));
324     }
325     
326     /* no qualifier */void flushMessageReceived() {
327 	IoFilterEvent event;
328 
329 	while ((event = messageReceivedEventQueue.poll()) != null) {
330 	    NextFilter nextFilter = event.getNextFilter();
331 	    nextFilter.messageReceived(session, event.getParameter());
332 	}
333     }
334 
335     /**
336      * Call when data are read from net. It will perform the initial hanshake or decrypt
337      * the data if SSL has been initialiaed.
338      * 
339      * @param buf buffer to decrypt
340      * @param nextFilter Next filter in chain
341      * @throws SSLException on errors
342      */
343     /* no qualifier */void messageReceived(NextFilter nextFilter, ByteBuffer buf) throws SSLException {
344         if (LOGGER.isDebugEnabled()) {
345             LOGGER.debug("{} Processing the received message", sslFilter.getSessionInfo(session));
346         }
347 
348         // append buf to inNetBuffer
349         if (inNetBuffer == null) {
350             inNetBuffer = IoBuffer.allocate(buf.remaining()).setAutoExpand(true);
351         }
352 
353         inNetBuffer.put(buf);
354 
355         if (!handshakeComplete) {
356             handshake(nextFilter);
357         } else {
358             // Prepare the net data for reading.
359             inNetBuffer.flip();
360 
361             if (!inNetBuffer.hasRemaining()) {
362                 return;
363             }
364 
365             SSLEngineResult res = unwrap();
366 
367             // prepare to be written again
368             if (inNetBuffer.hasRemaining()) {
369                 inNetBuffer.compact();
370             } else {
371                 inNetBuffer.free();
372                 inNetBuffer = null;
373             }
374 
375             checkStatus(res);
376 
377             renegotiateIfNeeded(nextFilter, res);
378         }
379 
380         if (isInboundDone()) {
381             // Rewind the MINA buffer if not all data is processed and inbound
382             // is finished.
383             int inNetBufferPosition = inNetBuffer == null ? 0 : inNetBuffer.position();
384             buf.position(buf.position() - inNetBufferPosition);
385 
386             if (inNetBuffer != null) {
387                 inNetBuffer.free();
388                 inNetBuffer = null;
389             }
390         }
391     }
392 
393     /**
394      * Get decrypted application data.
395      * 
396      * @return buffer with data
397      */
398     /* no qualifier */IoBuffer fetchAppBuffer() {
399         if (appBuffer == null) {
400             return IoBuffer.allocate(0);
401         } else {
402             IoBuffer newAppBuffer = appBuffer.flip();
403             appBuffer = null;
404 
405             return newAppBuffer.shrink();
406         }
407     }
408 
409     /**
410      * Get encrypted data to be sent.
411      * 
412      * @return buffer with data
413      */
414     /* no qualifier */IoBuffer fetchOutNetBuffer() {
415         IoBuffer answer = outNetBuffer;
416         
417         if (answer == null) {
418             return emptyBuffer;
419         }
420 
421         outNetBuffer = null;
422         
423         return answer.shrink();
424     }
425 
426     /**
427      * Encrypt provided buffer. Encrypted data returned by getOutNetBuffer().
428      * 
429      * @param src
430      *            data to encrypt
431      * @throws SSLException
432      *             on errors
433      */
434     /* no qualifier */void encrypt(ByteBuffer src) throws SSLException {
435         if (!handshakeComplete) {
436             throw new IllegalStateException();
437         }
438 
439         if (!src.hasRemaining()) {
440             if (outNetBuffer == null) {
441                 outNetBuffer = emptyBuffer;
442             }
443             return;
444         }
445 
446         createOutNetBuffer(src.remaining());
447 
448         // Loop until there is no more data in src
449         while (src.hasRemaining()) {
450 
451             SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf());
452             
453             if (result.getStatus() == SSLEngineResult.Status.OK) {
454                 if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
455                     doTasks();
456                 }
457             } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
458                 outNetBuffer.capacity(outNetBuffer.capacity() << 1);
459                 outNetBuffer.limit(outNetBuffer.capacity());
460             } else {
461                 throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src
462                         + "outNetBuffer: " + outNetBuffer);
463             }
464         }
465 
466         outNetBuffer.flip();
467     }
468 
469     /**
470      * Start SSL shutdown process.
471      * 
472      * @return <tt>true</tt> if shutdown process is started. <tt>false</tt> if
473      *         shutdown process is already finished.
474      * @throws SSLException
475      *             on errors
476      */
477     /* no qualifier */boolean closeOutbound() throws SSLException {
478         if (sslEngine == null || sslEngine.isOutboundDone()) {
479             return false;
480         }
481 
482         sslEngine.closeOutbound();
483 
484         createOutNetBuffer(0);
485         SSLEngineResult result;
486 
487         for (;;) {
488             result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
489             if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
490                 outNetBuffer.capacity(outNetBuffer.capacity() << 1);
491                 outNetBuffer.limit(outNetBuffer.capacity());
492             } else {
493                 break;
494             }
495         }
496 
497         if (result.getStatus() != SSLEngineResult.Status.CLOSED) {
498             throw new SSLException("Improper close state: " + result);
499         }
500 
501         outNetBuffer.flip();
502 
503         return true;
504     }
505 
506     /**
507      * @param res
508      * @throws SSLException
509      */
510     private void checkStatus(SSLEngineResult res) throws SSLException {
511 
512         SSLEngineResult.Status status = res.getStatus();
513 
514         /*
515          * The status may be:
516          * OK - Normal operation
517          * OVERFLOW - Should never happen since the application buffer is sized to hold the maximum
518          * packet size.
519          * UNDERFLOW - Need to read more data from the socket. It's normal.
520          * CLOSED - The other peer closed the socket. Also normal.
521          */
522         switch (status) {
523             case BUFFER_OVERFLOW:
524                 throw new SSLException("SSLEngine error during decrypt: " + status + " inNetBuffer: " + inNetBuffer
525                     + "appBuffer: " + appBuffer);
526             case CLOSED:
527                 Exception exception =new RuntimeIoException("SSL/TLS close_notify received");
528                 
529                 // Empty the Ssl queue
530                 for (IoFilterEvent event:filterWriteEventQueue) {
531                     EncryptedWriteRequest writeRequest = (EncryptedWriteRequest)event.getParameter();
532                     WriteFuture writeFuture = writeRequest.getParentRequest().getFuture();
533                     writeFuture.setException(exception);
534                     writeFuture.notifyAll();
535                 }
536                 
537                 // Empty the session queue
538                 WriteRequestQueue queue = session.getWriteRequestQueue();
539                 WriteRequest request = null;
540                
541     	    	while ((request = queue.poll(session)) != null) {
542     	    	    WriteFuture writeFuture = request.getFuture();
543     	    	    writeFuture.setException(exception);
544     	    	    writeFuture.notifyAll();
545         	}
546                     
547                 // We *must* shutdown session
548                 session.closeNow();
549                 break;
550             default: 
551                 break;
552         }
553     }
554 
555     /**
556      * Perform any handshaking processing.
557      */
558     /* no qualifier */void handshake(NextFilter nextFilter) throws SSLException {
559         for (;;) {
560             switch (handshakeStatus) {
561             case FINISHED:
562                 if (LOGGER.isDebugEnabled()) {
563                     LOGGER.debug("{} processing the FINISHED state", sslFilter.getSessionInfo(session));
564                 }
565 
566                 session.setAttribute(SslFilter.SSL_SESSION, sslEngine.getSession());
567                 handshakeComplete = true;
568 
569                 // Send the SECURE message only if it's the first SSL handshake
570                 if (firstSSLNegociation) {
571                     firstSSLNegociation = false;
572                     
573                     nextFilter.event(session, SslEvent.SECURED);
574                 }
575 
576                 if (LOGGER.isDebugEnabled()) {
577                     if (!isOutboundDone()) {
578                         LOGGER.debug("{} is now secured", sslFilter.getSessionInfo(session));
579                     } else {
580                         LOGGER.debug("{} is not secured yet", sslFilter.getSessionInfo(session));
581                     }
582                 }
583 
584                 return;
585 
586             case NEED_TASK:
587                 if (LOGGER.isDebugEnabled()) {
588                     LOGGER.debug("{} processing the NEED_TASK state", sslFilter.getSessionInfo(session));
589                 }
590 
591                 handshakeStatus = doTasks();
592                 break;
593 
594             case NEED_UNWRAP:
595                 if (LOGGER.isDebugEnabled()) {
596                     LOGGER.debug("{} processing the NEED_UNWRAP state", sslFilter.getSessionInfo(session));
597                 }
598                 // we need more data read
599                 SSLEngineResult.Status status = unwrapHandshake(nextFilter);
600 
601                 if (status == SSLEngineResult.Status.BUFFER_UNDERFLOW
602                         && handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED || isInboundDone()) {
603                     // We need more data or the session is closed
604                     return;
605                 }
606 
607                 break;
608 
609             case NEED_WRAP:
610             case NOT_HANDSHAKING:
611                 if (LOGGER.isDebugEnabled()) {
612                     LOGGER.debug("{} processing the NEED_WRAP state", sslFilter.getSessionInfo(session));
613                 }
614 
615                 // First make sure that the out buffer is completely empty.
616                 // Since we cannot call wrap with data left on the buffer
617                 if (outNetBuffer != null && outNetBuffer.hasRemaining()) {
618                     return;
619                 }
620 
621                 SSLEngineResult result;
622                 createOutNetBuffer(0);
623 
624                 result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
625 
626                 while ( result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW ) {
627                     outNetBuffer.capacity(outNetBuffer.capacity() << 1);
628                     outNetBuffer.limit(outNetBuffer.capacity());
629 
630                     result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
631                 }
632 
633                 outNetBuffer.flip();
634                 handshakeStatus = result.getHandshakeStatus();
635                 writeNetBuffer(nextFilter);
636                 break;
637 
638             default:
639                 String msg = "Invalid Handshaking State" + handshakeStatus
640                 + " while processing the Handshake for session " + session.getId();
641                 LOGGER.error(msg);
642                 throw new IllegalStateException(msg);
643             }
644         }
645     }
646 
647     private void createOutNetBuffer(int expectedRemaining) {
648         // SSLEngine requires us to allocate unnecessarily big buffer
649         // even for small data. *Shrug*
650         int capacity = Math.max(expectedRemaining, sslEngine.getSession().getPacketBufferSize());
651 
652         if (outNetBuffer != null) {
653             outNetBuffer.capacity(capacity);
654         } else {
655             outNetBuffer = IoBuffer.allocate(capacity).minimumCapacity(0);
656         }
657     }
658 
659     /* no qualifier */WriteFuture writeNetBuffer(NextFilter nextFilter) throws SSLException {
660         // Check if any net data needed to be writen
661         if (outNetBuffer == null || !outNetBuffer.hasRemaining()) {
662             // no; bail out
663             return null;
664         }
665 
666         // set flag that we are writing encrypted data
667         // (used in SSLFilter.filterWrite())
668         writingEncryptedData = true;
669 
670         // write net data
671         WriteFuture writeFuture = null;
672 
673         try {
674             IoBuffer writeBuffer = fetchOutNetBuffer();
675             writeFuture = new DefaultWriteFuture(session);
676             sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(writeBuffer, writeFuture));
677 
678             // loop while more writes required to complete handshake
679             while (needToCompleteHandshake()) {
680                 try {
681                     handshake(nextFilter);
682                 } catch (SSLException ssle) {
683                     SSLException newSsle = new SSLHandshakeException("SSL handshake failed.");
684                     newSsle.initCause(ssle);
685                     throw newSsle;
686                 }
687 
688                 IoBuffer currentOutNetBuffer = fetchOutNetBuffer();
689                 
690                 if (currentOutNetBuffer != null && currentOutNetBuffer.hasRemaining()) {
691                     writeFuture = new DefaultWriteFuture(session);
692                     sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(currentOutNetBuffer, writeFuture));
693                 }
694             }
695         } finally {
696             writingEncryptedData = false;
697         }
698 
699         return writeFuture;
700     }
701 
702     private SSLEngineResult.Status unwrapHandshake(NextFilter nextFilter) throws SSLException {
703         // Prepare the net data for reading.
704         if (inNetBuffer != null) {
705             inNetBuffer.flip();
706         }
707 
708         if ((inNetBuffer == null) || !inNetBuffer.hasRemaining()) {
709             // Need more data.
710             return SSLEngineResult.Status.BUFFER_UNDERFLOW;
711         }
712 
713         SSLEngineResult res = unwrap();
714         handshakeStatus = res.getHandshakeStatus();
715 
716         checkStatus(res);
717 
718         // If handshake finished, no data was produced, and the status is still
719         // ok, try to unwrap more
720         if ((handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
721                 && (res.getStatus() == SSLEngineResult.Status.OK)
722                 && inNetBuffer.hasRemaining()) {
723             res = unwrap();
724 
725             // prepare to be written again
726             if (inNetBuffer.hasRemaining()) {
727                 inNetBuffer.compact();
728             } else {
729                 inNetBuffer.free();
730                 inNetBuffer = null;
731             }
732 
733             renegotiateIfNeeded(nextFilter, res);
734         } else {
735             // prepare to be written again
736             if (inNetBuffer.hasRemaining()) {
737                 inNetBuffer.compact();
738             } else {
739                 inNetBuffer.free();
740                 inNetBuffer = null;
741             }
742         }
743 
744         return res.getStatus();
745     }
746 
747     private void renegotiateIfNeeded(NextFilter nextFilter, SSLEngineResult res) throws SSLException {
748         if ((res.getStatus() != SSLEngineResult.Status.CLOSED)
749                 && (res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW)
750                 && (res.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
751             // Renegotiation required.
752             handshakeComplete = false;
753             handshakeStatus = res.getHandshakeStatus();
754             handshake(nextFilter);
755         }
756     }
757 
758     /**
759      * Decrypt the incoming buffer and move the decrypted data to an
760      * application buffer.
761      */
762     private SSLEngineResult unwrap() throws SSLException {
763         // We first have to create the application buffer if it does not exist
764         if (appBuffer == null) {
765             appBuffer = IoBuffer.allocate(inNetBuffer.remaining());
766         } else {
767             // We already have one, just add the new data into it
768             appBuffer.expand(inNetBuffer.remaining());
769         }
770 
771         SSLEngineResult res;
772         Status status;
773         HandshakeStatus localHandshakeStatus;
774 
775         do {
776             // Decode the incoming data
777             res = sslEngine.unwrap(inNetBuffer.buf(), appBuffer.buf());
778             status = res.getStatus();
779 
780             // We can be processing the Handshake
781             localHandshakeStatus = res.getHandshakeStatus();
782 
783             if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) {
784                 // We have to grow the target buffer, it's too small.
785                 // Then we can call the unwrap method again
786                 int newCapacity = sslEngine.getSession().getApplicationBufferSize();
787                 
788                 if (appBuffer.remaining() >= newCapacity) {
789                     // The buffer is already larger than the max buffer size suggested by the SSL engine.
790                     // Raising it any more will not make sense and it will end up in an endless loop. Throwing an error is safer
791                     throw new SSLException("SSL buffer overflow");
792                 }
793 
794                 appBuffer.expand(newCapacity);
795                 continue;
796             }
797         } while (((status == SSLEngineResult.Status.OK) || (status == SSLEngineResult.Status.BUFFER_OVERFLOW))
798                 && ((localHandshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) || 
799                         (localHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)));
800 
801         return res;
802     }
803 
804     /**
805      * Do all the outstanding handshake tasks in the current Thread.
806      */
807     private SSLEngineResult.HandshakeStatus doTasks() {
808         /*
809          * We could run this in a separate thread, but I don't see the need for
810          * this when used from SSLFilter. Use thread filters in MINA instead?
811          */
812         Runnable runnable;
813         while ((runnable = sslEngine.getDelegatedTask()) != null) {
814             // TODO : we may have to use a thread pool here to improve the
815             // performances
816             runnable.run();
817         }
818         return sslEngine.getHandshakeStatus();
819     }
820 
821     /**
822      * Creates a new MINA buffer that is a deep copy of the remaining bytes in
823      * the given buffer (between index buf.position() and buf.limit())
824      * 
825      * @param src
826      *            the buffer to copy
827      * @return the new buffer, ready to read from
828      */
829     /* no qualifier */static IoBuffer copy(ByteBuffer src) {
830         IoBuffer copy = IoBuffer.allocate(src.remaining());
831         copy.put(src);
832         copy.flip();
833         return copy;
834     }
835 
836     /**
837      * {@inheritDoc}
838      */
839     @Override
840     public String toString() {
841         StringBuilder sb = new StringBuilder();
842 
843         sb.append("SSLStatus <");
844 
845         if (handshakeComplete) {
846             sb.append("SSL established");
847         } else {
848             sb.append("Processing Handshake").append("; ");
849             sb.append("Status : ").append(handshakeStatus).append("; ");
850         }
851 
852         sb.append(", ");
853         sb.append("HandshakeComplete :").append(handshakeComplete).append(", ");
854         sb.append(">");
855 
856         return sb.toString();
857     }
858 
859     /**
860      * Free the allocated buffers
861      */
862     /* no qualifier */void release() {
863         if (inNetBuffer != null) {
864             inNetBuffer.free();
865             inNetBuffer = null;
866         }
867 
868         if (outNetBuffer != null) {
869             outNetBuffer.free();
870             outNetBuffer = null;
871         }
872     }
873 }