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