001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2026, 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 v2.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 = true; 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 060 addInfo("hostnameVerification=" + hostnameVerification); 061 socket.setHostnameVerification(hostnameVerification); 062 } 063 064 public boolean getHostnameVerification() { 065 return hostnameVerification; 066 } 067 068 public void setHostnameVerification(boolean hostnameVerification) { 069 this.hostnameVerification = hostnameVerification; 070 } 071 072 /** 073 * Gets the set of enabled protocols based on the configuration. 074 * 075 * @param supportedProtocols protocols supported by the SSL engine 076 * @param defaultProtocols default protocols enabled by the SSL engine 077 * @return enabled protocols 078 */ 079 private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) { 080 if (enabledProtocols == null) { 081 // we're assuming that the same engine is used for all configurables 082 // so once we determine the enabled set, we won't do it again 083 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedProtocols()) 084 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedProtocols())) { 085 enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length); 086 } else { 087 enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols()); 088 } 089 for (String protocol : enabledProtocols) { 090 addInfo("enabled protocol: " + protocol); 091 } 092 } 093 return enabledProtocols; 094 } 095 096 /** 097 * Gets the set of enabled cipher suites based on the configuration. 098 * 099 * @param supportedCipherSuites cipher suites supported by the SSL engine 100 * @param defaultCipherSuites default cipher suites enabled by the SSL engine 101 * @return enabled cipher suites 102 */ 103 private String[] enabledCipherSuites(String[] supportedCipherSuites, String[] defaultCipherSuites) { 104 if (enabledCipherSuites == null) { 105 // we're assuming that the same engine is used for all configurables 106 // so once we determine the enabled set, we won't do it again 107 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedCipherSuites()) 108 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedCipherSuites())) { 109 enabledCipherSuites = Arrays.copyOf(defaultCipherSuites, defaultCipherSuites.length); 110 } else { 111 enabledCipherSuites = includedStrings(supportedCipherSuites, getIncludedCipherSuites(), 112 getExcludedCipherSuites()); 113 } 114 for (String cipherSuite : enabledCipherSuites) { 115 addInfo("enabled cipher suite: " + cipherSuite); 116 } 117 } 118 return enabledCipherSuites; 119 } 120 121 /** 122 * Applies include and exclude patterns to an array of default string values to 123 * produce an array of strings included by the patterns. 124 * 125 * @param defaults default list of string values 126 * @param included comma-separated patterns that identity values to include 127 * @param excluded comma-separated patterns that identity string to exclude 128 * @return an array of strings containing those strings from {@code defaults} 129 * that match at least one pattern in {@code included} that are not 130 * matched by any pattern in {@code excluded} 131 */ 132 private String[] includedStrings(String[] defaults, String included, String excluded) { 133 List<String> values = new ArrayList<String>(defaults.length); 134 values.addAll(Arrays.asList(defaults)); 135 if (included != null) { 136 StringCollectionUtil.retainMatching(values, stringToArray(included)); 137 } 138 if (excluded != null) { 139 StringCollectionUtil.removeMatching(values, stringToArray(excluded)); 140 } 141 return values.toArray(new String[values.size()]); 142 } 143 144 /** 145 * Splits a string containing comma-separated values into an array. 146 * 147 * @param s the subject string 148 * @return array of values contained in {@code s} 149 */ 150 private String[] stringToArray(String s) { 151 return s.split("\\s*,\\s*"); 152 } 153 154 /** 155 * Gets the JSSE secure transport protocols to include. 156 * 157 * @return a string containing comma-separated JSSE secure transport protocol 158 * names (e.g. {@code TLSv1}) 159 */ 160 public String getIncludedProtocols() { 161 return includedProtocols; 162 } 163 164 /** 165 * Sets the JSSE secure transport protocols to include. 166 * 167 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p> 168 * 169 * @param protocols a string containing comma-separated JSSE secure transport 170 * protocol names 171 */ 172 public void setIncludedProtocols(String protocols) { 173 this.includedProtocols = protocols; 174 } 175 176 /** 177 * Gets the JSSE secure transport protocols to exclude. 178 * 179 * @return a string containing comma-separated JSSE secure transport protocol 180 * names (e.g. {@code TLSv1}) 181 */ 182 public String getExcludedProtocols() { 183 return excludedProtocols; 184 } 185 186 /** 187 * Sets the JSSE secure transport protocols to exclude. 188 * 189 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p> 190 * 191 * @param protocols a string containing comma-separated JSSE secure transport 192 * protocol names 193 */ 194 public void setExcludedProtocols(String protocols) { 195 this.excludedProtocols = protocols; 196 } 197 198 /** 199 * Gets the JSSE cipher suite names to include. 200 * 201 * @return a string containing comma-separated JSSE cipher suite names (e.g. 202 * {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA}) 203 */ 204 public String getIncludedCipherSuites() { 205 return includedCipherSuites; 206 } 207 208 /** 209 * Sets the JSSE cipher suite names to include. 210 * 211 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p> 212 * 213 * @param cipherSuites a string containing comma-separated JSSE cipher suite 214 * names 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 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p> 234 * 235 * @param cipherSuites a string containing comma-separated JSSE cipher suite 236 * names 237 * 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}