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