Allow to enable session cache when using OpenSsl
Motivation: At the moment it is not possible to make use of the session cache when OpenSsl is used. This should be possible when server mode is used. Modifications: - Add OpenSslSessionContext (implements SSLSessionContext) which exposes all the methods to modify the session cache. - Add various extra methods to OpenSslSessionContext for extra functionality - Return OpenSslSessionContext when OpenSslEngine.getSession().getContext() is called. - Add sessionContext() to SslContext - Move OpenSsl specific session operations to OpenSslSessionContext and mark the old methods @deprecated Result: It's now possible to use session cache with OpenSsl
This commit is contained in:
parent
19f6b420a9
commit
b080fde03b
@ -16,7 +16,6 @@
|
|||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
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.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
|
|
||||||
import javax.net.ssl.SSLEngine;
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
@ -37,13 +35,13 @@ import java.security.KeyStoreException;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
* A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
||||||
*/
|
*/
|
||||||
public final class OpenSslClientContext extends OpenSslContext {
|
public final class OpenSslClientContext extends OpenSslContext {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslClientContext.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslClientContext.class);
|
||||||
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -151,6 +149,7 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sessionContext = new OpenSslClientSessionContext(ctx);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -182,12 +181,38 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSLEngine newEngine(ByteBufAllocator alloc) {
|
public OpenSslSessionContext sessionContext() {
|
||||||
List<String> protos = applicationProtocolNegotiator().protocols();
|
return sessionContext;
|
||||||
if (protos.isEmpty()) {
|
}
|
||||||
return new OpenSslEngine(ctx, alloc, null, isClient());
|
|
||||||
} else {
|
// No cache is currently supported for client side mode.
|
||||||
return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient());
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,6 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
/** The OpenSSL SSL_CTX object */
|
/** The OpenSSL SSL_CTX object */
|
||||||
protected final long ctx;
|
protected final long ctx;
|
||||||
private final int mode;
|
private final int mode;
|
||||||
private final OpenSslSessionStats stats;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
List<String> ciphers = new ArrayList<String>();
|
List<String> ciphers = new ArrayList<String>();
|
||||||
@ -191,8 +190,6 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
destroyPools();
|
destroyPools();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stats = new OpenSslSessionStats(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,6 +222,19 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
throw new UnsupportedOperationException();
|
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<String> 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.
|
* 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.
|
* Returns the stats of this context.
|
||||||
|
* @deprecated use {@link #sessionContext#stats()}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final OpenSslSessionStats stats() {
|
public final OpenSslSessionStats stats() {
|
||||||
return stats;
|
return sessionContext().stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -254,14 +266,16 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the SSL session ticket keys of this context.
|
* Sets the SSL session ticket keys of this context.
|
||||||
|
* @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final void setTicketKeys(byte[] keys) {
|
public final void setTicketKeys(byte[] keys) {
|
||||||
if (keys == null) {
|
sessionContext().setTicketKeys(keys);
|
||||||
throw new NullPointerException("keys");
|
|
||||||
}
|
|
||||||
SSLContext.setSessionTicketKeys(ctx, keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract OpenSslSessionContext sessionContext();
|
||||||
|
|
||||||
protected final void destroyPools() {
|
protected final void destroyPools() {
|
||||||
// Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
|
// Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
|
||||||
if (aprPool != 0 && DESTROY_UPDATER.compareAndSet(this, 0, 1)) {
|
if (aprPool != 0 && DESTROY_UPDATER.compareAndSet(this, 0, 1)) {
|
||||||
|
@ -129,6 +129,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
private final boolean clientMode;
|
private final boolean clientMode;
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
private final String fallbackApplicationProtocol;
|
private final String fallbackApplicationProtocol;
|
||||||
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private volatile SSLSession session;
|
private volatile SSLSession session;
|
||||||
@ -141,7 +142,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol) {
|
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 sslCtx an OpenSSL {@code SSL_CTX} object
|
||||||
* @param alloc the {@link ByteBufAllocator} that will be used by this engine
|
* @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 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,
|
OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol,
|
||||||
boolean clientMode) {
|
boolean clientMode, OpenSslSessionContext sessionContext) {
|
||||||
OpenSsl.ensureAvailability();
|
OpenSsl.ensureAvailability();
|
||||||
if (sslCtx == 0) {
|
if (sslCtx == 0) {
|
||||||
throw new NullPointerException("sslContext");
|
throw new NullPointerException("sslContext");
|
||||||
@ -166,6 +168,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
networkBIO = SSL.makeNetworkBIO(ssl);
|
networkBIO = SSL.makeNetworkBIO(ssl);
|
||||||
this.fallbackApplicationProtocol = fallbackApplicationProtocol;
|
this.fallbackApplicationProtocol = fallbackApplicationProtocol;
|
||||||
this.clientMode = clientMode;
|
this.clientMode = clientMode;
|
||||||
|
this.sessionContext = sessionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -717,7 +720,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSLSessionContext getSessionContext() {
|
public SSLSessionContext getSessionContext() {
|
||||||
return null;
|
return sessionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
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.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
|
|
||||||
import javax.net.ssl.SSLEngine;
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
@ -48,6 +46,8 @@ import static io.netty.util.internal.ObjectUtil.*;
|
|||||||
public final class OpenSslServerContext extends OpenSslContext {
|
public final class OpenSslServerContext extends OpenSslContext {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslServerContext.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslServerContext.class);
|
||||||
|
|
||||||
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
@ -247,6 +247,7 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sessionContext = new OpenSslServerSessionContext(ctx);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -256,12 +257,39 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSLEngine newEngine(ByteBufAllocator alloc) {
|
public OpenSslSessionContext sessionContext() {
|
||||||
List<String> protos = applicationProtocolNegotiator().protocols();
|
return sessionContext;
|
||||||
if (protos.isEmpty()) {
|
}
|
||||||
return new OpenSslEngine(ctx, alloc, null, isClient());
|
|
||||||
} else {
|
private static final class OpenSslServerSessionContext extends OpenSslSessionContext {
|
||||||
return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient());
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<byte[]> 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<byte[]> 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<byte[]> {
|
||||||
|
@Override
|
||||||
|
public boolean hasMoreElements() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] nextElement() {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ import javax.crypto.spec.PBEKeySpec;
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
import javax.net.ssl.SSLSessionContext;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -541,6 +542,11 @@ public abstract class SslContext {
|
|||||||
*/
|
*/
|
||||||
public abstract SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort);
|
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}.
|
* Creates a new {@link SslHandler}.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user