1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.ssl;
21
22 import java.net.InetSocketAddress;
23 import java.nio.ByteBuffer;
24 import java.util.Queue;
25 import java.util.concurrent.ConcurrentLinkedQueue;
26 import java.util.concurrent.atomic.AtomicInteger;
27 import java.util.concurrent.locks.ReentrantLock;
28
29 import javax.net.ssl.SSLEngine;
30 import javax.net.ssl.SSLEngineResult;
31 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
32 import javax.net.ssl.SSLEngineResult.Status;
33 import javax.net.ssl.SSLException;
34 import javax.net.ssl.SSLHandshakeException;
35
36 import org.apache.mina.core.RuntimeIoException;
37 import org.apache.mina.core.buffer.IoBuffer;
38 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
39 import org.apache.mina.core.filterchain.IoFilterEvent;
40 import org.apache.mina.core.future.DefaultWriteFuture;
41 import org.apache.mina.core.future.WriteFuture;
42 import org.apache.mina.core.session.IoEventType;
43 import org.apache.mina.core.session.IoSession;
44 import org.apache.mina.core.write.DefaultWriteRequest;
45 import org.apache.mina.core.write.WriteRequest;
46 import org.apache.mina.core.write.WriteRequestQueue;
47 import org.apache.mina.filter.ssl.SslFilter.EncryptedWriteRequest;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 class SslHandler {
67
68 private static final Logger LOGGER = LoggerFactory.getLogger(SslHandler.class);
69
70
71 private final SslFilter sslFilter;
72
73
74 private final IoSession session;
75
76 private final Queue<IoFilterEvent> preHandshakeEventQueue = new ConcurrentLinkedQueue<>();
77
78 private final Queue<IoFilterEvent> filterWriteEventQueue = new ConcurrentLinkedQueue<>();
79
80
81 private final Queue<IoFilterEvent> messageReceivedEventQueue = new ConcurrentLinkedQueue<>();
82
83 private SSLEngine sslEngine;
84
85
86
87
88 private IoBuffer inNetBuffer;
89
90
91
92
93 private IoBuffer outNetBuffer;
94
95
96
97
98 private IoBuffer appBuffer;
99
100
101
102
103 private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
104
105 private SSLEngineResult.HandshakeStatus handshakeStatus;
106
107
108
109
110
111
112 private boolean firstSSLNegociation;
113
114
115 private boolean handshakeComplete;
116
117
118
119
120 private boolean writingEncryptedData;
121
122
123
124
125
126
127
128 SslHandler(SslFilter sslFilter, IoSession session) {
129 this.sslFilter = sslFilter;
130 this.session = session;
131 }
132
133
134
135
136
137
138 void init() throws SSLException {
139 if (sslEngine != null) {
140
141 return;
142 }
143
144 if (LOGGER.isDebugEnabled()) {
145 LOGGER.debug("{} Initializing the SSL Handler", sslFilter.getSessionInfo(session));
146 }
147
148 InetSocketAddress peer = (InetSocketAddress) session.getAttribute(SslFilter.PEER_ADDRESS);
149
150
151 if (peer == null) {
152 sslEngine = sslFilter.sslContext.createSSLEngine();
153 } else {
154 sslEngine = sslFilter.sslContext.createSSLEngine(peer.getHostName(), peer.getPort());
155 }
156
157
158 sslEngine.setUseClientMode(sslFilter.isUseClientMode());
159
160
161 if (!sslEngine.getUseClientMode()) {
162
163 if (sslFilter.isWantClientAuth()) {
164 sslEngine.setWantClientAuth(true);
165 }
166
167 if (sslFilter.isNeedClientAuth()) {
168 sslEngine.setNeedClientAuth(true);
169 }
170 }
171
172
173 if (sslFilter.getEnabledCipherSuites() != null) {
174 sslEngine.setEnabledCipherSuites(sslFilter.getEnabledCipherSuites());
175 }
176
177
178 if (sslFilter.getEnabledProtocols() != null) {
179 sslEngine.setEnabledProtocols(sslFilter.getEnabledProtocols());
180 }
181
182
183
184 handshakeStatus = sslEngine.getHandshakeStatus();
185
186
187 writingEncryptedData = false;
188
189
190
191 firstSSLNegociation = true;
192 handshakeComplete = false;
193
194 if (LOGGER.isDebugEnabled()) {
195 LOGGER.debug("{} SSL Handler Initialization done.", sslFilter.getSessionInfo(session));
196 }
197 }
198
199
200
201
202
203 void destroy() {
204 if (sslEngine == null) {
205 return;
206 }
207
208
209 try {
210 sslEngine.closeInbound();
211 } catch (SSLException e) {
212 if (LOGGER.isDebugEnabled()) {
213 LOGGER.debug("Unexpected exception from SSLEngine.closeInbound().", e);
214 }
215 }
216
217 if (outNetBuffer != null) {
218 outNetBuffer.capacity(sslEngine.getSession().getPacketBufferSize());
219 } else {
220 createOutNetBuffer(0);
221 }
222 try {
223 do {
224 outNetBuffer.clear();
225 } while (sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()).bytesProduced() > 0);
226 } catch (SSLException e) {
227
228 } finally {
229 outNetBuffer.free();
230 outNetBuffer = null;
231 }
232
233 sslEngine.closeOutbound();
234 sslEngine = null;
235
236 preHandshakeEventQueue.clear();
237 }
238
239
240
241
242 SslFilter getSslFilter() {
243 return sslFilter;
244 }
245
246 IoSession getSession() {
247 return session;
248 }
249
250
251
252
253 boolean isWritingEncryptedData() {
254 return writingEncryptedData;
255 }
256
257
258
259
260 boolean isHandshakeComplete() {
261 return handshakeComplete;
262 }
263
264
265
266
267 boolean notHandshaking() {
268 return handshakeStatus == HandshakeStatus.FINISHED || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING;
269 }
270
271 boolean isInboundDone() {
272 return sslEngine == null || sslEngine.isInboundDone();
273 }
274
275 boolean isOutboundDone() {
276 return sslEngine == null || sslEngine.isOutboundDone();
277 }
278
279
280
281
282 boolean needToCompleteHandshake() {
283 return handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !isInboundDone();
284 }
285
286 void schedulePreHandshakeWriteRequest(NextFilter nextFilter, WriteRequest writeRequest) {
287 preHandshakeEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
288 }
289
290 void flushPreHandshakeEvents() throws SSLException {
291 IoFilterEvent scheduledWrite;
292
293 while ((scheduledWrite = preHandshakeEventQueue.poll()) != null) {
294 sslFilter
295 .filterWrite(scheduledWrite.getNextFilter(), session, (WriteRequest) scheduledWrite.getParameter());
296 }
297 }
298
299 void scheduleFilterWrite(NextFilter nextFilter, WriteRequest writeRequest) {
300 filterWriteEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
301 }
302
303 void flushFilterWrite() {
304
305 IoFilterEvent event;
306
307
308
309 while ((event = filterWriteEventQueue.poll()) != null) {
310 NextFilter nextFilter = event.getNextFilter();
311 nextFilter.filterWrite(session, (WriteRequest) event.getParameter());
312 }
313 }
314
315
316
317
318
319
320
321
322 void scheduleMessageReceived(NextFilter nextFilter, Object message) {
323 messageReceivedEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.MESSAGE_RECEIVED, session, message));
324 }
325
326 void flushMessageReceived() {
327 IoFilterEvent event;
328
329 while ((event = messageReceivedEventQueue.poll()) != null) {
330 NextFilter nextFilter = event.getNextFilter();
331 nextFilter.messageReceived(session, event.getParameter());
332 }
333 }
334
335
336
337
338
339
340
341
342
343 void messageReceived(NextFilter nextFilter, ByteBuffer buf) throws SSLException {
344 if (LOGGER.isDebugEnabled()) {
345 LOGGER.debug("{} Processing the received message", sslFilter.getSessionInfo(session));
346 }
347
348
349 if (inNetBuffer == null) {
350 inNetBuffer = IoBuffer.allocate(buf.remaining()).setAutoExpand(true);
351 }
352
353 inNetBuffer.put(buf);
354
355 if (!handshakeComplete) {
356 handshake(nextFilter);
357 } else {
358
359 inNetBuffer.flip();
360
361 if (!inNetBuffer.hasRemaining()) {
362 return;
363 }
364
365 SSLEngineResult res = unwrap();
366
367
368 if (inNetBuffer.hasRemaining()) {
369 inNetBuffer.compact();
370 } else {
371 inNetBuffer.free();
372 inNetBuffer = null;
373 }
374
375 checkStatus(res);
376
377 renegotiateIfNeeded(nextFilter, res);
378 }
379
380 if (isInboundDone()) {
381
382
383 int inNetBufferPosition = inNetBuffer == null ? 0 : inNetBuffer.position();
384 buf.position(buf.position() - inNetBufferPosition);
385
386 if (inNetBuffer != null) {
387 inNetBuffer.free();
388 inNetBuffer = null;
389 }
390 }
391 }
392
393
394
395
396
397
398 IoBuffer fetchAppBuffer() {
399 if (appBuffer == null) {
400 return IoBuffer.allocate(0);
401 } else {
402 IoBuffer newAppBuffer = appBuffer.flip();
403 appBuffer = null;
404
405 return newAppBuffer.shrink();
406 }
407 }
408
409
410
411
412
413
414 IoBuffer fetchOutNetBuffer() {
415 IoBuffer answer = outNetBuffer;
416
417 if (answer == null) {
418 return emptyBuffer;
419 }
420
421 outNetBuffer = null;
422
423 return answer.shrink();
424 }
425
426
427
428
429
430
431
432
433
434 void encrypt(ByteBuffer src) throws SSLException {
435 if (!handshakeComplete) {
436 throw new IllegalStateException();
437 }
438
439 if (!src.hasRemaining()) {
440 if (outNetBuffer == null) {
441 outNetBuffer = emptyBuffer;
442 }
443 return;
444 }
445
446 createOutNetBuffer(src.remaining());
447
448
449 while (src.hasRemaining()) {
450
451 SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf());
452
453 if (result.getStatus() == SSLEngineResult.Status.OK) {
454 if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
455 doTasks();
456 }
457 } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
458 outNetBuffer.capacity(outNetBuffer.capacity() << 1);
459 outNetBuffer.limit(outNetBuffer.capacity());
460 } else {
461 throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src
462 + "outNetBuffer: " + outNetBuffer);
463 }
464 }
465
466 outNetBuffer.flip();
467 }
468
469
470
471
472
473
474
475
476
477 boolean closeOutbound() throws SSLException {
478 if (sslEngine == null || sslEngine.isOutboundDone()) {
479 return false;
480 }
481
482 sslEngine.closeOutbound();
483
484 createOutNetBuffer(0);
485 SSLEngineResult result;
486
487 for (;;) {
488 result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
489 if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
490 outNetBuffer.capacity(outNetBuffer.capacity() << 1);
491 outNetBuffer.limit(outNetBuffer.capacity());
492 } else {
493 break;
494 }
495 }
496
497 if (result.getStatus() != SSLEngineResult.Status.CLOSED) {
498 throw new SSLException("Improper close state: " + result);
499 }
500
501 outNetBuffer.flip();
502
503 return true;
504 }
505
506
507
508
509
510 private void checkStatus(SSLEngineResult res) throws SSLException {
511
512 SSLEngineResult.Status status = res.getStatus();
513
514
515
516
517
518
519
520
521
522 switch (status) {
523 case BUFFER_OVERFLOW:
524 throw new SSLException("SSLEngine error during decrypt: " + status + " inNetBuffer: " + inNetBuffer
525 + "appBuffer: " + appBuffer);
526 case CLOSED:
527 Exception exception =new RuntimeIoException("SSL/TLS close_notify received");
528
529
530 for (IoFilterEvent event:filterWriteEventQueue) {
531 EncryptedWriteRequest writeRequest = (EncryptedWriteRequest)event.getParameter();
532 WriteFuture writeFuture = writeRequest.getParentRequest().getFuture();
533 writeFuture.setException(exception);
534 writeFuture.notifyAll();
535 }
536
537
538 WriteRequestQueue queue = session.getWriteRequestQueue();
539 WriteRequest request = null;
540
541 while ((request = queue.poll(session)) != null) {
542 WriteFuture writeFuture = request.getFuture();
543 writeFuture.setException(exception);
544 writeFuture.notifyAll();
545 }
546
547
548 session.closeNow();
549 break;
550 default:
551 break;
552 }
553 }
554
555
556
557
558 void handshake(NextFilter nextFilter) throws SSLException {
559 for (;;) {
560 switch (handshakeStatus) {
561 case FINISHED:
562 if (LOGGER.isDebugEnabled()) {
563 LOGGER.debug("{} processing the FINISHED state", sslFilter.getSessionInfo(session));
564 }
565
566 session.setAttribute(SslFilter.SSL_SESSION, sslEngine.getSession());
567 handshakeComplete = true;
568
569
570 if (firstSSLNegociation) {
571 firstSSLNegociation = false;
572
573 nextFilter.event(session, SslEvent.SECURED);
574 }
575
576 if (LOGGER.isDebugEnabled()) {
577 if (!isOutboundDone()) {
578 LOGGER.debug("{} is now secured", sslFilter.getSessionInfo(session));
579 } else {
580 LOGGER.debug("{} is not secured yet", sslFilter.getSessionInfo(session));
581 }
582 }
583
584 return;
585
586 case NEED_TASK:
587 if (LOGGER.isDebugEnabled()) {
588 LOGGER.debug("{} processing the NEED_TASK state", sslFilter.getSessionInfo(session));
589 }
590
591 handshakeStatus = doTasks();
592 break;
593
594 case NEED_UNWRAP:
595 if (LOGGER.isDebugEnabled()) {
596 LOGGER.debug("{} processing the NEED_UNWRAP state", sslFilter.getSessionInfo(session));
597 }
598
599 SSLEngineResult.Status status = unwrapHandshake(nextFilter);
600
601 if (status == SSLEngineResult.Status.BUFFER_UNDERFLOW
602 && handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED || isInboundDone()) {
603
604 return;
605 }
606
607 break;
608
609 case NEED_WRAP:
610 case NOT_HANDSHAKING:
611 if (LOGGER.isDebugEnabled()) {
612 LOGGER.debug("{} processing the NEED_WRAP state", sslFilter.getSessionInfo(session));
613 }
614
615
616
617 if (outNetBuffer != null && outNetBuffer.hasRemaining()) {
618 return;
619 }
620
621 SSLEngineResult result;
622 createOutNetBuffer(0);
623
624 result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
625
626 while ( result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW ) {
627 outNetBuffer.capacity(outNetBuffer.capacity() << 1);
628 outNetBuffer.limit(outNetBuffer.capacity());
629
630 result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
631 }
632
633 outNetBuffer.flip();
634 handshakeStatus = result.getHandshakeStatus();
635 writeNetBuffer(nextFilter);
636 break;
637
638 default:
639 String msg = "Invalid Handshaking State" + handshakeStatus
640 + " while processing the Handshake for session " + session.getId();
641 LOGGER.error(msg);
642 throw new IllegalStateException(msg);
643 }
644 }
645 }
646
647 private void createOutNetBuffer(int expectedRemaining) {
648
649
650 int capacity = Math.max(expectedRemaining, sslEngine.getSession().getPacketBufferSize());
651
652 if (outNetBuffer != null) {
653 outNetBuffer.capacity(capacity);
654 } else {
655 outNetBuffer = IoBuffer.allocate(capacity).minimumCapacity(0);
656 }
657 }
658
659 WriteFuture writeNetBuffer(NextFilter nextFilter) throws SSLException {
660
661 if (outNetBuffer == null || !outNetBuffer.hasRemaining()) {
662
663 return null;
664 }
665
666
667
668 writingEncryptedData = true;
669
670
671 WriteFuture writeFuture = null;
672
673 try {
674 IoBuffer writeBuffer = fetchOutNetBuffer();
675 writeFuture = new DefaultWriteFuture(session);
676 sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(writeBuffer, writeFuture));
677
678
679 while (needToCompleteHandshake()) {
680 try {
681 handshake(nextFilter);
682 } catch (SSLException ssle) {
683 SSLException newSsle = new SSLHandshakeException("SSL handshake failed.");
684 newSsle.initCause(ssle);
685 throw newSsle;
686 }
687
688 IoBuffer currentOutNetBuffer = fetchOutNetBuffer();
689
690 if (currentOutNetBuffer != null && currentOutNetBuffer.hasRemaining()) {
691 writeFuture = new DefaultWriteFuture(session);
692 sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(currentOutNetBuffer, writeFuture));
693 }
694 }
695 } finally {
696 writingEncryptedData = false;
697 }
698
699 return writeFuture;
700 }
701
702 private SSLEngineResult.Status unwrapHandshake(NextFilter nextFilter) throws SSLException {
703
704 if (inNetBuffer != null) {
705 inNetBuffer.flip();
706 }
707
708 if ((inNetBuffer == null) || !inNetBuffer.hasRemaining()) {
709
710 return SSLEngineResult.Status.BUFFER_UNDERFLOW;
711 }
712
713 SSLEngineResult res = unwrap();
714 handshakeStatus = res.getHandshakeStatus();
715
716 checkStatus(res);
717
718
719
720 if ((handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
721 && (res.getStatus() == SSLEngineResult.Status.OK)
722 && inNetBuffer.hasRemaining()) {
723 res = unwrap();
724
725
726 if (inNetBuffer.hasRemaining()) {
727 inNetBuffer.compact();
728 } else {
729 inNetBuffer.free();
730 inNetBuffer = null;
731 }
732
733 renegotiateIfNeeded(nextFilter, res);
734 } else {
735
736 if (inNetBuffer.hasRemaining()) {
737 inNetBuffer.compact();
738 } else {
739 inNetBuffer.free();
740 inNetBuffer = null;
741 }
742 }
743
744 return res.getStatus();
745 }
746
747 private void renegotiateIfNeeded(NextFilter nextFilter, SSLEngineResult res) throws SSLException {
748 if ((res.getStatus() != SSLEngineResult.Status.CLOSED)
749 && (res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW)
750 && (res.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
751
752 handshakeComplete = false;
753 handshakeStatus = res.getHandshakeStatus();
754 handshake(nextFilter);
755 }
756 }
757
758
759
760
761
762 private SSLEngineResult unwrap() throws SSLException {
763
764 if (appBuffer == null) {
765 appBuffer = IoBuffer.allocate(inNetBuffer.remaining());
766 } else {
767
768 appBuffer.expand(inNetBuffer.remaining());
769 }
770
771 SSLEngineResult res;
772 Status status;
773 HandshakeStatus localHandshakeStatus;
774
775 do {
776
777 res = sslEngine.unwrap(inNetBuffer.buf(), appBuffer.buf());
778 status = res.getStatus();
779
780
781 localHandshakeStatus = res.getHandshakeStatus();
782
783 if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) {
784
785
786 int newCapacity = sslEngine.getSession().getApplicationBufferSize();
787
788 if (appBuffer.remaining() >= newCapacity) {
789
790
791 throw new SSLException("SSL buffer overflow");
792 }
793
794 appBuffer.expand(newCapacity);
795 continue;
796 }
797 } while (((status == SSLEngineResult.Status.OK) || (status == SSLEngineResult.Status.BUFFER_OVERFLOW))
798 && ((localHandshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) ||
799 (localHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)));
800
801 return res;
802 }
803
804
805
806
807 private SSLEngineResult.HandshakeStatus doTasks() {
808
809
810
811
812 Runnable runnable;
813 while ((runnable = sslEngine.getDelegatedTask()) != null) {
814
815
816 runnable.run();
817 }
818 return sslEngine.getHandshakeStatus();
819 }
820
821
822
823
824
825
826
827
828
829 static IoBuffer copy(ByteBuffer src) {
830 IoBuffer copy = IoBuffer.allocate(src.remaining());
831 copy.put(src);
832 copy.flip();
833 return copy;
834 }
835
836
837
838
839 @Override
840 public String toString() {
841 StringBuilder sb = new StringBuilder();
842
843 sb.append("SSLStatus <");
844
845 if (handshakeComplete) {
846 sb.append("SSL established");
847 } else {
848 sb.append("Processing Handshake").append("; ");
849 sb.append("Status : ").append(handshakeStatus).append("; ");
850 }
851
852 sb.append(", ");
853 sb.append("HandshakeComplete :").append(handshakeComplete).append(", ");
854 sb.append(">");
855
856 return sb.toString();
857 }
858
859
860
861
862 void release() {
863 if (inNetBuffer != null) {
864 inNetBuffer.free();
865 inNetBuffer = null;
866 }
867
868 if (outNetBuffer != null) {
869 outNetBuffer.free();
870 outNetBuffer = null;
871 }
872 }
873 }