001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.net.ssl; 015 016import java.util.ArrayList; 017import java.util.Arrays; 018import java.util.List; 019 020import javax.net.ssl.SSLEngine; 021 022import org.codehaus.janino.Java; 023 024import ch.qos.logback.core.spi.ContextAwareBase; 025import ch.qos.logback.core.util.OptionHelper; 026import ch.qos.logback.core.util.StringCollectionUtil; 027 028/** 029 * A configuration of SSL parameters for an {@link SSLEngine}. 030 * 031 * @author Carl Harris 032 * @author Bruno Harbulot 033 */ 034public class SSLParametersConfiguration extends ContextAwareBase { 035 036 private String includedProtocols; 037 private String excludedProtocols; 038 private String includedCipherSuites; 039 private String excludedCipherSuites; 040 private Boolean needClientAuth; 041 private Boolean wantClientAuth; 042 private String[] enabledProtocols; 043 private String[] enabledCipherSuites; 044 private Boolean hostnameVerification; 045 046 /** 047 * Configures SSL parameters on an {@link SSLConfigurable}. 048 * 049 * @param socket the subject configurable 050 */ 051 public void configure(SSLConfigurable socket) { 052 socket.setEnabledProtocols(enabledProtocols(socket.getSupportedProtocols(), socket.getDefaultProtocols())); 053 socket.setEnabledCipherSuites( 054 enabledCipherSuites(socket.getSupportedCipherSuites(), socket.getDefaultCipherSuites())); 055 if (isNeedClientAuth() != null) { 056 socket.setNeedClientAuth(isNeedClientAuth()); 057 } 058 if (isWantClientAuth() != null) { 059 socket.setWantClientAuth(isWantClientAuth()); 060 } 061 if (hostnameVerification != null) { 062 addInfo("hostnameVerification=" + hostnameVerification); 063 socket.setHostnameVerification(hostnameVerification); 064 } 065 } 066 067 public boolean getHostnameVerification() { 068 if (hostnameVerification == null) 069 return false; 070 return hostnameVerification; 071 } 072 073 public void setHostnameVerification(boolean hostnameVerification) { 074 this.hostnameVerification = hostnameVerification; 075 } 076 077 /** 078 * Gets the set of enabled protocols based on the configuration. 079 * 080 * @param supportedProtocols protocols supported by the SSL engine 081 * @param defaultProtocols default protocols enabled by the SSL engine 082 * @return enabled protocols 083 */ 084 private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) { 085 if (enabledProtocols == null) { 086 // we're assuming that the same engine is used for all configurables 087 // so once we determine the enabled set, we won't do it again 088 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedProtocols()) 089 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedProtocols())) { 090 enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length); 091 } else { 092 enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols()); 093 } 094 for (String protocol : enabledProtocols) { 095 addInfo("enabled protocol: " + protocol); 096 } 097 } 098 return enabledProtocols; 099 } 100 101 /** 102 * Gets the set of enabled cipher suites based on the configuration. 103 * 104 * @param supportedCipherSuites cipher suites supported by the SSL engine 105 * @param defaultCipherSuites default cipher suites enabled by the SSL engine 106 * @return enabled cipher suites 107 */ 108 private String[] enabledCipherSuites(String[] supportedCipherSuites, String[] defaultCipherSuites) { 109 if (enabledCipherSuites == null) { 110 // we're assuming that the same engine is used for all configurables 111 // so once we determine the enabled set, we won't do it again 112 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedCipherSuites()) 113 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedCipherSuites())) { 114 enabledCipherSuites = Arrays.copyOf(defaultCipherSuites, defaultCipherSuites.length); 115 } else { 116 enabledCipherSuites = includedStrings(supportedCipherSuites, getIncludedCipherSuites(), 117 getExcludedCipherSuites()); 118 } 119 for (String cipherSuite : enabledCipherSuites) { 120 addInfo("enabled cipher suite: " + cipherSuite); 121 } 122 } 123 return enabledCipherSuites; 124 } 125 126 /** 127 * Applies include and exclude patterns to an array of default string values to 128 * produce an array of strings included by the patterns. 129 * 130 * @param defaults default list of string values 131 * @param included comma-separated patterns that identity values to include 132 * @param excluded comma-separated patterns that identity string to exclude 133 * @return an array of strings containing those strings from {@code defaults} 134 * that match at least one pattern in {@code included} that are not 135 * matched by any pattern in {@code excluded} 136 */ 137 private String[] includedStrings(String[] defaults, String included, String excluded) { 138 List<String> values = new ArrayList<String>(defaults.length); 139 values.addAll(Arrays.asList(defaults)); 140 if (included != null) { 141 StringCollectionUtil.retainMatching(values, stringToArray(included)); 142 } 143 if (excluded != null) { 144 StringCollectionUtil.removeMatching(values, stringToArray(excluded)); 145 } 146 return values.toArray(new String[values.size()]); 147 } 148 149 /** 150 * Splits a string containing comma-separated values into an array. 151 * 152 * @param s the subject string 153 * @return array of values contained in {@code s} 154 */ 155 private String[] stringToArray(String s) { 156 return s.split("\\s*,\\s*"); 157 } 158 159 /** 160 * Gets the JSSE secure transport protocols to include. 161 * 162 * @return a string containing comma-separated JSSE secure transport protocol 163 * names (e.g. {@code TLSv1}) 164 */ 165 public String getIncludedProtocols() { 166 return includedProtocols; 167 } 168 169 /** 170 * Sets the JSSE secure transport protocols to include. 171 * 172 * @param protocols a string containing comma-separated JSSE secure transport 173 * protocol names 174 * @see Java Cryptography Architecture Standard Algorithm Name Documentation 175 */ 176 public void setIncludedProtocols(String protocols) { 177 this.includedProtocols = protocols; 178 } 179 180 /** 181 * Gets the JSSE secure transport protocols to exclude. 182 * 183 * @return a string containing comma-separated JSSE secure transport protocol 184 * names (e.g. {@code TLSv1}) 185 */ 186 public String getExcludedProtocols() { 187 return excludedProtocols; 188 } 189 190 /** 191 * Sets the JSSE secure transport protocols to exclude. 192 * 193 * @param protocols a string containing comma-separated JSSE secure transport 194 * protocol names 195 * @see Java Cryptography Architecture Standard Algorithm Name Documentation 196 */ 197 public void setExcludedProtocols(String protocols) { 198 this.excludedProtocols = protocols; 199 } 200 201 /** 202 * Gets the JSSE cipher suite names to include. 203 * 204 * @return a string containing comma-separated JSSE cipher suite names (e.g. 205 * {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA}) 206 */ 207 public String getIncludedCipherSuites() { 208 return includedCipherSuites; 209 } 210 211 /** 212 * Sets the JSSE cipher suite names to include. 213 * 214 * @param cipherSuites a string containing comma-separated JSSE cipher suite 215 * names 216 * @see Java Cryptography Architecture Standard Algorithm Name Documentation 217 */ 218 public void setIncludedCipherSuites(String cipherSuites) { 219 this.includedCipherSuites = cipherSuites; 220 } 221 222 /** 223 * Gets the JSSE cipher suite names to exclude. 224 * 225 * @return a string containing comma-separated JSSE cipher suite names (e.g. 226 * {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA}) 227 */ 228 public String getExcludedCipherSuites() { 229 return excludedCipherSuites; 230 } 231 232 /** 233 * Sets the JSSE cipher suite names to exclude. 234 * 235 * @param cipherSuites a string containing comma-separated JSSE cipher suite 236 * names 237 * @see Java Cryptography Architecture Standard Algorithm Name Documentation 238 */ 239 public void setExcludedCipherSuites(String cipherSuites) { 240 this.excludedCipherSuites = cipherSuites; 241 } 242 243 /** 244 * Gets a flag indicating whether client authentication is required. 245 * 246 * @return flag state 247 */ 248 public Boolean isNeedClientAuth() { 249 return needClientAuth; 250 } 251 252 /** 253 * Sets a flag indicating whether client authentication is required. 254 * 255 * @param needClientAuth the flag state to set 256 */ 257 public void setNeedClientAuth(Boolean needClientAuth) { 258 this.needClientAuth = needClientAuth; 259 } 260 261 /** 262 * Gets a flag indicating whether client authentication is desired. 263 * 264 * @return flag state 265 */ 266 public Boolean isWantClientAuth() { 267 return wantClientAuth; 268 } 269 270 /** 271 * Sets a flag indicating whether client authentication is desired. 272 * 273 * @param wantClientAuth the flag state to set 274 */ 275 public void setWantClientAuth(Boolean wantClientAuth) { 276 this.wantClientAuth = wantClientAuth; 277 } 278 279}