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 * @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 }