1 /*
2 * Logback: the reliable, generic, fast and flexible logging framework.
3 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4 *
5 * This program and the accompanying materials are dual-licensed under
6 * either the terms of the Eclipse Public License v2.0 as published by
7 * the Eclipse Foundation
8 *
9 * or (per the licensee's choosing)
10 *
11 * under the terms of the GNU Lesser General Public License version 2.1
12 * as published by the Free Software Foundation.
13 */
14 package ch.qos.logback.core.net.ssl;
15
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19
20 import javax.net.ssl.SSLEngine;
21
22 import ch.qos.logback.core.spi.ContextAwareBase;
23 import ch.qos.logback.core.util.OptionHelper;
24 import ch.qos.logback.core.util.StringCollectionUtil;
25
26 /**
27 * A configuration of SSL parameters for an {@link SSLEngine}.
28 *
29 * @author Carl Harris
30 * @author Bruno Harbulot
31 */
32 public class SSLParametersConfiguration extends ContextAwareBase {
33
34 private String includedProtocols;
35 private String excludedProtocols;
36 private String includedCipherSuites;
37 private String excludedCipherSuites;
38 private Boolean needClientAuth;
39 private Boolean wantClientAuth;
40 private String[] enabledProtocols;
41 private String[] enabledCipherSuites;
42 private boolean hostnameVerification = true;
43
44 /**
45 * Configures SSL parameters on an {@link SSLConfigurable}.
46 *
47 * @param socket the subject configurable
48 */
49 public void configure(SSLConfigurable socket) {
50 socket.setEnabledProtocols(enabledProtocols(socket.getSupportedProtocols(), socket.getDefaultProtocols()));
51 socket.setEnabledCipherSuites(
52 enabledCipherSuites(socket.getSupportedCipherSuites(), socket.getDefaultCipherSuites()));
53 if (isNeedClientAuth() != null) {
54 socket.setNeedClientAuth(isNeedClientAuth());
55 }
56 if (isWantClientAuth() != null) {
57 socket.setWantClientAuth(isWantClientAuth());
58 }
59
60 addInfo("hostnameVerification=" + hostnameVerification);
61 socket.setHostnameVerification(hostnameVerification);
62 }
63
64 public boolean getHostnameVerification() {
65 return hostnameVerification;
66 }
67
68 public void setHostnameVerification(boolean hostnameVerification) {
69 this.hostnameVerification = hostnameVerification;
70 }
71
72 /**
73 * Gets the set of enabled protocols based on the configuration.
74 *
75 * @param supportedProtocols protocols supported by the SSL engine
76 * @param defaultProtocols default protocols enabled by the SSL engine
77 * @return enabled protocols
78 */
79 private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) {
80 if (enabledProtocols == null) {
81 // we're assuming that the same engine is used for all configurables
82 // so once we determine the enabled set, we won't do it again
83 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedProtocols())
84 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedProtocols())) {
85 enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length);
86 } else {
87 enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols());
88 }
89 for (String protocol : enabledProtocols) {
90 addInfo("enabled protocol: " + protocol);
91 }
92 }
93 return enabledProtocols;
94 }
95
96 /**
97 * Gets the set of enabled cipher suites based on the configuration.
98 *
99 * @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 }