View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.io.ssl;
20  
21  import java.io.IOException;
22  import java.nio.ByteBuffer;
23  import java.nio.channels.ClosedChannelException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.concurrent.Executor;
27  
28  import javax.net.ssl.SSLEngine;
29  import javax.net.ssl.SSLEngineResult;
30  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
31  import javax.net.ssl.SSLEngineResult.Status;
32  import javax.net.ssl.SSLException;
33  import javax.net.ssl.SSLHandshakeException;
34  
35  import org.eclipse.jetty.io.AbstractConnection;
36  import org.eclipse.jetty.io.AbstractEndPoint;
37  import org.eclipse.jetty.io.ByteBufferPool;
38  import org.eclipse.jetty.io.Connection;
39  import org.eclipse.jetty.io.EndPoint;
40  import org.eclipse.jetty.io.EofException;
41  import org.eclipse.jetty.io.SelectChannelEndPoint;
42  import org.eclipse.jetty.io.WriteFlusher;
43  import org.eclipse.jetty.util.BufferUtil;
44  import org.eclipse.jetty.util.Callback;
45  import org.eclipse.jetty.util.log.Log;
46  import org.eclipse.jetty.util.log.Logger;
47  
48  /**
49   * A Connection that acts as an interceptor between an EndPoint providing SSL encrypted data
50   * and another consumer of an EndPoint (typically an {@link Connection} like HttpConnection) that
51   * wants unencrypted data.
52   * <p>
53   * The connector uses an {@link EndPoint} (typically {@link SelectChannelEndPoint}) as
54   * it's source/sink of encrypted data.   It then provides an endpoint via {@link #getDecryptedEndPoint()} to
55   * expose a source/sink of unencrypted data to another connection (eg HttpConnection).
56   * <p>
57   * The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any
58   * asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
59   * <p>
60   * The passive methods are {@link DecryptedEndPoint#fill(ByteBuffer)} and {@link DecryptedEndPoint#flush(ByteBuffer...)}. They make best
61   * effort attempts to progress the connection using only calls to the encrypted {@link EndPoint#fill(ByteBuffer)} and {@link EndPoint#flush(ByteBuffer...)}
62   * methods.  They will never block nor schedule any readInterest or write callbacks.   If a fill/flush cannot progress either because
63   * of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
64   * Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
65   * encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Callback)}.
66   * <p>
67   * It is only the active methods : {@link DecryptedEndPoint#fillInterested(Callback)} and
68   * {@link DecryptedEndPoint#write(Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
69   * {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Callback, ByteBuffer...)}
70   * methods.  For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
71   * write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
72   * to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
73   * <p>
74   * MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing
75   * themselves.  Instead they simple make the callbacks to the decrypted callbacks, so that the passive encrypted fill/flush will
76   * be called again and make another best effort attempt to progress the connection.
77   *
78   */
79  public class SslConnection extends AbstractConnection
80  {
81      private static final Logger LOG = Log.getLogger(SslConnection.class);
82      private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0);
83      private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0);
84  
85      private final List<SslHandshakeListener> handshakeListeners = new ArrayList<>();
86      private final ByteBufferPool _bufferPool;
87      private final SSLEngine _sslEngine;
88      private final DecryptedEndPoint _decryptedEndPoint;
89      private ByteBuffer _decryptedInput;
90      private ByteBuffer _encryptedInput;
91      private ByteBuffer _encryptedOutput;
92      private final boolean _encryptedDirectBuffers = true;
93      private final boolean _decryptedDirectBuffers = false;
94      private boolean _renegotiationAllowed;
95      private boolean _closedOutbound;
96      private final Runnable _runCompletWrite = new Runnable()
97      {
98          @Override
99          public void run()
100         {
101             _decryptedEndPoint.getWriteFlusher().completeWrite();
102         }
103     };
104     private final Runnable _runFillable = new Runnable()
105     {
106         @Override
107         public void run()
108         {
109             _decryptedEndPoint.getFillInterest().fillable();
110         }
111     };
112 
113     public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine)
114     {
115         // This connection does not execute calls to onFillable(), so they will be called by the selector thread.
116         // onFillable() does not block and will only wakeup another thread to do the actual reading and handling.
117         super(endPoint, executor);
118         this._bufferPool = byteBufferPool;
119         this._sslEngine = sslEngine;
120         this._decryptedEndPoint = newDecryptedEndPoint();
121     }
122 
123     public void addHandshakeListener(SslHandshakeListener listener)
124     {
125         handshakeListeners.add(listener);
126     }
127 
128     public boolean removeHandshakeListener(SslHandshakeListener listener)
129     {
130         return handshakeListeners.remove(listener);
131     }
132 
133     protected DecryptedEndPoint newDecryptedEndPoint()
134     {
135         return new DecryptedEndPoint();
136     }
137 
138     public SSLEngine getSSLEngine()
139     {
140         return _sslEngine;
141     }
142 
143     public DecryptedEndPoint getDecryptedEndPoint()
144     {
145         return _decryptedEndPoint;
146     }
147 
148     public boolean isRenegotiationAllowed()
149     {
150         return _renegotiationAllowed;
151     }
152 
153     public void setRenegotiationAllowed(boolean renegotiationAllowed)
154     {
155         this._renegotiationAllowed = renegotiationAllowed;
156     }
157 
158     @Override
159     public void onOpen()
160     {
161         super.onOpen();
162         getDecryptedEndPoint().getConnection().onOpen();
163     }
164 
165     @Override
166     public void onClose()
167     {
168         _decryptedEndPoint.getConnection().onClose();
169         super.onClose();
170     }
171 
172     @Override
173     public void close()
174     {
175         getDecryptedEndPoint().getConnection().close();
176     }
177 
178     @Override
179     public boolean onIdleExpired()
180     {
181         return getDecryptedEndPoint().getConnection().onIdleExpired();
182     }
183 
184     @Override
185     public void onFillable()
186     {
187         // onFillable means that there are encrypted bytes ready to be filled.
188         // however we do not fill them here on this callback, but instead wakeup
189         // the decrypted readInterest and/or writeFlusher so that they will attempt
190         // to do the fill and/or flush again and these calls will do the actually
191         // filling.
192 
193         if (LOG.isDebugEnabled())
194             LOG.debug("onFillable enter {}", _decryptedEndPoint);
195 
196         // We have received a close handshake, close the end point to send FIN.
197         if (_decryptedEndPoint.isInputShutdown())
198             _decryptedEndPoint.close();
199 
200         // wake up whoever is doing the fill or the flush so they can
201         // do all the filling, unwrapping, wrapping and flushing
202         _decryptedEndPoint.getFillInterest().fillable();
203 
204         // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
205         synchronized(_decryptedEndPoint)
206         {
207             if (_decryptedEndPoint._flushRequiresFillToProgress)
208             {
209                 _decryptedEndPoint._flushRequiresFillToProgress = false;
210                 _runCompletWrite.run();
211             }
212         }
213 
214         if (LOG.isDebugEnabled())
215             LOG.debug("onFillable exit {}", _decryptedEndPoint);
216     }
217 
218     @Override
219     public void onFillInterestedFailed(Throwable cause)
220     {
221         // this means that the fill interest in encrypted bytes has failed.
222         // However we do not handle that here on this callback, but instead wakeup
223         // the decrypted readInterest and/or writeFlusher so that they will attempt
224         // to do the fill and/or flush again and these calls will do the actually
225         // handle the cause.
226         _decryptedEndPoint.getFillInterest().onFail(cause);
227 
228         boolean failFlusher = false;
229         synchronized(_decryptedEndPoint)
230         {
231             if (_decryptedEndPoint._flushRequiresFillToProgress)
232             {
233                 _decryptedEndPoint._flushRequiresFillToProgress = false;
234                 failFlusher = true;
235             }
236         }
237         if (failFlusher)
238             _decryptedEndPoint.getWriteFlusher().onFail(cause);
239     }
240 
241     @Override
242     public String toString()
243     {
244         ByteBuffer b = _encryptedInput;
245         int ei=b==null?-1:b.remaining();
246         b = _encryptedOutput;
247         int eo=b==null?-1:b.remaining();
248         b = _decryptedInput;
249         int di=b==null?-1:b.remaining();
250 
251         return String.format("SslConnection@%x{%s,eio=%d/%d,di=%d} -> %s",
252                 hashCode(),
253                 _sslEngine.getHandshakeStatus(),
254                 ei,eo,di,
255                 _decryptedEndPoint.getConnection());
256     }
257 
258     public class DecryptedEndPoint extends AbstractEndPoint
259     {
260         private boolean _fillRequiresFlushToProgress;
261         private boolean _flushRequiresFillToProgress;
262         private boolean _cannotAcceptMoreAppDataToFlush;
263         private boolean _handshaken;
264         private boolean _underFlown;
265 
266         private final Callback _writeCallback = new Callback()
267         {
268             @Override
269             public void succeeded()
270             {
271                 // This means that a write of encrypted data has completed.  Writes are done
272                 // only if there is a pending writeflusher or a read needed to write
273                 // data.  In either case the appropriate callback is passed on.
274                 boolean fillable = false;
275                 synchronized (DecryptedEndPoint.this)
276                 {
277                     if (LOG.isDebugEnabled())
278                         LOG.debug("write.complete {}", SslConnection.this.getEndPoint());
279 
280                     releaseEncryptedOutputBuffer();
281 
282                     _cannotAcceptMoreAppDataToFlush = false;
283 
284                     if (_fillRequiresFlushToProgress)
285                     {
286                         _fillRequiresFlushToProgress = false;
287                         fillable = true;
288                     }
289                 }
290                 if (fillable)
291                     getFillInterest().fillable();
292                 _runCompletWrite.run();
293             }
294 
295             @Override
296             public void failed(final Throwable x)
297             {
298                 // This means that a write of data has failed.  Writes are done
299                 // only if there is an active writeflusher or a read needed to write
300                 // data.  In either case the appropriate callback is passed on.
301                 boolean fail_filler = false;
302                 synchronized (DecryptedEndPoint.this)
303                 {
304                     if (LOG.isDebugEnabled())
305                         LOG.debug("{} write.failed", SslConnection.this, x);
306                     BufferUtil.clear(_encryptedOutput);
307                     releaseEncryptedOutputBuffer();
308 
309                     _cannotAcceptMoreAppDataToFlush = false;
310 
311                     if (_fillRequiresFlushToProgress)
312                     {
313                         _fillRequiresFlushToProgress = false;
314                         fail_filler = true;
315                     }
316                 }
317 
318                 final boolean filler_failed=fail_filler;
319 
320                 failedCallback(new Callback()
321                 {
322                     @Override
323                     public void failed(Throwable x)
324                     {
325                         if (filler_failed)
326                             getFillInterest().onFail(x);
327                         getWriteFlusher().onFail(x);
328                     }
329                 },x);
330             }
331         };
332 
333         public DecryptedEndPoint()
334         {
335             // Disable idle timeout checking: no scheduler and -1 timeout for this instance.
336             super(null, getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
337             super.setIdleTimeout(-1);
338         }
339 
340         @Override
341         public long getIdleTimeout()
342         {
343             return getEndPoint().getIdleTimeout();
344         }
345 
346         @Override
347         public void setIdleTimeout(long idleTimeout)
348         {
349             getEndPoint().setIdleTimeout(idleTimeout);
350         }
351 
352         @Override
353         public boolean isOpen()
354         {
355             return getEndPoint().isOpen();
356         }
357 
358         @Override
359         protected WriteFlusher getWriteFlusher()
360         {
361             return super.getWriteFlusher();
362         }
363 
364         @Override
365         protected void onIncompleteFlush()
366         {
367             // This means that the decrypted endpoint write method was called and not
368             // all data could be wrapped. So either we need to write some encrypted data,
369             // OR if we are handshaking we need to read some encrypted data OR
370             // if neither then we should just try the flush again.
371             boolean try_again = false;
372             synchronized (DecryptedEndPoint.this)
373             {
374                 if (LOG.isDebugEnabled())
375                     LOG.debug("onIncompleteFlush {}", SslConnection.this);
376                 // If we have pending output data,
377                 if (BufferUtil.hasContent(_encryptedOutput))
378                 {
379                     // write it
380                     _cannotAcceptMoreAppDataToFlush = true;
381                     getEndPoint().write(_writeCallback, _encryptedOutput);
382                 }
383                 // If we are handshaking and need to read,
384                 else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
385                 {
386                     // check if we are actually read blocked in order to write
387                     _flushRequiresFillToProgress = true;
388 
389                     ensureFillInterested();
390                 }
391                 else
392                 {
393                     // We can get here because the WriteFlusher might not see progress
394                     // when it has just flushed the encrypted data, but not consumed anymore
395                     // of the application buffers.  This is mostly avoided by another iteration
396                     // within DecryptedEndPoint flush(), but I cannot convince myself that
397                     // this is never ever the case.
398                     try_again = true;
399                 }
400             }
401 
402 
403             if (try_again)
404             {
405                 // If the output is closed,
406                 if (isOutputShutdown())
407                 {
408                     // don't bother writing, just notify of close
409                     getWriteFlusher().onClose();
410                 }
411                 // Else,
412                 else
413                 {
414                     // try to flush what is pending
415                     // execute to avoid recursion
416                     getExecutor().execute(_runCompletWrite);
417                 }
418             }
419         }
420 
421         @Override
422         protected void needsFillInterest() throws IOException
423         {
424             // This means that the decrypted data consumer has called the fillInterested
425             // method on the DecryptedEndPoint, so we have to work out if there is
426             // decrypted data to be filled or what callbacks to setup to be told when there
427             // might be more encrypted data available to attempt another call to fill
428 
429             synchronized (DecryptedEndPoint.this)
430             {
431                 // Do we already have some app data, then app can fill now so return true
432                 boolean fillable = (BufferUtil.hasContent(_decryptedInput))
433                         // or if we have encryptedInput and have not underflowed yet, the it is worth trying a fill
434                         || BufferUtil.hasContent(_encryptedInput) && !_underFlown;
435 
436                 // If we have no encrypted data to decrypt OR we have some, but it is not enough
437                 if (!fillable)
438                 {
439                     // We are not ready to read data
440 
441                     // Are we actually write blocked?
442                     if (_fillRequiresFlushToProgress)
443                     {
444                         // we must be blocked trying to write before we can read
445 
446                         // Do we have data to write
447                         if (BufferUtil.hasContent(_encryptedOutput))
448                         {
449                             // write it
450                             _cannotAcceptMoreAppDataToFlush = true;
451                             getEndPoint().write(_writeCallback, _encryptedOutput);
452                         }
453                         else
454                         {
455                             // we have already written the net data
456                             // pretend we are readable so the wrap is done by next readable callback
457                             _fillRequiresFlushToProgress = false;
458                             fillable=true;
459                         }
460                     }
461                 }
462 
463                 if (fillable)
464                     getExecutor().execute(_runFillable);
465                 else
466                     ensureFillInterested();
467             }
468         }
469 
470         @Override
471         public void setConnection(Connection connection)
472         {
473             if (connection instanceof AbstractConnection)
474             {
475                 AbstractConnection a = (AbstractConnection)connection;
476                 if (a.getInputBufferSize()<_sslEngine.getSession().getApplicationBufferSize())
477                     a.setInputBufferSize(_sslEngine.getSession().getApplicationBufferSize());
478             }
479             super.setConnection(connection);
480         }
481 
482         public SslConnection getSslConnection()
483         {
484             return SslConnection.this;
485         }
486 
487         @Override
488         public synchronized int fill(ByteBuffer buffer) throws IOException
489         {
490             try
491             {
492                 // Do we already have some decrypted data?
493                 if (BufferUtil.hasContent(_decryptedInput))
494                     return BufferUtil.append(buffer,_decryptedInput);
495 
496                 // We will need a network buffer
497                 if (_encryptedInput == null)
498                     _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
499                 else
500                     BufferUtil.compact(_encryptedInput);
501 
502                 // We also need an app buffer, but can use the passed buffer if it is big enough
503                 ByteBuffer app_in;
504                 if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
505                     app_in = buffer;
506                 else if (_decryptedInput == null)
507                     app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
508                 else
509                     app_in = _decryptedInput;
510 
511                 // loop filling and unwrapping until we have something
512                 while (true)
513                 {
514                     // Let's try reading some encrypted data... even if we have some already.
515                     int net_filled = getEndPoint().fill(_encryptedInput);
516 
517                     decryption: while (true)
518                     {
519                         // Let's unwrap even if we have no net data because in that
520                         // case we want to fall through to the handshake handling
521                         int pos = BufferUtil.flipToFill(app_in);
522                         SSLEngineResult unwrapResult;
523                         try
524                         {
525                             unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
526                         }
527                         finally
528                         {
529                             BufferUtil.flipToFlush(app_in, pos);
530                         }
531                         if (LOG.isDebugEnabled())
532                         {
533                             LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' '));
534                             LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer));
535                         }
536 
537                         HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
538                         HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
539                         Status unwrapResultStatus = unwrapResult.getStatus();
540 
541                         // Extra check on unwrapResultStatus == OK with zero length buffer is due
542                         // to SSL client on android (see bug #454773)
543                         _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0;
544 
545                         if (_underFlown)
546                         {
547                             if (net_filled < 0)
548                                 closeInbound();
549                             if (net_filled <= 0)
550                                 return net_filled;
551                         }
552 
553                         switch (unwrapResultStatus)
554                         {
555                             case CLOSED:
556                             {
557                                 switch (handshakeStatus)
558                                 {
559                                     case NOT_HANDSHAKING:
560                                     {
561                                         // We were not handshaking, so just tell the app we are closed
562                                         return -1;
563                                     }
564                                     case NEED_TASK:
565                                     {
566                                         _sslEngine.getDelegatedTask().run();
567                                         continue;
568                                     }
569                                     case NEED_WRAP:
570                                     {
571                                         // We need to send some handshake data (probably the close handshake).
572                                         // We return -1 so that the application can drive the close by flushing
573                                         // or shutting down the output.
574                                         return -1;
575                                     }
576                                     case NEED_UNWRAP:
577                                     {
578                                         // We expected to read more, but we got closed.
579                                         // Return -1 to indicate to the application to drive the close.
580                                         return -1;
581                                     }
582                                     default:
583                                     {
584                                         throw new IllegalStateException();
585                                     }
586                                 }
587                             }
588                             case BUFFER_UNDERFLOW:
589                             case OK:
590                             {
591                                 if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
592                                 {
593                                     _handshaken = true;
594                                     if (LOG.isDebugEnabled())
595                                         LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
596                                                 _sslEngine.getUseClientMode() ? "client" : "resumed server",
597                                                 _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
598                                     notifyHandshakeSucceeded(_sslEngine);
599                                 }
600 
601                                 // Check whether renegotiation is allowed
602                                 if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
603                                 {
604                                     if (LOG.isDebugEnabled())
605                                         LOG.debug("{} renegotiation denied", SslConnection.this);
606                                     closeInbound();
607                                     return -1;
608                                 }
609 
610                                 // If bytes were produced, don't bother with the handshake status;
611                                 // pass the decrypted data to the application, which will perform
612                                 // another call to fill() or flush().
613                                 if (unwrapResult.bytesProduced() > 0)
614                                 {
615                                     if (app_in == buffer)
616                                         return unwrapResult.bytesProduced();
617                                     return BufferUtil.append(buffer,_decryptedInput);
618                                 }
619 
620                                 switch (handshakeStatus)
621                                 {
622                                     case NOT_HANDSHAKING:
623                                     {
624                                         if (_underFlown)
625                                             break decryption;
626                                         continue;
627                                     }
628                                     case NEED_TASK:
629                                     {
630                                         _sslEngine.getDelegatedTask().run();
631                                         continue;
632                                     }
633                                     case NEED_WRAP:
634                                     {
635                                         // If we are called from flush()
636                                         // return to let it do the wrapping.
637                                         if (buffer == __FLUSH_CALLED_FILL)
638                                             return 0;
639 
640                                         _fillRequiresFlushToProgress = true;
641                                         flush(__FILL_CALLED_FLUSH);
642                                         if (BufferUtil.isEmpty(_encryptedOutput))
643                                         {
644                                             // The flush wrote all the encrypted bytes so continue to fill
645                                             _fillRequiresFlushToProgress = false;
646                                             continue;
647                                         }
648                                         else
649                                         {
650                                             // The flush did not complete, return from fill()
651                                             // and let the write completion mechanism to kick in.
652                                             return 0;
653                                         }
654                                     }
655                                     case NEED_UNWRAP:
656                                     {
657                                         if (_underFlown)
658                                             break decryption;
659                                         continue;
660                                     }
661                                     default:
662                                     {
663                                         throw new IllegalStateException();
664                                     }
665                                 }
666                             }
667                             default:
668                             {
669                                 throw new IllegalStateException();
670                             }
671                         }
672                     }
673                 }
674             }
675             catch (SSLHandshakeException x)
676             {
677                 notifyHandshakeFailed(_sslEngine, x);
678                 close(x);
679                 throw x;
680             }
681             catch (SSLException x)
682             {
683                 if (!_handshaken)
684                 {
685                     x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x);
686                     notifyHandshakeFailed(_sslEngine, x);
687                 }
688                 close(x);
689                 throw x;
690             }
691             catch (Throwable x)
692             {
693                 close(x);
694                 throw x;
695             }
696             finally
697             {
698                 // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
699                 if (_flushRequiresFillToProgress)
700                 {
701                     _flushRequiresFillToProgress = false;
702                     getExecutor().execute(_runCompletWrite);
703                 }
704 
705                 if (_encryptedInput != null && !_encryptedInput.hasRemaining())
706                 {
707                     _bufferPool.release(_encryptedInput);
708                     _encryptedInput = null;
709                 }
710                 if (_decryptedInput != null && !_decryptedInput.hasRemaining())
711                 {
712                     _bufferPool.release(_decryptedInput);
713                     _decryptedInput = null;
714                 }
715             }
716         }
717 
718         private void closeInbound()
719         {
720             try
721             {
722                 _sslEngine.closeInbound();
723             }
724             catch (SSLException x)
725             {
726                 LOG.ignore(x);
727             }
728         }
729 
730         @Override
731         public synchronized boolean flush(ByteBuffer... appOuts) throws IOException
732         {
733             // The contract for flush does not require that all appOuts bytes are written
734             // or even that any appOut bytes are written!  If the connection is write block
735             // or busy handshaking, then zero bytes may be taken from appOuts and this method
736             // will return 0 (even if some handshake bytes were flushed and filled).
737             // it is the applications responsibility to call flush again - either in a busy loop
738             // or better yet by using EndPoint#write to do the flushing.
739 
740             if (LOG.isDebugEnabled())
741             {
742                 for (ByteBuffer b : appOuts)
743                     LOG.debug("{} flush {}", SslConnection.this, BufferUtil.toHexSummary(b));
744             }
745 
746             try
747             {
748                 if (_cannotAcceptMoreAppDataToFlush)
749                 {
750                     if (_sslEngine.isOutboundDone())
751                         throw new EofException(new ClosedChannelException());
752                     return false;
753                 }
754 
755                 // We will need a network buffer
756                 if (_encryptedOutput == null)
757                     _encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
758 
759                 while (true)
760                 {
761                     // We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
762                     BufferUtil.compact(_encryptedOutput);
763                     int pos = BufferUtil.flipToFill(_encryptedOutput);
764                     SSLEngineResult wrapResult;
765                     try
766                     {
767                         wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
768                     }
769                     finally
770                     {
771                         BufferUtil.flipToFlush(_encryptedOutput, pos);
772                     }
773                     if (LOG.isDebugEnabled())
774                         LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' '));
775 
776                     Status wrapResultStatus = wrapResult.getStatus();
777 
778                     boolean allConsumed=true;
779                     for (ByteBuffer b : appOuts)
780                         if (BufferUtil.hasContent(b))
781                             allConsumed=false;
782 
783                     // and deal with the results returned from the sslEngineWrap
784                     switch (wrapResultStatus)
785                     {
786                         case CLOSED:
787                         {
788                             // The SSL engine has close, but there may be close handshake that needs to be written
789                             if (BufferUtil.hasContent(_encryptedOutput))
790                             {
791                                 _cannotAcceptMoreAppDataToFlush = true;
792                                 getEndPoint().flush(_encryptedOutput);
793                                 getEndPoint().shutdownOutput();
794                                 // If we failed to flush the close handshake then we will just pretend that
795                                 // the write has progressed normally and let a subsequent call to flush
796                                 // (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
797                                 // The caller will find out about the close on a subsequent flush or fill.
798                                 if (BufferUtil.hasContent(_encryptedOutput))
799                                     return false;
800                             }
801                             // otherwise we have written, and the caller will close the underlying connection
802                             else
803                             {
804                                 getEndPoint().shutdownOutput();
805                             }
806                             return allConsumed;
807                         }
808                         case BUFFER_UNDERFLOW:
809                         {
810                             throw new IllegalStateException();
811                         }
812                         default:
813                         {
814                             if (LOG.isDebugEnabled())
815                                 LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
816 
817                             if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
818                             {
819                                 _handshaken = true;
820                                 if (LOG.isDebugEnabled())
821                                     LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
822                                             _sslEngine.getUseClientMode() ? "resumed client" : "server",
823                                             _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
824                                 notifyHandshakeSucceeded(_sslEngine);
825                             }
826 
827                             HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
828 
829                             // Check whether renegotiation is allowed
830                             if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
831                             {
832                                 if (LOG.isDebugEnabled())
833                                     LOG.debug("{} renegotiation denied", SslConnection.this);
834                                 getEndPoint().shutdownOutput();
835                                 return allConsumed;
836                             }
837 
838                             // if we have net bytes, let's try to flush them
839                             if (BufferUtil.hasContent(_encryptedOutput))
840                                 if (!getEndPoint().flush(_encryptedOutput))
841                                     getEndPoint().flush(_encryptedOutput); // one retry
842 
843                             // But we also might have more to do for the handshaking state.
844                             switch (handshakeStatus)
845                             {
846                                 case NOT_HANDSHAKING:
847                                     // If we have not consumed all and had just finished handshaking, then we may
848                                     // have just flushed the last handshake in the encrypted buffers, so we should
849                                     // try again.
850                                     if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
851                                         continue;
852 
853                                     // Return true if we consumed all the bytes and encrypted are all flushed
854                                     return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
855 
856                                 case NEED_TASK:
857                                     // run the task and continue
858                                     _sslEngine.getDelegatedTask().run();
859                                     continue;
860 
861                                 case NEED_WRAP:
862                                     // Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
863                                     continue;
864 
865                                 case NEED_UNWRAP:
866                                     // Ah we need to fill some data so we can write.
867                                     // So if we were not called from fill and the app is not reading anyway
868                                     if (appOuts[0]!=__FILL_CALLED_FLUSH && !getFillInterest().isInterested())
869                                     {
870                                         // Tell the onFillable method that there might be a write to complete
871                                         _flushRequiresFillToProgress = true;
872                                         fill(__FLUSH_CALLED_FILL);
873                                         // Check if after the fill() we need to wrap again
874                                         if (handshakeStatus == HandshakeStatus.NEED_WRAP)
875                                             continue;
876                                     }
877                                     return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
878 
879                                 case FINISHED:
880                                     throw new IllegalStateException();
881                             }
882                         }
883                     }
884                 }
885             }
886             catch (SSLHandshakeException x)
887             {
888                 notifyHandshakeFailed(_sslEngine, x);
889                 close(x);
890                 throw x;
891             }
892             catch (Throwable x)
893             {
894                 close(x);
895                 throw x;
896             }
897             finally
898             {
899                 releaseEncryptedOutputBuffer();
900             }
901         }
902 
903         private void releaseEncryptedOutputBuffer()
904         {
905             if (!Thread.holdsLock(DecryptedEndPoint.this))
906                 throw new IllegalStateException();
907             if (_encryptedOutput != null && !_encryptedOutput.hasRemaining())
908             {
909                 _bufferPool.release(_encryptedOutput);
910                 _encryptedOutput = null;
911             }
912         }
913 
914         @Override
915         public void shutdownOutput()
916         {
917             try
918             {
919                 synchronized (this)
920                 {
921                     boolean ishut = isInputShutdown();
922                     boolean oshut = isOutputShutdown();
923                     if (LOG.isDebugEnabled())
924                         LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, oshut, ishut);
925                     
926                     if (!oshut)
927                     {
928                         if (!_closedOutbound)
929                         {
930                             _closedOutbound=true; // Only attempt this once
931                             _sslEngine.closeOutbound();
932                             flush(BufferUtil.EMPTY_BUFFER); // Send the TLS close message.
933                         }
934                         if (ishut)
935                             getEndPoint().close();
936                         else
937                             ensureFillInterested();
938                     }
939                 }
940             }
941             catch (Throwable x)
942             {
943                 LOG.ignore(x);
944                 getEndPoint().close();
945             }
946         }
947 
948         private void ensureFillInterested()
949         {
950             if (!SslConnection.this.isFillInterested())
951                 SslConnection.this.fillInterested();
952         }
953 
954         @Override
955         public boolean isOutputShutdown()
956         {
957             return _sslEngine.isOutboundDone() || getEndPoint().isOutputShutdown();
958         }
959 
960         @Override
961         public void close()
962         {
963             // First send the TLS Close Alert, then the FIN.
964             shutdownOutput();
965             getEndPoint().close();
966             super.close();
967         }
968 
969         protected void close(Throwable failure)
970         {
971             // First send the TLS Close Alert, then the FIN.
972             shutdownOutput();
973             getEndPoint().close();
974             super.close(failure);
975         }
976 
977         @Override
978         public Object getTransport()
979         {
980             return getEndPoint();
981         }
982 
983         @Override
984         public boolean isInputShutdown()
985         {
986             return _sslEngine.isInboundDone();
987         }
988 
989         private void notifyHandshakeSucceeded(SSLEngine sslEngine)
990         {
991             SslHandshakeListener.Event event = null;
992             for (SslHandshakeListener listener : handshakeListeners)
993             {
994                 if (event == null)
995                     event = new SslHandshakeListener.Event(sslEngine);
996                 try
997                 {
998                     listener.handshakeSucceeded(event);
999                 }
1000                 catch (Throwable x)
1001                 {
1002                     LOG.info("Exception while notifying listener " + listener, x);
1003                 }
1004             }
1005         }
1006 
1007         private void notifyHandshakeFailed(SSLEngine sslEngine, Throwable failure)
1008         {
1009             SslHandshakeListener.Event event = null;
1010             for (SslHandshakeListener listener : handshakeListeners)
1011             {
1012                 if (event == null)
1013                     event = new SslHandshakeListener.Event(sslEngine);
1014                 try
1015                 {
1016                     listener.handshakeFailed(event, failure);
1017                 }
1018                 catch (Throwable x)
1019                 {
1020                     LOG.info("Exception while notifying listener " + listener, x);
1021                 }
1022             }
1023         }
1024 
1025         @Override
1026         public String toString()
1027         {
1028             return super.toString()+"->"+getEndPoint().toString();
1029         }
1030     }
1031 }