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