package water.network; import water.util.Log; import java.io.*; import java.security.*; import java.util.Properties; public class SecurityUtils { private static SecureRandom RANDOM = new SecureRandom(); private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private final static String[] keyToolCandidates = new String[]{ "sun.security.tools.KeyTool", // Java6 "sun.security.tools.keytool.Main", // Java7+ "com.ibm.crypto.tools.KeyTool" // IBM Java }; private static StoreCredentials generateKeystore(String password) throws Exception { return generateKeystore(password, "h2o-internal.jks", ""); } private static StoreCredentials generateKeystore(String password, String name, String location) throws Exception { String path = null != location && !location.isEmpty() ? location + File.pathSeparator + name : name; if(new File(path).exists()) { throw new IllegalStateException("A file under the location " + path + " already exists. Please delete it first."); } String[] genKeyArgs = new String[]{ "-genkeypair", "-alias", "h2o-internal", "-keyalg", "RSA", "-sigalg", "SHA256withRSA", "-dname", "CN=Java", "-storetype", "JKS", "-keypass", password, "-keystore", path, "-storepass", password, "-validity", "3650" }; Class<?> keytool = getKeyToolClass(); keytool.getMethod("main", String[].class).invoke(null, (Object) genKeyArgs); return new StoreCredentials(name, location, password); } private static Class<?> getKeyToolClass() { for (String keyToolCandidate : keyToolCandidates) { try { return Class.forName(keyToolCandidate); } catch (Exception e) { // Ignore, try other candidates } } // Unsuported JRE/JDK String errorMsg = "This version of Java is not supported. Please use Oracle/OpenJDK/IBM JDK version 6/7/8."; Log.err(errorMsg); throw new IllegalStateException(errorMsg); } public static SSLCredentials generateSSLPair(String passwd, String name, String location) throws Exception { StoreCredentials jks = generateKeystore(passwd, name, location); return new SSLCredentials(jks, jks); } public static SSLCredentials generateSSLPair() throws Exception { StoreCredentials jks = generateKeystore(passwordGenerator(16)); return new SSLCredentials(jks, jks); } private static String passwordGenerator(int len) { StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { sb.append(AB.charAt(RANDOM.nextInt(AB.length()))); } return sb.toString(); } public static String generateSSLConfig(SSLCredentials credentials) throws IOException { return generateSSLConfig(credentials, "ssl.properties"); } public static String generateSSLConfig(SSLCredentials credentials, String file) throws IOException { Properties sslConfig = new Properties(); sslConfig.put("h2o_ssl_protocol", defaultTLSVersion()); sslConfig.put("h2o_ssl_jks_internal", credentials.jks.getLocation()); sslConfig.put("h2o_ssl_jks_password", credentials.jks.pass); sslConfig.put("h2o_ssl_jts", credentials.jts.getLocation()); sslConfig.put("h2o_ssl_jts_password", credentials.jts.pass); FileOutputStream output = new FileOutputStream(file); sslConfig.store(output, ""); return file; } public static String defaultTLSVersion() { return System.getProperty("java.version", "NA").startsWith("1.6") ? "TLSv1" : "TLSv1.2"; } public static class StoreCredentials { public String name = null; public String path = null; public String pass = null; StoreCredentials(String name, String path, String pass) { this.name = name; this.path = path; this.pass = pass; } public String getLocation() { return null != path && !path.isEmpty() ? path + File.pathSeparator + name : name; } } public static class SSLCredentials { public StoreCredentials jks; public StoreCredentials jts; SSLCredentials(StoreCredentials jks, StoreCredentials jts) { this.jks = jks; this.jts = jts; } } }