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