001/* 002Copyright 2015 Hendrik Saly 003 004Licensed under the Apache License, Version 2.0 (the "License"); 005you may not use this file except in compliance with the License. 006You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010Unless required by applicable law or agreed to in writing, software 011distributed under the License is distributed on an "AS IS" BASIS, 012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013See the License for the specific language governing permissions and 014limitations under the License. 015 */ 016 017package de.saly.es.example.tssl.util; 018 019import java.io.File; 020import java.io.UnsupportedEncodingException; 021import java.net.URL; 022import java.net.URLDecoder; 023import java.security.NoSuchAlgorithmException; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.List; 027 028import javax.crypto.Cipher; 029import javax.net.ssl.SSLContext; 030import javax.net.ssl.SSLEngine; 031 032import org.elasticsearch.common.logging.ESLogger; 033import org.elasticsearch.common.logging.Loggers; 034 035public class SecurityUtil { 036 037 private static final ESLogger log = Loggers.getLogger(SecurityUtil.class); 038 private static final String[] PREFERRED_SSL_CIPHERS = { "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", 039 "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 040 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 041 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 042 "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" }; 043 private static final String[] PREFERRED_SSL_PROTOCOLS = { "TLSv1", "TLSv1.1", "TLSv1.2" }; 044 045 public static String[] ENABLED_SSL_PROTOCOLS = null; 046 public static String[] ENABLED_SSL_CIPHERS = null; 047 public static boolean UNLIMITED_STRENGTH_SUPPORTED; 048 049 private SecurityUtil() { 050 051 } 052 053 static { 054 try { 055 final int aesMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES"); 056 057 if (aesMaxKeyLength < 256) { 058 log.warn("AES 256 not supported, max key length for AES is " + aesMaxKeyLength 059 + ". To enable AES 256 install 'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files'"); 060 } else { 061 UNLIMITED_STRENGTH_SUPPORTED = true; 062 } 063 } catch (final NoSuchAlgorithmException e) { 064 log.error("AES encryption not supported. " + e); 065 066 } 067 068 try { 069 070 final SSLContext serverContext = SSLContext.getInstance("TLS"); 071 serverContext.init(null, null, null); 072 final SSLEngine engine = serverContext.createSSLEngine(); 073 final List<String> supportedCipherSuites = new ArrayList<String>(Arrays.asList(engine.getSupportedCipherSuites())); 074 final List<String> supportedProtocols = new ArrayList<String>(Arrays.asList(engine.getSupportedProtocols())); 075 076 final List<String> preferredCipherSuites = Arrays.asList(PREFERRED_SSL_CIPHERS); 077 final List<String> preferredProtocols = Arrays.asList(PREFERRED_SSL_PROTOCOLS); 078 079 supportedCipherSuites.retainAll(preferredCipherSuites); 080 supportedProtocols.retainAll(preferredProtocols); 081 082 if (supportedCipherSuites.isEmpty()) { 083 log.error("No usable SSL/TLS cipher suites found"); 084 } else { 085 ENABLED_SSL_CIPHERS = supportedCipherSuites.toArray(new String[supportedCipherSuites.size()]); 086 } 087 088 if (supportedProtocols.isEmpty()) { 089 log.error("No usable SSL/TLS protocols found"); 090 } else { 091 ENABLED_SSL_PROTOCOLS = supportedProtocols.toArray(new String[supportedProtocols.size()]); 092 } 093 094 log.debug("Usable SSL/TLS protocols: {}", supportedProtocols); 095 log.debug("Usable SSL/TLS cipher suites: {}", supportedCipherSuites); 096 097 } catch (final Exception e) { 098 log.error("Error while evaluating supported crypto", e); 099 } 100 } 101 102 public static File getAbsoluteFilePathFromClassPath(final String fileNameFromClasspath) { 103 104 File jaasConfigFile = null; 105 final URL jaasConfigURL = SecurityUtil.class.getClassLoader().getResource(fileNameFromClasspath); 106 if (jaasConfigURL != null) { 107 try { 108 jaasConfigFile = new File(URLDecoder.decode(jaasConfigURL.getFile(), "UTF-8")); 109 } catch (final UnsupportedEncodingException e) { 110 return null; 111 } 112 113 if (jaasConfigFile.exists() && jaasConfigFile.canRead()) { 114 return jaasConfigFile; 115 } else { 116 log.error("Cannot read from {}, maybe the file does not exists? ", jaasConfigFile.getAbsolutePath()); 117 } 118 119 } else { 120 log.error("Failed to load " + fileNameFromClasspath); 121 } 122 123 return null; 124 125 } 126 127 public static boolean setSystemPropertyToAbsoluteFilePathFromClassPath(final String property, final String fileNameFromClasspath) { 128 if (System.getProperty(property) == null) { 129 File jaasConfigFile = null; 130 final URL jaasConfigURL = SecurityUtil.class.getClassLoader().getResource(fileNameFromClasspath); 131 if (jaasConfigURL != null) { 132 try { 133 jaasConfigFile = new File(URLDecoder.decode(jaasConfigURL.getFile(), "UTF-8")); 134 } catch (final UnsupportedEncodingException e) { 135 return false; 136 } 137 138 if (jaasConfigFile.exists() && jaasConfigFile.canRead()) { 139 System.setProperty(property, jaasConfigFile.getAbsolutePath()); 140 141 log.debug("Load " + fileNameFromClasspath + " from {} ", jaasConfigFile.getAbsolutePath()); 142 return true; 143 } else { 144 log.error("Cannot read from {}, maybe the file does not exists? ", jaasConfigFile.getAbsolutePath()); 145 } 146 147 } else { 148 log.error("Failed to load " + fileNameFromClasspath); 149 } 150 } else { 151 log.warn("Property " + property + " already set to " + System.getProperty(property)); 152 } 153 154 return false; 155 } 156 157 public static boolean setSystemPropertyToAbsoluteFile(final String property, final String fileName) { 158 if (System.getProperty(property) == null) { 159 160 if (fileName == null) { 161 log.error("Cannot set property " + property + " because filename is null"); 162 163 return false; 164 } 165 166 final File jaasConfigFile = new File(fileName).getAbsoluteFile(); 167 168 if (jaasConfigFile.exists() && jaasConfigFile.canRead()) { 169 System.setProperty(property, jaasConfigFile.getAbsolutePath()); 170 171 log.debug("Load " + fileName + " from {} ", jaasConfigFile.getAbsolutePath()); 172 return true; 173 } else { 174 log.error("Cannot read from {}, maybe the file does not exists? ", jaasConfigFile.getAbsolutePath()); 175 } 176 177 } else { 178 log.warn("Property " + property + " already set to " + System.getProperty(property)); 179 } 180 181 return false; 182 } 183}