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 }