diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java index d325282c20..5574a6ee90 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java @@ -16,7 +16,6 @@ package io.netty.handler.ssl; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -24,7 +23,6 @@ import org.apache.tomcat.jni.CertificateVerifier; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; @@ -37,13 +35,13 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.List; /** * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation. */ public final class OpenSslClientContext extends OpenSslContext { private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslClientContext.class); + private final OpenSslSessionContext sessionContext; /** * Creates a new instance. @@ -151,6 +149,7 @@ public final class OpenSslClientContext extends OpenSslContext { throw new SSLException("unable to setup trustmanager", e); } } + sessionContext = new OpenSslClientSessionContext(ctx); success = true; } finally { if (!success) { @@ -182,12 +181,38 @@ public final class OpenSslClientContext extends OpenSslContext { } @Override - public SSLEngine newEngine(ByteBufAllocator alloc) { - List protos = applicationProtocolNegotiator().protocols(); - if (protos.isEmpty()) { - return new OpenSslEngine(ctx, alloc, null, isClient()); - } else { - return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient()); + public OpenSslSessionContext sessionContext() { + return sessionContext; + } + + // No cache is currently supported for client side mode. + private static final class OpenSslClientSessionContext extends OpenSslSessionContext { + private OpenSslClientSessionContext(long context) { + super(context); + } + + @Override + public void setSessionTimeout(int seconds) { + if (seconds < 0) { + throw new IllegalArgumentException(); + } + } + + @Override + public int getSessionTimeout() { + return 0; + } + + @Override + public void setSessionCacheSize(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + } + + @Override + public int getSessionCacheSize() { + return 0; } } } diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java index d7ee1e311e..d8dd8d162e 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java @@ -55,7 +55,6 @@ public abstract class OpenSslContext extends SslContext { /** The OpenSSL SSL_CTX object */ protected final long ctx; private final int mode; - private final OpenSslSessionStats stats; static { List ciphers = new ArrayList(); @@ -191,8 +190,6 @@ public abstract class OpenSslContext extends SslContext { destroyPools(); } } - - stats = new OpenSslSessionStats(ctx); } @Override @@ -225,6 +222,19 @@ public abstract class OpenSslContext extends SslContext { throw new UnsupportedOperationException(); } + /** + * Returns a new server-side {@link javax.net.ssl.SSLEngine} with the current configuration. + */ + @Override + public final SSLEngine newEngine(ByteBufAllocator alloc) { + List protos = applicationProtocolNegotiator().protocols(); + if (protos.isEmpty()) { + return new OpenSslEngine(ctx, alloc, null, isClient(), sessionContext()); + } else { + return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient(), sessionContext()); + } + } + /** * Returns the {@code SSL_CTX} object of this context. */ @@ -234,9 +244,11 @@ public abstract class OpenSslContext extends SslContext { /** * Returns the stats of this context. + * @deprecated use {@link #sessionContext#stats()} */ + @Deprecated public final OpenSslSessionStats stats() { - return stats; + return sessionContext().stats(); } @Override @@ -254,14 +266,16 @@ public abstract class OpenSslContext extends SslContext { /** * Sets the SSL session ticket keys of this context. + * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])} */ + @Deprecated public final void setTicketKeys(byte[] keys) { - if (keys == null) { - throw new NullPointerException("keys"); - } - SSLContext.setSessionTicketKeys(ctx, keys); + sessionContext().setTicketKeys(keys); } + @Override + public abstract OpenSslSessionContext sessionContext(); + protected final void destroyPools() { // Guard against multiple destroyPools() calls triggered by construction exception and finalize() later if (aprPool != 0 && DESTROY_UPDATER.compareAndSet(this, 0, 1)) { diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java index c1cc03a6c7..d268dface6 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java @@ -129,6 +129,7 @@ public final class OpenSslEngine extends SSLEngine { private final boolean clientMode; private final ByteBufAllocator alloc; private final String fallbackApplicationProtocol; + private final OpenSslSessionContext sessionContext; @SuppressWarnings("unused") private volatile SSLSession session; @@ -141,7 +142,7 @@ public final class OpenSslEngine extends SSLEngine { */ @Deprecated public OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol) { - this(sslCtx, alloc, fallbackApplicationProtocol, false); + this(sslCtx, alloc, fallbackApplicationProtocol, false, null); } /** @@ -150,9 +151,10 @@ public final class OpenSslEngine extends SSLEngine { * @param sslCtx an OpenSSL {@code SSL_CTX} object * @param alloc the {@link ByteBufAllocator} that will be used by this engine * @param clientMode {@code true} if this is used for clients, {@code false} otherwise + * @param sessionContext the {@link OpenSslSessionContext} this {@link SSLEngine} belongs to. */ OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol, - boolean clientMode) { + boolean clientMode, OpenSslSessionContext sessionContext) { OpenSsl.ensureAvailability(); if (sslCtx == 0) { throw new NullPointerException("sslContext"); @@ -166,6 +168,7 @@ public final class OpenSslEngine extends SSLEngine { networkBIO = SSL.makeNetworkBIO(ssl); this.fallbackApplicationProtocol = fallbackApplicationProtocol; this.clientMode = clientMode; + this.sessionContext = sessionContext; } /** @@ -717,7 +720,7 @@ public final class OpenSslEngine extends SSLEngine { @Override public SSLSessionContext getSessionContext() { - return null; + return sessionContext; } @Override diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java index 3361508167..cade7537d7 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java @@ -16,7 +16,6 @@ package io.netty.handler.ssl; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -24,7 +23,6 @@ import org.apache.tomcat.jni.CertificateVerifier; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; @@ -48,6 +46,8 @@ import static io.netty.util.internal.ObjectUtil.*; public final class OpenSslServerContext extends OpenSslContext { private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslServerContext.class); + private final OpenSslSessionContext sessionContext; + /** * Creates a new instance. * @@ -275,6 +275,7 @@ public final class OpenSslServerContext extends OpenSslContext { throw new SSLException("unable to setup trustmanager", e); } } + sessionContext = new OpenSslServerSessionContext(ctx); success = true; } finally { if (!success) { @@ -284,12 +285,39 @@ public final class OpenSslServerContext extends OpenSslContext { } @Override - public SSLEngine newEngine(ByteBufAllocator alloc) { - List protos = applicationProtocolNegotiator().protocols(); - if (protos.isEmpty()) { - return new OpenSslEngine(ctx, alloc, null, isClient()); - } else { - return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient()); + public OpenSslSessionContext sessionContext() { + return sessionContext; + } + + private static final class OpenSslServerSessionContext extends OpenSslSessionContext { + private OpenSslServerSessionContext(long context) { + super(context); + } + + @Override + public void setSessionTimeout(int seconds) { + if (seconds < 0) { + throw new IllegalArgumentException(); + } + SSLContext.setSessionCacheTimeout(context, seconds); + } + + @Override + public int getSessionTimeout() { + return (int) SSLContext.getSessionCacheTimeout(context); + } + + @Override + public void setSessionCacheSize(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + SSLContext.setSessionCacheSize(context, size); + } + + @Override + public int getSessionCacheSize() { + return (int) SSLContext.getSessionCacheSize(context); } } } diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java new file mode 100644 index 0000000000..bde75884fd --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project 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 io.netty.handler.ssl; + +import org.apache.tomcat.jni.SSLContext; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * OpenSSL specific {@link SSLSessionContext} implementation. + */ +public abstract class OpenSslSessionContext implements SSLSessionContext { + private static final Enumeration EMPTY = new EmptyEnumeration(); + + private final OpenSslSessionStats stats; + final long context; + + OpenSslSessionContext(long context) { + this.context = context; + stats = new OpenSslSessionStats(context); + } + + @Override + public SSLSession getSession(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException("bytes"); + } + return null; + } + + @Override + public Enumeration getIds() { + return EMPTY; + } + + /** + * Sets the SSL session ticket keys of this context. + */ + public void setTicketKeys(byte[] keys) { + if (keys == null) { + throw new NullPointerException("keys"); + } + SSLContext.setSessionTicketKeys(context, keys); + } + + /** + * Returns the stats of this context. + */ + public OpenSslSessionStats stats() { + return stats; + } + + private static final class EmptyEnumeration implements Enumeration { + @Override + public boolean hasMoreElements() { + return false; + } + + @Override + public byte[] nextElement() { + throw new NoSuchElementException(); + } + } +} diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java index d4b8728b61..3865240f0b 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java @@ -34,6 +34,7 @@ import javax.crypto.spec.PBEKeySpec; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSessionContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import java.io.File; @@ -731,6 +732,11 @@ public abstract class SslContext { */ public abstract SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort); + /** + * Returns the {@link SSLSessionContext} object held by this context. + */ + public abstract SSLSessionContext sessionContext(); + /** * Creates a new {@link SslHandler}. *