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