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