1 /**
2 * Logback: the reliable, generic, fast and flexible logging framework.
3 * Copyright (C) 1999-2015, 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 v1.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;
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 if (hostnameVerification != null) {
60 addInfo("hostnameVerification=" + hostnameVerification);
61 socket.setHostnameVerification(hostnameVerification);
62 }
63 }
64
65 public boolean getHostnameVerification() {
66 if (hostnameVerification == null)
67 return false;
68 return hostnameVerification;
69 }
70
71 public void setHostnameVerification(boolean hostnameVerification) {
72 this.hostnameVerification = hostnameVerification;
73 }
74
75 /**
76 * Gets the set of enabled protocols based on the configuration.
77 *
78 * @param supportedProtocols protocols supported by the SSL engine
79 * @param defaultProtocols default protocols enabled by the SSL engine
80 * @return enabled protocols
81 */
82 private String[] enabledProtocols(String[] supportedProtocols, String[] defaultProtocols) {
83 if (enabledProtocols == null) {
84 // we're assuming that the same engine is used for all configurables
85 // so once we determine the enabled set, we won't do it again
86 if (OptionHelper.isNullOrEmptyOrAllSpaces(getIncludedProtocols())
87 && OptionHelper.isNullOrEmptyOrAllSpaces(getExcludedProtocols())) {
88 enabledProtocols = Arrays.copyOf(defaultProtocols, defaultProtocols.length);
89 } else {
90 enabledProtocols = includedStrings(supportedProtocols, getIncludedProtocols(), getExcludedProtocols());
91 }
92 for (String protocol : enabledProtocols) {
93 addInfo("enabled protocol: " + protocol);
94 }
95 }
96 return enabledProtocols;
97 }
98
99 /**
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 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p>
171 *
172 * @param protocols a string containing comma-separated JSSE secure transport
173 * protocol names
174 */
175 public void setIncludedProtocols(String protocols) {
176 this.includedProtocols = protocols;
177 }
178
179 /**
180 * Gets the JSSE secure transport protocols to exclude.
181 *
182 * @return a string containing comma-separated JSSE secure transport protocol
183 * names (e.g. {@code TLSv1})
184 */
185 public String getExcludedProtocols() {
186 return excludedProtocols;
187 }
188
189 /**
190 * Sets the JSSE secure transport protocols to exclude.
191 *
192 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p>
193 *
194 * @param protocols a string containing comma-separated JSSE secure transport
195 * protocol names
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 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p>
215 *
216 * @param cipherSuites a string containing comma-separated JSSE cipher suite
217 * names
218 */
219 public void setIncludedCipherSuites(String cipherSuites) {
220 this.includedCipherSuites = cipherSuites;
221 }
222
223 /**
224 * Gets the JSSE cipher suite names to exclude.
225 *
226 * @return a string containing comma-separated JSSE cipher suite names (e.g.
227 * {@code TLS_DHE_RSA_WITH_AES_256_CBC_SHA})
228 */
229 public String getExcludedCipherSuites() {
230 return excludedCipherSuites;
231 }
232
233 /**
234 * Sets the JSSE cipher suite names to exclude.
235 *
236 * <p>See Java Cryptography Architecture Standard Algorithm Name Documentation</p>
237 *
238 * @param cipherSuites a string containing comma-separated JSSE cipher suite
239 * names
240 *
241 */
242 public void setExcludedCipherSuites(String cipherSuites) {
243 this.excludedCipherSuites = cipherSuites;
244 }
245
246 /**
247 * Gets a flag indicating whether client authentication is required.
248 *
249 * @return flag state
250 */
251 public Boolean isNeedClientAuth() {
252 return needClientAuth;
253 }
254
255 /**
256 * Sets a flag indicating whether client authentication is required.
257 *
258 * @param needClientAuth the flag state to set
259 */
260 public void setNeedClientAuth(Boolean needClientAuth) {
261 this.needClientAuth = needClientAuth;
262 }
263
264 /**
265 * Gets a flag indicating whether client authentication is desired.
266 *
267 * @return flag state
268 */
269 public Boolean isWantClientAuth() {
270 return wantClientAuth;
271 }
272
273 /**
274 * Sets a flag indicating whether client authentication is desired.
275 *
276 * @param wantClientAuth the flag state to set
277 */
278 public void setWantClientAuth(Boolean wantClientAuth) {
279 this.wantClientAuth = wantClientAuth;
280 }
281
282 }