1 20 package org.apache.mina.filter; 21 22 import javax.net.ssl.SSLContext; 23 import javax.net.ssl.SSLEngine; 24 import javax.net.ssl.SSLException; 25 import javax.net.ssl.SSLHandshakeException; 26 import javax.net.ssl.SSLSession; 27 28 import org.apache.mina.common.ByteBuffer; 29 import org.apache.mina.common.ByteBufferProxy; 30 import org.apache.mina.common.IoFilterAdapter; 31 import org.apache.mina.common.IoFilterChain; 32 import org.apache.mina.common.IoFuture; 33 import org.apache.mina.common.IoFutureListener; 34 import org.apache.mina.common.IoHandler; 35 import org.apache.mina.common.IoSession; 36 import org.apache.mina.common.WriteFuture; 37 import org.apache.mina.common.support.DefaultWriteFuture; 38 import org.apache.mina.filter.support.SSLHandler; 39 import org.apache.mina.util.SessionLog; 40 41 80 public class SSLFilter extends IoFilterAdapter { 81 85 public static final String SSL_SESSION = SSLFilter.class.getName() 86 + ".SSLSession"; 87 88 98 public static final String DISABLE_ENCRYPTION_ONCE = SSLFilter.class 99 .getName() 100 + ".DisableEncryptionOnce"; 101 102 110 public static final String USE_NOTIFICATION = SSLFilter.class.getName() 111 + ".UseNotification"; 112 113 118 public static final SSLFilterMessage SESSION_SECURED = new SSLFilterMessage( 119 "SESSION_SECURED"); 120 121 126 public static final SSLFilterMessage SESSION_UNSECURED = new SSLFilterMessage( 127 "SESSION_UNSECURED"); 128 129 private static final String NEXT_FILTER = SSLFilter.class.getName() 130 + ".NextFilter"; 131 132 private static final String SSL_HANDLER = SSLFilter.class.getName() 133 + ".SSLHandler"; 134 135 private SSLContext sslContext; 137 138 private boolean client; 139 140 private boolean needClientAuth; 141 142 private boolean wantClientAuth; 143 144 private String [] enabledCipherSuites; 145 146 private String [] enabledProtocols; 147 148 151 public SSLFilter(SSLContext sslContext) { 152 if (sslContext == null) { 153 throw new NullPointerException ("sslContext"); 154 } 155 156 this.sslContext = sslContext; 157 } 158 159 164 public SSLSession getSSLSession(IoSession session) { 165 return (SSLSession) session.getAttribute(SSL_SESSION); 166 } 167 168 176 public boolean startSSL(IoSession session) throws SSLException { 177 SSLHandler handler = getSSLSessionHandler(session); 178 boolean started; 179 synchronized (handler) { 180 if (handler.isOutboundDone()) { 181 NextFilter nextFilter = (NextFilter) session 182 .getAttribute(NEXT_FILTER); 183 handler.destroy(); 184 handler.init(); 185 handler.handshake(nextFilter); 186 started = true; 187 } else { 188 started = false; 189 } 190 } 191 192 handler.flushScheduledEvents(); 193 return started; 194 } 195 196 202 public boolean isSSLStarted(IoSession session) { 203 SSLHandler handler = getSSLSessionHandler0(session); 204 if (handler == null) { 205 return false; 206 } 207 208 synchronized (handler) { 209 return !handler.isOutboundDone(); 210 } 211 } 212 213 221 public WriteFuture stopSSL(IoSession session) throws SSLException { 222 SSLHandler handler = getSSLSessionHandler(session); 223 NextFilter nextFilter = (NextFilter) session.getAttribute(NEXT_FILTER); 224 WriteFuture future; 225 synchronized (handler) { 226 future = initiateClosure(nextFilter, session); 227 } 228 229 handler.flushScheduledEvents(); 230 231 return future; 232 } 233 234 238 public boolean isUseClientMode() { 239 return client; 240 } 241 242 245 public void setUseClientMode(boolean clientMode) { 246 this.client = clientMode; 247 } 248 249 253 public boolean isNeedClientAuth() { 254 return needClientAuth; 255 } 256 257 261 public void setNeedClientAuth(boolean needClientAuth) { 262 this.needClientAuth = needClientAuth; 263 } 264 265 269 public boolean isWantClientAuth() { 270 return wantClientAuth; 271 } 272 273 277 public void setWantClientAuth(boolean wantClientAuth) { 278 this.wantClientAuth = wantClientAuth; 279 } 280 281 287 public String [] getEnabledCipherSuites() { 288 return enabledCipherSuites; 289 } 290 291 297 public void setEnabledCipherSuites(String [] cipherSuites) { 298 this.enabledCipherSuites = cipherSuites; 299 } 300 301 307 public String [] getEnabledProtocols() { 308 return enabledProtocols; 309 } 310 311 317 public void setEnabledProtocols(String [] protocols) { 318 this.enabledProtocols = protocols; 319 } 320 321 public void onPreAdd(IoFilterChain parent, String name, 322 NextFilter nextFilter) throws SSLException { 323 if (parent.contains(SSLFilter.class)) { 324 throw new IllegalStateException ( 325 "A filter chain cannot contain more than one SSLFilter."); 326 } 327 328 IoSession session = parent.getSession(); 329 session.setAttribute(NEXT_FILTER, nextFilter); 330 331 SSLHandler handler = new SSLHandler(this, sslContext, session); 333 session.setAttribute(SSL_HANDLER, handler); 334 } 335 336 public void onPostAdd(IoFilterChain parent, String name, 337 NextFilter nextFilter) throws SSLException { 338 SSLHandler handler = getSSLSessionHandler(parent.getSession()); 339 synchronized (handler) { 340 handler.handshake(nextFilter); 341 } 342 handler.flushScheduledEvents(); 343 } 344 345 public void onPreRemove(IoFilterChain parent, String name, 346 NextFilter nextFilter) throws SSLException { 347 IoSession session = parent.getSession(); 348 stopSSL(session); 349 session.removeAttribute(NEXT_FILTER); 350 session.removeAttribute(SSL_HANDLER); 351 } 352 353 public void sessionClosed(NextFilter nextFilter, IoSession session) 355 throws SSLException { 356 SSLHandler handler = getSSLSessionHandler(session); 357 try { 358 synchronized (handler) { 359 if (isSSLStarted(session)) { 360 if (SessionLog.isDebugEnabled(session)) { 361 SessionLog.debug(session, " Closed: " 362 + getSSLSessionHandler(session)); 363 } 364 } 365 366 handler.destroy(); 368 } 369 370 handler.flushScheduledEvents(); 371 } finally { 372 nextFilter.sessionClosed(session); 374 } 375 } 376 377 public void messageReceived(NextFilter nextFilter, IoSession session, 378 Object message) throws SSLException { 379 SSLHandler handler = getSSLSessionHandler(session); 380 synchronized (handler) { 381 if (!isSSLStarted(session) && handler.isInboundDone()) { 382 handler.scheduleMessageReceived(nextFilter, message); 383 } else { 384 ByteBuffer buf = (ByteBuffer) message; 385 if (SessionLog.isDebugEnabled(session)) { 386 SessionLog.debug(session, " Data Read: " + handler + " (" 387 + buf + ')'); 388 } 389 390 try { 391 handler.messageReceived(nextFilter, buf.buf()); 393 394 handleSSLData(nextFilter, handler); 396 397 if (handler.isInboundDone()) { 398 if (handler.isOutboundDone()) { 399 if (SessionLog.isDebugEnabled(session)) { 400 SessionLog.debug(session, 401 " SSL Session closed."); 402 } 403 404 handler.destroy(); 405 } else { 406 initiateClosure(nextFilter, session); 407 } 408 409 if (buf.hasRemaining()) { 410 handler.scheduleMessageReceived(nextFilter, 411 buf); 412 } 413 } 414 } catch (SSLException ssle) { 415 if (!handler.isInitialHandshakeComplete()) { 416 SSLException newSSLE = new SSLHandshakeException( 417 "Initial SSL handshake failed."); 418 newSSLE.initCause(ssle); 419 ssle = newSSLE; 420 } 421 422 throw ssle; 423 } 424 } 425 } 426 427 handler.flushScheduledEvents(); 428 } 429 430 public void messageSent(NextFilter nextFilter, IoSession session, 431 Object message) { 432 if (message instanceof EncryptedBuffer) { 433 EncryptedBuffer buf = (EncryptedBuffer) message; 434 buf.release(); 435 nextFilter.messageSent(session, buf.originalBuffer); 436 } else { 437 } 439 } 440 441 public void filterWrite(NextFilter nextFilter, IoSession session, 442 WriteRequest writeRequest) throws SSLException { 443 boolean needsFlush = true; 444 SSLHandler handler = getSSLSessionHandler(session); 445 synchronized (handler) { 446 if (!isSSLStarted(session)) { 447 handler.scheduleFilterWrite(nextFilter, 448 writeRequest); 449 } 450 else if (session.containsAttribute(DISABLE_ENCRYPTION_ONCE)) { 452 session.removeAttribute(DISABLE_ENCRYPTION_ONCE); 454 handler.scheduleFilterWrite(nextFilter, 455 writeRequest); 456 } else { 457 ByteBuffer buf = (ByteBuffer) writeRequest.getMessage(); 459 460 if (SessionLog.isDebugEnabled(session)) { 461 SessionLog.debug(session, " Filtered Write: " + handler); 462 } 463 464 if (handler.isWritingEncryptedData()) { 465 if (SessionLog.isDebugEnabled(session)) { 467 SessionLog.debug(session, " already encrypted: " 468 + buf); 469 } 470 handler.scheduleFilterWrite(nextFilter, 471 writeRequest); 472 } else if (handler.isInitialHandshakeComplete()) { 473 if (SessionLog.isDebugEnabled(session)) { 475 SessionLog.debug(session, " encrypt: " + buf); 476 } 477 478 int pos = buf.position(); 479 handler.encrypt(buf.buf()); 480 buf.position(pos); 481 ByteBuffer encryptedBuffer = new EncryptedBuffer(SSLHandler 482 .copy(handler.getOutNetBuffer()), buf); 483 484 if (SessionLog.isDebugEnabled(session)) { 485 SessionLog.debug(session, " encrypted buf: " 486 + encryptedBuffer); 487 } 488 handler.scheduleFilterWrite(nextFilter, 489 new WriteRequest(encryptedBuffer, writeRequest 490 .getFuture())); 491 } else { 492 if (!session.isConnected()) { 493 if (SessionLog.isDebugEnabled(session)) { 494 SessionLog.debug(session, 495 " Write request on closed session."); 496 } 497 } else { 498 if (SessionLog.isDebugEnabled(session)) { 499 SessionLog 500 .debug(session, 501 " Handshaking is not complete yet. Buffering write request."); 502 } 503 handler.schedulePreHandshakeWriteRequest(nextFilter, 504 writeRequest); 505 } 506 needsFlush = false; 507 } 508 } 509 } 510 511 if (needsFlush) { 512 handler.flushScheduledEvents(); 513 } 514 } 515 516 public void filterClose(final NextFilter nextFilter, final IoSession session) 517 throws SSLException { 518 SSLHandler handler = getSSLSessionHandler0(session); 519 if (handler == null) { 520 nextFilter.filterClose(session); 523 return; 524 } 525 526 WriteFuture future = null; 527 try { 528 synchronized (handler) { 529 if (isSSLStarted(session)) { 530 future = initiateClosure(nextFilter, session); 531 } 532 } 533 534 handler.flushScheduledEvents(); 535 } finally { 536 if (future == null) { 537 nextFilter.filterClose(session); 538 } else { 539 future.addListener(new IoFutureListener() { 540 public void operationComplete(IoFuture future) { 541 nextFilter.filterClose(session); 542 } 543 }); 544 } 545 } 546 } 547 548 private WriteFuture initiateClosure(NextFilter nextFilter, IoSession session) 549 throws SSLException { 550 SSLHandler handler = getSSLSessionHandler(session); 551 if (!handler.closeOutbound()) { 553 return DefaultWriteFuture.newNotWrittenFuture(session); 554 } 555 556 WriteFuture future = handler.writeNetBuffer(nextFilter); 558 559 if (handler.isInboundDone()) { 560 handler.destroy(); 561 } 562 563 if (session.containsAttribute(USE_NOTIFICATION)) { 564 handler.scheduleMessageReceived(nextFilter, SESSION_UNSECURED); 565 } 566 567 return future; 568 } 569 570 572 private void handleSSLData(NextFilter nextFilter, SSLHandler handler) 573 throws SSLException { 574 if (handler.isInitialHandshakeComplete()) { 576 handler.flushPreHandshakeEvents(); 577 } 578 579 handler.writeNetBuffer(nextFilter); 581 582 handleAppDataRead(nextFilter, handler); 584 } 585 586 private void handleAppDataRead(NextFilter nextFilter, SSLHandler handler) { 587 IoSession session = handler.getSession(); 588 if (!handler.getAppBuffer().hasRemaining()) { 589 return; 590 } 591 592 if (SessionLog.isDebugEnabled(session)) { 593 SessionLog.debug(session, " appBuffer: " + handler.getAppBuffer()); 594 } 595 596 ByteBuffer readBuffer = SSLHandler.copy(handler.getAppBuffer()); 598 if (SessionLog.isDebugEnabled(session)) { 599 SessionLog.debug(session, " app data read: " + readBuffer + " (" 600 + readBuffer.getHexDump() + ')'); 601 } 602 603 handler.scheduleMessageReceived(nextFilter, readBuffer); 604 } 605 606 private SSLHandler getSSLSessionHandler(IoSession session) { 607 SSLHandler handler = getSSLSessionHandler0(session); 608 if (handler == null) { 609 throw new IllegalStateException (); 610 } 611 if (handler.getParent() != this) { 612 throw new IllegalArgumentException ("Not managed by this filter."); 613 } 614 return handler; 615 } 616 617 private SSLHandler getSSLSessionHandler0(IoSession session) { 618 return (SSLHandler) session.getAttribute(SSL_HANDLER); 619 } 620 621 628 public static class SSLFilterMessage { 629 private final String name; 630 631 private SSLFilterMessage(String name) { 632 this.name = name; 633 } 634 635 public String toString() { 636 return name; 637 } 638 } 639 640 private static class EncryptedBuffer extends ByteBufferProxy { 641 private final ByteBuffer originalBuffer; 642 643 private EncryptedBuffer(ByteBuffer buf, ByteBuffer originalBuffer) { 644 super(buf); 645 this.originalBuffer = originalBuffer; 646 } 647 } 648 } 649 | Popular Tags |