1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.io.nio;
15
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18 import java.nio.channels.SelectionKey;
19 import java.nio.channels.SocketChannel;
20 import javax.net.ssl.SSLEngine;
21 import javax.net.ssl.SSLEngineResult;
22 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
23 import javax.net.ssl.SSLException;
24 import javax.net.ssl.SSLSession;
25
26 import org.eclipse.jetty.io.Buffer;
27 import org.eclipse.jetty.io.Buffers;
28 import org.eclipse.jetty.io.EofException;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31
32
33
34
35
36
37
38
39
40
41
42 public class SslSelectChannelEndPoint extends SelectChannelEndPoint
43 {
44 public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio").getLogger("ssl");
45
46 private static final ByteBuffer[] __NO_BUFFERS={};
47
48 private final Buffers _buffers;
49
50 private final SSLEngine _engine;
51 private final SSLSession _session;
52 private volatile NIOBuffer _inNIOBuffer;
53 private volatile NIOBuffer _outNIOBuffer;
54
55 private final ByteBuffer[] _gather=new ByteBuffer[2];
56
57 private boolean _closing=false;
58 private SSLEngineResult _result;
59
60 private boolean _handshook=false;
61 private boolean _allowRenegotiate=false;
62
63 private final boolean _debug = __log.isDebugEnabled();
64
65
66 public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine, int maxIdleTime)
67 throws IOException
68 {
69 super(channel,selectSet,key, maxIdleTime);
70 _buffers=buffers;
71
72
73 _engine=engine;
74 _session=engine.getSession();
75
76 if (_debug) __log.debug(_session+" channel="+channel);
77 }
78
79
80 public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine)
81 throws IOException
82 {
83 super(channel,selectSet,key);
84 _buffers=buffers;
85
86
87 _engine=engine;
88 _session=engine.getSession();
89
90 if (_debug) __log.debug(_session+" channel="+channel);
91 }
92
93 int _outCount;
94
95
96 private void needOutBuffer()
97 {
98 synchronized (this)
99 {
100 _outCount++;
101 if (_outNIOBuffer==null)
102 _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
103 }
104 }
105
106
107 private void freeOutBuffer()
108 {
109 synchronized (this)
110 {
111 if (--_outCount<=0 && _outNIOBuffer!=null && _outNIOBuffer.length()==0)
112 {
113 _buffers.returnBuffer(_outNIOBuffer);
114 _outNIOBuffer=null;
115 _outCount=0;
116 }
117 }
118 }
119
120 int _inCount;
121
122 private void needInBuffer()
123 {
124 synchronized (this)
125 {
126 _inCount++;
127 if(_inNIOBuffer==null)
128 _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
129 }
130 }
131
132
133 private void freeInBuffer()
134 {
135 synchronized (this)
136 {
137 if (--_inCount<=0 &&_inNIOBuffer!=null && _inNIOBuffer.length()==0)
138 {
139 _buffers.returnBuffer(_inNIOBuffer);
140 _inNIOBuffer=null;
141 _inCount=0;
142 }
143 }
144 }
145
146
147
148
149
150 public boolean isAllowRenegotiate()
151 {
152 return _allowRenegotiate;
153 }
154
155
156
157
158
159
160
161
162
163 public void setAllowRenegotiate(boolean allowRenegotiate)
164 {
165 _allowRenegotiate = allowRenegotiate;
166 }
167
168
169
170 @Override
171 public boolean isOutputShutdown()
172 {
173 return _engine!=null && _engine.isOutboundDone();
174 }
175
176
177 @Override
178 public boolean isInputShutdown()
179 {
180 return _engine!=null && _engine.isInboundDone();
181 }
182
183
184 @Override
185 public void shutdownOutput() throws IOException
186 {
187 try
188 {
189 sslClose();
190 }
191 finally
192 {
193 super.shutdownOutput();
194 }
195 }
196
197
198 protected void sslClose() throws IOException
199 {
200 if (_closing)
201 return;
202 _closing=true;
203
204
205 long end=System.currentTimeMillis()+getMaxIdleTime();
206 try
207 {
208 while (isOpen() && isBufferingOutput()&& System.currentTimeMillis()<end)
209 {
210 flush();
211 if (isBufferingOutput())
212 {
213 Thread.sleep(50);
214 flush();
215 }
216 }
217
218 _engine.closeOutbound();
219
220 loop: while (isOpen() && !(_engine.isInboundDone() && _engine.isOutboundDone()) && System.currentTimeMillis()<end)
221 {
222 while (isOpen() && isBufferingOutput() && System.currentTimeMillis()<end)
223 {
224 flush();
225 if (isBufferingOutput())
226 Thread.sleep(50);
227 }
228
229 if (_debug) __log.debug(_session+" closing "+_engine.getHandshakeStatus());
230 switch(_engine.getHandshakeStatus())
231 {
232 case FINISHED:
233 case NOT_HANDSHAKING:
234 _handshook=true;
235 break loop;
236
237 case NEED_UNWRAP:
238 Buffer buffer =_buffers.getBuffer(_engine.getSession().getApplicationBufferSize());
239 try
240 {
241 ByteBuffer bbuffer = ((NIOBuffer)buffer).getByteBuffer();
242 if (!unwrap(bbuffer) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
243 {
244 break loop;
245 }
246 }
247 catch(SSLException e)
248 {
249 super.close();
250 Log.ignore(e);
251 }
252 finally
253 {
254 _buffers.returnBuffer(buffer);
255 }
256 break;
257
258 case NEED_TASK:
259 {
260 Runnable task;
261 while ((task=_engine.getDelegatedTask())!=null)
262 {
263 task.run();
264 }
265 break;
266 }
267
268 case NEED_WRAP:
269 {
270 needOutBuffer();
271 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
272 try
273 {
274 if (_outNIOBuffer.length()>0)
275 flush();
276 _outNIOBuffer.compact();
277 int put=_outNIOBuffer.putIndex();
278 out_buffer.position(put);
279 _result=null;
280 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
281 if (_debug) __log.debug(_session+" close wrap "+_result);
282 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
283 }
284 catch(SSLException e)
285 {
286 super.close();
287 throw e;
288 }
289 finally
290 {
291 out_buffer.position(0);
292 freeOutBuffer();
293 }
294
295 break;
296 }
297 }
298 }
299 }
300 catch (Exception x)
301 {
302 Log.debug(x);
303 super.close();
304 }
305 }
306
307
308 @Override
309 public void close() throws IOException
310 {
311 try
312 {
313 sslClose();
314 }
315 finally
316 {
317 super.close();
318 }
319 }
320
321
322
323
324
325
326 @Override
327 public int fill(Buffer buffer) throws IOException
328 {
329
330
331
332 final ByteBuffer bbuf=extractInputBuffer(buffer);
333
334
335 int size=buffer.length();
336
337 HandshakeStatus initialStatus = _engine.getHandshakeStatus();
338
339 synchronized (bbuf)
340 {
341 try
342 {
343
344
345
346 unwrap(bbuf);
347
348
349
350 int wraps=0;
351 loop: while (true)
352 {
353
354 if (isBufferingOutput())
355 {
356
357
358
359 flush();
360
361
362
363
364
365 if (isBufferingOutput())
366 break loop;
367 }
368
369
370 switch(_engine.getHandshakeStatus())
371 {
372 case FINISHED:
373 case NOT_HANDSHAKING:
374
375
376 if (_closing)
377 return -1;
378
379
380 break loop;
381
382 case NEED_UNWRAP:
383 checkRenegotiate();
384
385 if (!unwrap(bbuf) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
386 {
387
388
389
390 break loop;
391 }
392
393 break;
394
395 case NEED_TASK:
396 {
397
398
399 Runnable task;
400 while ((task=_engine.getDelegatedTask())!=null)
401 {
402 task.run();
403 }
404
405
406 if(initialStatus==HandshakeStatus.NOT_HANDSHAKING &&
407 _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP && wraps==0)
408 {
409
410
411
412
413 if (_debug) __log.warn(_session+" JETTY-567");
414 return -1;
415 }
416 break;
417 }
418
419 case NEED_WRAP:
420 {
421 checkRenegotiate();
422
423
424 wraps++;
425 needOutBuffer();
426 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
427 synchronized(out_buffer)
428 {
429 try
430 {
431
432
433 _outNIOBuffer.compact();
434 int put=_outNIOBuffer.putIndex();
435 out_buffer.position();
436 _result=null;
437 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
438 if (_debug) __log.debug(_session+" fill wrap "+_result);
439 switch(_result.getStatus())
440 {
441 case BUFFER_OVERFLOW:
442 case BUFFER_UNDERFLOW:
443 Log.warn("wrap {}",_result);
444 case CLOSED:
445 _closing=true;
446 }
447
448 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
449 }
450 catch(SSLException e)
451 {
452 super.close();
453 throw e;
454 }
455 finally
456 {
457 out_buffer.position(0);
458 }
459 }
460
461
462 flush();
463 freeOutBuffer();
464
465 break;
466 }
467 }
468 }
469 }
470 finally
471 {
472
473 buffer.setPutIndex(bbuf.position());
474 bbuf.position(0);
475 }
476
477
478 int filled=buffer.length()-size;
479 if (filled>0)
480 _handshook=true;
481 return filled;
482 }
483 }
484
485
486 @Override
487 public int flush(Buffer buffer) throws IOException
488 {
489 return flush(buffer,null,null);
490 }
491
492
493
494
495
496 @Override
497 public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
498 {
499 int consumed=0;
500 int available=header.length();
501 if (buffer!=null)
502 available+=buffer.length();
503
504 needOutBuffer();
505 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
506 loop: while (true)
507 {
508 if (_outNIOBuffer.length()>0)
509 {
510 flush();
511 if (isBufferingOutput())
512 break loop;
513 }
514
515 switch(_engine.getHandshakeStatus())
516 {
517 case FINISHED:
518 case NOT_HANDSHAKING:
519 if (_closing || available==0)
520 {
521 if (consumed==0)
522 consumed= -1;
523 break loop;
524 }
525
526 int c;
527 if (header!=null && header.length()>0)
528 {
529 if (buffer!=null && buffer.length()>0)
530 c=wrap(header,buffer);
531 else
532 c=wrap(header);
533 }
534 else
535 c=wrap(buffer);
536
537
538 if (c>0)
539 {
540 _handshook=true;
541 consumed+=c;
542 available-=c;
543 }
544 else if (c<0)
545 {
546 if (consumed==0)
547 consumed=-1;
548 break loop;
549 }
550
551 break;
552
553 case NEED_UNWRAP:
554 checkRenegotiate();
555 Buffer buf =_buffers.getBuffer(_engine.getSession().getApplicationBufferSize());
556 try
557 {
558 ByteBuffer bbuf = ((NIOBuffer)buf).getByteBuffer();
559 if (!unwrap(bbuf) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
560 {
561 break loop;
562 }
563 }
564 finally
565 {
566 _buffers.returnBuffer(buf);
567 }
568
569 break;
570
571 case NEED_TASK:
572 {
573 Runnable task;
574 while ((task=_engine.getDelegatedTask())!=null)
575 {
576 task.run();
577 }
578 break;
579 }
580
581 case NEED_WRAP:
582 {
583 checkRenegotiate();
584 synchronized(out_buffer)
585 {
586 try
587 {
588 _outNIOBuffer.compact();
589 int put=_outNIOBuffer.putIndex();
590 out_buffer.position();
591 _result=null;
592 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
593 if (_debug) __log.debug(_session+" flush wrap "+_result);
594 switch(_result.getStatus())
595 {
596 case BUFFER_OVERFLOW:
597 case BUFFER_UNDERFLOW:
598 Log.warn("unwrap {}",_result);
599 case CLOSED:
600 _closing=true;
601 }
602 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
603 }
604 catch(SSLException e)
605 {
606 super.close();
607 throw e;
608 }
609 finally
610 {
611 out_buffer.position(0);
612 }
613 }
614
615 flush();
616 if (isBufferingOutput())
617 break loop;
618
619 break;
620 }
621 }
622 }
623
624 freeOutBuffer();
625 return consumed;
626 }
627
628
629 @Override
630 public void flush() throws IOException
631 {
632 if (_outNIOBuffer==null)
633 return;
634
635 int len=_outNIOBuffer.length();
636 if (isBufferingOutput())
637 {
638 int flushed=super.flush(_outNIOBuffer);
639 if (_debug) __log.debug(_session+" Flushed "+flushed+"/"+len);
640 if (isBufferingOutput())
641 {
642
643 Thread.yield();
644 flushed=super.flush(_outNIOBuffer);
645 if (_debug) __log.debug(_session+" flushed "+flushed+"/"+len);
646 }
647 else if (_closing && !_engine.isOutboundDone())
648 {
649 _engine.closeOutbound();
650 }
651 }
652 }
653
654
655 private void checkRenegotiate() throws IOException
656 {
657 if (_handshook && !_allowRenegotiate && _channel!=null && _channel.isOpen())
658 {
659 Log.warn("SSL renegotiate denied: "+_channel);
660 super.close();
661 }
662 }
663
664
665 private ByteBuffer extractInputBuffer(Buffer buffer)
666 {
667 assert buffer instanceof NIOBuffer;
668 NIOBuffer nbuf=(NIOBuffer)buffer;
669 ByteBuffer bbuf=nbuf.getByteBuffer();
670 bbuf.position(buffer.putIndex());
671 return bbuf;
672 }
673
674
675
676
677
678 private boolean unwrap(ByteBuffer buffer) throws IOException
679 {
680 needInBuffer();
681 ByteBuffer in_buffer=_inNIOBuffer.getByteBuffer();
682
683 if (_inNIOBuffer.hasContent())
684 _inNIOBuffer.compact();
685 else
686 _inNIOBuffer.clear();
687
688 int total_filled=0;
689 boolean remoteClosed = false;
690
691 while (_inNIOBuffer.space()>0 && super.isOpen())
692 {
693 try
694 {
695 int filled=super.fill(_inNIOBuffer);
696 if (_debug) __log.debug(_session+" unwrap filled "+filled);
697 if (filled < 0)
698 remoteClosed = true;
699
700 if (filled<=0)
701 break;
702 total_filled+=filled;
703 }
704 catch(IOException e)
705 {
706 if (_inNIOBuffer.length()==0)
707 {
708 freeInBuffer();
709 if (_outNIOBuffer!=null)
710 {
711 _outNIOBuffer.clear();
712 freeOutBuffer();
713 }
714 throw e;
715 }
716 break;
717 }
718 }
719
720
721 if (total_filled==0 && _inNIOBuffer.length()==0)
722 {
723 if (isOpen() && remoteClosed)
724 {
725 try
726 {
727 _engine.closeInbound();
728 }
729 catch (SSLException x)
730 {
731
732
733 super.close();
734 }
735 }
736
737 freeInBuffer();
738 freeOutBuffer();
739
740 if (!isOpen())
741 throw new EofException();
742
743 return false;
744 }
745
746
747 try
748 {
749
750
751 in_buffer.position(_inNIOBuffer.getIndex());
752 in_buffer.limit(_inNIOBuffer.putIndex());
753
754
755 _result=_engine.unwrap(in_buffer,buffer);
756 if (_debug) __log.debug(_session+" unwrap unwrap "+_result);
757
758
759 _inNIOBuffer.skip(_result.bytesConsumed());
760 }
761 catch(SSLException e)
762 {
763 Log.warn(getRemoteAddr() + ":" + getRemotePort() + " " + e);
764 freeOutBuffer();
765 super.close();
766 throw e;
767 }
768 finally
769 {
770
771 in_buffer.position(0);
772 in_buffer.limit(in_buffer.capacity());
773 freeInBuffer();
774 }
775
776
777 switch(_result.getStatus())
778 {
779 case BUFFER_OVERFLOW:
780 throw new IllegalStateException(_result.toString()+" "+buffer.position()+" "+buffer.limit());
781
782 case BUFFER_UNDERFLOW:
783
784
785
786
787 if (Log.isDebugEnabled()) Log.debug("unwrap {}",_result);
788 if(!isOpen())
789 {
790 _inNIOBuffer.clear();
791 if (_outNIOBuffer!=null)
792 _outNIOBuffer.clear();
793 throw new EofException();
794 }
795 return (total_filled > 0);
796
797 case CLOSED:
798 _closing=true;
799
800 return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
801 case OK:
802
803 return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
804 default:
805 Log.warn("unwrap "+_result);
806 throw new IOException(_result.toString());
807 }
808 }
809
810
811
812 private ByteBuffer extractOutputBuffer(Buffer buffer)
813 {
814 if (buffer.buffer() instanceof NIOBuffer)
815 return ((NIOBuffer)buffer.buffer()).getByteBuffer();
816
817 return ByteBuffer.wrap(buffer.array());
818 }
819
820
821 private int wrap(final Buffer header, final Buffer buffer) throws IOException
822 {
823 _gather[0]=extractOutputBuffer(header);
824
825 synchronized(_gather[0])
826 {
827 _gather[0].position(header.getIndex());
828 _gather[0].limit(header.putIndex());
829
830 _gather[1]=extractOutputBuffer(buffer);
831
832 synchronized(_gather[1])
833 {
834 _gather[1].position(buffer.getIndex());
835 _gather[1].limit(buffer.putIndex());
836
837 needOutBuffer();
838 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
839 synchronized(out_buffer)
840 {
841 int consumed=0;
842 try
843 {
844 _outNIOBuffer.clear();
845 out_buffer.position(0);
846 out_buffer.limit(out_buffer.capacity());
847
848 _result=null;
849 _result=_engine.wrap(_gather,out_buffer);
850 if (_debug) __log.debug(_session+" wrap wrap "+_result);
851 _outNIOBuffer.setGetIndex(0);
852 _outNIOBuffer.setPutIndex(_result.bytesProduced());
853 consumed=_result.bytesConsumed();
854 }
855 catch(SSLException e)
856 {
857 Log.warn(getRemoteAddr()+":"+getRemotePort()+" "+e);
858 super.close();
859 throw e;
860 }
861 finally
862 {
863 out_buffer.position(0);
864
865 if (consumed>0)
866 {
867 int len=consumed<header.length()?consumed:header.length();
868 header.skip(len);
869 consumed-=len;
870 _gather[0].position(0);
871 _gather[0].limit(_gather[0].capacity());
872 }
873 if (consumed>0)
874 {
875 int len=consumed<buffer.length()?consumed:buffer.length();
876 buffer.skip(len);
877 consumed-=len;
878 _gather[1].position(0);
879 _gather[1].limit(_gather[1].capacity());
880 }
881 assert consumed==0;
882
883 freeOutBuffer();
884 }
885 }
886 }
887 }
888
889
890 switch(_result.getStatus())
891 {
892 case BUFFER_OVERFLOW:
893 case BUFFER_UNDERFLOW:
894 Log.warn("unwrap {}",_result);
895
896 case OK:
897 return _result.bytesConsumed();
898 case CLOSED:
899 _closing=true;
900 return _result.bytesConsumed()>0?_result.bytesConsumed():-1;
901
902 default:
903 Log.warn("wrap "+_result);
904 throw new IOException(_result.toString());
905 }
906 }
907
908
909 private int wrap(final Buffer buffer) throws IOException
910 {
911 _gather[0]=extractOutputBuffer(buffer);
912 synchronized(_gather[0])
913 {
914 ByteBuffer bb;
915
916 _gather[0].position(buffer.getIndex());
917 _gather[0].limit(buffer.putIndex());
918
919 int consumed=0;
920 needOutBuffer();
921 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
922 synchronized(out_buffer)
923 {
924 try
925 {
926 _outNIOBuffer.clear();
927 out_buffer.position(0);
928 out_buffer.limit(out_buffer.capacity());
929 _result=null;
930 _result=_engine.wrap(_gather[0],out_buffer);
931 if (_debug) __log.debug(_session+" wrap wrap "+_result);
932 _outNIOBuffer.setGetIndex(0);
933 _outNIOBuffer.setPutIndex(_result.bytesProduced());
934 consumed=_result.bytesConsumed();
935 }
936 catch(SSLException e)
937 {
938 Log.warn(getRemoteAddr()+":"+getRemotePort()+" "+e);
939 super.close();
940 throw e;
941 }
942 finally
943 {
944 out_buffer.position(0);
945
946 if (consumed>0)
947 {
948 int len=consumed<buffer.length()?consumed:buffer.length();
949 buffer.skip(len);
950 consumed-=len;
951 _gather[0].position(0);
952 _gather[0].limit(_gather[0].capacity());
953 }
954 assert consumed==0;
955
956 freeOutBuffer();
957 }
958 }
959 }
960 switch(_result.getStatus())
961 {
962 case BUFFER_OVERFLOW:
963 case BUFFER_UNDERFLOW:
964 Log.warn("unwrap {}",_result);
965
966 case OK:
967 return _result.bytesConsumed();
968 case CLOSED:
969 _closing=true;
970 return _result.bytesConsumed()>0?_result.bytesConsumed():-1;
971
972 default:
973 Log.warn("wrap "+_result);
974 throw new IOException(_result.toString());
975 }
976 }
977
978
979 @Override
980 public boolean isBufferingInput()
981 {
982 final Buffer in = _inNIOBuffer;
983 return in==null?false:_inNIOBuffer.hasContent();
984 }
985
986
987 @Override
988 public boolean isBufferingOutput()
989 {
990 final NIOBuffer b=_outNIOBuffer;
991 return b==null?false:b.hasContent();
992 }
993
994
995 @Override
996 public boolean isBufferred()
997 {
998 return true;
999 }
1000
1001
1002 public SSLEngine getSSLEngine()
1003 {
1004 return _engine;
1005 }
1006
1007
1008 @Override
1009 public void scheduleWrite()
1010 {
1011
1012 if (!HandshakeStatus.NEED_UNWRAP.equals(_engine.getHandshakeStatus()) || super.isBufferingOutput())
1013 super.scheduleWrite();
1014 }
1015
1016
1017 @Override
1018 public String toString()
1019 {
1020 final NIOBuffer i=_inNIOBuffer;
1021 final NIOBuffer o=_outNIOBuffer;
1022 return "SSL"+super.toString()+","+_engine.getHandshakeStatus()+", in/out="+
1023 (i==null?0:_inNIOBuffer.length())+"/"+(o==null?0:o.length())+
1024 " bi/o="+isBufferingInput()+"/"+isBufferingOutput()+
1025 " "+_result;
1026 }
1027 }