You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jo...@apache.org on 2021/09/14 17:58:03 UTC
[mina] 03/05: Updates SSL & unit tests for the main SSL package
changes
This is an automated email from the ASF dual-hosted git repository.
johnnyv pushed a commit to branch 2.2.X
in repository https://gitbox.apache.org/repos/asf/mina.git
commit 8b61c5b33448cdf1c88f72bc506b517258829b8d
Author: Jonathan Valliere <jo...@apache.org>
AuthorDate: Thu Sep 9 12:46:58 2021 -0400
Updates SSL & unit tests for the main SSL package changes
---
.../mina/core/session/AbstractIoSession.java | 3 +-
.../mina/filter/codec/textline/LineDelimiter.java | 2 +-
.../mina/filter/ssl/BogusTrustManagerFactory.java | 1 +
...lEvent.java => DisableEncryptWriteRequest.java} | 13 +-
.../{SslEvent.java => EncryptedWriteRequest.java} | 30 +-
...lContextFactory.java => SSLContextFactory.java} | 2 +-
.../filter/ssl/{SslEvent.java => SSLEvent.java} | 2 +-
.../{ssl2/SSL2Filter.java => ssl/SSLFilter.java} | 35 +-
.../{ssl2/SSL2Handler.java => ssl/SSLHandler.java} | 33 +-
.../SSL2HandlerG0.java => ssl/SSLHandlerG0.java} | 46 +-
.../java/org/apache/mina/filter/ssl/SslFilter.java | 909 ---------------------
.../org/apache/mina/filter/ssl/SslHandler.java | 872 --------------------
.../mina/filter/ssl2/EncryptedWriteRequest.java | 19 -
.../transport/socket/nio/NioSocketSession.java | 8 +-
.../SslTestHandshakeExceptionDIRMINA1077Test.java | 35 +-
...lDIRMINA937Test.java => SSLDIRMINA937Test.java} | 13 +-
.../org/apache/mina/filter/ssl/SSLEngineTest.java | 465 +++++++++++
.../SSL2SimpleTest.java => ssl/SSLFilterMain.java} | 11 +-
.../org/apache/mina/filter/ssl/SslEngineTest.java | 486 -----------
.../org/apache/mina/filter/ssl/SslFilterTest.java | 142 ----
.../java/org/apache/mina/filter/ssl/SslTest.java | 266 ------
.../java/org/apache/mina/example/chat/Main.java | 4 +-
.../example/chat/client/ChatClientSupport.java | 5 +-
.../org/apache/mina/example/echoserver/Main.java | 4 +-
.../apache/mina/example/tcp/perf/TcpSslClient.java | 5 +-
.../apache/mina/example/tcp/perf/TcpSslServer.java | 4 +-
.../mina/example/echoserver/AbstractTest.java | 9 +-
.../mina/example/echoserver/ConnectorTest.java | 13 +-
.../mina/example/echoserver/ssl/SslFilterTest.java | 6 +-
29 files changed, 633 insertions(+), 2810 deletions(-)
diff --git a/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java b/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
index 1bd9786..3da42dc 100644
--- a/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
+++ b/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
@@ -575,8 +575,7 @@ public abstract class AbstractIoSession implements IoSession {
filterChain.fireFilterWrite(writeRequest);
// TODO : This is not our business ! The caller has created a
- // FileChannel,
- // he has to close it !
+ // FileChannel and has to close it !
if (openedFileChannel != null) {
// If we opened a FileChannel, it needs to be closed when the write
// has completed
diff --git a/mina-core/src/main/java/org/apache/mina/filter/codec/textline/LineDelimiter.java b/mina-core/src/main/java/org/apache/mina/filter/codec/textline/LineDelimiter.java
index 9910f99..8fd1a5a 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/codec/textline/LineDelimiter.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/codec/textline/LineDelimiter.java
@@ -38,7 +38,7 @@ public class LineDelimiter {
/** the line delimiter constant of the current O/S. */
public static final LineDelimiter DEFAULT;
- /** Compute the default delimiter on he current OS */
+ /** Compute the default delimiter on the current OS */
static {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintWriter out = new PrintWriter(bout, true);
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/BogusTrustManagerFactory.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/BogusTrustManagerFactory.java
index e0402c2..36be305 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/BogusTrustManagerFactory.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/BogusTrustManagerFactory.java
@@ -70,6 +70,7 @@ public class BogusTrustManagerFactory extends TrustManagerFactory {
/**
* Creates a new BogusTrustManagerFactory instance
*/
+ @SuppressWarnings("deprecation")
public BogusTrustManagerFactory() {
super(new BogusTrustManagerFactorySpi(), new Provider("MinaBogus", 1.0, "") {
private static final long serialVersionUID = -4024169055312053827L;
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/DisableEncryptWriteRequest.java
similarity index 76%
copy from mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
copy to mina-core/src/main/java/org/apache/mina/filter/ssl/DisableEncryptWriteRequest.java
index e1c497d..5f92555 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/DisableEncryptWriteRequest.java
@@ -19,14 +19,11 @@
*/
package org.apache.mina.filter.ssl;
-import org.apache.mina.filter.FilterEvent;
+import org.apache.mina.core.write.WriteRequest;
/**
- * A SSL event sent by {@link SslFilter} when the session is secured or not
- * secured.
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ * Interface used to designate WriteRequest objects which should not be encrypted.
*/
-public enum SslEvent implements FilterEvent {
- SECURED, UNSECURED
-}
+public interface DisableEncryptWriteRequest extends WriteRequest {
+
+}
\ No newline at end of file
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/EncryptedWriteRequest.java
similarity index 51%
copy from mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
copy to mina-core/src/main/java/org/apache/mina/filter/ssl/EncryptedWriteRequest.java
index e1c497d..8279dc7 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/EncryptedWriteRequest.java
@@ -19,14 +19,28 @@
*/
package org.apache.mina.filter.ssl;
-import org.apache.mina.filter.FilterEvent;
+import org.apache.mina.core.write.DefaultWriteRequest;
+import org.apache.mina.core.write.WriteRequest;
/**
- * A SSL event sent by {@link SslFilter} when the session is secured or not
- * secured.
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ * Specialty WriteRequest which indicates that the contents has been encrypted.
+ * <p>
+ * This prevents a WriteRequest from being encrypted twice and allows unwrapping
+ * of these WriteRequets when dispatching the messageSent events.
+ * <p>
+ * Users should not create their own EncryptedWriteRequest objects.
*/
-public enum SslEvent implements FilterEvent {
- SECURED, UNSECURED
-}
+public class EncryptedWriteRequest extends DefaultWriteRequest {
+
+ // The original message
+ private WriteRequest originalRequest;
+
+ public EncryptedWriteRequest(Object encodedMessage, WriteRequest parent) {
+ super(encodedMessage, parent != null ? parent.getFuture() : null);
+ this.originalRequest = parent != null ? parent : this;
+ }
+
+ public WriteRequest getOriginalRequest() {
+ return this.originalRequest;
+ }
+}
\ No newline at end of file
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslContextFactory.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLContextFactory.java
similarity index 99%
rename from mina-core/src/main/java/org/apache/mina/filter/ssl/SslContextFactory.java
rename to mina-core/src/main/java/org/apache/mina/filter/ssl/SSLContextFactory.java
index 255eeb5..f942091 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslContextFactory.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLContextFactory.java
@@ -49,7 +49,7 @@ import javax.net.ssl.TrustManagerFactory;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class SslContextFactory {
+public class SSLContextFactory {
private String provider = null;
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLEvent.java
similarity index 95%
rename from mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
rename to mina-core/src/main/java/org/apache/mina/filter/ssl/SSLEvent.java
index e1c497d..ff60a71 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslEvent.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLEvent.java
@@ -27,6 +27,6 @@ import org.apache.mina.filter.FilterEvent;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public enum SslEvent implements FilterEvent {
+public enum SSLEvent implements FilterEvent {
SECURED, UNSECURED
}
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLFilter.java
similarity index 90%
rename from mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java
rename to mina-core/src/main/java/org/apache/mina/filter/ssl/SSLFilter.java
index 00554db..ab32b75 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Filter.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLFilter.java
@@ -17,7 +17,7 @@
* under the License.
*
*/
-package org.apache.mina.filter.ssl2;
+package org.apache.mina.filter.ssl;
import java.net.InetSocketAddress;
import java.util.Objects;
@@ -40,30 +40,31 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * An simple SSL processor which performs flow control of encrypted information
+ * A SSL processor which performs flow control of encrypted information
* on the filter-chain.
* <p>
* The initial handshake is automatically enabled for "client" sessions once the
* filter is added to the filter-chain and the session is connected.
*
+ * @author Jonathan Valliere
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class SSL2Filter extends IoFilterAdapter {
+public class SSLFilter extends IoFilterAdapter {
/**
* The presence of this attribute in a session indicates that the session is
* secured.
*/
- static public final AttributeKey SSL_SECURED = new AttributeKey(SSL2Filter.class, "status");
+ static public final AttributeKey SSL_SECURED = new AttributeKey(SSLFilter.class, "status");
/**
* Returns the SSL2Handler object
*/
- static protected final AttributeKey SSL_HANDLER = new AttributeKey(SSL2Filter.class, "handler");
+ static protected final AttributeKey SSL_HANDLER = new AttributeKey(SSLFilter.class, "handler");
/**
* The logger
*/
- static protected final Logger LOGGER = LoggerFactory.getLogger(SSL2Filter.class);
+ static protected final Logger LOGGER = LoggerFactory.getLogger(SSLFilter.class);
/**
* Task executor for processing handshakes
@@ -82,7 +83,7 @@ public class SSL2Filter extends IoFilterAdapter {
*
* @param context The SSLContext to use
*/
- public SSL2Filter(SSLContext context) {
+ public SSLFilter(SSLContext context) {
Objects.requireNonNull(context, "ssl must not be null");
this.mContext = context;
@@ -166,7 +167,7 @@ public class SSL2Filter extends IoFilterAdapter {
@Override
public void onPreAdd(IoFilterChain parent, String name, NextFilter next) throws Exception {
// Check that we don't have a SSL filter already present in the chain
- if (parent.contains(SSL2Filter.class)) {
+ if (parent.contains(SSLFilter.class)) {
throw new IllegalStateException("Only one SSL filter is permitted in a chain");
}
@@ -193,7 +194,7 @@ public class SSL2Filter extends IoFilterAdapter {
@Override
public void onPreRemove(IoFilterChain parent, String name, NextFilter next) throws Exception {
IoSession session = parent.getSession();
- onClose(next, session, false);
+ this.onClose(next, session, false);
}
/**
@@ -205,12 +206,12 @@ public class SSL2Filter extends IoFilterAdapter {
* @throws Exception
*/
synchronized protected void onConnected(NextFilter next, IoSession session) throws Exception {
- SSL2Handler x = SSL2Handler.class.cast(session.getAttribute(SSL_HANDLER));
+ SSLHandler x = SSLHandler.class.cast(session.getAttribute(SSL_HANDLER));
if (x == null) {
final InetSocketAddress s = InetSocketAddress.class.cast(session.getRemoteAddress());
final SSLEngine e = this.createEngine(session, s);
- x = new SSL2HandlerG0(e, EXECUTOR, session);
+ x = new SSLHandlerG0(e, EXECUTOR, session);
session.setAttribute(SSL_HANDLER, x);
}
@@ -219,12 +220,12 @@ public class SSL2Filter extends IoFilterAdapter {
synchronized protected void onClose(NextFilter next, IoSession session, boolean linger) throws Exception {
session.removeAttribute(SSL_SECURED);
- SSL2Handler x = SSL2Handler.class.cast(session.removeAttribute(SSL_HANDLER));
+ SSLHandler x = SSLHandler.class.cast(session.removeAttribute(SSL_HANDLER));
if (x != null) {
x.close(next, linger);
}
}
-
+
/**
* Customization handler for creating the engine
*
@@ -277,7 +278,7 @@ public class SSL2Filter extends IoFilterAdapter {
public void messageReceived(NextFilter next, IoSession session, Object message) throws Exception {
if (LOGGER.isDebugEnabled())
LOGGER.debug("session {} received {}", session, message);
- SSL2Handler x = SSL2Handler.class.cast(session.getAttribute(SSL_HANDLER));
+ SSLHandler x = SSLHandler.class.cast(session.getAttribute(SSL_HANDLER));
x.receive(next, IoBuffer.class.cast(message));
}
@@ -291,7 +292,7 @@ public class SSL2Filter extends IoFilterAdapter {
if (request instanceof EncryptedWriteRequest) {
EncryptedWriteRequest e = EncryptedWriteRequest.class.cast(request);
- SSL2Handler x = SSL2Handler.class.cast(session.getAttribute(SSL_HANDLER));
+ SSLHandler x = SSLHandler.class.cast(session.getAttribute(SSL_HANDLER));
x.ack(next, request);
if (e.getOriginalRequest() != e) {
next.messageSent(session, e.getOriginalRequest());
@@ -309,10 +310,10 @@ public class SSL2Filter extends IoFilterAdapter {
if (LOGGER.isDebugEnabled())
LOGGER.debug("session {} write {}", session, request);
- if (request instanceof EncryptedWriteRequest) {
+ if (request instanceof EncryptedWriteRequest || request instanceof DisableEncryptWriteRequest) {
super.filterWrite(next, session, request);
} else {
- SSL2Handler x = SSL2Handler.class.cast(session.getAttribute(SSL_HANDLER));
+ SSLHandler x = SSLHandler.class.cast(session.getAttribute(SSL_HANDLER));
x.write(next, request);
}
}
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandler.java
similarity index 84%
rename from mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java
rename to mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandler.java
index b5e522b..029d7be 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2Handler.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandler.java
@@ -1,4 +1,23 @@
-package org.apache.mina.filter.ssl2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.filter.ssl;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
@@ -16,7 +35,13 @@ import org.apache.mina.core.write.WriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public abstract class SSL2Handler {
+/**
+ * Default interface for SSL exposed to the {@link SSLFilter}
+ *
+ * @author Jonathan Valliere
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public abstract class SSLHandler {
/**
* Minimum size of encoder buffer in packets
@@ -36,7 +61,7 @@ public abstract class SSL2Handler {
/**
* Static logger
*/
- static protected final Logger LOGGER = LoggerFactory.getLogger(SSL2Handler.class);
+ static protected final Logger LOGGER = LoggerFactory.getLogger(SSLHandler.class);
/**
* Write Requests which are enqueued prior to the completion of the handshaking
@@ -75,7 +100,7 @@ public abstract class SSL2Handler {
* @param e executor
* @param s session
*/
- public SSL2Handler(SSLEngine p, Executor e, IoSession s) {
+ public SSLHandler(SSLEngine p, Executor e, IoSession s) {
this.mEngine = p;
this.mExecutor = e;
this.mSession = s;
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandlerG0.java
similarity index 91%
rename from mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java
rename to mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandlerG0.java
index fd2ecd1..de99b7f 100644
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/SSL2HandlerG0.java
+++ b/mina-core/src/main/java/org/apache/mina/filter/ssl/SSLHandlerG0.java
@@ -1,4 +1,23 @@
-package org.apache.mina.filter.ssl2;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.filter.ssl;
import java.nio.BufferOverflowException;
import java.util.ArrayList;
@@ -13,9 +32,17 @@ import org.apache.mina.core.filterchain.IoFilter.NextFilter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRejectedException;
import org.apache.mina.core.write.WriteRequest;
-import org.apache.mina.filter.ssl.SslEvent;
-public class SSL2HandlerG0 extends SSL2Handler {
+/**
+ * Default implementation of SSLHandler
+ * <p>
+ * The concurrency model is enforced using a simple mutex to ensure that the
+ * state of the decode buffer and closure is concurrent with the SSLEngine.
+ *
+ * @author Jonathan Valliere
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class SSLHandlerG0 extends SSLHandler {
/**
* Maximum number of queued messages waiting for encoding
@@ -69,7 +96,7 @@ public class SSL2HandlerG0 extends SSL2Handler {
* @param e executor
* @param s session
*/
- public SSL2HandlerG0(SSLEngine p, Executor e, IoSession s) {
+ public SSLHandlerG0(SSLEngine p, Executor e, IoSession s) {
super(p, e, s);
}
@@ -462,8 +489,8 @@ public class SSL2HandlerG0 extends SSL2Handler {
synchronized protected void lfinish(final NextFilter next) throws SSLException {
if (this.mHandshakeComplete == false) {
this.mHandshakeComplete = true;
- this.mSession.setAttribute(SSL2Filter.SSL_SECURED, this.mEngine.getSession());
- next.event(this.mSession, SslEvent.SECURED);
+ this.mSession.setAttribute(SSLFilter.SSL_SECURED, this.mEngine.getSession());
+ next.event(this.mSession, SSLEvent.SECURED);
}
/**
* There exists a bug in the JDK which emits FINISHED twice instead of once.
@@ -518,9 +545,14 @@ public class SSL2HandlerG0 extends SSL2Handler {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("{} close() - closing session", toString());
}
+
+ if (this.mHandshakeComplete) {
+ next.event(this.mSession, SSLEvent.UNSECURED);
+ }
this.mOutboundLinger = linger;
this.mOutboundClosing = true;
+
if (linger == false) {
if (this.mEncodeQueue.size() != 0) {
next.exceptionCaught(this.mSession,
@@ -542,7 +574,7 @@ public class SSL2HandlerG0 extends SSL2Handler {
this.mExecutor.execute(new Runnable() {
@Override
public void run() {
- SSL2HandlerG0.this.execute_task(next);
+ SSLHandlerG0.this.execute_task(next);
}
});
}
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
deleted file mode 100644
index 1c4a532..0000000
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslFilter.java
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.mina.filter.ssl;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
-
-import org.apache.mina.core.buffer.IoBuffer;
-import org.apache.mina.core.filterchain.IoFilter;
-import org.apache.mina.core.filterchain.IoFilterAdapter;
-import org.apache.mina.core.filterchain.IoFilterChain;
-import org.apache.mina.core.future.DefaultWriteFuture;
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
-import org.apache.mina.core.future.WriteFuture;
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.service.IoHandler;
-import org.apache.mina.core.session.AttributeKey;
-import org.apache.mina.core.session.IoSession;
-import org.apache.mina.core.write.DefaultWriteRequest;
-import org.apache.mina.core.write.WriteRequest;
-import org.apache.mina.core.write.WriteToClosedSessionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * An SSL filter that encrypts and decrypts the data exchanged in the session.
- * Adding this filter triggers SSL handshake procedure immediately by sending
- * a SSL 'hello' message, so you don't need to call
- * {@link #startSsl(IoSession)} manually unless you are implementing StartTLS
- * (see below). If you don't want the handshake procedure to start
- * immediately, please specify {@code false} as {@code autoStart} parameter in
- * the constructor.
- * <p>
- * This filter uses an {@link SSLEngine} which was introduced in Java 5, so
- * Java version 5 or above is mandatory to use this filter. And please note that
- * this filter only works for TCP/IP connections.
- *
- * <h2>Implementing StartTLS</h2>
- * <p>
- * You can use {@link #DISABLE_ENCRYPTION_ONCE} attribute to implement StartTLS:
- * <pre>
- * public void messageReceived(IoSession session, Object message) {
- * if (message instanceof MyStartTLSRequest) {
- * // Insert SSLFilter to get ready for handshaking
- * session.getFilterChain().addFirst(sslFilter);
- *
- * // Disable encryption temporarily.
- * // This attribute will be removed by SSLFilter
- * // inside the Session.write() call below.
- * session.setAttribute(SSLFilter.DISABLE_ENCRYPTION_ONCE, Boolean.TRUE);
- *
- * // Write StartTLSResponse which won't be encrypted.
- * session.write(new MyStartTLSResponse(OK));
- *
- * // Now DISABLE_ENCRYPTION_ONCE attribute is cleared.
- * assert session.getAttribute(SSLFilter.DISABLE_ENCRYPTION_ONCE) == null;
- * }
- * }
- * </pre>
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- * @org.apache.xbean.XBean
- */
-public class SslFilter extends IoFilterAdapter {
- /** The logger */
- private static final Logger LOGGER = LoggerFactory.getLogger(SslFilter.class);
-
- /**
- * A session attribute key that stores underlying {@link SSLSession}
- * for each session.
- */
- public static final AttributeKey SSL_SESSION = new AttributeKey(SslFilter.class, "session");
-
- /**
- * A session attribute key that makes next one write request bypass
- * this filter (not encrypting the data). This is a marker attribute,
- * which means that you can put whatever as its value. ({@link Boolean#TRUE}
- * is preferred.) The attribute is automatically removed from the session
- * attribute map as soon as {@link IoSession#write(Object)} is invoked,
- * and therefore should be put again if you want to make more messages
- * bypass this filter. This is especially useful when you implement
- * StartTLS.
- */
- public static final AttributeKey DISABLE_ENCRYPTION_ONCE = new AttributeKey(SslFilter.class, "disableOnce");
-
- /**
- * A session attribute key that makes this filter to emit a
- * {@link IoHandler#messageReceived(IoSession, Object)} event with a
- * special message ({@link SslEvent#SECURED} or {@link SslEvent#UNSECURED}).
- * This is a marker attribute, which means that you can put whatever as its
- * value. ({@link Boolean#TRUE} is preferred.) By default, this filter
- * doesn't emit any events related with SSL session flow control.
- */
- public static final AttributeKey USE_NOTIFICATION = new AttributeKey(SslFilter.class, "useNotification");
-
- /**
- * A session attribute key that should be set to an {@link InetSocketAddress}.
- * Setting this attribute causes
- * {@link SSLContext#createSSLEngine(String, int)} to be called passing the
- * hostname and port of the {@link InetSocketAddress} to get an
- * {@link SSLEngine} instance. If not set {@link SSLContext#createSSLEngine()}
- * will be called.
- * <br>
- * Using this feature {@link SSLSession} objects may be cached and reused
- * when in client mode.
- *
- * @see SSLContext#createSSLEngine(String, int)
- */
- public static final AttributeKey PEER_ADDRESS = new AttributeKey(SslFilter.class, "peerAddress");
-
- /** An attribute containing the next filter */
- private static final AttributeKey NEXT_FILTER = new AttributeKey(SslFilter.class, "nextFilter");
-
- private static final AttributeKey SSL_HANDLER = new AttributeKey(SslFilter.class, "handler");
-
- /** The SslContext used */
- /* No qualifier */final SSLContext sslContext;
-
- /** A flag used to tell the filter to start the handshake immediately */
- private final boolean autoStart;
-
- /** A flag used to determinate if the handshake should start immediately */
- public static final boolean START_HANDSHAKE = true;
-
- /** A flag used to determinate if the handshake should wait for the client to initiate the handshake */
- public static final boolean CLIENT_HANDSHAKE = false;
-
- private boolean client;
-
- private boolean needClientAuth;
-
- private boolean wantClientAuth;
-
- private String[] enabledCipherSuites;
-
- private String[] enabledProtocols;
-
- /**
- * Creates a new SSL filter using the specified {@link SSLContext}.
- * The handshake will start immediately after the filter has been added
- * to the chain.
- *
- * @param sslContext The SSLContext to use
- */
- public SslFilter(SSLContext sslContext) {
- this(sslContext, START_HANDSHAKE);
- }
-
- /**
- * Creates a new SSL filter using the specified {@link SSLContext}.
- * If the <tt>autostart</tt> flag is set to <tt>true</tt>, the
- * handshake will start immediately after the filter has been added
- * to the chain.
- *
- * @param sslContext The SSLContext to use
- * @param autoStart The flag used to tell the filter to start the handshake immediately
- */
- public SslFilter(SSLContext sslContext, boolean autoStart) {
- if (sslContext == null) {
- throw new IllegalArgumentException("sslContext");
- }
-
- this.sslContext = sslContext;
- this.autoStart = autoStart;
- }
-
- /**
- * Returns the underlying {@link SSLSession} for the specified session.
- *
- * @param session The current session
- * @return <tt>null</tt> if no {@link SSLSession} is initialized yet.
- */
- public SSLSession getSslSession(IoSession session) {
- return (SSLSession) session.getAttribute(SSL_SESSION);
- }
-
- /**
- * (Re)starts SSL session for the specified <tt>session</tt> if not started yet.
- * Please note that SSL session is automatically started by default, and therefore
- * you don't need to call this method unless you've used TLS closure.
- *
- * @param session The session that will be switched to SSL mode
- * @return <tt>true</tt> if the SSL session has been started, <tt>false</tt> if already started.
- * @throws SSLException if failed to start the SSL session
- */
- public boolean startSsl(IoSession session) throws SSLException {
- SslHandler sslHandler = getSslSessionHandler(session);
- boolean started;
-
- try {
- synchronized (sslHandler) {
- if (sslHandler.isOutboundDone()) {
- NextFilter nextFilter = (NextFilter) session.getAttribute(NEXT_FILTER);
- sslHandler.destroy();
- sslHandler.init();
- sslHandler.handshake(nextFilter);
- started = true;
- } else {
- started = false;
- }
- sslHandler.flushFilterWrite();
- }
- sslHandler.flushMessageReceived();
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- }
-
- return started;
- }
-
- /**
- * An extended toString() method for sessions. If the SSL handshake
- * is not yet completed, we will print (ssl) in small caps. Once it's
- * completed, we will use SSL capitalized.
- */
- /* no qualifier */String getSessionInfo(IoSession session) {
- StringBuilder sb = new StringBuilder();
-
- if (session.getService() instanceof IoAcceptor) {
- sb.append("Session Server");
-
- } else {
- sb.append("Session Client");
- }
-
- sb.append('[').append(session.getId()).append(']');
-
- SslHandler sslHandler = (SslHandler) session.getAttribute(SSL_HANDLER);
-
- if (sslHandler == null) {
- sb.append("(no sslEngine)");
- } else if (isSslStarted(session)) {
- if (sslHandler.isHandshakeComplete()) {
- sb.append("(SSL)");
- } else {
- sb.append("(ssl...)");
- }
- }
-
- return sb.toString();
- }
-
- /**
- * @return <tt>true</tt> if and only if the specified <tt>session</tt> is
- * encrypted/decrypted over SSL/TLS currently. This method will start
- * to return <tt>false</tt> after TLS <tt>close_notify</tt> message
- * is sent and any messages written after then is not going to get encrypted.
- *
- * @param session the session we want to check
- */
- public boolean isSslStarted(IoSession session) {
- SslHandler sslHandler = (SslHandler) session.getAttribute(SSL_HANDLER);
-
- if (sslHandler == null) {
- return false;
- }
-
- synchronized (sslHandler) {
- return !sslHandler.isOutboundDone();
- }
- }
-
- /**
- * @return <tt>true</tt> if and only if the conditions for
- * {@link #isSslStarted(IoSession)} are met, and the handhake has
- * completed.
- *
- * @param session the session we want to check
- */
- public boolean isSecured(IoSession session) {
- SslHandler sslHandler = (SslHandler) session.getAttribute(SSL_HANDLER);
-
- if (sslHandler == null) {
- return false;
- }
-
- synchronized (sslHandler) {
- return !sslHandler.isOutboundDone() && sslHandler.isHandshakeComplete();
- }
- }
-
-
- /**
- * Stops the SSL session by sending TLS <tt>close_notify</tt> message to
- * initiate TLS closure.
- *
- * @param session the {@link IoSession} to initiate TLS closure
- * @return The Future for the initiated closure
- * @throws SSLException if failed to initiate TLS closure
- */
- public WriteFuture stopSsl(IoSession session) throws SSLException {
- SslHandler sslHandler = getSslSessionHandler(session);
- NextFilter nextFilter = (NextFilter) session.getAttribute(NEXT_FILTER);
- WriteFuture future;
-
- try {
- synchronized (sslHandler) {
- future = initiateClosure(nextFilter, session);
- sslHandler.flushFilterWrite();
- }
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- }
-
- return future;
- }
-
- /**
- * @return <tt>true</tt> if the engine is set to use client mode
- * when handshaking.
- */
- public boolean isUseClientMode() {
- return client;
- }
-
- /**
- * Configures the engine to use client (or server) mode when handshaking.
- *
- * @param clientMode <tt>true</tt> when we are in client mode, <tt>false</tt> when in server mode
- */
- public void setUseClientMode(boolean clientMode) {
- this.client = clientMode;
- }
-
- /**
- * @return <tt>true</tt> if the engine will <em>require</em> client authentication.
- * This option is only useful to engines in the server mode.
- */
- public boolean isNeedClientAuth() {
- return needClientAuth;
- }
-
- /**
- * Configures the engine to <em>require</em> client authentication.
- * This option is only useful for engines in the server mode.
- *
- * @param needClientAuth A flag set when we need to authenticate the client
- */
- public void setNeedClientAuth(boolean needClientAuth) {
- this.needClientAuth = needClientAuth;
- }
-
- /**
- * @return <tt>true</tt> if the engine will <em>request</em> client authentication.
- * This option is only useful to engines in the server mode.
- */
- public boolean isWantClientAuth() {
- return wantClientAuth;
- }
-
- /**
- * Configures the engine to <em>request</em> client authentication.
- * This option is only useful for engines in the server mode.
- *
- * @param wantClientAuth A flag set when we want to check the client authentication
- */
- public void setWantClientAuth(boolean wantClientAuth) {
- this.wantClientAuth = wantClientAuth;
- }
-
- /**
- * @return the list of cipher suites to be enabled when {@link SSLEngine}
- * is initialized. <tt>null</tt> means 'use {@link SSLEngine}'s default.'
- */
- public String[] getEnabledCipherSuites() {
- return enabledCipherSuites;
- }
-
- /**
- * Sets the list of cipher suites to be enabled when {@link SSLEngine}
- * is initialized.
- *
- * @param cipherSuites <tt>null</tt> means 'use {@link SSLEngine}'s default.'
- */
- public void setEnabledCipherSuites(String[] cipherSuites) {
- this.enabledCipherSuites = cipherSuites;
- }
-
- /**
- * @return the list of protocols to be enabled when {@link SSLEngine}
- * is initialized. <tt>null</tt> means 'use {@link SSLEngine}'s default.'
- */
- public String[] getEnabledProtocols() {
- return enabledProtocols;
- }
-
- /**
- * Sets the list of protocols to be enabled when {@link SSLEngine}
- * is initialized.
- *
- * @param protocols <tt>null</tt> means 'use {@link SSLEngine}'s default.'
- */
- public void setEnabledProtocols(String[] protocols) {
- this.enabledProtocols = protocols;
- }
-
- /**
- * Executed just before the filter is added into the chain, we do :
- * <ul>
- * <li>check that we don't have a SSL filter already present
- * <li>we update the next filter
- * <li>we create the SSL handler helper class
- * <li>and we store it into the session's Attributes
- * </ul>
- */
- @Override
- public void onPreAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException {
- // Check that we don't have a SSL filter already present in the chain
- if (parent.contains(SslFilter.class)) {
- String msg = "Only one SSL filter is permitted in a chain.";
- LOGGER.error(msg);
- throw new IllegalStateException(msg);
- }
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Adding the SSL Filter {} to the chain", name);
- }
-
- IoSession session = parent.getSession();
- session.setAttribute(NEXT_FILTER, nextFilter);
-
- // Create a SSL handler and start handshake.
- SslHandler sslHandler = new SslHandler(this, session);
-
- // Adding the supported ciphers in the SSLHandler
- if ((enabledCipherSuites == null) || (enabledCipherSuites.length == 0)) {
- enabledCipherSuites = sslContext.getServerSocketFactory().getSupportedCipherSuites();
- }
-
- sslHandler.init();
-
- session.setAttribute(SSL_HANDLER, sslHandler);
- }
-
- @Override
- public void onPostAdd(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException {
- if (autoStart == START_HANDSHAKE) {
- initiateHandshake(nextFilter, parent.getSession());
- }
- }
-
- @Override
- public void onPreRemove(IoFilterChain parent, String name, NextFilter nextFilter) throws SSLException {
- IoSession session = parent.getSession();
- stopSsl(session);
- session.removeAttribute(NEXT_FILTER);
- session.removeAttribute(SSL_HANDLER);
- }
-
- // IoFilter impl.
- @Override
- public void sessionClosed(NextFilter nextFilter, IoSession session) throws SSLException {
- SslHandler sslHandler = getSslSessionHandler(session);
-
- try {
- synchronized (sslHandler) {
- // release resources
- sslHandler.destroy();
- }
- } finally {
- // notify closed session
- nextFilter.sessionClosed(session);
- }
- }
-
- @Override
- public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws SSLException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{}: Message received : {}", getSessionInfo(session), message);
- }
-
- SslHandler sslHandler = getSslSessionHandler(session);
- AtomicBoolean canPushMessage = new AtomicBoolean( false );
-
- // The SslHandler instance is *guaranteed* to nit be null here
-
- synchronized (sslHandler) {
- if (sslHandler.isOutboundDone() && sslHandler.isInboundDone()) {
- // We aren't handshaking here. Let's push the message to the next filter
-
- // Note: we can push the message to the queue immediately,
- // but don't do so in the synchronized block. We use a protected
- // flag to do so.
- canPushMessage.set( true );
- } else {
- canPushMessage.set( false );
- IoBuffer buf = (IoBuffer) message;
-
- try {
- if (sslHandler.isOutboundDone()) {
- sslHandler.destroy();
- throw new SSLException("Outbound done");
- }
-
- // forward read encrypted data to SSL handler
- sslHandler.messageReceived(nextFilter, buf.buf());
-
- // Handle data to be forwarded to application or written to net
- handleSslData(nextFilter, sslHandler);
-
- if (sslHandler.isInboundDone()) {
- if (sslHandler.isOutboundDone()) {
- sslHandler.destroy();
- } else {
- initiateClosure(nextFilter, session);
- }
-
- if (buf.hasRemaining()) {
- // Forward the data received after closure.
- sslHandler.scheduleMessageReceived(nextFilter, buf);
- }
- }
- } catch (SSLException ssle) {
- if (!sslHandler.isHandshakeComplete()) {
- SSLException newSsle = new SSLHandshakeException("SSL handshake failed.");
- newSsle.initCause(ssle);
- ssle = newSsle;
-
- // Close the session immediately, the handshake has failed
- session.closeNow();
- } else {
- // Free the SSL Handler buffers
- sslHandler.release();
- }
-
- throw ssle;
- }
- }
- }
-
- if (canPushMessage.get()) {
- nextFilter.messageReceived(session, message);
- } else {
- sslHandler.flushMessageReceived();
- }
- }
-
- @Override
- public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
- if (writeRequest instanceof EncryptedWriteRequest) {
- EncryptedWriteRequest wrappedRequest = (EncryptedWriteRequest) writeRequest;
- nextFilter.messageSent(session, wrappedRequest.getParentRequest());
- } else {
- // ignore extra buffers used for handshaking
- }
- }
-
- @Override
- public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
-
- if (cause instanceof WriteToClosedSessionException) {
- // Filter out SSL close notify, which is likely to fail to flush
- // due to disconnection.
- WriteToClosedSessionException e = (WriteToClosedSessionException) cause;
- List<WriteRequest> failedRequests = e.getRequests();
- boolean containsCloseNotify = false;
-
- for (WriteRequest r : failedRequests) {
- if (isCloseNotify(r.getMessage())) {
- containsCloseNotify = true;
- break;
- }
- }
-
- if (containsCloseNotify) {
- if (failedRequests.size() == 1) {
- // close notify is the only failed request; bail out.
- return;
- }
-
- List<WriteRequest> newFailedRequests = new ArrayList<>(failedRequests.size() - 1);
-
- for (WriteRequest r : failedRequests) {
- if (!isCloseNotify(r.getMessage())) {
- newFailedRequests.add(r);
- }
- }
-
- if (newFailedRequests.isEmpty()) {
- // the failedRequests were full with close notify; bail out.
- return;
- }
-
- cause = new WriteToClosedSessionException(newFailedRequests, cause.getMessage(), cause.getCause());
- }
- }
-
- nextFilter.exceptionCaught(session, cause);
- }
-
- private boolean isCloseNotify(Object message) {
- if (!(message instanceof IoBuffer)) {
- return false;
- }
-
- IoBuffer buf = (IoBuffer) message;
- int offset = buf.position();
-
- return (buf.get(offset + 0) == 0x15) /* Alert */
- && (buf.get(offset + 1) == 0x03) /* TLS/SSL */
- && ((buf.get(offset + 2) == 0x00) /* SSL 3.0 */
- || (buf.get(offset + 2) == 0x01) /* TLS 1.0 */
- || (buf.get(offset + 2) == 0x02) /* TLS 1.1 */
- || (buf.get(offset + 2) == 0x03)) /* TLS 1.2 */
- && (buf.get(offset + 3) == 0x00); /* close_notify */
- }
-
- @Override
- public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws SSLException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{}: Writing Message : {}", getSessionInfo(session), writeRequest);
- }
-
- boolean needsFlush = true;
- SslHandler sslHandler = getSslSessionHandler(session);
-
- try {
- synchronized (sslHandler) {
- if (!isSslStarted(session)) {
- sslHandler.scheduleFilterWrite(nextFilter, writeRequest);
- }
- // Don't encrypt the data if encryption is disabled.
- else if (session.containsAttribute(DISABLE_ENCRYPTION_ONCE)) {
- // Remove the marker attribute because it is temporary.
- session.removeAttribute(DISABLE_ENCRYPTION_ONCE);
- sslHandler.scheduleFilterWrite(nextFilter, writeRequest);
- } else {
- // Otherwise, encrypt the buffer.
- IoBuffer buf = (IoBuffer) writeRequest.getMessage();
-
- if (sslHandler.isWritingEncryptedData()) {
- // data already encrypted; simply return buffer
- sslHandler.scheduleFilterWrite(nextFilter, writeRequest);
- } else if (sslHandler.isHandshakeComplete()) {
- // SSL encrypt
- sslHandler.encrypt(buf.buf());
- IoBuffer encryptedBuffer = sslHandler.fetchOutNetBuffer();
- writeRequest.setMessage( encryptedBuffer );
- sslHandler.scheduleFilterWrite(nextFilter, new EncryptedWriteRequest(writeRequest,
- encryptedBuffer));
- } else {
- if (session.isConnected()) {
- // Handshake not complete yet.
- sslHandler.schedulePreHandshakeWriteRequest(nextFilter, writeRequest);
- }
-
- needsFlush = false;
- }
- }
- if (needsFlush) {
- sslHandler.flushFilterWrite();
- }
- }
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- }
- }
-
- @Override
- public void filterClose(final NextFilter nextFilter, final IoSession session) throws SSLException {
- SslHandler sslHandler = (SslHandler) session.getAttribute(SSL_HANDLER);
-
- if (sslHandler == null) {
- // The connection might already have closed, or
- // SSL might have not started yet.
- nextFilter.filterClose(session);
- return;
- }
-
- WriteFuture future = null;
-
- try {
- synchronized (sslHandler) {
- if (isSslStarted(session)) {
- future = initiateClosure(nextFilter, session);
- future.addListener(new IoFutureListener<IoFuture>() {
- @Override
- public void operationComplete(IoFuture future) {
- nextFilter.filterClose(session);
- }
- });
- }
- sslHandler.flushFilterWrite();
- }
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- } finally {
- if (future == null) {
- nextFilter.filterClose(session);
- }
- }
- }
-
- /**
- * Initiate the SSL handshake. This can be invoked if you have set the 'autoStart' to
- * false when creating the SslFilter instance.
- *
- * @param session The session for which the SSL handshake should be done
- * @throws SSLException If the handshake failed
- */
- public void initiateHandshake(IoSession session) throws SSLException {
- IoFilterChain filterChain = session.getFilterChain();
-
- if (filterChain == null) {
- throw new SSLException("No filter chain");
- }
-
- IoFilter.NextFilter nextFilter = filterChain.getNextFilter(SslFilter.class);
-
- if (nextFilter == null) {
- throw new SSLException("No SSL next filter in the chain");
- }
-
- initiateHandshake(nextFilter, session);
- }
-
- private void initiateHandshake(NextFilter nextFilter, IoSession session) throws SSLException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} : Starting the first handshake", getSessionInfo(session));
- }
-
- SslHandler sslHandler = getSslSessionHandler(session);
-
- try {
- synchronized (sslHandler) {
- sslHandler.handshake(nextFilter);
- sslHandler.flushFilterWrite();
- }
- sslHandler.flushMessageReceived();
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- }
- }
-
- private WriteFuture initiateClosure(NextFilter nextFilter, IoSession session) throws SSLException {
- SslHandler sslHandler = getSslSessionHandler(session);
- WriteFuture future = null;
-
- // if already shut down
- try {
- synchronized(sslHandler) {
- if (!sslHandler.closeOutbound()) {
- return DefaultWriteFuture.newNotWrittenFuture(session, new IllegalStateException(
- "SSL session is shut down already."));
- }
-
- // there might be data to write out here?
- future = sslHandler.writeNetBuffer(nextFilter);
-
- if (future == null) {
- future = DefaultWriteFuture.newWrittenFuture(session);
- }
-
- if (sslHandler.isInboundDone()) {
- sslHandler.destroy();
- }
- }
-
- // Inform that the session is not any more secured
- session.getFilterChain().fireEvent(SslEvent.UNSECURED);
- } catch (SSLException se) {
- sslHandler.release();
- throw se;
- }
-
- return future;
- }
-
- // Utilities
- private void handleSslData(NextFilter nextFilter, SslHandler sslHandler) throws SSLException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{}: Processing the SSL Data ", getSessionInfo(sslHandler.getSession()));
- }
-
- // Flush any buffered write requests occurred before handshaking.
- if (sslHandler.isHandshakeComplete()) {
- sslHandler.flushPreHandshakeEvents();
- }
-
- // Write encrypted data to be written (if any)
- sslHandler.writeNetBuffer(nextFilter);
-
- // handle app. data read (if any)
- handleAppDataRead(nextFilter, sslHandler);
- }
-
- private void handleAppDataRead(NextFilter nextFilter, SslHandler sslHandler) {
- // forward read app data
- IoBuffer readBuffer = sslHandler.fetchAppBuffer();
-
- if (readBuffer.hasRemaining()) {
- sslHandler.scheduleMessageReceived(nextFilter, readBuffer);
- }
- }
-
- private SslHandler getSslSessionHandler(IoSession session) {
- SslHandler sslHandler = (SslHandler) session.getAttribute(SSL_HANDLER);
-
- if (sslHandler == null) {
- throw new IllegalStateException();
- }
-
- synchronized(sslHandler) {
- if (sslHandler.getSslFilter() != this) {
- throw new IllegalArgumentException("Not managed by this filter.");
- }
- }
-
- return sslHandler;
- }
-
- /**
- * A message that is sent from {@link SslFilter} when the connection became
- * secure or is not secure anymore.
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
- public static class SslFilterMessage {
- private final String name;
-
- private SslFilterMessage(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- /**
- * A private class used to store encrypted messages. This is necessary
- * to be able to emit the messageSent event with the proper original
- * message, but not for handshake messages, which will be swallowed.
- *
- */
- /* package protected */ static class EncryptedWriteRequest extends DefaultWriteRequest {
- // Thee encrypted messagee
- private final IoBuffer encryptedMessage;
-
- // The original message
- private WriteRequest parentRequest;
-
- /**
- * Create a new instance of an EncryptedWriteRequest
- * @param writeRequest The parent request
- * @param encryptedMessage The encrypted message
- */
- private EncryptedWriteRequest(WriteRequest writeRequest, IoBuffer encryptedMessage) {
- super(encryptedMessage);
- parentRequest = writeRequest;
- this.encryptedMessage = encryptedMessage;
- }
-
- /**
- * @return teh encrypted message
- */
- @Override
- public Object getMessage() {
- return encryptedMessage;
- }
-
- /**
- * @return The parent WriteRequest
- */
- public WriteRequest getParentRequest() {
- return parentRequest;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public WriteFuture getFuture() {
- return parentRequest.getFuture();
- }
- }
-}
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java b/mina-core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java
deleted file mode 100644
index 6198100..0000000
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl/SslHandler.java
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.mina.filter.ssl;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLEngineResult.HandshakeStatus;
-import javax.net.ssl.SSLEngineResult.Status;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-
-import org.apache.mina.core.RuntimeIoException;
-import org.apache.mina.core.buffer.IoBuffer;
-import org.apache.mina.core.filterchain.IoFilter.NextFilter;
-import org.apache.mina.core.filterchain.IoFilterEvent;
-import org.apache.mina.core.future.DefaultWriteFuture;
-import org.apache.mina.core.future.WriteFuture;
-import org.apache.mina.core.session.IoEventType;
-import org.apache.mina.core.session.IoSession;
-import org.apache.mina.core.write.DefaultWriteRequest;
-import org.apache.mina.core.write.WriteRequest;
-import org.apache.mina.core.write.WriteRequestQueue;
-import org.apache.mina.filter.ssl.SslFilter.EncryptedWriteRequest;
-import org.apache.mina.filter.ssl2.SSL2Filter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A helper class using the SSLEngine API to decrypt/encrypt data.
- * <p/>
- * Each connection has a SSLEngine that is used through the lifetime of the connection.
- * We allocate buffers for use as the outbound and inbound network buffers.
- * These buffers handle all of the intermediary data for the SSL connection. To make things easy,
- * we'll require outNetBuffer be completely flushed before trying to wrap any more data.
- * <p/>
- * This class is not to be used by any client, it's closely associated with the SSL Filter.
- * None of its methods are public as they should not be used by any other class but from
- * the SslFilter class, in the same package
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-/** No qualifier*/
-class SslHandler {
- /** A logger for this class */
- private static final Logger LOGGER = LoggerFactory.getLogger(SslHandler.class);
-
- /** The SSL Filter which has created this handler */
- private final SslFilter sslFilter;
-
- /** The current session */
- private final IoSession session;
-
- private final Queue<IoFilterEvent> preHandshakeEventQueue = new ConcurrentLinkedQueue<>();
-
- private final Queue<IoFilterEvent> filterWriteEventQueue = new ConcurrentLinkedQueue<>();
-
- /** A queue used to stack all the incoming data until the SSL session is established */
- private final Queue<IoFilterEvent> messageReceivedEventQueue = new ConcurrentLinkedQueue<>();
-
- private SSLEngine sslEngine;
-
- /**
- * Encrypted data from the net
- */
- private IoBuffer inNetBuffer;
-
- /**
- * Encrypted data to be written to the net
- */
- private IoBuffer outNetBuffer;
-
- /**
- * Application cleartext data to be read by application
- */
- private IoBuffer appBuffer;
-
- /**
- * Empty buffer used during initial handshake and close operations
- */
- private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
-
- private SSLEngineResult.HandshakeStatus handshakeStatus;
-
- /**
- * A flag set to true when the first SSL handshake has been completed
- * This is used to avoid sending a notification to the application handler
- * when we switch to a SECURE or UNSECURE session.
- */
- private boolean firstSSLNegociation;
-
- /** A flag set to true when a SSL Handshake has been completed */
- private boolean handshakeComplete;
-
- /** A flag used to indicate to the SslFilter that the buffer
- * it will write is already encrypted (this will be the case
- * for data being produced during the handshake). */
- private boolean writingEncryptedData;
-
- /**
- * Create a new SSL Handler, and initialize it.
- *
- * @param sslContext
- * @throws SSLException
- */
- /* no qualifier */SslHandler(SslFilter sslFilter, IoSession session) {
- this.sslFilter = sslFilter;
- this.session = session;
- }
-
- /**
- * Initialize the SSL handshake.
- *
- * @throws SSLException If the underlying SSLEngine handshake initialization failed
- */
- /* no qualifier */void init() throws SSLException {
- if (sslEngine != null) {
- // We already have a SSL engine created, no need to create a new one
- return;
- }
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} Initializing the SSL Handler", sslFilter.getSessionInfo(session));
- }
-
- InetSocketAddress peer = (InetSocketAddress) session.getAttribute(SslFilter.PEER_ADDRESS);
-
- // Create the SSL engine here
- if (peer == null) {
- sslEngine = sslFilter.sslContext.createSSLEngine();
- } else {
- sslEngine = sslFilter.sslContext.createSSLEngine(peer.getHostName(), peer.getPort());
- }
-
- // Initialize the engine in client mode if necessary
- sslEngine.setUseClientMode(sslFilter.isUseClientMode());
-
- // Initialize the different SslEngine modes
- if (!sslEngine.getUseClientMode()) {
- // Those parameters are only valid when in server mode
- if (sslFilter.isWantClientAuth()) {
- sslEngine.setWantClientAuth(true);
- }
-
- if (sslFilter.isNeedClientAuth()) {
- sslEngine.setNeedClientAuth(true);
- }
- }
-
- // Set the cipher suite to use by this SslEngine instance
- if (sslFilter.getEnabledCipherSuites() != null) {
- sslEngine.setEnabledCipherSuites(sslFilter.getEnabledCipherSuites());
- }
-
- // Set the list of enabled protocols
- if (sslFilter.getEnabledProtocols() != null) {
- sslEngine.setEnabledProtocols(sslFilter.getEnabledProtocols());
- }
-
- // TODO : we may not need to call this method...
- // However, if we don't call it here, the tests are failing. Why?
- handshakeStatus = sslEngine.getHandshakeStatus();
-
- // Default value
- writingEncryptedData = false;
-
- // We haven't yet started a SSL negotiation
- // set the flags accordingly
- firstSSLNegociation = true;
- handshakeComplete = false;
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} SSL Handler Initialization done.", sslFilter.getSessionInfo(session));
- }
- }
-
-
- /**
- * Release allocated buffers.
- */
- /* no qualifier */void destroy() {
- if (sslEngine == null) {
- return;
- }
-
- // Close inbound and flush all remaining data if available.
- try {
- sslEngine.closeInbound();
- } catch (SSLException e) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Unexpected exception from SSLEngine.closeInbound().", e);
- }
- }
-
- if (outNetBuffer != null) {
- outNetBuffer.capacity(sslEngine.getSession().getPacketBufferSize());
- } else {
- createOutNetBuffer(0);
- }
- try {
- do {
- outNetBuffer.clear();
- } while (sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()).bytesProduced() > 0);
- } catch (SSLException e) {
- // Ignore.
- } finally {
- outNetBuffer.free();
- outNetBuffer = null;
- }
-
- sslEngine.closeOutbound();
- sslEngine = null;
-
- preHandshakeEventQueue.clear();
- }
-
- /**
- * @return The SSL filter which has created this handler
- */
- /* no qualifier */SslFilter getSslFilter() {
- return sslFilter;
- }
-
- /* no qualifier */IoSession getSession() {
- return session;
- }
-
- /**
- * Check if we are writing encrypted data.
- */
- /* no qualifier */boolean isWritingEncryptedData() {
- return writingEncryptedData;
- }
-
- /**
- * Check if handshake is completed.
- */
- /* no qualifier */boolean isHandshakeComplete() {
- return handshakeComplete;
- }
-
- /**
- * Check if handshake is on going.
- */
- /* no qualifier */boolean notHandshaking() {
- return handshakeStatus == HandshakeStatus.FINISHED || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING;
- }
-
- /* no qualifier */boolean isInboundDone() {
- return sslEngine == null || sslEngine.isInboundDone();
- }
-
- /* no qualifier */boolean isOutboundDone() {
- return sslEngine == null || sslEngine.isOutboundDone();
- }
-
- /**
- * Check if there is any need to complete handshake.
- */
- /* no qualifier */boolean needToCompleteHandshake() {
- return handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !isInboundDone();
- }
-
- /* no qualifier */void schedulePreHandshakeWriteRequest(NextFilter nextFilter, WriteRequest writeRequest) {
- preHandshakeEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
- }
-
- /* no qualifier */void flushPreHandshakeEvents() throws SSLException {
- IoFilterEvent scheduledWrite;
-
- while ((scheduledWrite = preHandshakeEventQueue.poll()) != null) {
- sslFilter
- .filterWrite(scheduledWrite.getNextFilter(), session, (WriteRequest) scheduledWrite.getParameter());
- }
- }
-
- /* no qualifier */void scheduleFilterWrite(NextFilter nextFilter, WriteRequest writeRequest) {
- filterWriteEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.WRITE, session, writeRequest));
- }
-
- /* no qualifier */void flushFilterWrite() {
- // Fire events only when the lock is available for this handler.
- IoFilterEvent event;
-
- // We need synchronization here inevitably because filterWrite can be
- // called simultaneously and cause 'bad record MAC' integrity error.
- while ((event = filterWriteEventQueue.poll()) != null) {
- NextFilter nextFilter = event.getNextFilter();
- nextFilter.filterWrite(session, (WriteRequest) event.getParameter());
- }
- }
-
- /**
- * Push the newly received data into a queue, waiting for the SSL session
- * to be fully established
- *
- * @param nextFilter The next filter to call
- * @param message The incoming data
- */
- /* no qualifier */void scheduleMessageReceived(NextFilter nextFilter, Object message) {
- messageReceivedEventQueue.add(new IoFilterEvent(nextFilter, IoEventType.MESSAGE_RECEIVED, session, message));
- }
-
- /* no qualifier */void flushMessageReceived() {
- IoFilterEvent event;
-
- while ((event = messageReceivedEventQueue.poll()) != null) {
- NextFilter nextFilter = event.getNextFilter();
- nextFilter.messageReceived(session, event.getParameter());
- }
- }
-
- /**
- * Call when data are read from net. It will perform the initial hanshake or decrypt
- * the data if SSL has been initialiaed.
- *
- * @param buf buffer to decrypt
- * @param nextFilter Next filter in chain
- * @throws SSLException on errors
- */
- /* no qualifier */void messageReceived(NextFilter nextFilter, ByteBuffer buf) throws SSLException {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} Processing the received message", sslFilter.getSessionInfo(session));
- }
-
- // append buf to inNetBuffer
- if (inNetBuffer == null) {
- inNetBuffer = IoBuffer.allocate(buf.remaining()).setAutoExpand(true);
- }
-
- inNetBuffer.put(buf);
-
- if (!handshakeComplete) {
- handshake(nextFilter);
- } else {
- // Prepare the net data for reading.
- inNetBuffer.flip();
-
- if (!inNetBuffer.hasRemaining()) {
- return;
- }
-
- SSLEngineResult res = unwrap();
-
- // prepare to be written again
- if (inNetBuffer.hasRemaining()) {
- inNetBuffer.compact();
- } else {
- inNetBuffer.free();
- inNetBuffer = null;
- }
-
- checkStatus(res);
-
- renegotiateIfNeeded(nextFilter, res);
- }
-
- if (isInboundDone()) {
- // Rewind the MINA buffer if not all data is processed and inbound
- // is finished.
- int inNetBufferPosition = inNetBuffer == null ? 0 : inNetBuffer.position();
- buf.position(buf.position() - inNetBufferPosition);
-
- if (inNetBuffer != null) {
- inNetBuffer.free();
- inNetBuffer = null;
- }
- }
- }
-
- /**
- * Get decrypted application data.
- *
- * @return buffer with data
- */
- /* no qualifier */IoBuffer fetchAppBuffer() {
- if (appBuffer == null) {
- return IoBuffer.allocate(0);
- } else {
- IoBuffer newAppBuffer = appBuffer.flip();
- appBuffer = null;
-
- return newAppBuffer.shrink();
- }
- }
-
- /**
- * Get encrypted data to be sent.
- *
- * @return buffer with data
- */
- /* no qualifier */IoBuffer fetchOutNetBuffer() {
- IoBuffer answer = outNetBuffer;
-
- if (answer == null) {
- return emptyBuffer;
- }
-
- outNetBuffer = null;
-
- return answer.shrink();
- }
-
- /**
- * Encrypt provided buffer. Encrypted data returned by getOutNetBuffer().
- *
- * @param src
- * data to encrypt
- * @throws SSLException
- * on errors
- */
- /* no qualifier */void encrypt(ByteBuffer src) throws SSLException {
- if (!handshakeComplete) {
- throw new IllegalStateException();
- }
-
- if (!src.hasRemaining()) {
- if (outNetBuffer == null) {
- outNetBuffer = emptyBuffer;
- }
- return;
- }
-
- createOutNetBuffer(src.remaining());
-
- // Loop until there is no more data in src
- while (src.hasRemaining()) {
-
- SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf());
-
- if (result.getStatus() == SSLEngineResult.Status.OK) {
- if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
- doTasks();
- }
- } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
- outNetBuffer.capacity(outNetBuffer.capacity() << 1);
- outNetBuffer.limit(outNetBuffer.capacity());
- } else {
- throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src
- + "outNetBuffer: " + outNetBuffer);
- }
- }
-
- outNetBuffer.flip();
- }
-
- /**
- * Start SSL shutdown process.
- *
- * @return <tt>true</tt> if shutdown process is started. <tt>false</tt> if
- * shutdown process is already finished.
- * @throws SSLException
- * on errors
- */
- /* no qualifier */boolean closeOutbound() throws SSLException {
- if (sslEngine == null || sslEngine.isOutboundDone()) {
- return false;
- }
-
- sslEngine.closeOutbound();
-
- createOutNetBuffer(0);
- SSLEngineResult result;
-
- for (;;) {
- result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
- if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
- outNetBuffer.capacity(outNetBuffer.capacity() << 1);
- outNetBuffer.limit(outNetBuffer.capacity());
- } else {
- break;
- }
- }
-
- if (result.getStatus() != SSLEngineResult.Status.CLOSED) {
- throw new SSLException("Improper close state: " + result);
- }
-
- outNetBuffer.flip();
-
- return true;
- }
-
- /**
- * @param res
- * @throws SSLException
- */
- private void checkStatus(SSLEngineResult res) throws SSLException {
-
- SSLEngineResult.Status status = res.getStatus();
-
- /*
- * The status may be:
- * OK - Normal operation
- * OVERFLOW - Should never happen since the application buffer is sized to hold the maximum
- * packet size.
- * UNDERFLOW - Need to read more data from the socket. It's normal.
- * CLOSED - The other peer closed the socket. Also normal.
- */
- switch (status) {
- case BUFFER_OVERFLOW:
- throw new SSLException("SSLEngine error during decrypt: " + status + " inNetBuffer: " + inNetBuffer
- + "appBuffer: " + appBuffer);
- case CLOSED:
- Exception exception =new RuntimeIoException("SSL/TLS close_notify received");
-
- // Empty the Ssl queue
- for (IoFilterEvent event:filterWriteEventQueue) {
- EncryptedWriteRequest writeRequest = (EncryptedWriteRequest)event.getParameter();
- WriteFuture writeFuture = writeRequest.getParentRequest().getFuture();
- writeFuture.setException(exception);
- writeFuture.notifyAll();
- }
-
- // Empty the session queue
- WriteRequestQueue queue = session.getWriteRequestQueue();
- WriteRequest request = null;
-
- while ((request = queue.poll(session)) != null) {
- WriteFuture writeFuture = request.getFuture();
- writeFuture.setException(exception);
- writeFuture.notifyAll();
- }
-
- // We *must* shutdown session
- session.closeNow();
- break;
- default:
- break;
- }
- }
-
- /**
- * Perform any handshaking processing.
- */
- /* no qualifier */void handshake(NextFilter nextFilter) throws SSLException {
- for (;;) {
- switch (handshakeStatus) {
- case FINISHED:
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} processing the FINISHED state", sslFilter.getSessionInfo(session));
- }
-
- session.setAttribute(SslFilter.SSL_SESSION, sslEngine.getSession());
- handshakeComplete = true;
-
- // Send the SECURE message only if it's the first SSL handshake
- if (firstSSLNegociation) {
- firstSSLNegociation = false;
- this.session.setAttribute(SSL2Filter.SSL_SECURED, this);
- nextFilter.event(session, SslEvent.SECURED);
- }
-
- if (LOGGER.isDebugEnabled()) {
- if (!isOutboundDone()) {
- LOGGER.debug("{} is now secured", sslFilter.getSessionInfo(session));
- } else {
- LOGGER.debug("{} is not secured yet", sslFilter.getSessionInfo(session));
- }
- }
-
- return;
-
- case NEED_TASK:
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} processing the NEED_TASK state", sslFilter.getSessionInfo(session));
- }
-
- handshakeStatus = doTasks();
- break;
-
- case NEED_UNWRAP:
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} processing the NEED_UNWRAP state", sslFilter.getSessionInfo(session));
- }
- // we need more data read
- SSLEngineResult.Status status = unwrapHandshake(nextFilter);
-
- if (status == SSLEngineResult.Status.BUFFER_UNDERFLOW
- && handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED || isInboundDone()) {
- // We need more data or the session is closed
- return;
- }
-
- break;
-
- case NEED_WRAP:
- case NOT_HANDSHAKING:
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("{} processing the NEED_WRAP state", sslFilter.getSessionInfo(session));
- }
-
- // First make sure that the out buffer is completely empty.
- // Since we cannot call wrap with data left on the buffer
- if (outNetBuffer != null && outNetBuffer.hasRemaining()) {
- return;
- }
-
- SSLEngineResult result;
- createOutNetBuffer(0);
-
- result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
-
- while ( result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW ) {
- outNetBuffer.capacity(outNetBuffer.capacity() << 1);
- outNetBuffer.limit(outNetBuffer.capacity());
-
- result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf());
- }
-
- outNetBuffer.flip();
- handshakeStatus = result.getHandshakeStatus();
- writeNetBuffer(nextFilter);
- break;
-
- default:
- String msg = "Invalid Handshaking State" + handshakeStatus
- + " while processing the Handshake for session " + session.getId();
- LOGGER.error(msg);
- throw new IllegalStateException(msg);
- }
- }
- }
-
- private void createOutNetBuffer(int expectedRemaining) {
- // SSLEngine requires us to allocate unnecessarily big buffer
- // even for small data. *Shrug*
- int capacity = Math.max(expectedRemaining, sslEngine.getSession().getPacketBufferSize());
-
- if (outNetBuffer != null) {
- outNetBuffer.capacity(capacity);
- } else {
- outNetBuffer = IoBuffer.allocate(capacity).minimumCapacity(0);
- }
- }
-
- /* no qualifier */WriteFuture writeNetBuffer(NextFilter nextFilter) throws SSLException {
- // Check if any net data needed to be writen
- if (outNetBuffer == null || !outNetBuffer.hasRemaining()) {
- // no; bail out
- return null;
- }
-
- // set flag that we are writing encrypted data
- // (used in SSLFilter.filterWrite())
- writingEncryptedData = true;
-
- // write net data
- WriteFuture writeFuture = null;
-
- try {
- IoBuffer writeBuffer = fetchOutNetBuffer();
- writeFuture = new DefaultWriteFuture(session);
- sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(writeBuffer, writeFuture));
-
- // loop while more writes required to complete handshake
- while (needToCompleteHandshake()) {
- try {
- handshake(nextFilter);
- } catch (SSLException ssle) {
- SSLException newSsle = new SSLHandshakeException("SSL handshake failed.");
- newSsle.initCause(ssle);
- throw newSsle;
- }
-
- IoBuffer currentOutNetBuffer = fetchOutNetBuffer();
-
- if (currentOutNetBuffer != null && currentOutNetBuffer.hasRemaining()) {
- writeFuture = new DefaultWriteFuture(session);
- sslFilter.filterWrite(nextFilter, session, new DefaultWriteRequest(currentOutNetBuffer, writeFuture));
- }
- }
- } finally {
- writingEncryptedData = false;
- }
-
- return writeFuture;
- }
-
- private SSLEngineResult.Status unwrapHandshake(NextFilter nextFilter) throws SSLException {
- // Prepare the net data for reading.
- if (inNetBuffer != null) {
- inNetBuffer.flip();
- }
-
- if ((inNetBuffer == null) || !inNetBuffer.hasRemaining()) {
- // Need more data.
- return SSLEngineResult.Status.BUFFER_UNDERFLOW;
- }
-
- SSLEngineResult res = unwrap();
- handshakeStatus = res.getHandshakeStatus();
-
- checkStatus(res);
-
- // If handshake finished, no data was produced, and the status is still
- // ok, try to unwrap more
- if ((handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
- && (res.getStatus() == SSLEngineResult.Status.OK)
- && inNetBuffer.hasRemaining()) {
- res = unwrap();
-
- // prepare to be written again
- if (inNetBuffer.hasRemaining()) {
- inNetBuffer.compact();
- } else {
- inNetBuffer.free();
- inNetBuffer = null;
- }
-
- renegotiateIfNeeded(nextFilter, res);
- } else {
- // prepare to be written again
- if (inNetBuffer.hasRemaining()) {
- inNetBuffer.compact();
- } else {
- inNetBuffer.free();
- inNetBuffer = null;
- }
- }
-
- return res.getStatus();
- }
-
- private void renegotiateIfNeeded(NextFilter nextFilter, SSLEngineResult res) throws SSLException {
- if ((res.getStatus() != SSLEngineResult.Status.CLOSED)
- && (res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW)
- && (res.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
- // Renegotiation required.
- handshakeComplete = false;
- handshakeStatus = res.getHandshakeStatus();
- handshake(nextFilter);
- }
- }
-
- /**
- * Decrypt the incoming buffer and move the decrypted data to an
- * application buffer.
- */
- private SSLEngineResult unwrap() throws SSLException {
- // We first have to create the application buffer if it does not exist
- if (appBuffer == null) {
- appBuffer = IoBuffer.allocate(inNetBuffer.remaining());
- } else {
- // We already have one, just add the new data into it
- appBuffer.expand(inNetBuffer.remaining());
- }
-
- SSLEngineResult res;
- Status status;
- HandshakeStatus localHandshakeStatus;
-
- do {
- // Decode the incoming data
- res = sslEngine.unwrap(inNetBuffer.buf(), appBuffer.buf());
- status = res.getStatus();
-
- // We can be processing the Handshake
- localHandshakeStatus = res.getHandshakeStatus();
-
- if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) {
- // We have to grow the target buffer, it's too small.
- // Then we can call the unwrap method again
- int newCapacity = sslEngine.getSession().getApplicationBufferSize();
-
- if (appBuffer.remaining() >= newCapacity) {
- // The buffer is already larger than the max buffer size suggested by the SSL engine.
- // Raising it any more will not make sense and it will end up in an endless loop. Throwing an error is safer
- throw new SSLException("SSL buffer overflow");
- }
-
- appBuffer.expand(newCapacity);
- continue;
- }
- } while (((status == SSLEngineResult.Status.OK) || (status == SSLEngineResult.Status.BUFFER_OVERFLOW))
- && ((localHandshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) ||
- (localHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)));
-
- return res;
- }
-
- /**
- * Do all the outstanding handshake tasks in the current Thread.
- */
- private SSLEngineResult.HandshakeStatus doTasks() {
- /*
- * We could run this in a separate thread, but I don't see the need for
- * this when used from SSLFilter. Use thread filters in MINA instead?
- */
- Runnable runnable;
- while ((runnable = sslEngine.getDelegatedTask()) != null) {
- // TODO : we may have to use a thread pool here to improve the
- // performances
- runnable.run();
- }
- return sslEngine.getHandshakeStatus();
- }
-
- /**
- * Creates a new MINA buffer that is a deep copy of the remaining bytes in
- * the given buffer (between index buf.position() and buf.limit())
- *
- * @param src
- * the buffer to copy
- * @return the new buffer, ready to read from
- */
- /* no qualifier */static IoBuffer copy(ByteBuffer src) {
- IoBuffer copy = IoBuffer.allocate(src.remaining());
- copy.put(src);
- copy.flip();
- return copy;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("SSLStatus <");
-
- if (handshakeComplete) {
- sb.append("SSL established");
- } else {
- sb.append("Processing Handshake").append("; ");
- sb.append("Status : ").append(handshakeStatus).append("; ");
- }
-
- sb.append(", ");
- sb.append("HandshakeComplete :").append(handshakeComplete).append(", ");
- sb.append(">");
-
- return sb.toString();
- }
-
- /**
- * Free the allocated buffers
- */
- /* no qualifier */void release() {
- if (inNetBuffer != null) {
- inNetBuffer.free();
- inNetBuffer = null;
- }
-
- if (outNetBuffer != null) {
- outNetBuffer.free();
- outNetBuffer = null;
- }
- }
-}
diff --git a/mina-core/src/main/java/org/apache/mina/filter/ssl2/EncryptedWriteRequest.java b/mina-core/src/main/java/org/apache/mina/filter/ssl2/EncryptedWriteRequest.java
deleted file mode 100644
index caf32d7..0000000
--- a/mina-core/src/main/java/org/apache/mina/filter/ssl2/EncryptedWriteRequest.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.apache.mina.filter.ssl2;
-
-import org.apache.mina.core.write.DefaultWriteRequest;
-import org.apache.mina.core.write.WriteRequest;
-
-public class EncryptedWriteRequest extends DefaultWriteRequest {
-
- // The original message
- private WriteRequest originalRequest;
-
- public EncryptedWriteRequest(Object encodedMessage, WriteRequest parent) {
- super(encodedMessage, parent != null ? parent.getFuture() : null);
- this.originalRequest = parent != null ? parent : this;
- }
-
- public WriteRequest getOriginalRequest() {
- return this.originalRequest;
- }
-}
\ No newline at end of file
diff --git a/mina-core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketSession.java b/mina-core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketSession.java
index 34064a3..4fb1b5f 100644
--- a/mina-core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketSession.java
+++ b/mina-core/src/main/java/org/apache/mina/transport/socket/nio/NioSocketSession.java
@@ -27,16 +27,12 @@ import java.nio.channels.SocketChannel;
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.file.FileRegion;
-import org.apache.mina.core.filterchain.IoFilter;
-import org.apache.mina.core.filterchain.IoFilterChain;
import org.apache.mina.core.service.DefaultTransportMetadata;
import org.apache.mina.core.service.IoProcessor;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.service.TransportMetadata;
import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.ssl.SslFilter;
-import org.apache.mina.filter.ssl2.SSL2Filter;
-import org.apache.mina.filter.ssl2.SSL2Handler;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.AbstractSocketSessionConfig;
import org.apache.mina.transport.socket.SocketSessionConfig;
@@ -344,6 +340,6 @@ class NioSocketSession extends NioSession {
*/
@Override
public final boolean isSecured() {
- return (this.getAttribute(SSL2Filter.SSL_SECURED) != null);
+ return (this.getAttribute(SSLFilter.SSL_SECURED) != null);
}
}
diff --git a/mina-core/src/test/java/org/apache/mina/core/service/SslTestHandshakeExceptionDIRMINA1077Test.java b/mina-core/src/test/java/org/apache/mina/core/service/SslTestHandshakeExceptionDIRMINA1077Test.java
index a44c9c7..9561f7e 100644
--- a/mina-core/src/test/java/org/apache/mina/core/service/SslTestHandshakeExceptionDIRMINA1077Test.java
+++ b/mina-core/src/test/java/org/apache/mina/core/service/SslTestHandshakeExceptionDIRMINA1077Test.java
@@ -22,33 +22,31 @@ package org.apache.mina.core.service;
import static org.junit.Assert.fail;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.Security;
+import java.util.concurrent.CountDownLatch;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
-import org.apache.mina.core.service.AbstractIoService;
-import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.apache.mina.util.AvailablePortFinder;
import org.junit.Ignore;
import org.junit.Test;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.Security;
-import java.util.concurrent.CountDownLatch;
-
/**
* Test a SSL session and provoke HandshakeException.
* This test should not hang or timeout when DIRMINA-1076/1077 is fixed.
@@ -92,7 +90,7 @@ public class SslTestHandshakeExceptionDIRMINA1077Test {
DefaultIoFilterChainBuilder filters = acceptor.getFilterChain();
// Inject the SSL filter
- SslFilter sslFilter = new SslFilter(createSSLContext(true));
+ SSLFilter sslFilter = new SSLFilter(createSSLContext(true));
filters.addLast("sslFilter", sslFilter);
sslFilter.setNeedClientAuth(true);
@@ -113,8 +111,7 @@ public class SslTestHandshakeExceptionDIRMINA1077Test {
DefaultIoFilterChainBuilder filters = nioSocketConnector.getFilterChain();
// Inject the SSL filter
- SslFilter sslFilter = new SslFilter(createSSLContext(false));
- sslFilter.setUseClientMode( true );
+ SSLFilter sslFilter = new SSLFilter(createSSLContext(false));
filters.addLast("sslFilter", sslFilter);
address = InetAddress.getByName("localhost");
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslDIRMINA937Test.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLDIRMINA937Test.java
similarity index 94%
rename from mina-core/src/test/java/org/apache/mina/filter/ssl/SslDIRMINA937Test.java
rename to mina-core/src/test/java/org/apache/mina/filter/ssl/SSLDIRMINA937Test.java
index 3fe5c45..da3f66e 100644
--- a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslDIRMINA937Test.java
+++ b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLDIRMINA937Test.java
@@ -50,7 +50,7 @@ import org.junit.Test;
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
-public class SslDIRMINA937Test {
+public class SSLDIRMINA937Test {
/** A static port used for his test, chosen to avoid collisions */
private static final int port = AvailablePortFinder.getNextAvailable(5555);
@@ -92,7 +92,7 @@ public class SslDIRMINA937Test {
// Inject the SSL filter
SSLContext context = createSSLContext("TLSv1");
- SslFilter sslFilter = new SslFilter(context);
+ SSLFilter sslFilter = new SSLFilter(context);
sslFilter.setEnabledProtocols(new String[] { "TLSv1" });
//sslFilter.setEnabledCipherSuites(getServerCipherSuites(context.getDefaultSSLParameters().getCipherSuites()));
filters.addLast("sslFilter", sslFilter);
@@ -111,9 +111,8 @@ public class SslDIRMINA937Test {
NioSocketConnector connector = new NioSocketConnector();
DefaultIoFilterChainBuilder filters = connector.getFilterChain();
- SslFilter sslFilter = new SslFilter(createSSLContext("TLSv1.1"));
+ SSLFilter sslFilter = new SSLFilter(createSSLContext("TLSv1.1"));
sslFilter.setEnabledProtocols(new String[] { "TLSv1.1" });
- sslFilter.setUseClientMode(true);
//sslFilter.setEnabledCipherSuites(getClientCipherSuites());
filters.addLast("sslFilter", sslFilter);
connector.setHandler(new IoHandlerAdapter() {
@@ -123,7 +122,7 @@ public class SslDIRMINA937Test {
@Override
public void event(IoSession session, FilterEvent event) throws Exception {
- if (event == SslEvent.UNSECURED ) {
+ if (event == SSLEvent.UNSECURED ) {
counter.countDown();
}
}
@@ -141,8 +140,8 @@ public class SslDIRMINA937Test {
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
- ks.load(SslDIRMINA937Test.class.getResourceAsStream("keystore.sslTest"), passphrase);
- ts.load(SslDIRMINA937Test.class.getResourceAsStream("truststore.sslTest"), passphrase);
+ ks.load(SSLDIRMINA937Test.class.getResourceAsStream("keystore.sslTest"), passphrase);
+ ts.load(SSLDIRMINA937Test.class.getResourceAsStream("truststore.sslTest"), passphrase);
kmf.init(ks, passphrase);
tmf.init(ts);
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLEngineTest.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLEngineTest.java
new file mode 100644
index 0000000..54937d8
--- /dev/null
+++ b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLEngineTest.java
@@ -0,0 +1,465 @@
+package org.apache.mina.filter.ssl;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.Security;
+import java.util.Deque;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.LinkedBlockingDeque;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class SSLEngineTest {
+ private BlockingDeque<ByteBuffer> clientQueue = new LinkedBlockingDeque<>();
+ private BlockingDeque<ByteBuffer> serverQueue = new LinkedBlockingDeque<>();
+
+ private class Handshaker implements Runnable {
+ private SSLEngine sslEngine;
+ private ByteBuffer workBuffer;
+ private ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
+
+ private void push(Deque<ByteBuffer> queue, ByteBuffer buffer) {
+ ByteBuffer result = ByteBuffer.allocate(buffer.capacity());
+ result.put(buffer);
+ queue.addFirst(result);
+ }
+
+ public void run() {
+ HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
+ SSLEngineResult result;
+
+ try {
+ while (handshakeStatus != HandshakeStatus.FINISHED) {
+ switch (handshakeStatus) {
+ case NEED_TASK:
+ break;
+
+ case NEED_UNWRAP:
+ // The SSLEngine waits for some input.
+ // We may have received too few data (TCP fragmentation)
+ //
+ ByteBuffer data = serverQueue.takeLast();
+ result = sslEngine.unwrap(data, workBuffer);
+
+ while (result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
+ // We need more data, until then, wait.
+ // ByteBuffer data = serverQueue.takeLast();
+ result = sslEngine.unwrap(data, workBuffer);
+ }
+
+ handshakeStatus = sslEngine.getHandshakeStatus();
+ break;
+
+ case NEED_WRAP:
+ case NOT_HANDSHAKING:
+ result = sslEngine.wrap(emptyBuffer, workBuffer);
+
+ workBuffer.flip();
+
+ if (workBuffer.hasRemaining()) {
+ push(clientQueue, workBuffer);
+ workBuffer.clear();
+ }
+
+ handshakeStatus = result.getHandshakeStatus();
+
+ break;
+
+ case FINISHED:
+
+ }
+ }
+ } catch (SSLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public Handshaker(SSLEngine sslEngine) {
+ this.sslEngine = sslEngine;
+ int packetBufferSize = sslEngine.getSession().getPacketBufferSize();
+ workBuffer = ByteBuffer.allocate(packetBufferSize);
+ }
+ }
+
+ /** A JVM independant KEY_MANAGER_FACTORY algorithm */
+ private static final String KEY_MANAGER_FACTORY_ALGORITHM;
+
+ static {
+ String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
+ if (algorithm == null) {
+ algorithm = KeyManagerFactory.getDefaultAlgorithm();
+ }
+
+ KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
+ }
+
+ /** App data buffer for the client SSLEngine */
+ private IoBuffer inNetBufferClient;
+
+ /** Net data buffer for the client SSLEngine */
+ private IoBuffer outNetBufferClient;
+
+ /** App data buffer for the server SSLEngine */
+ private IoBuffer inNetBufferServer;
+
+ /** Net data buffer for the server SSLEngine */
+ private IoBuffer outNetBufferServer;
+
+ private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
+
+ private static SSLContext createSSLContext() throws IOException, GeneralSecurityException {
+ char[] passphrase = "password".toCharArray();
+
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ KeyStore ts = KeyStore.getInstance("JKS");
+
+ ks.load(SSLEngineTest.class.getResourceAsStream("keystore.jks"), passphrase);
+ ts.load(SSLEngineTest.class.getResourceAsStream("truststore.jks"), passphrase);
+
+ kmf.init(ks, passphrase);
+ tmf.init(ts);
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+ return ctx;
+ }
+
+ /**
+ * Decrypt the incoming buffer and move the decrypted data to an application
+ * buffer.
+ */
+ private SSLEngineResult unwrap(SSLEngine sslEngine, IoBuffer inBuffer, IoBuffer outBuffer) throws SSLException {
+ // We first have to create the application buffer if it does not exist
+ if (outBuffer == null) {
+ outBuffer = IoBuffer.allocate(inBuffer.remaining());
+ } else {
+ // We already have one, just add the new data into it
+ outBuffer.expand(inBuffer.remaining());
+ }
+
+ SSLEngineResult res;
+ Status status;
+ HandshakeStatus localHandshakeStatus;
+
+ do {
+ // Decode the incoming data
+ res = sslEngine.unwrap(inBuffer.buf(), outBuffer.buf());
+ status = res.getStatus();
+
+ // We can be processing the Handshake
+ localHandshakeStatus = res.getHandshakeStatus();
+
+ if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+ // We have to grow the target buffer, it's too small.
+ // Then we can call the unwrap method again
+ int newCapacity = sslEngine.getSession().getApplicationBufferSize();
+
+ if (inBuffer.remaining() >= newCapacity) {
+ // The buffer is already larger than the max buffer size suggested by the SSL
+ // engine.
+ // Raising it any more will not make sense and it will end up in an endless
+ // loop. Throwing an error is safer
+ throw new SSLException("SSL buffer overflow");
+ }
+
+ inBuffer.expand(newCapacity);
+ continue;
+ }
+ } while (((status == SSLEngineResult.Status.OK) || (status == SSLEngineResult.Status.BUFFER_OVERFLOW))
+ && ((localHandshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
+ || (localHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)));
+
+ return res;
+ }
+
+ private SSLEngineResult.Status unwrapHandshake(SSLEngine sslEngine, IoBuffer appBuffer, IoBuffer netBuffer)
+ throws SSLException {
+ // Prepare the net data for reading.
+ if ((appBuffer == null) || !appBuffer.hasRemaining()) {
+ // Need more data.
+ return SSLEngineResult.Status.BUFFER_UNDERFLOW;
+ }
+
+ SSLEngineResult res = unwrap(sslEngine, appBuffer, netBuffer);
+ HandshakeStatus handshakeStatus = res.getHandshakeStatus();
+
+ // checkStatus(res);
+
+ // If handshake finished, no data was produced, and the status is still
+ // ok, try to unwrap more
+ if ((handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
+ && (res.getStatus() == SSLEngineResult.Status.OK) && appBuffer.hasRemaining()) {
+ res = unwrap(sslEngine, appBuffer, netBuffer);
+
+ // prepare to be written again
+ if (appBuffer.hasRemaining()) {
+ appBuffer.compact();
+ } else {
+ appBuffer.free();
+ appBuffer = null;
+ }
+ } else {
+ // prepare to be written again
+ if (appBuffer.hasRemaining()) {
+ appBuffer.compact();
+ } else {
+ appBuffer.free();
+ appBuffer = null;
+ }
+ }
+
+ return res.getStatus();
+ }
+
+ /* no qualifier */boolean isInboundDone(SSLEngine sslEngine) {
+ return sslEngine == null || sslEngine.isInboundDone();
+ }
+
+ /* no qualifier */boolean isOutboundDone(SSLEngine sslEngine) {
+ return sslEngine == null || sslEngine.isOutboundDone();
+ }
+
+ /**
+ * Perform any handshaking processing.
+ */
+ /* no qualifier */HandshakeStatus handshake(SSLEngine sslEngine, IoBuffer appBuffer, IoBuffer netBuffer)
+ throws SSLException {
+ SSLEngineResult result;
+ HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
+
+ for (;;) {
+ switch (handshakeStatus) {
+ case FINISHED:
+ // handshakeComplete = true;
+ return handshakeStatus;
+
+ case NEED_TASK:
+ // handshakeStatus = doTasks();
+ break;
+
+ case NEED_UNWRAP:
+ // we need more data read
+ SSLEngineResult.Status status = unwrapHandshake(sslEngine, appBuffer, netBuffer);
+ handshakeStatus = sslEngine.getHandshakeStatus();
+
+ return handshakeStatus;
+
+ case NEED_WRAP:
+ result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
+
+ while (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+ netBuffer.capacity(netBuffer.capacity() << 1);
+ netBuffer.limit(netBuffer.capacity());
+
+ result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
+ }
+
+ netBuffer.flip();
+ return result.getHandshakeStatus();
+
+ case NOT_HANDSHAKING:
+ result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
+
+ while (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+ netBuffer.capacity(netBuffer.capacity() << 1);
+ netBuffer.limit(netBuffer.capacity());
+
+ result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
+ }
+
+ netBuffer.flip();
+ handshakeStatus = result.getHandshakeStatus();
+ return handshakeStatus;
+
+ default:
+ throw new IllegalStateException("error");
+ }
+ }
+ }
+
+ /**
+ * Do all the outstanding handshake tasks in the current Thread.
+ */
+ private SSLEngineResult.HandshakeStatus doTasks(SSLEngine sslEngine) {
+ /*
+ * We could run this in a separate thread, but I don't see the need for this
+ * when used from SSLFilter. Use thread filters in MINA instead?
+ */
+ Runnable runnable;
+ while ((runnable = sslEngine.getDelegatedTask()) != null) {
+ // Thread thread = new Thread(runnable);
+ // thread.start();
+ runnable.run();
+ }
+ return sslEngine.getHandshakeStatus();
+ }
+
+ private HandshakeStatus handshake(SSLEngine sslEngine, HandshakeStatus expected, IoBuffer inBuffer,
+ IoBuffer outBuffer, boolean dumpBuffer) throws SSLException {
+ HandshakeStatus handshakeStatus = handshake(sslEngine, inBuffer, outBuffer);
+
+ if (handshakeStatus != expected) {
+ fail();
+ }
+
+ if (dumpBuffer) {
+ System.out.println("Message:" + outBuffer);
+ }
+
+ return handshakeStatus;
+ }
+
+ @Test
+ @Ignore
+ public void testSSL() throws Exception {
+ // Initialise the client SSLEngine
+ SSLContext sslContextClient = createSSLContext();
+ SSLEngine sslEngineClient = sslContextClient.createSSLEngine();
+ int packetBufferSize = sslEngineClient.getSession().getPacketBufferSize();
+ inNetBufferClient = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
+ outNetBufferClient = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
+
+ sslEngineClient.setUseClientMode(true);
+
+ // Initialise the Server SSLEngine
+ SSLContext sslContextServer = createSSLContext();
+ SSLEngine sslEngineServer = sslContextServer.createSSLEngine();
+ packetBufferSize = sslEngineServer.getSession().getPacketBufferSize();
+ inNetBufferServer = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
+ outNetBufferServer = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
+
+ sslEngineServer.setUseClientMode(false);
+
+ Handshaker handshakerClient = new Handshaker(sslEngineClient);
+ Handshaker handshakerServer = new Handshaker(sslEngineServer);
+
+ handshakerServer.run();
+
+ HandshakeStatus handshakeStatusClient = sslEngineClient.getHandshakeStatus();
+ HandshakeStatus handshakeStatusServer = sslEngineServer.getHandshakeStatus();
+
+ // <<< Server
+ // Start the server
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP, null, outNetBufferServer,
+ false);
+
+ // >>> Client
+ // Now start the client, which will generate a CLIENT_HELLO,
+ // stored into the outNetBufferClient
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP, null, outNetBufferClient, true);
+
+ // <<< Server
+ // Process the CLIENT_HELLO on the server
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_TASK, outNetBufferClient,
+ outNetBufferServer, false);
+
+ // Process the tasks on the server, prepare the SERVER_HELLO message
+ handshakeStatusServer = doTasks(sslEngineServer);
+
+ // We should be ready to generate the SERVER_HELLO message
+ if (handshakeStatusServer != HandshakeStatus.NEED_WRAP) {
+ fail();
+ }
+
+ // Get the SERVER_HELLO message, with all the associated messages
+ // ([Certificate], [ServerKeyExchange], [CertificateRequest], ServerHelloDone)
+ outNetBufferServer.clear();
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP, null, outNetBufferServer, true);
+
+ // >>> Client
+ // Process the SERVER_HELLO message on the client
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_TASK, outNetBufferServer,
+ inNetBufferClient, false);
+
+ // Prepare the client response
+ handshakeStatusClient = doTasks(sslEngineClient);
+
+ // We should get back the Client messages ([Certificate],
+ // ClientKeyExchange, [CertificateVerify])
+ if (handshakeStatusClient != HandshakeStatus.NEED_WRAP) {
+ fail();
+ }
+
+ // Generate the [Certificate], ClientKeyExchange, [CertificateVerify] messages
+ outNetBufferClient.clear();
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_WRAP, null, outNetBufferClient, true);
+
+ // <<< Server
+ // Process the CLIENT_KEY_EXCHANGE on the server
+ outNetBufferServer.clear();
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_TASK, outNetBufferClient,
+ outNetBufferServer, false);
+
+ // Do the controls
+ handshakeStatusServer = doTasks(sslEngineServer);
+
+ // The server is waiting for more
+ if (handshakeStatusServer != HandshakeStatus.NEED_UNWRAP) {
+ fail();
+ }
+
+ // >>> Client
+ // The CHANGE_CIPHER_SPEC message generation
+ outNetBufferClient.clear();
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_WRAP, null, outNetBufferClient, true);
+
+ // <<< Server
+ // Process the CHANGE_CIPHER_SPEC on the server
+ outNetBufferServer.clear();
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP, outNetBufferClient,
+ outNetBufferServer, false);
+
+ // >>> Client
+ // Generate the FINISHED message on thee client
+ outNetBufferClient.clear();
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP, null, outNetBufferClient, true);
+
+ // <<< Server
+ // Process the client FINISHED message
+ outNetBufferServer.clear();
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_WRAP, outNetBufferClient,
+ outNetBufferServer, false);
+
+ // Generate the CHANGE_CIPHER_SPEC message on the server
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_WRAP, null, outNetBufferServer, true);
+
+ // >>> Client
+ // Process the server CHANGE_SCIPHER_SPEC message on the client
+ outNetBufferClient.clear();
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP, outNetBufferServer,
+ outNetBufferClient, false);
+
+ // <<< Server
+ // Generate the server FINISHED message
+ outNetBufferServer.clear();
+ handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.FINISHED, null, outNetBufferServer, true);
+
+ // >>> Client
+ // Process the server FINISHED message on the client
+ outNetBufferClient.clear();
+ handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NOT_HANDSHAKING, outNetBufferServer,
+ outNetBufferClient, false);
+ }
+}
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl2/SSL2SimpleTest.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLFilterMain.java
similarity index 91%
rename from mina-core/src/test/java/org/apache/mina/filter/ssl2/SSL2SimpleTest.java
rename to mina-core/src/test/java/org/apache/mina/filter/ssl/SSLFilterMain.java
index ce1a310..841e777 100644
--- a/mina-core/src/test/java/org/apache/mina/filter/ssl2/SSL2SimpleTest.java
+++ b/mina-core/src/test/java/org/apache/mina/filter/ssl/SSLFilterMain.java
@@ -1,4 +1,4 @@
-package org.apache.mina.filter.ssl2;
+package org.apache.mina.filter.ssl;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -21,13 +21,12 @@ import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.ssl.SslDIRMINA937Test;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class SSL2SimpleTest {
+public class SSLFilterMain {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException,
UnrecoverableKeyException, CertificateException, IOException {
@@ -41,8 +40,8 @@ public class SSL2SimpleTest {
final char[] password = "password".toCharArray();
- ks.load(SSL2SimpleTest.class.getResourceAsStream("keystore.jks"), password);
- ts.load(SSL2SimpleTest.class.getResourceAsStream("truststore.jks"), password);
+ ks.load(SSLFilterMain.class.getResourceAsStream("keystore.jks"), password);
+ ts.load(SSLFilterMain.class.getResourceAsStream("truststore.jks"), password);
kmf.init(ks, password);
tmf.init(ts);
@@ -50,7 +49,7 @@ public class SSL2SimpleTest {
final SSLContext context = SSLContext.getInstance("TLSv1.3");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
- final SSL2Filter filter = new SSL2Filter(context);
+ final SSLFilter filter = new SSLFilter(context);
filter.setEnabledCipherSuites(new String[] { "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384" });
filter.setEnabledProtocols(new String[] { "TLSv1.3" });
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslEngineTest.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SslEngineTest.java
deleted file mode 100644
index 28b1122..0000000
--- a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslEngineTest.java
+++ /dev/null
@@ -1,486 +0,0 @@
-package org.apache.mina.filter.ssl;
-
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.Security;
-import java.util.Deque;
-import java.util.concurrent.BlockingDeque;
-import java.util.concurrent.LinkedBlockingDeque;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLEngineResult.HandshakeStatus;
-import javax.net.ssl.SSLEngineResult.Status;
-import javax.net.ssl.TrustManagerFactory;
-
-import org.apache.mina.core.buffer.IoBuffer;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class SslEngineTest
-{
- private BlockingDeque<ByteBuffer> clientQueue = new LinkedBlockingDeque<>();
- private BlockingDeque<ByteBuffer> serverQueue = new LinkedBlockingDeque<>();
-
- private class Handshaker implements Runnable {
- private SSLEngine sslEngine;
- private ByteBuffer workBuffer;
- private ByteBuffer emptyBuffer= ByteBuffer.allocate(0);
-
- private void push(Deque<ByteBuffer> queue, ByteBuffer buffer) {
- ByteBuffer result = ByteBuffer.allocate(buffer.capacity());
- result.put(buffer);
- queue.addFirst(result);
- }
-
- public void run()
- {
- HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
- SSLEngineResult result;
-
- try
- {
- while (handshakeStatus != HandshakeStatus.FINISHED) {
- switch (handshakeStatus)
- {
- case NEED_TASK:
- break;
-
- case NEED_UNWRAP:
- // The SSLEngine waits for some input.
- // We may have received too few data (TCP fragmentation)
- //
- ByteBuffer data = serverQueue.takeLast();
- result = sslEngine.unwrap(data, workBuffer);
-
- while (result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
- // We need more data, until then, wait.
- //ByteBuffer data = serverQueue.takeLast();
- result = sslEngine.unwrap(data, workBuffer);
- }
-
- handshakeStatus = sslEngine.getHandshakeStatus();
- break;
-
- case NEED_WRAP:
- case NOT_HANDSHAKING:
- result = sslEngine.wrap(emptyBuffer, workBuffer);
-
- workBuffer.flip();
-
- if (workBuffer.hasRemaining()) {
- push(clientQueue, workBuffer);
- workBuffer.clear();
- }
-
- handshakeStatus = result.getHandshakeStatus();
-
- break;
-
- case FINISHED:
-
- }
- }
- }
- catch ( SSLException e )
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- catch ( InterruptedException e )
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- public Handshaker(SSLEngine sslEngine) {
- this.sslEngine = sslEngine;
- int packetBufferSize = sslEngine.getSession().getPacketBufferSize();
- workBuffer = ByteBuffer.allocate(packetBufferSize);
- }
- }
-
- /** A JVM independant KEY_MANAGER_FACTORY algorithm */
- private static final String KEY_MANAGER_FACTORY_ALGORITHM;
-
- static {
- String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
- if (algorithm == null) {
- algorithm = KeyManagerFactory.getDefaultAlgorithm();
- }
-
- KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
- }
-
- /** App data buffer for the client SSLEngine*/
- private IoBuffer inNetBufferClient;
-
- /** Net data buffer for the client SSLEngine */
- private IoBuffer outNetBufferClient;
-
- /** App data buffer for the server SSLEngine */
- private IoBuffer inNetBufferServer;
-
- /** Net data buffer for the server SSLEngine */
- private IoBuffer outNetBufferServer;
-
- private final IoBuffer emptyBuffer = IoBuffer.allocate(0);
-
-
- private static SSLContext createSSLContext() throws IOException, GeneralSecurityException {
- char[] passphrase = "password".toCharArray();
-
- SSLContext ctx = SSLContext.getInstance("TLS");
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
-
- KeyStore ks = KeyStore.getInstance("JKS");
- KeyStore ts = KeyStore.getInstance("JKS");
-
- ks.load(SslTest.class.getResourceAsStream("keystore.sslTest"), passphrase);
- ts.load(SslTest.class.getResourceAsStream("truststore.sslTest"), passphrase);
-
- kmf.init(ks, passphrase);
- tmf.init(ts);
- ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-
- return ctx;
- }
-
-
- /**
- * Decrypt the incoming buffer and move the decrypted data to an
- * application buffer.
- */
- private SSLEngineResult unwrap(SSLEngine sslEngine, IoBuffer inBuffer, IoBuffer outBuffer) throws SSLException {
- // We first have to create the application buffer if it does not exist
- if (outBuffer == null) {
- outBuffer = IoBuffer.allocate(inBuffer.remaining());
- } else {
- // We already have one, just add the new data into it
- outBuffer.expand(inBuffer.remaining());
- }
-
- SSLEngineResult res;
- Status status;
- HandshakeStatus localHandshakeStatus;
-
- do {
- // Decode the incoming data
- res = sslEngine.unwrap(inBuffer.buf(), outBuffer.buf());
- status = res.getStatus();
-
- // We can be processing the Handshake
- localHandshakeStatus = res.getHandshakeStatus();
-
- if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) {
- // We have to grow the target buffer, it's too small.
- // Then we can call the unwrap method again
- int newCapacity = sslEngine.getSession().getApplicationBufferSize();
-
- if (inBuffer.remaining() >= newCapacity) {
- // The buffer is already larger than the max buffer size suggested by the SSL engine.
- // Raising it any more will not make sense and it will end up in an endless loop. Throwing an error is safer
- throw new SSLException("SSL buffer overflow");
- }
-
- inBuffer.expand(newCapacity);
- continue;
- }
- } while (((status == SSLEngineResult.Status.OK) || (status == SSLEngineResult.Status.BUFFER_OVERFLOW))
- && ((localHandshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) ||
- (localHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)));
-
- return res;
- }
-
-
- private SSLEngineResult.Status unwrapHandshake(SSLEngine sslEngine, IoBuffer appBuffer, IoBuffer netBuffer) throws SSLException {
- // Prepare the net data for reading.
- if ((appBuffer == null) || !appBuffer.hasRemaining()) {
- // Need more data.
- return SSLEngineResult.Status.BUFFER_UNDERFLOW;
- }
-
- SSLEngineResult res = unwrap(sslEngine, appBuffer, netBuffer);
- HandshakeStatus handshakeStatus = res.getHandshakeStatus();
-
- //checkStatus(res);
-
- // If handshake finished, no data was produced, and the status is still
- // ok, try to unwrap more
- if ((handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
- && (res.getStatus() == SSLEngineResult.Status.OK)
- && appBuffer.hasRemaining()) {
- res = unwrap(sslEngine, appBuffer, netBuffer);
-
- // prepare to be written again
- if (appBuffer.hasRemaining()) {
- appBuffer.compact();
- } else {
- appBuffer.free();
- appBuffer = null;
- }
- } else {
- // prepare to be written again
- if (appBuffer.hasRemaining()) {
- appBuffer.compact();
- } else {
- appBuffer.free();
- appBuffer = null;
- }
- }
-
- return res.getStatus();
- }
-
-
- /* no qualifier */boolean isInboundDone(SSLEngine sslEngine) {
- return sslEngine == null || sslEngine.isInboundDone();
- }
-
-
- /* no qualifier */boolean isOutboundDone(SSLEngine sslEngine) {
- return sslEngine == null || sslEngine.isOutboundDone();
- }
-
-
- /**
- * Perform any handshaking processing.
- */
- /* no qualifier */HandshakeStatus handshake(SSLEngine sslEngine, IoBuffer appBuffer, IoBuffer netBuffer ) throws SSLException {
- SSLEngineResult result;
- HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus();
-
- for (;;) {
- switch (handshakeStatus) {
- case FINISHED:
- //handshakeComplete = true;
- return handshakeStatus;
-
- case NEED_TASK:
- //handshakeStatus = doTasks();
- break;
-
- case NEED_UNWRAP:
- // we need more data read
- SSLEngineResult.Status status = unwrapHandshake(sslEngine, appBuffer, netBuffer);
- handshakeStatus = sslEngine.getHandshakeStatus();
-
- return handshakeStatus;
-
- case NEED_WRAP:
- result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
-
- while ( result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW ) {
- netBuffer.capacity(netBuffer.capacity() << 1);
- netBuffer.limit(netBuffer.capacity());
-
- result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
- }
-
- netBuffer.flip();
- return result.getHandshakeStatus();
-
- case NOT_HANDSHAKING:
- result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
-
- while ( result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW ) {
- netBuffer.capacity(netBuffer.capacity() << 1);
- netBuffer.limit(netBuffer.capacity());
-
- result = sslEngine.wrap(emptyBuffer.buf(), netBuffer.buf());
- }
-
- netBuffer.flip();
- handshakeStatus = result.getHandshakeStatus();
- return handshakeStatus;
-
- default:
- throw new IllegalStateException("error");
- }
- }
- }
-
-
- /**
- * Do all the outstanding handshake tasks in the current Thread.
- */
- private SSLEngineResult.HandshakeStatus doTasks(SSLEngine sslEngine) {
- /*
- * We could run this in a separate thread, but I don't see the need for
- * this when used from SSLFilter. Use thread filters in MINA instead?
- */
- Runnable runnable;
- while ((runnable = sslEngine.getDelegatedTask()) != null) {
- //Thread thread = new Thread(runnable);
- //thread.start();
- runnable.run();
- }
- return sslEngine.getHandshakeStatus();
- }
-
-
- private HandshakeStatus handshake(SSLEngine sslEngine, HandshakeStatus expected,
- IoBuffer inBuffer, IoBuffer outBuffer, boolean dumpBuffer) throws SSLException {
- HandshakeStatus handshakeStatus = handshake(sslEngine, inBuffer, outBuffer);
-
- if ( handshakeStatus != expected) {
- fail();
- }
-
- if (dumpBuffer) {
- System.out.println("Message:" + outBuffer);
- }
-
- return handshakeStatus;
- }
-
-
- @Test
- @Ignore
- public void testSSL() throws Exception {
- // Initialise the client SSLEngine
- SSLContext sslContextClient = createSSLContext();
- SSLEngine sslEngineClient = sslContextClient.createSSLEngine();
- int packetBufferSize = sslEngineClient.getSession().getPacketBufferSize();
- inNetBufferClient = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
- outNetBufferClient = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
-
- sslEngineClient.setUseClientMode(true);
-
- // Initialise the Server SSLEngine
- SSLContext sslContextServer = createSSLContext();
- SSLEngine sslEngineServer = sslContextServer.createSSLEngine();
- packetBufferSize = sslEngineServer.getSession().getPacketBufferSize();
- inNetBufferServer = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
- outNetBufferServer = IoBuffer.allocate(packetBufferSize).setAutoExpand(true);
-
- sslEngineServer.setUseClientMode(false);
-
- Handshaker handshakerClient = new Handshaker( sslEngineClient );
- Handshaker handshakerServer = new Handshaker( sslEngineServer );
-
- handshakerServer.run();
-
- HandshakeStatus handshakeStatusClient = sslEngineClient.getHandshakeStatus();
- HandshakeStatus handshakeStatusServer = sslEngineServer.getHandshakeStatus();
-
- // <<< Server
- // Start the server
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP,
- null, outNetBufferServer, false);
-
- // >>> Client
- // Now start the client, which will generate a CLIENT_HELLO,
- // stored into the outNetBufferClient
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP,
- null, outNetBufferClient, true);
-
- // <<< Server
- // Process the CLIENT_HELLO on the server
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_TASK,
- outNetBufferClient, outNetBufferServer, false);
-
- // Process the tasks on the server, prepare the SERVER_HELLO message
- handshakeStatusServer = doTasks(sslEngineServer);
-
- // We should be ready to generate the SERVER_HELLO message
- if ( handshakeStatusServer != HandshakeStatus.NEED_WRAP) {
- fail();
- }
-
- // Get the SERVER_HELLO message, with all the associated messages
- // ([Certificate], [ServerKeyExchange], [CertificateRequest], ServerHelloDone)
- outNetBufferServer.clear();
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP,
- null, outNetBufferServer, true);
-
- // >>> Client
- // Process the SERVER_HELLO message on the client
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_TASK,
- outNetBufferServer, inNetBufferClient, false);
-
- // Prepare the client response
- handshakeStatusClient = doTasks(sslEngineClient);
-
- // We should get back the Client messages ([Certificate],
- // ClientKeyExchange, [CertificateVerify])
- if ( handshakeStatusClient != HandshakeStatus.NEED_WRAP) {
- fail();
- }
-
- // Generate the [Certificate], ClientKeyExchange, [CertificateVerify] messages
- outNetBufferClient.clear();
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_WRAP,
- null, outNetBufferClient, true);
-
- // <<< Server
- // Process the CLIENT_KEY_EXCHANGE on the server
- outNetBufferServer.clear();
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_TASK,
- outNetBufferClient, outNetBufferServer, false);
-
- // Do the controls
- handshakeStatusServer = doTasks(sslEngineServer);
-
- // The server is waiting for more
- if ( handshakeStatusServer != HandshakeStatus.NEED_UNWRAP) {
- fail();
- }
-
- // >>> Client
- // The CHANGE_CIPHER_SPEC message generation
- outNetBufferClient.clear();
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_WRAP,
- null, outNetBufferClient, true);
-
- // <<< Server
- // Process the CHANGE_CIPHER_SPEC on the server
- outNetBufferServer.clear();
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_UNWRAP,
- outNetBufferClient, outNetBufferServer, false);
-
- // >>> Client
- // Generate the FINISHED message on thee client
- outNetBufferClient.clear();
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP,
- null, outNetBufferClient, true);
-
- // <<< Server
- // Process the client FINISHED message
- outNetBufferServer.clear();
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_WRAP,
- outNetBufferClient, outNetBufferServer, false);
-
- // Generate the CHANGE_CIPHER_SPEC message on the server
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.NEED_WRAP,
- null, outNetBufferServer, true);
-
- // >>> Client
- // Process the server CHANGE_SCIPHER_SPEC message on the client
- outNetBufferClient.clear();
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NEED_UNWRAP,
- outNetBufferServer, outNetBufferClient, false);
-
- // <<< Server
- // Generate the server FINISHED message
- outNetBufferServer.clear();
- handshakeStatusServer = handshake(sslEngineServer, HandshakeStatus.FINISHED,
- null, outNetBufferServer, true);
-
- // >>> Client
- // Process the server FINISHED message on the client
- outNetBufferClient.clear();
- handshakeStatusClient = handshake(sslEngineClient, HandshakeStatus.NOT_HANDSHAKING,
- outNetBufferServer, outNetBufferClient, false);
- }
-}
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslFilterTest.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SslFilterTest.java
deleted file mode 100644
index 5838e3c..0000000
--- a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslFilterTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.mina.filter.ssl;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import javax.net.ssl.SSLException;
-
-import org.apache.mina.core.filterchain.IoFilter.NextFilter;
-import org.apache.mina.core.session.DummySession;
-import org.apache.mina.core.session.IdleStatus;
-import org.apache.mina.core.session.IoSession;
-import org.apache.mina.core.write.DefaultWriteRequest;
-import org.apache.mina.core.write.WriteRequest;
-import org.apache.mina.filter.FilterEvent;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * A test for DIRMINA-1019
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-abstract class AbstractNextFilter implements NextFilter {
- public abstract void messageReceived(IoSession session, Object message);
-
- public abstract void filterWrite(IoSession session, WriteRequest writeRequest);
-
- // Following are unimplemented as they aren't used in test
- public void sessionCreated(IoSession session) { }
-
- public void sessionOpened(IoSession session) { }
-
- public void sessionClosed(IoSession session) { }
-
- public void sessionIdle(IoSession session, IdleStatus status) { }
-
- public void exceptionCaught(IoSession session, Throwable cause) { }
-
- public void inputClosed(IoSession session) { }
-
- public void messageSent(IoSession session, WriteRequest writeRequest) { }
-
- public void filterClose(IoSession session) { }
-
- public void event(IoSession session, FilterEvent event) { }
-
- public String toString() {
- return null;
- }
-};
-
-/**
- * A test for DIRMINA-1019
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class SslFilterTest {
- SslHandler test_class;
-
- @Before
- public void init() throws SSLException {
- test_class = new SslHandler(null, new DummySession());
- }
-
- @Test
- public void testFlushRaceCondition() {
- final ExecutorService executor = Executors.newFixedThreadPool(1);
- final List<Object> message_received_messages = new ArrayList<Object>();
- final List<WriteRequest> filter_write_requests = new ArrayList<WriteRequest>();
-
- final AbstractNextFilter write_filter = new AbstractNextFilter()
- {
- @Override
- public void messageReceived(IoSession session, Object message) { }
-
- @Override
- public void filterWrite(IoSession session, WriteRequest writeRequest) {
- filter_write_requests.add(writeRequest);
- }
- };
-
- AbstractNextFilter receive_filter = new AbstractNextFilter()
- {
- @Override
- public void messageReceived(IoSession session, Object message) {
- message_received_messages.add(message);
-
- // This is where the race condition occurs. If a thread calls SslHandler.scheduleFilterWrite(),
- // followed by SslHandler.flushScheduledEvents(), the queued event will not be processed as
- // the current thread owns the SslHandler.sslLock and has already "dequeued" all the queued
- // filterWriteEventQueue.
- Future<?> write_scheduler = executor.submit(new Runnable() {
- public void run() {
- synchronized(test_class) {
- test_class.scheduleFilterWrite(write_filter, new DefaultWriteRequest(new byte[] {}));
- test_class.flushFilterWrite();
- }
- }
- });
-
- try {
- write_scheduler.get();
- } catch (Exception e) { }
- }
-
- @Override
- public void filterWrite(IoSession session, WriteRequest writeRequest) { }
- };
-
- synchronized(test_class) {
- test_class.scheduleMessageReceived(receive_filter, new byte[] {});
- }
-
- test_class.flushMessageReceived();
-
- assertEquals(1, message_received_messages.size());
- assertEquals(1, filter_write_requests.size());
- }
-}
diff --git a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslTest.java b/mina-core/src/test/java/org/apache/mina/filter/ssl/SslTest.java
deleted file mode 100644
index e61bad6..0000000
--- a/mina-core/src/test/java/org/apache/mina/filter/ssl/SslTest.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */package org.apache.mina.filter.ssl;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.Security;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManagerFactory;
-
-import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
-import org.apache.mina.core.service.IoHandlerAdapter;
-import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.codec.ProtocolCodecFilter;
-import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
-import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
-import org.apache.mina.util.AvailablePortFinder;
-import org.junit.Test;
-
-/**
- * Test a SSL session where the connection is established and closed twice. It should be
- * processed correctly (Test for DIRMINA-650)
- *
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class SslTest {
- /** A static port used for his test, chosen to avoid collisions */
- private static final int port = AvailablePortFinder.getNextAvailable(5555);
-
- private static Exception clientError = null;
-
- private static InetAddress address;
-
- private static SSLSocketFactory factory;
-
- private static NioSocketAcceptor acceptor;
-
- /** A JVM independant KEY_MANAGER_FACTORY algorithm */
- private static final String KEY_MANAGER_FACTORY_ALGORITHM;
-
- static {
- String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
- if (algorithm == null) {
- algorithm = KeyManagerFactory.getDefaultAlgorithm();
- }
-
- KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
- }
-
- private static class TestHandler extends IoHandlerAdapter {
- public void messageReceived(IoSession session, Object message) throws Exception {
- String line = (String) message;
-
- if (line.startsWith("hello")) {
- //System.out.println("Server got: 'hello', waiting for 'send'");
- Thread.sleep(1500);
- } else if (line.startsWith("send")) {
- //System.out.println("Server got: 'send', sending 'data'");
- StringBuilder sb = new StringBuilder();
-
- for ( int i = 0; i < 10000; i++) {
- sb.append('A');
- }
-
- session.write(sb.toString());
- session.closeOnFlush();
- }
- }
- }
-
- /**
- * Starts a Server with the SSL Filter and a simple text line
- * protocol codec filter
- */
- private static void startServer() throws Exception {
- acceptor = new NioSocketAcceptor();
-
- acceptor.setReuseAddress(true);
- DefaultIoFilterChainBuilder filters = acceptor.getFilterChain();
-
- // Inject the SSL filter
- SslFilter sslFilter = new SslFilter(createSSLContext());
- filters.addLast("sslFilter", sslFilter);
- sslFilter.setNeedClientAuth(true);
-
- // Inject the TestLine codec filter
- filters.addLast("text", new ProtocolCodecFilter(new TextLineCodecFactory()));
-
- acceptor.setHandler(new TestHandler());
- acceptor.bind(new InetSocketAddress(port));
- }
-
- private static void stopServer() {
- acceptor.dispose();
- }
-
- /**
- * Starts a client which will connect twice using SSL
- */
- private static void startClient() throws Exception {
- address = InetAddress.getByName("localhost");
-
- SSLContext context = createSSLContext();
- factory = context.getSocketFactory();
-
- connectAndSend();
-
- // This one will throw a SocketTimeoutException if DIRMINA-650 is not fixed
- connectAndSend();
- }
-
- private static void connectAndSend() throws Exception {
- Socket parent = new Socket(address, port);
- Socket socket = factory.createSocket(parent, address.getCanonicalHostName(), port, false);
-
- //System.out.println("Client sending: hello");
- socket.getOutputStream().write("hello \n".getBytes());
- socket.getOutputStream().flush();
- socket.setSoTimeout(1000000);
-
- //System.out.println("Client sending: send");
- socket.getOutputStream().write("send\n".getBytes());
- socket.getOutputStream().flush();
-
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- String line = in.readLine();
- //System.out.println("Client got: " + line);
- socket.close();
- }
-
- private static SSLContext createSSLContext() throws IOException, GeneralSecurityException {
- char[] passphrase = "password".toCharArray();
-
- SSLContext ctx = SSLContext.getInstance("TLS");
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
-
- KeyStore ks = KeyStore.getInstance("JKS");
- KeyStore ts = KeyStore.getInstance("JKS");
-
- ks.load(SslTest.class.getResourceAsStream("keystore.sslTest"), passphrase);
- ts.load(SslTest.class.getResourceAsStream("truststore.sslTest"), passphrase);
-
- kmf.init(ks, passphrase);
- tmf.init(ts);
- ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-
- return ctx;
- }
-
- @Test
- public void testSSL() throws Exception {
- try {
- startServer();
-
- Thread t = new Thread() {
- public void run() {
- try {
- startClient();
- } catch (Exception e) {
- clientError = e;
- }
- }
- };
- t.start();
- t.join();
-
- if (clientError != null) {
- throw clientError;
- }
- } finally {
- stopServer();
- }
- }
-
-
- @Test
- public void unsecureClientTryToConnectoToSecureServer() throws Exception {
- try {
- startServer(); // Start Server with SSLFilter
-
- //Now start a client without any SSL
- Thread t = new Thread() {
- @Override
- public void run() {
- try {
- address = InetAddress.getByName("localhost");
-
- Socket socket = new Socket(address, port);
- socket.setSoTimeout(10000);
-
- String response = null;
-
- while (response == null) {
- try {
- System.out.println(socket.isConnected());
- // System.out.println("Client sending: hello");
- socket.getOutputStream().write("hello \n".getBytes());
- socket.getOutputStream().flush();
- socket.setSoTimeout(1000);
-
- // System.out.println("Client sending: send");
- socket.getOutputStream().write("send\n".getBytes());
- socket.getOutputStream().flush();
-
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- String line = "";
-
- while ((line = in.readLine()) != null) {
- response = response + line;
- }
- } catch (SocketTimeoutException timeout) {
- // donothing
- timeout.printStackTrace();
- }
- }
-
- if (response.contains("AAAAAAA")){
- throw new IllegalStateException("getting response:" + response);
- }
-
- // System.out.println("Client got: " + line);
- socket.close();
- } catch (Exception e) {
- clientError = e;
- }
- }
- };
-
- t.start();
- t.join();
-
- if (clientError != null) {
- throw clientError;
- }
- } finally {
- stopServer();
- }
- }
-}
diff --git a/mina-example/src/main/java/org/apache/mina/example/chat/Main.java b/mina-example/src/main/java/org/apache/mina/example/chat/Main.java
index 1e76ad6..a2b847c 100644
--- a/mina-example/src/main/java/org/apache/mina/example/chat/Main.java
+++ b/mina-example/src/main/java/org/apache/mina/example/chat/Main.java
@@ -28,7 +28,7 @@ import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.compression.CompressionFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.logging.MdcInjectionFilter;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/**
@@ -72,7 +72,7 @@ public class Main {
private static void addSSLSupport(DefaultIoFilterChainBuilder chain)
throws Exception {
- SslFilter sslFilter = new SslFilter(BogusSslContextFactory
+ SSLFilter sslFilter = new SSLFilter(BogusSslContextFactory
.getInstance(true));
chain.addLast("sslFilter", sslFilter);
System.out.println("SSL ON");
diff --git a/mina-example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java b/mina-example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java
index f099ff6..dea4122 100644
--- a/mina-example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java
+++ b/mina-example/src/main/java/org/apache/mina/example/chat/client/ChatClientSupport.java
@@ -28,12 +28,12 @@ import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
-import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.compression.CompressionFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.logging.MdcInjectionFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
/**
@@ -79,8 +79,7 @@ public class ChatClientSupport {
if (useSsl) {
SSLContext sslContext = BogusSslContextFactory
.getInstance(false);
- SslFilter sslFilter = new SslFilter(sslContext);
- sslFilter.setUseClientMode(true);
+ SSLFilter sslFilter = new SSLFilter(sslContext);
connector.getFilterChain().addFirst("sslFilter", sslFilter);
}
diff --git a/mina-example/src/main/java/org/apache/mina/example/echoserver/Main.java b/mina-example/src/main/java/org/apache/mina/example/echoserver/Main.java
index 6501e78..72b820a 100644
--- a/mina-example/src/main/java/org/apache/mina/example/echoserver/Main.java
+++ b/mina-example/src/main/java/org/apache/mina/example/echoserver/Main.java
@@ -24,7 +24,7 @@ import java.net.InetSocketAddress;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
import org.apache.mina.filter.compression.CompressionFilter;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
@@ -68,7 +68,7 @@ public class Main {
private static void addSSLSupport(DefaultIoFilterChainBuilder chain)
throws Exception {
- SslFilter sslFilter = new SslFilter(BogusSslContextFactory
+ SSLFilter sslFilter = new SSLFilter(BogusSslContextFactory
.getInstance(true));
chain.addLast("sslFilter", sslFilter);
System.out.println("SSL ON");
diff --git a/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslClient.java b/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslClient.java
index 7588c54..3b12175 100644
--- a/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslClient.java
+++ b/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslClient.java
@@ -32,7 +32,7 @@ import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
/**
@@ -70,8 +70,7 @@ public class TcpSslClient extends IoHandlerAdapter {
// Inject teh SSL filter
SSLContext sslContext = BogusSslContextFactory
.getInstance(false);
- SslFilter sslFilter = new SslFilter(sslContext);
- sslFilter.setUseClientMode(true);
+ SSLFilter sslFilter = new SSLFilter(sslContext);
connector.getFilterChain().addFirst("sslFilter", sslFilter);
connector.setHandler(this);
diff --git a/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslServer.java b/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslServer.java
index 13aaf07..0e88963 100644
--- a/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslServer.java
+++ b/mina-example/src/main/java/org/apache/mina/example/tcp/perf/TcpSslServer.java
@@ -29,7 +29,7 @@ import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/**
@@ -136,7 +136,7 @@ public class TcpSslServer extends IoHandlerAdapter {
// Inject the SSL filter
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
- SslFilter sslFilter = new SslFilter(BogusSslContextFactory
+ SSLFilter sslFilter = new SSLFilter(BogusSslContextFactory
.getInstance(true));
chain.addLast("sslFilter", sslFilter);
diff --git a/mina-example/src/test/java/org/apache/mina/example/echoserver/AbstractTest.java b/mina-example/src/test/java/org/apache/mina/example/echoserver/AbstractTest.java
index 508f331..8116099 100644
--- a/mina-example/src/test/java/org/apache/mina/example/echoserver/AbstractTest.java
+++ b/mina-example/src/test/java/org/apache/mina/example/echoserver/AbstractTest.java
@@ -30,7 +30,7 @@ import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
import org.apache.mina.filter.FilterEvent;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.DatagramSessionConfig;
import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
@@ -122,7 +122,7 @@ public abstract class AbstractTest {
try {
session.getFilterChain().addFirst(
"SSL",
- new SslFilter(BogusSslContextFactory
+ new SSLFilter(BogusSslContextFactory
.getInstance(true)));
} catch (GeneralSecurityException e) {
LOGGER.error("", e);
@@ -143,16 +143,13 @@ public abstract class AbstractTest {
buf.mark();
- if (session.getFilterChain().contains("SSL")
+ if (session.isSecured()
&& buf.remaining() == 1 && buf.get() == (byte) '.') {
LOGGER.info("TLS Reentrance");
- ((SslFilter) session.getFilterChain().get("SSL"))
- .startSsl(session);
// Send a response
buf.capacity(1);
buf.flip();
- session.setAttribute(SslFilter.DISABLE_ENCRYPTION_ONCE);
session.write(buf);
} else {
buf.reset();
diff --git a/mina-example/src/test/java/org/apache/mina/example/echoserver/ConnectorTest.java b/mina-example/src/test/java/org/apache/mina/example/echoserver/ConnectorTest.java
index 8f3163f..76a66a6 100644
--- a/mina-example/src/test/java/org/apache/mina/example/echoserver/ConnectorTest.java
+++ b/mina-example/src/test/java/org/apache/mina/example/echoserver/ConnectorTest.java
@@ -20,7 +20,6 @@
package org.apache.mina.example.echoserver;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.InetAddress;
@@ -34,7 +33,7 @@ import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteException;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.nio.NioDatagramConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.apache.mina.util.AvailablePortFinder;
@@ -59,7 +58,7 @@ public class ConnectorTest extends AbstractTest {
private final int DATA_SIZE = 16;
private EchoConnectorHandler handler;
- private SslFilter connectorSSLFilter;
+ private SSLFilter connectorSSLFilter;
public ConnectorTest() {
// Do nothing
@@ -69,9 +68,8 @@ public class ConnectorTest extends AbstractTest {
public void setUp() throws Exception {
super.setUp();
handler = new EchoConnectorHandler();
- connectorSSLFilter = new SslFilter(BogusSslContextFactory
+ connectorSSLFilter = new SSLFilter(BogusSslContextFactory
.getInstance(false));
- connectorSSLFilter.setUseClientMode(true); // set client mode
}
@Test
@@ -81,7 +79,6 @@ public class ConnectorTest extends AbstractTest {
}
@Test
- @Ignore
public void testTCPWithSSL() throws Exception {
useSSL = true;
// Create a connector
@@ -135,7 +132,7 @@ public class ConnectorTest extends AbstractTest {
// Send closeNotify to test TLS closure if it is TLS connection.
if (useSSL) {
- connectorSSLFilter.stopSsl(session).awaitUninterruptibly();
+ session.getFilterChain().remove("SSL");
System.out
.println("-------------------------------------------------------------------------------");
@@ -161,7 +158,7 @@ public class ConnectorTest extends AbstractTest {
assertEquals((byte) '.', handler.readBuf.get());
// Now start TLS connection
- assertTrue(connectorSSLFilter.startSsl(session));
+ session.getFilterChain().addFirst("SSL", connectorSSLFilter);
testConnector0(session);
}
diff --git a/mina-example/src/test/java/org/apache/mina/example/echoserver/ssl/SslFilterTest.java b/mina-example/src/test/java/org/apache/mina/example/echoserver/ssl/SslFilterTest.java
index c5ac40e..7a999aa 100644
--- a/mina-example/src/test/java/org/apache/mina/example/echoserver/ssl/SslFilterTest.java
+++ b/mina-example/src/test/java/org/apache/mina/example/echoserver/ssl/SslFilterTest.java
@@ -38,7 +38,7 @@ import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
-import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.filter.ssl.SSLFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.junit.After;
@@ -80,9 +80,9 @@ public class SslFilterTest {
// Workaround to fix TLS issue : http://java.sun.com/javase/javaseforbusiness/docs/TLSReadme.html
java.lang.System.setProperty( "sun.security.ssl.allowUnsafeRenegotiation", "true" );
- SslFilter sslFilter = null;
+ SSLFilter sslFilter = null;
if (useSSL) {
- sslFilter = new SslFilter(BogusSslContextFactory.getInstance(true));
+ sslFilter = new SSLFilter(BogusSslContextFactory.getInstance(true));
acceptor.getFilterChain().addLast("sslFilter", sslFilter);
}
acceptor.getFilterChain().addLast(