/**
* This file is part of Waarp Project.
*
* Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
* COPYRIGHT.txt in the distribution for a full listing of individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Waarp . If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.waarp.common.crypto.ssl;
import java.security.Security;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSessionContext;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
/**
* SSL ContextFactory for Netty.
*
* @author Frederic Bregier
*
*/
public class WaarpSslContextFactory {
protected static final int DEFAULT_SESSIONCACHE_TIMEOUTSEC = 60;
protected static final int DEFAULT_SESSIONCACHE_SIZE = 1024;
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory
.getLogger(WaarpSslContextFactory.class);
/**
*
*/
private static final String PROTOCOL = "TLS";
/**
*
*/
private final SSLContext SERVER_CONTEXT;
/**
*
*/
private final SSLContext CLIENT_CONTEXT;
private boolean needClientAuthentication = false;
/**
* Create both CONTEXT
*
* @param ggSecureKeyStore
*/
public WaarpSslContextFactory(WaarpSecureKeyStore ggSecureKeyStore) {
// Both construct Client and Server mode
SERVER_CONTEXT = initSslContextFactory(ggSecureKeyStore, true);
CLIENT_CONTEXT = initSslContextFactory(ggSecureKeyStore, false);
}
/**
* Create only one of the CONTEXT
*
* @param ggSecureKeyStore
* @param serverMode
*/
public WaarpSslContextFactory(WaarpSecureKeyStore ggSecureKeyStore, boolean serverMode) {
if (serverMode) {
SERVER_CONTEXT = initSslContextFactory(ggSecureKeyStore, serverMode);
CLIENT_CONTEXT = null;
} else {
CLIENT_CONTEXT = initSslContextFactory(ggSecureKeyStore, serverMode);
SERVER_CONTEXT = null;
}
}
/**
*
* @param cacheSize
* default being 1024
* @param timeOutInSeconds
* default being 60s
*/
public void setSessionCacheTime(int cacheSize, int timeOutInSeconds) {
if (SERVER_CONTEXT != null) {
SSLSessionContext sslSessionContext = SERVER_CONTEXT.getServerSessionContext();
if (sslSessionContext != null) {
sslSessionContext.setSessionCacheSize(cacheSize);
sslSessionContext.setSessionTimeout(timeOutInSeconds);
}
}
}
/**
*
* @param ggSecureKeyStore
* @param serverMode
* @return the SSLContext
*/
private SSLContext initSslContextFactory(WaarpSecureKeyStore ggSecureKeyStore,
boolean serverMode) {
String algorithm = Security
.getProperty("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
SSLContext serverContext = null;
SSLContext clientContext = null;
if (serverMode) {
try {
// Initialize the SSLContext to work with our key managers.
serverContext = SSLContext.getInstance(PROTOCOL);
WaarpSecureTrustManagerFactory secureTrustManagerFactory =
ggSecureKeyStore.getSecureTrustManagerFactory();
needClientAuthentication = secureTrustManagerFactory.needAuthentication();
if (secureTrustManagerFactory.hasTrustStore()) {
logger.debug("Has TrustManager");
serverContext.init(ggSecureKeyStore.getKeyManagerFactory().getKeyManagers(),
secureTrustManagerFactory.getTrustManagers(), null);
} else {
logger.debug("No TrustManager");
serverContext.init(ggSecureKeyStore.getKeyManagerFactory().getKeyManagers(),
null, null);
}
SSLSessionContext sslSessionContext = serverContext.getServerSessionContext();
if (sslSessionContext != null) {
sslSessionContext.setSessionCacheSize(DEFAULT_SESSIONCACHE_SIZE);
sslSessionContext.setSessionTimeout(DEFAULT_SESSIONCACHE_TIMEOUTSEC);
}
return serverContext;
} catch (Throwable e) {
logger.error("Failed to initialize the server-side SSLContext", e);
throw new Error("Failed to initialize the server-side SSLContext",
e);
}
} else {
try {
clientContext = SSLContext.getInstance(PROTOCOL);
WaarpSecureTrustManagerFactory secureTrustManagerFactory =
ggSecureKeyStore.getSecureTrustManagerFactory();
needClientAuthentication = secureTrustManagerFactory.needAuthentication();
if (secureTrustManagerFactory.hasTrustStore()) {
logger.debug("Has TrustManager");
clientContext.init(ggSecureKeyStore.getKeyManagerFactory().getKeyManagers(),
secureTrustManagerFactory.getTrustManagers(), null);
} else {
logger.debug("No TrustManager");
clientContext.init(ggSecureKeyStore.getKeyManagerFactory().getKeyManagers(),
null, null);
}
SSLSessionContext sslSessionContext = clientContext.getServerSessionContext();
if (sslSessionContext != null) {
sslSessionContext.setSessionCacheSize(DEFAULT_SESSIONCACHE_SIZE);
sslSessionContext.setSessionTimeout(DEFAULT_SESSIONCACHE_TIMEOUTSEC);
}
return clientContext;
} catch (Throwable e) {
logger.error("Failed to initialize the client-side SSLContext", e);
throw new Error("Failed to initialize the client-side SSLContext",
e);
}
}
}
/**
* @return the Server Context
*/
public SSLContext getServerContext() {
return SERVER_CONTEXT;
}
/**
* @return the Client Context
*/
public SSLContext getClientContext() {
return CLIENT_CONTEXT;
}
/**
* To be called before adding as first entry in the Initializer as<br>
* pipeline.addLast("ssl", sslhandler);<br>
*
* @param serverMode
* True if in Server Mode, else False in Client mode
* @param needClientAuth
* True if the client needs to be authenticated (only if serverMode is True)
* @return the sslhandler
*/
public WaarpSslHandler initInitializer(boolean serverMode,
boolean needClientAuth) {
// Add SSL handler first to encrypt and decrypt everything.
SSLEngine engine;
logger.debug("Has TrustManager? " + needClientAuth + " Is ServerMode? " + serverMode);
if (serverMode) {
engine = getServerContext().createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(needClientAuth);
} else {
engine = getClientContext().createSSLEngine();
engine.setUseClientMode(true);
}
WaarpSslHandler handler = new WaarpSslHandler(engine);
return handler;
}
/**
* To be called before adding as first entry in the Initializer as<br>
* pipeline.addLast("ssl", sslhandler);<br>
*
* @param serverMode
* True if in Server Mode, else False in Client mode
* @param needClientAuth
* True if the client needs to be authenticated (only if serverMode is True)
* @param host
* Host for which a resume is allowed
* @param port
* port associated with the host for which a resume is allowed
* @return the sslhandler
*/
public WaarpSslHandler initInitializer(boolean serverMode,
boolean needClientAuth, String host, int port) {
// Add SSL handler first to encrypt and decrypt everything.
SSLEngine engine;
logger.debug("Has TrustManager? " + needClientAuth + " Is ServerMode? " + serverMode);
if (serverMode) {
engine = getServerContext().createSSLEngine(host, port);
engine.setUseClientMode(false);
engine.setNeedClientAuth(needClientAuth);
} else {
engine = getClientContext().createSSLEngine(host, port);
engine.setUseClientMode(true);
}
WaarpSslHandler handler = new WaarpSslHandler(engine);
return handler;
}
/**
*
* @return True if the associated KeyStore has a TrustStore
*/
public boolean needClientAuthentication() {
return needClientAuthentication;
}
}