
io.jsync.net.impl.TCPSSLHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.net.impl;
import io.jsync.file.impl.PathAdjuster;
import io.jsync.impl.AsyncInternal;
import io.jsync.logging.Logger;
import io.jsync.logging.impl.LoggerFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Helper class for TCP and SSL attributes
*
* @author Tim Fox
*/
public class TCPSSLHelper {
private static final Logger log = LoggerFactory.getLogger(TCPSSLHelper.class);
// Make sure SSLv3 is NOT enabled due to POODLE issue http://en.wikipedia.org/wiki/POODLE
private static final String[] ENABLED_PROTOCOLS = {"SSLv2Hello", "TLSv1", "TLSv1.1", "TLSv1.2"};
private static SocketDefaults defaults = SocketDefaults.instance;
private boolean ssl;
private boolean verifyHost = false;
private String keyStorePath;
private String keyStorePassword;
private String trustStorePath;
private String trustStorePassword;
private boolean trustAll;
private ClientAuth clientAuth = ClientAuth.NONE;
private boolean tcpNoDelay = true;
private int tcpSendBufferSize = -1;
private int tcpReceiveBufferSize = -1;
private boolean tcpKeepAlive = defaults.isTcpKeepAlive();
private boolean reuseAddress = defaults.isReuseAddress();
private int soLinger = defaults.getSoLinger();
private int trafficClass = -1;
private int acceptBackLog = 1024;
private int connectTimeout = 60000;
private boolean usePooledBuffers;
private SSLContext sslContext;
private SSLContext externalSSLContext = null;
public TCPSSLHelper() {
}
// Create a TrustManager which trusts everything
private static TrustManager createTrustAllTrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
private static TrustManager[] getTrustMgrs(AsyncInternal async, final String tsPath,
final String tsPassword) throws Exception {
TrustManagerFactory fact = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ts = loadStore(async, tsPath, tsPassword);
fact.init(ts);
return fact.getTrustManagers();
}
private static KeyManager[] getKeyMgrs(AsyncInternal async, final String ksPath, final String ksPassword) throws Exception {
KeyManagerFactory fact = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = loadStore(async, ksPath, ksPassword);
fact.init(ks, ksPassword != null ? ksPassword.toCharArray() : null);
return fact.getKeyManagers();
}
private static KeyStore loadStore(AsyncInternal async, String path, final String ksPassword) throws Exception {
final String ksPath = PathAdjuster.adjust(async, path);
KeyStore ks = KeyStore.getInstance("JKS");
InputStream in = null;
try {
in = new FileInputStream(new File(ksPath));
ks.load(in, ksPassword != null ? ksPassword.toCharArray() : null);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignore) {
}
}
}
return ks;
}
public void checkSSL(AsyncInternal async) {
if (ssl) {
sslContext = createContext(async, keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, trustAll);
}
}
public void applyConnectionOptions(ServerBootstrap bootstrap) {
bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay);
if (tcpSendBufferSize != -1) {
bootstrap.childOption(ChannelOption.SO_SNDBUF, tcpSendBufferSize);
}
if (tcpReceiveBufferSize != -1) {
bootstrap.childOption(ChannelOption.SO_RCVBUF, tcpReceiveBufferSize);
bootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(tcpReceiveBufferSize));
}
bootstrap.option(ChannelOption.SO_LINGER, soLinger);
if (trafficClass != -1) {
bootstrap.childOption(ChannelOption.IP_TOS, trafficClass);
}
bootstrap.childOption(ChannelOption.ALLOCATOR, PartialPooledByteBufAllocator.INSTANCE);
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, tcpKeepAlive);
bootstrap.option(ChannelOption.SO_REUSEADDR, reuseAddress);
bootstrap.option(ChannelOption.SO_BACKLOG, acceptBackLog);
}
public void applyConnectionOptions(Bootstrap bootstrap) {
bootstrap.option(ChannelOption.TCP_NODELAY, tcpNoDelay);
if (tcpSendBufferSize != -1) {
bootstrap.option(ChannelOption.SO_SNDBUF, tcpSendBufferSize);
}
if (tcpReceiveBufferSize != -1) {
bootstrap.option(ChannelOption.SO_RCVBUF, tcpReceiveBufferSize);
bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(tcpReceiveBufferSize));
}
bootstrap.option(ChannelOption.SO_LINGER, soLinger);
if (trafficClass != -1) {
bootstrap.option(ChannelOption.IP_TOS, trafficClass);
}
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
bootstrap.option(ChannelOption.ALLOCATOR, PartialPooledByteBufAllocator.INSTANCE);
bootstrap.option(ChannelOption.SO_KEEPALIVE, tcpKeepAlive);
}
public boolean isTCPNoDelay() {
return tcpNoDelay;
}
public void setTCPNoDelay(boolean tcpNoDelay) {
this.tcpNoDelay = tcpNoDelay;
}
public int getSendBufferSize() {
return tcpSendBufferSize;
}
public void setSendBufferSize(int size) {
if (size < 1) {
throw new IllegalArgumentException("TCP send buffer size must be >= 1");
}
this.tcpSendBufferSize = size;
}
public int getReceiveBufferSize() {
return tcpReceiveBufferSize;
}
public void setReceiveBufferSize(int size) {
if (size < 1) {
throw new IllegalArgumentException("TCP receive buffer size must be >= 1");
}
this.tcpReceiveBufferSize = size;
}
public boolean isTCPKeepAlive() {
return tcpKeepAlive;
}
public void setTCPKeepAlive(boolean keepAlive) {
this.tcpKeepAlive = keepAlive;
}
public boolean isReuseAddress() {
return reuseAddress;
}
public void setReuseAddress(boolean reuse) {
this.reuseAddress = reuse;
}
public int getSoLinger() {
return soLinger;
}
public void setSoLinger(int linger) {
this.soLinger = linger;
}
public int getTrafficClass() {
return trafficClass;
}
public void setTrafficClass(int trafficClass) {
this.trafficClass = trafficClass;
}
public boolean isSSL() {
return ssl;
}
public void setSSL(boolean ssl) {
this.ssl = ssl;
}
public boolean isVerifyHost() {
return verifyHost;
}
public void setVerifyHost(boolean verifyHost) {
this.verifyHost = verifyHost;
}
public String getKeyStorePath() {
return keyStorePath;
}
public void setKeyStorePath(String path) {
this.keyStorePath = path;
}
public String getKeyStorePassword() {
return keyStorePassword;
}
public void setKeyStorePassword(String pwd) {
this.keyStorePassword = pwd;
}
public String getTrustStorePath() {
return trustStorePath;
}
public void setTrustStorePath(String path) {
this.trustStorePath = path;
}
public String getTrustStorePassword() {
return trustStorePassword;
}
public void setTrustStorePassword(String pwd) {
this.trustStorePassword = pwd;
}
public ClientAuth getClientAuth() {
return clientAuth;
}
public boolean isTrustAll() {
return trustAll;
}
public void setTrustAll(boolean trustAll) {
this.trustAll = trustAll;
}
public void setExternalSSLContext(SSLContext externalSSLContext) {
this.externalSSLContext = externalSSLContext;
}
public void setClientAuthRequired(boolean required) {
clientAuth = required ? ClientAuth.REQUIRED : ClientAuth.NONE;
}
public int getAcceptBacklog() {
return acceptBackLog;
}
public void setAcceptBacklog(int acceptBackLog) {
if (acceptBackLog < 0) {
throw new IllegalArgumentException("acceptBackLog must be >= 0");
}
this.acceptBackLog = acceptBackLog;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
if (connectTimeout < 0) {
throw new IllegalArgumentException("connectTimeout must be >= 0");
}
this.connectTimeout = connectTimeout;
}
public boolean isUsePooledBuffers() {
return usePooledBuffers;
}
public void setUsePooledBuffers(boolean usePooledBuffers) {
this.usePooledBuffers = usePooledBuffers;
}
/*
If you don't specify a trust store, and you haven't set system properties, the system will try to use either a file
called jsssecacerts or cacerts in the JDK/JRE security directory.
You can override this by specifying the javax.echo.ssl.trustStore system property
If you don't specify a key store, and don't specify a system property no key store will be used
You can override this by specifying the javax.echo.ssl.keyStore system property
*/
public SSLContext createContext(AsyncInternal async, final String ksPath,
final String ksPassword,
final String tsPath,
final String tsPassword,
final boolean trustAll) {
if (externalSSLContext != null) {
return externalSSLContext;
}
try {
SSLContext context = SSLContext.getInstance("TLS");
KeyManager[] keyMgrs = ksPath == null ? null : getKeyMgrs(async, ksPath, ksPassword);
TrustManager[] trustMgrs;
if (trustAll) {
trustMgrs = new TrustManager[]{createTrustAllTrustManager()};
} else {
trustMgrs = tsPath == null ? null : getTrustMgrs(async, tsPath, tsPassword);
}
context.init(keyMgrs, trustMgrs, new SecureRandom());
return context;
} catch (Exception e) {
//TODO better logging
log.error("Failed to create context", e);
throw new RuntimeException(e.getMessage());
}
}
private SslHandler createHandler(SSLEngine engine, boolean client) {
engine.setEnabledProtocols(ENABLED_PROTOCOLS);
engine.setUseClientMode(client);
if (!client) {
switch (getClientAuth()) {
case REQUEST: {
engine.setWantClientAuth(true);
break;
}
case REQUIRED: {
engine.setNeedClientAuth(true);
break;
}
case NONE: {
engine.setNeedClientAuth(false);
break;
}
}
} else if (verifyHost) {
SSLParameters sslParameters = engine.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
engine.setSSLParameters(sslParameters);
}
return new SslHandler(engine);
}
private SSLContext getContext(AsyncInternal async) {
if (sslContext == null) {
sslContext = createContext(async, keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, trustAll);
}
return sslContext;
}
public SslHandler createSslHandler(AsyncInternal async, boolean client, String host, int port) {
SSLEngine engine = getContext(async).createSSLEngine(host, port);
return createHandler(engine, client);
}
public SslHandler createSslHandler(AsyncInternal async, boolean client) {
SSLEngine engine = getContext(async).createSSLEngine();
return createHandler(engine, client);
}
public enum ClientAuth {
NONE, REQUEST, REQUIRED
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy