/* * Copyright 2015-2025 the original author or authors. * * Licensed 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 sockslib.common; import com.google.common.base.Strings; import sockslib.utils.PathUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.security.KeyStore; import java.util.Properties; import static com.google.common.base.Preconditions.checkNotNull; /** * The class <code>SSLConfiguration</code> represents a configuration of SSL. * * @author Youchao Feng * @version 1.0 * @date May 17, 2015 6:52:52 PM */ public class SSLConfiguration { private static final Logger logger = LoggerFactory.getLogger(SSLConfiguration.class); private KeyStoreInfo keyStoreInfo; private KeyStoreInfo trustKeyStoreInfo; private boolean needClientAuth = false; public SSLConfiguration(KeyStoreInfo keyStoreInfo, KeyStoreInfo trustKeyStoreInfo) { this(keyStoreInfo, trustKeyStoreInfo, false); } public SSLConfiguration(@Nullable KeyStoreInfo keyStoreInfo, @Nullable KeyStoreInfo trustKeyStoreInfo, boolean clientAuth) { this.keyStoreInfo = keyStoreInfo; this.trustKeyStoreInfo = trustKeyStoreInfo; this.needClientAuth = clientAuth; } /** * Creates a {@link SSLConfiguration} instance with a string.<br> * The string should format as: <br> * <pre> * KEYS_TORE_PATH,KEY_STORE_PASSWORD,TRUST_KEY_STORE_PATH,TRUST_KEY_STORE_PASSWORD,CLIENT_AUTH * </pre> * * @param configuration configuration as a string. * @return the instance of {@link SSLConfiguration}. */ public static SSLConfiguration parse(String configuration) { String[] strings = configuration.split(","); if (strings.length == 2) { KeyStoreInfo keyStoreInfo = new KeyStoreInfo(strings[0], strings[1]); return new SSLConfiguration(keyStoreInfo, null); } else if (strings.length == 4) { KeyStoreInfo keyStoreInfo = new KeyStoreInfo(strings[0], strings[1]); KeyStoreInfo trustKeyStoreInfo = new KeyStoreInfo(strings[2], strings[3]); return new SSLConfiguration(keyStoreInfo, trustKeyStoreInfo); } else if (strings.length == 5) { KeyStoreInfo keyStoreInfo = new KeyStoreInfo(strings[0], strings[1]); KeyStoreInfo trustKeyStoreInfo = new KeyStoreInfo(strings[2], strings[3]); return new SSLConfiguration(keyStoreInfo, trustKeyStoreInfo, strings[4].equals("true")); } return null; } public static SSLConfiguration load(String filePath) throws FileNotFoundException, IOException { checkNotNull(filePath, "Argument [filePath] may not be null"); logger.debug("load SSL configuration file:{}", filePath); KeyStoreInfo keyStoreInfo = null; KeyStoreInfo trustKeyStoreInfo = null; Properties properties = new Properties(); properties.load(new FileInputStream(filePath)); String keystorePath = PathUtil.getAbstractPath(properties.getProperty("ssl.keystore.location")); String password = properties.getProperty("ssl.keystore.password"); String type = properties.getProperty("ssl.keystore.type", "JSK"); String trustKeystorePath = PathUtil.getAbstractPath(properties.getProperty("ssl.trustStore.location")); String trustPassword = properties.getProperty("ssl.trustStore.password"); String trustType = properties.getProperty("ssl.trustStore.type", "JSK"); if (!Strings.isNullOrEmpty(keystorePath)) { keyStoreInfo = new KeyStoreInfo(keystorePath, password, type); } if (!Strings.isNullOrEmpty(trustKeystorePath)) { trustKeyStoreInfo = new KeyStoreInfo(trustKeystorePath, trustPassword, trustType); } String clientAuthValue = properties.getProperty("ssl.client.auth", "false"); boolean clientAuth = false; if (clientAuthValue.equalsIgnoreCase("true")) { clientAuth = true; } return new SSLConfiguration(keyStoreInfo, trustKeyStoreInfo, clientAuth); } public static SSLConfiguration loadClassPath(String filePath) throws FileNotFoundException, IOException { checkNotNull(filePath, "Argument [filePath] may not be null"); if (!filePath.startsWith(File.separator)) { filePath = File.separator + filePath; } URL url = SSLConfiguration.class.getResource(filePath); if (url == null) { throw new FileNotFoundException("classpath:" + filePath); } String path = url.getPath(); return load(path); } public SSLSocketFactory getSSLSocketFactory() throws SSLConfigurationException { checkNotNull(trustKeyStoreInfo, "trustKeyStoreInfo may not be null"); KeyStore keyStore = null; KeyStore trustKeyStore = null; try { SSLContext context = SSLContext.getInstance("SSL"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); trustKeyStore = KeyStore.getInstance(trustKeyStoreInfo.getType()); trustKeyStore.load(new FileInputStream(trustKeyStoreInfo.getKeyStorePath()), trustKeyStoreInfo.getPassword().toCharArray()); trustManagerFactory.init(trustKeyStore); if (keyStoreInfo != null && keyStoreInfo.getKeyStorePath() != null) { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyStore = KeyStore.getInstance(keyStoreInfo.getType()); keyStore.load(new FileInputStream(keyStoreInfo.getKeyStorePath()), keyStoreInfo .getPassword().toCharArray()); keyManagerFactory.init(keyStore, keyStoreInfo.getPassword().toCharArray()); context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); } else { context.init(null, trustManagerFactory.getTrustManagers(), null); } if (keyStore != null) { logger.info("SSL: Key store:{}", keyStoreInfo.getKeyStorePath()); } logger.info("SSL: Trust key store:{}", trustKeyStoreInfo.getKeyStorePath()); return context.getSocketFactory(); } catch (Exception e) { logger.error(e.getMessage(), e); throw new SSLConfigurationException(e.getMessage()); } } public SSLServerSocketFactory getSSLServerSocketFactory() throws SSLConfigurationException { checkNotNull(keyStoreInfo, "keyStoreInfo may not be null"); String KEY_STORE_PASSWORD = getKeyStoreInfo().getPassword(); String KEY_STORE_PATH = getKeyStoreInfo().getKeyStorePath(); KeyStore keyStore = null; KeyStore trustKeyStore = null; try { SSLContext ctx = SSLContext.getInstance("SSL"); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream(KEY_STORE_PATH), KEY_STORE_PASSWORD.toCharArray()); keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray()); if (needClientAuth && trustKeyStoreInfo != null) { String TRUST_KEY_STORE_PATH = getTrustKeyStoreInfo().getKeyStorePath(); String TRUST_KEY_STORE_PASSWORD = getTrustKeyStoreInfo().getPassword(); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); trustKeyStore = KeyStore.getInstance("JKS"); trustKeyStore.load(new FileInputStream(TRUST_KEY_STORE_PATH), TRUST_KEY_STORE_PASSWORD .toCharArray()); trustManagerFactory.init(trustKeyStore); ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); } else { ctx.init(keyManagerFactory.getKeyManagers(), null, null); } logger.info("SSL: Key store:{}", keyStoreInfo.getKeyStorePath()); if (trustKeyStore != null) { logger.info("SSL: Trust key store:{}", trustKeyStoreInfo.getKeyStorePath()); } logger.info("SSL: Client authentication:{}", needClientAuth); ; return ctx.getServerSocketFactory(); } catch (Exception e) { throw new SSLConfigurationException(e.getMessage()); } } /** * Returns the keyStoreInfo. * * @return the keyStoreInfo */ public KeyStoreInfo getKeyStoreInfo() { return keyStoreInfo; } /** * @param keyStoreInfo the keyStoreInfo to set */ public void setKeyStoreInfo(KeyStoreInfo keyStoreInfo) { this.keyStoreInfo = keyStoreInfo; } /** * @return the trustKeyStoreInfo */ public KeyStoreInfo getTrustKeyStoreInfo() { return trustKeyStoreInfo; } /** * @param trustKeyStoreInfo the trustKeyStoreInfo to set */ public void setTrustKeyStoreInfo(KeyStoreInfo trustKeyStoreInfo) { this.trustKeyStoreInfo = trustKeyStoreInfo; } /** * Returns the needClientAuth. * * @return the needClientAuth */ public boolean isNeedClientAuth() { return needClientAuth; } /** * @param needClientAuth the needClientAuth to set */ public void setNeedClientAuth(boolean needClientAuth) { this.needClientAuth = needClientAuth; } }