001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.util.jsse;
018
019 import java.io.IOException;
020 import java.net.InetAddress;
021 import java.net.ServerSocket;
022 import java.net.Socket;
023 import java.net.UnknownHostException;
024 import java.security.GeneralSecurityException;
025 import java.security.KeyManagementException;
026 import java.security.SecureRandom;
027 import java.util.ArrayList;
028 import java.util.Arrays;
029 import java.util.Collection;
030 import java.util.Collections;
031 import java.util.LinkedList;
032 import java.util.List;
033 import java.util.regex.Matcher;
034 import java.util.regex.Pattern;
035
036 import javax.net.ssl.KeyManager;
037 import javax.net.ssl.SSLContext;
038 import javax.net.ssl.SSLContextSpi;
039 import javax.net.ssl.SSLEngine;
040 import javax.net.ssl.SSLServerSocket;
041 import javax.net.ssl.SSLServerSocketFactory;
042 import javax.net.ssl.SSLSessionContext;
043 import javax.net.ssl.SSLSocket;
044 import javax.net.ssl.SSLSocketFactory;
045 import javax.net.ssl.TrustManager;
046
047 import org.apache.camel.util.jsse.FilterParameters.Patterns;
048
049 import org.slf4j.Logger;
050 import org.slf4j.LoggerFactory;
051
052 import static org.apache.camel.util.CollectionHelper.collectionAsCommaDelimitedString;
053
054 /**
055 * Represents configuration options that can be applied in the client-side
056 * or server-side context depending on what they are applied to.
057 */
058 public abstract class BaseSSLContextParameters extends JsseParameters {
059
060 protected static final List<String> DEFAULT_CIPHER_SUITES_FILTER_INCLUDE =
061 Collections.unmodifiableList(Arrays.asList(".*"));
062
063 protected static final List<String> DEFAULT_CIPHER_SUITES_FILTER_EXCLUDE =
064 Collections.unmodifiableList(Arrays.asList(".*_NULL_.*", ".*_anon_.*"));
065
066 protected static final List<String> DEFAULT_SECURE_SOCKET_PROTOCOLS_FILTER_INCLUDE =
067 Collections.unmodifiableList(Arrays.asList(".*"));
068
069 private static final Logger LOG = LoggerFactory.getLogger(BaseSSLContextParameters.class);
070
071 private static final String LS = System.getProperty("line.separator");
072
073 private static final String SSL_ENGINE_CIPHER_SUITE_LOG_MSG = createCipherSuiteLogMessage("SSLEngine");
074
075 private static final String SSL_SOCKET_CIPHER_SUITE_LOG_MSG = createCipherSuiteLogMessage("SSLSocket");
076
077 private static final String SSL_SERVER_SOCKET_CIPHER_SUITE_LOG_MSG = createCipherSuiteLogMessage("SSLServerSocket");
078
079 private static final String SSL_ENGINE_PROTOCOL_LOG_MSG = createProtocolLogMessage("SSLEngine");
080
081 private static final String SSL_SOCKET_PROTOCOL_LOG_MSG = createProtocolLogMessage("SSLSocket");
082
083 private static final String SSL_SERVER_SOCKET_PROTOCOL_LOG_MSG = createProtocolLogMessage("SSLServerSocket");
084
085 /**
086 * The optional explicitly configured cipher suites for this configuration.
087 */
088 private CipherSuitesParameters cipherSuites;
089
090 /**
091 * The optional cipher suite filter configuration for this configuration.
092 */
093 private FilterParameters cipherSuitesFilter;
094
095 /**
096 * The optional explicitly configured secure socket protocol names for this configuration.
097 */
098 private SecureSocketProtocolsParameters secureSocketProtocols;
099
100 /**
101 * The option secure socket protocol name filter configuration for this configuration.
102 */
103 private FilterParameters secureSocketProtocolsFilter;
104
105 /**
106 * The optional {@link SSLSessionContext} timeout time for {@link javax.net.ssl.SSLSession}s in seconds.
107 */
108 private String sessionTimeout;
109
110
111 /**
112 * Returns the optional explicitly configured cipher suites for this configuration.
113 * These options are used in the configuration of {@link SSLEngine},
114 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
115 * on the context in which they are applied.
116 * <p/>
117 * These values override any filters supplied in {@link #setCipherSuitesFilter(FilterParameters)}
118 */
119 public CipherSuitesParameters getCipherSuites() {
120 return cipherSuites;
121 }
122
123 /**
124 * Sets the optional explicitly configured cipher suites for this configuration.
125 * These options are used in the configuration of {@link SSLEngine},
126 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
127 * on the context in which they are applied.
128 * <p/>
129 * These values override any filters supplied in {@link #setCipherSuitesFilter(FilterParameters)}
130 *
131 * @param cipherSuites the suite configuration
132 */
133 public void setCipherSuites(CipherSuitesParameters cipherSuites) {
134 this.cipherSuites = cipherSuites;
135 }
136
137 /**
138 * Returns the optional cipher suite filter for this configuration.
139 * These options are used in the configuration of {@link SSLEngine},
140 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
141 * on the context in which they are applied.
142 * <p/>
143 * These values are ignored if {@link #setCipherSuites(CipherSuitesParameters)} is
144 * called with a non {@code null} argument.
145 */
146 public FilterParameters getCipherSuitesFilter() {
147 return cipherSuitesFilter;
148 }
149
150 /**
151 * Sets the optional cipher suite filter for this JSSE configuration.
152 * These options are used in the configuration of {@link SSLEngine},
153 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
154 * on the context in which they are applied.
155 * <p/>
156 * These values are ignored if {@link #setCipherSuites(CipherSuitesParameters)} is
157 * called with a non {@code null} argument.
158 *
159 * @param cipherSuitesFilter the filter configuration
160 */
161 public void setCipherSuitesFilter(FilterParameters cipherSuitesFilter) {
162 this.cipherSuitesFilter = cipherSuitesFilter;
163 }
164
165 /**
166 * Returns the explicitly configured secure socket protocol names for this configuration.
167 * These options are used in the configuration of {@link SSLEngine},
168 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
169 * on the context in which they are applied.
170 * <p/>
171 * These values override any filters supplied in {@link #setSecureSocketProtocolsFilter(FilterParameters)}
172 */
173 public SecureSocketProtocolsParameters getSecureSocketProtocols() {
174 return secureSocketProtocols;
175 }
176
177 /**
178 * Sets the explicitly configured secure socket protocol names for this configuration.
179 * These options are used in the configuration of {@link SSLEngine},
180 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
181 * on the context in which they are applied.
182 * <p/>
183 * These values override any filters supplied in {@link #setSecureSocketProtocolsFilter(FilterParameters)}
184 */
185 public void setSecureSocketProtocols(SecureSocketProtocolsParameters secureSocketProtocols) {
186 this.secureSocketProtocols = secureSocketProtocols;
187 }
188
189 /**
190 * Returns the optional secure socket protocol filter for this configuration.
191 * These options are used in the configuration of {@link SSLEngine},
192 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
193 * on the context in which they are applied.
194 * <p/>
195 * These values are ignored if {@link #setSecureSocketProtocols(SecureSocketProtocolsParameters)} is
196 * called with a non-{@code null} argument.
197 */
198 public FilterParameters getSecureSocketProtocolsFilter() {
199 return secureSocketProtocolsFilter;
200 }
201
202 /**
203 * Sets the optional secure socket protocol filter for this JSSE configuration.
204 * These options are used in the configuration of {@link SSLEngine},
205 * {@link SSLSocketFactory} and {@link SSLServerSocketFactory} depending
206 * on the context in which they are applied.
207 * <p/>
208 * These values are ignored if {@link #setSecureSocketProtocols(SecureSocketProtocolsParameters)} is
209 * called with a non-{@code null} argument.
210 *
211 * @param secureSocketProtocolsFilter the filter configuration
212 */
213 public void setSecureSocketProtocolsFilter(FilterParameters secureSocketProtocolsFilter) {
214 this.secureSocketProtocolsFilter = secureSocketProtocolsFilter;
215 }
216
217 /**
218 * Returns the optional {@link SSLSessionContext} timeout time for {@link javax.net.ssl.SSLSession}s
219 * in seconds.
220 */
221 public String getSessionTimeout() {
222 return sessionTimeout;
223 }
224
225 /**
226 * Sets the optional {@link SSLSessionContext} timeout time for {@link javax.net.ssl.SSLSession}s
227 * in seconds.
228 *
229 * @param sessionTimeout the timeout value or {@code null} to use the default
230 */
231 public void setSessionTimeout(String sessionTimeout) {
232 this.sessionTimeout = sessionTimeout;
233 }
234
235 /**
236 * Returns a flag indicating if default values should be applied in the event that no other property
237 * of the instance configures a particular aspect of the entity produced by the instance.
238 * This flag is used to allow instances of this class to produce a configurer that simply
239 * passes through the current configuration of a configured entity when the instance of this
240 * class would otherwise only apply some default configuration.
241 *
242 * @see SSLContextClientParameters
243 * @see SSLContextServerParameters
244 */
245 protected boolean getAllowPassthrough() {
246 return false;
247 }
248
249 /**
250 * Configures the actual {@link SSLContext} itself with direct setter calls. This method differs from
251 * configuration options that are handled by a configurer instance in that the options are part of the
252 * context itself and are not part of some factory or instance object returned by the context.
253 *
254 * @param context the context to configure
255 *
256 * @throws GeneralSecurityException if there is an error configuring the context
257 */
258 protected void configureSSLContext(SSLContext context) throws GeneralSecurityException {
259 LOG.trace("Configuring client and server side SSLContext parameters on SSLContext [{}]...", context);
260
261 if (this.getSessionTimeout() != null) {
262 LOG.debug("Configuring client and server side SSLContext session timeout on SSLContext [{}] to [{}]",
263 context, this.getSessionTimeout());
264 this.configureSessionContext(context.getClientSessionContext(), this.getSessionTimeout());
265 this.configureSessionContext(context.getServerSessionContext(), this.getSessionTimeout());
266 }
267
268 LOG.trace("Configured client and server side SSLContext parameters on SSLContext [{}].", context);
269 }
270
271 protected FilterParameters getDefaultCipherSuitesFilter() {
272 FilterParameters filter = new FilterParameters();
273
274 filter.getInclude().addAll(DEFAULT_CIPHER_SUITES_FILTER_INCLUDE);
275 filter.getExclude().addAll(DEFAULT_CIPHER_SUITES_FILTER_EXCLUDE);
276
277 return filter;
278 }
279
280 protected FilterParameters getDefaultSecureSocketProcotolFilter() {
281 FilterParameters filter = new FilterParameters();
282
283 filter.getInclude().addAll(DEFAULT_SECURE_SOCKET_PROTOCOLS_FILTER_INCLUDE);
284
285 return filter;
286 }
287
288 /**
289 * Returns the list of configurers to apply to an {@link SSLEngine} in order
290 * to fully configure it in compliance with the provided configuration options.
291 * The configurers are to be applied in the order in which they appear in the list.
292 *
293 * @param context the context that serves as the factory for {@code SSLEngine} instances
294 *
295 * @return the needed configurers
296 */
297 protected List<Configurer<SSLEngine>> getSSLEngineConfigurers(SSLContext context) {
298
299 final List<String> enabledCipherSuites = this.getCipherSuites() == null
300 ? null : this.parsePropertyValues(this.getCipherSuites().getCipherSuite());
301
302 final Patterns enabledCipherSuitePatterns;
303 final Patterns defaultEnabledCipherSuitePatterns = this.getDefaultCipherSuitesFilter().getPatterns();
304
305 if (this.getCipherSuitesFilter() != null) {
306 enabledCipherSuitePatterns = this.getCipherSuitesFilter().getPatterns();
307 } else {
308 enabledCipherSuitePatterns = null;
309 }
310
311 ///
312
313 final List<String> enabledSecureSocketProtocols = this.getSecureSocketProtocols() == null
314 ? null : this.parsePropertyValues(this.getSecureSocketProtocols().getSecureSocketProtocol());
315
316 final Patterns enabledSecureSocketProtocolsPatterns;
317 final Patterns defaultEnabledSecureSocketProtocolsPatterns =
318 this.getDefaultSecureSocketProcotolFilter().getPatterns();
319
320 if (this.getSecureSocketProtocolsFilter() != null) {
321 enabledSecureSocketProtocolsPatterns = this.getSecureSocketProtocolsFilter().getPatterns();
322 } else {
323 enabledSecureSocketProtocolsPatterns = null;
324 }
325
326 //
327
328 final boolean allowPassthrough = getAllowPassthrough();
329
330 //////
331
332 Configurer<SSLEngine> sslEngineConfigurer = new Configurer<SSLEngine>() {
333
334 @Override
335 public SSLEngine configure(SSLEngine engine) {
336
337 Collection<String> filteredCipherSuites = BaseSSLContextParameters.this
338 .filter(enabledCipherSuites, Arrays.asList(engine.getSSLParameters().getCipherSuites()),
339 Arrays.asList(engine.getEnabledCipherSuites()),
340 enabledCipherSuitePatterns, defaultEnabledCipherSuitePatterns,
341 !allowPassthrough);
342
343 if (LOG.isDebugEnabled()) {
344 LOG.debug(SSL_ENGINE_CIPHER_SUITE_LOG_MSG,
345 new Object[] {engine,
346 enabledCipherSuites,
347 enabledCipherSuitePatterns,
348 engine.getSSLParameters().getCipherSuites(),
349 engine.getEnabledCipherSuites(),
350 defaultEnabledCipherSuitePatterns,
351 filteredCipherSuites});
352 }
353
354 engine.setEnabledCipherSuites(filteredCipherSuites.toArray(new String[filteredCipherSuites.size()]));
355
356 Collection<String> filteredSecureSocketProtocols = BaseSSLContextParameters.this
357 .filter(enabledSecureSocketProtocols, Arrays.asList(engine.getSSLParameters().getProtocols()),
358 Arrays.asList(engine.getEnabledProtocols()),
359 enabledSecureSocketProtocolsPatterns, defaultEnabledSecureSocketProtocolsPatterns,
360 !allowPassthrough);
361
362 if (LOG.isDebugEnabled()) {
363 LOG.debug(SSL_ENGINE_PROTOCOL_LOG_MSG,
364 new Object[] {engine,
365 enabledSecureSocketProtocols,
366 enabledSecureSocketProtocolsPatterns,
367 engine.getSSLParameters().getProtocols(),
368 engine.getEnabledProtocols(),
369 defaultEnabledSecureSocketProtocolsPatterns,
370 filteredSecureSocketProtocols});
371 }
372
373 engine.setEnabledProtocols(filteredSecureSocketProtocols.toArray(new String[filteredSecureSocketProtocols.size()]));
374
375 return engine;
376 }
377 };
378
379 List<Configurer<SSLEngine>> sslEngineConfigurers = new LinkedList<Configurer<SSLEngine>>();
380 sslEngineConfigurers.add(sslEngineConfigurer);
381
382 return sslEngineConfigurers;
383 }
384
385 /**
386 * Returns the list of configurers to apply to an {@link SSLSocketFactory} in order
387 * to fully configure it in compliance with the provided configuration options.
388 * The configurers are to be applied in the order in which they appear in the list.
389 * <p/>
390 * It is preferred to use {@link #getSSLSocketFactorySSLSocketConfigurers(SSLContext)} instead
391 * of this method as {@code SSLSocketFactory} does not contain any configuration options that
392 * are non-proprietary.
393 *
394 * @param context the context that serves as the factory for {@code SSLSocketFactory} instances
395 *
396 * @return the needed configurers
397 *
398 * @see #getSSLSocketFactorySSLSocketConfigurers(SSLContext)
399 */
400 protected List<Configurer<SSLSocketFactory>> getSSLSocketFactoryConfigurers(SSLContext context) {
401
402 final List<Configurer<SSLSocket>> sslSocketConfigurers =
403 this.getSSLSocketFactorySSLSocketConfigurers(context);
404
405 Configurer<SSLSocketFactory> sslSocketFactoryConfigurer = new Configurer<SSLSocketFactory>() {
406
407 @Override
408 public SSLSocketFactory configure(SSLSocketFactory factory) {
409 return new SSLSocketFactoryDecorator(
410 factory,
411 sslSocketConfigurers);
412 }
413 };
414
415
416 List<Configurer<SSLSocketFactory>> sslSocketFactoryConfigurers =
417 new LinkedList<Configurer<SSLSocketFactory>>();
418 sslSocketFactoryConfigurers.add(sslSocketFactoryConfigurer);
419
420 return sslSocketFactoryConfigurers;
421 }
422
423 /**
424 * Returns the list of configurers to apply to an {@link SSLServerSocketFactory} in order
425 * to fully configure it in compliance with the provided configuration options.
426 * The configurers are to be applied in the order in which they appear in the list.
427 * <p/>
428 * It is preferred to use {@link #getSSLServerSocketFactorySSLServerSocketConfigurers(SSLContext)} instead
429 * of this method as {@code SSLServerSocketFactory} does not contain any configuration options that
430 * are non-proprietary.
431 *
432 * @param context the context that serves as the factory for {@code SSLServerSocketFactory} instances
433 *
434 * @return the needed configurers
435 *
436 * @see #getSSLServerSocketFactorySSLServerSocketConfigurers(SSLContext)
437 */
438 protected List<Configurer<SSLServerSocketFactory>> getSSLServerSocketFactoryConfigurers(SSLContext context) {
439
440 final List<Configurer<SSLServerSocket>> sslServerSocketConfigurers =
441 this.getSSLServerSocketFactorySSLServerSocketConfigurers(context);
442
443 Configurer<SSLServerSocketFactory> sslServerSocketFactoryConfigurer = new Configurer<SSLServerSocketFactory>() {
444
445 @Override
446 public SSLServerSocketFactory configure(SSLServerSocketFactory factory) {
447 return new SSLServerSocketFactoryDecorator(
448 factory,
449 sslServerSocketConfigurers);
450 }
451 };
452
453
454 List<Configurer<SSLServerSocketFactory>> sslServerSocketFactoryConfigurers =
455 new LinkedList<Configurer<SSLServerSocketFactory>>();
456 sslServerSocketFactoryConfigurers.add(sslServerSocketFactoryConfigurer);
457
458 return sslServerSocketFactoryConfigurers;
459 }
460
461 /**
462 * Returns the list of configurers to apply to an {@link SSLSocket} in order
463 * to fully configure it in compliance with the provided configuration
464 * options. These configurers are intended for sockets produced by a
465 * {@link SSLSocketFactory}, see
466 * {@link #getSSLServerSocketFactorySSLServerSocketConfigurers(SSLContext)} for
467 * configurers related to sockets produced by a
468 * {@link SSLServerSocketFactory}. The configurers are to be applied in
469 * the order in which they appear in the list.
470 *
471 * @param context the context that serves as the factory for
472 * {@code SSLSocketFactory} instances
473 *
474 * @return the needed configurers
475 */
476 protected List<Configurer<SSLSocket>> getSSLSocketFactorySSLSocketConfigurers(SSLContext context) {
477 final List<String> enabledCipherSuites = this.getCipherSuites() == null
478 ? null : this.parsePropertyValues(this.getCipherSuites().getCipherSuite());
479
480 final Patterns enabledCipherSuitePatterns;
481 final Patterns defaultEnabledCipherSuitePatterns = this.getDefaultCipherSuitesFilter().getPatterns();
482
483 if (this.getCipherSuitesFilter() != null) {
484 enabledCipherSuitePatterns = this.getCipherSuitesFilter().getPatterns();
485 } else {
486 enabledCipherSuitePatterns = null;
487 }
488
489 ///
490
491 final List<String> enabledSecureSocketProtocols = this.getSecureSocketProtocols() == null
492 ? null : this.parsePropertyValues(this.getSecureSocketProtocols().getSecureSocketProtocol());
493
494 final Patterns enabledSecureSocketProtocolsPatterns;
495 final Patterns defaultEnabledSecureSocketProtocolsPatterns =
496 this.getDefaultSecureSocketProcotolFilter().getPatterns();
497
498 if (this.getSecureSocketProtocolsFilter() != null) {
499 enabledSecureSocketProtocolsPatterns = this.getSecureSocketProtocolsFilter().getPatterns();
500 } else {
501 enabledSecureSocketProtocolsPatterns = null;
502 }
503
504 //
505
506 final boolean allowPassthrough = getAllowPassthrough();
507
508 //////
509
510 Configurer<SSLSocket> sslSocketConfigurer = new Configurer<SSLSocket>() {
511
512 @Override
513 public SSLSocket configure(SSLSocket socket) {
514
515 Collection<String> filteredCipherSuites = BaseSSLContextParameters.this
516 .filter(enabledCipherSuites, Arrays.asList(socket.getSSLParameters().getCipherSuites()),
517 Arrays.asList(socket.getEnabledCipherSuites()),
518 enabledCipherSuitePatterns, defaultEnabledCipherSuitePatterns,
519 !allowPassthrough);
520 if (LOG.isDebugEnabled()) {
521 LOG.debug(SSL_SOCKET_CIPHER_SUITE_LOG_MSG,
522 new Object[] {socket,
523 enabledCipherSuites,
524 enabledCipherSuitePatterns,
525 socket.getSSLParameters().getCipherSuites(),
526 socket.getEnabledCipherSuites(),
527 defaultEnabledCipherSuitePatterns,
528 filteredCipherSuites});
529 }
530
531 socket.setEnabledCipherSuites(filteredCipherSuites.toArray(new String[filteredCipherSuites.size()]));
532
533 Collection<String> filteredSecureSocketProtocols = BaseSSLContextParameters.this
534 .filter(enabledSecureSocketProtocols, Arrays.asList(socket.getSSLParameters().getProtocols()),
535 Arrays.asList(socket.getEnabledProtocols()),
536 enabledSecureSocketProtocolsPatterns, defaultEnabledSecureSocketProtocolsPatterns,
537 !allowPassthrough);
538
539 if (LOG.isDebugEnabled()) {
540 LOG.debug(SSL_SOCKET_PROTOCOL_LOG_MSG,
541 new Object[] {socket,
542 enabledSecureSocketProtocols,
543 enabledSecureSocketProtocolsPatterns,
544 socket.getSSLParameters().getProtocols(),
545 socket.getEnabledProtocols(),
546 defaultEnabledSecureSocketProtocolsPatterns,
547 filteredSecureSocketProtocols});
548 }
549
550 socket.setEnabledProtocols(filteredSecureSocketProtocols.toArray(new String[filteredSecureSocketProtocols.size()]));
551 return socket;
552 }
553 };
554
555 List<Configurer<SSLSocket>> sslSocketConfigurers = new LinkedList<Configurer<SSLSocket>>();
556 sslSocketConfigurers.add(sslSocketConfigurer);
557
558 return sslSocketConfigurers;
559 }
560
561 /**
562 * Returns the list of configurers to apply to an {@link SSLServerSocket} in order
563 * to fully configure it in compliance with the provided configuration
564 * options. These configurers are intended for sockets produced by a
565 * {@link SSLServerSocketFactory}, see
566 * {@link #getSSLSocketFactorySSLSocketConfigurers(SSLContext)} for
567 * configurers related to sockets produced by a
568 * {@link SSLSocketFactory}. The configurers are to be applied in
569 * the order in which they appear in the list.
570 *
571 * @param context the context that serves as the factory for
572 * {@code SSLServerSocketFactory} instances
573 * @return the needed configurers
574 */
575 protected List<Configurer<SSLServerSocket>> getSSLServerSocketFactorySSLServerSocketConfigurers(SSLContext context) {
576 final List<String> enabledCipherSuites = this.getCipherSuites() == null
577 ? null : this.parsePropertyValues(this.getCipherSuites().getCipherSuite());
578
579 final Patterns enabledCipherSuitePatterns;
580 final Patterns defaultEnabledCipherSuitePatterns = this.getDefaultCipherSuitesFilter().getPatterns();
581
582 if (this.getCipherSuitesFilter() != null) {
583 enabledCipherSuitePatterns = this.getCipherSuitesFilter().getPatterns();
584 } else {
585 enabledCipherSuitePatterns = null;
586 }
587
588 ///
589
590 final List<String> enabledSecureSocketProtocols = this.getSecureSocketProtocols() == null
591 ? null : this.parsePropertyValues(this.getSecureSocketProtocols().getSecureSocketProtocol());
592
593 final Patterns enabledSecureSocketProtocolsPatterns;
594 final Patterns defaultEnabledSecureSocketProtocolsPatterns =
595 this.getDefaultSecureSocketProcotolFilter().getPatterns();
596
597 if (this.getSecureSocketProtocolsFilter() != null) {
598 enabledSecureSocketProtocolsPatterns = this.getSecureSocketProtocolsFilter().getPatterns();
599 } else {
600 enabledSecureSocketProtocolsPatterns = null;
601 }
602
603 //
604
605 final boolean allowPassthrough = getAllowPassthrough();
606
607 //////
608
609 Configurer<SSLServerSocket> sslServerSocketConfigurer = new Configurer<SSLServerSocket>() {
610
611 @Override
612 public SSLServerSocket configure(SSLServerSocket socket) {
613
614 Collection<String> filteredCipherSuites = BaseSSLContextParameters.this
615 .filter(enabledCipherSuites, Arrays.asList(socket.getSupportedCipherSuites()),
616 Arrays.asList(socket.getEnabledCipherSuites()),
617 enabledCipherSuitePatterns, defaultEnabledCipherSuitePatterns,
618 !allowPassthrough);
619
620 if (LOG.isDebugEnabled()) {
621 LOG.debug(SSL_SERVER_SOCKET_CIPHER_SUITE_LOG_MSG,
622 new Object[] {socket,
623 enabledCipherSuites,
624 enabledCipherSuitePatterns,
625 socket.getSupportedCipherSuites(),
626 socket.getEnabledCipherSuites(),
627 defaultEnabledCipherSuitePatterns,
628 filteredCipherSuites});
629 }
630
631 socket.setEnabledCipherSuites(filteredCipherSuites.toArray(new String[filteredCipherSuites.size()]));
632
633 Collection<String> filteredSecureSocketProtocols = BaseSSLContextParameters.this
634 .filter(enabledSecureSocketProtocols, Arrays.asList(socket.getSupportedProtocols()),
635 Arrays.asList(socket.getEnabledProtocols()),
636 enabledSecureSocketProtocolsPatterns, defaultEnabledSecureSocketProtocolsPatterns,
637 !allowPassthrough);
638
639 if (LOG.isDebugEnabled()) {
640 LOG.debug(SSL_SERVER_SOCKET_PROTOCOL_LOG_MSG,
641 new Object[] {socket,
642 enabledSecureSocketProtocols,
643 enabledSecureSocketProtocolsPatterns,
644 socket.getSupportedProtocols(),
645 socket.getEnabledProtocols(),
646 defaultEnabledSecureSocketProtocolsPatterns,
647 filteredSecureSocketProtocols});
648 }
649
650 socket.setEnabledProtocols(filteredSecureSocketProtocols.toArray(new String[filteredSecureSocketProtocols.size()]));
651 return socket;
652 }
653 };
654
655 List<Configurer<SSLServerSocket>> sslServerSocketConfigurers = new LinkedList<Configurer<SSLServerSocket>>();
656 sslServerSocketConfigurers.add(sslServerSocketConfigurer);
657
658 return sslServerSocketConfigurers;
659 }
660
661 /**
662 * Configures a {@link SSLSessionContext}, client or server, with the supplied session timeout.
663 *
664 * @param sessionContext the context to configure
665 * @param sessionTimeout the timeout time period
666 * @throws GeneralSecurityException if {@code sessionContext} is {@code null}
667 */
668 protected void configureSessionContext(
669 SSLSessionContext sessionContext, String sessionTimeout) throws GeneralSecurityException {
670
671 int sessionTimeoutInt = Integer.parseInt(this.parsePropertyValue(sessionTimeout));
672
673 if (sessionContext != null) {
674 sessionContext.setSessionTimeout(sessionTimeoutInt);
675 } else {
676 throw new GeneralSecurityException(
677 "The SSLContext does not support SSLSessionContext, "
678 + "but a session timeout is configured. Set sessionTimeout to null "
679 + "to avoid this error.");
680 }
681 }
682
683 /**
684 * Filters the values in {@code availableValues} returning only the values that
685 * are explicitly listed in {@code explicitValues} (returns them regardless
686 * of if they appear in {@code availableValues} or not) if {@code explicitValues} is not
687 * {@code null} or according to the following rules:
688 * <ol>
689 * <li>Match the include patterns in {@code patterns} and don't match the exclude patterns in {@code patterns}
690 * if patterns is not {@code null}.</li>
691 * <li>Match the include patterns in {@code defaultPatterns} and don't match the exclude patterns in {@code defaultPatterns}
692 * if patterns is {@code null} and {@code applyDefaults} is true.</li>
693 * <li>Are provided in currentValues if if patterns is {@code null} and {@code applyDefaults} is false.</li>
694 * </ol>
695 *
696 * @param explicitValues the optional explicit values to use
697 * @param availableValues the available values to filter from
698 * @param patterns the optional patterns to use when {@code explicitValues} is not used
699 * @param defaultPatterns the required patterns to use when {@code explicitValues} and {@code patterns} are not used
700 * @param applyDefaults flag indicating whether or not to apply defaults in the event that no explicit values and no
701 * patterns apply
702 *
703 * @return the filtered values
704 *
705 * @see #filter(Collection, Collection, List, List)
706 */
707 protected Collection<String> filter(
708 Collection<String> explicitValues, Collection<String> availableValues,
709 Collection<String> currentValues, Patterns patterns, Patterns defaultPatterns,
710 boolean applyDefaults) {
711
712 final List<Pattern> enabledIncludePatterns;
713 final List<Pattern> enabledExcludePatterns;
714
715 if (explicitValues == null && patterns == null && !applyDefaults) {
716 return currentValues;
717 }
718
719 if (patterns != null) {
720 enabledIncludePatterns = patterns.getIncludes();
721 enabledExcludePatterns = patterns.getExcludes();
722 } else {
723 enabledIncludePatterns = defaultPatterns.getIncludes();
724 enabledExcludePatterns = defaultPatterns.getExcludes();
725 }
726
727 return this.filter(
728 explicitValues,
729 availableValues,
730 enabledIncludePatterns, enabledExcludePatterns);
731 }
732
733 /**
734 * Filters the values in {@code availableValues} returning only the values that
735 * are explicitly listed in {@code explicitValues} (returns them regardless
736 * of if they appear in {@code availableValues} or not) if {@code explicitValues} is not
737 * {@code null} or as match the patterns in {@code includePatterns} and do
738 * not match the patterns in {@code excludePatterns} if {@code explicitValues} is {@code null}.
739 *
740 * @param explicitValues the optional explicit values to use
741 * @param availableValues the available values to filter from if {@code explicitValues} is {@code null}
742 * @param includePatterns the patterns to use for inclusion filtering, required if {@code explicitValues} is {@code null}
743 * @param excludePatterns the patterns to use for exclusion filtering, required if {@code explicitValues} is {@code null}
744 *
745 * @return the filtered values
746 */
747 protected Collection<String> filter(Collection<String> explicitValues, Collection<String> availableValues,
748 List<Pattern> includePatterns, List<Pattern> excludePatterns) {
749 Collection<String> returnValues;
750
751 // Explicit list has precedence over filters, even when the list is
752 // empty.
753 if (explicitValues != null) {
754 returnValues = new ArrayList<String>(explicitValues);
755 } else {
756 returnValues = new LinkedList<String>();
757
758 for (String value : availableValues) {
759 if (this.matchesOneOf(value, includePatterns)
760 && !this.matchesOneOf(value, excludePatterns)) {
761 returnValues.add(value);
762 }
763 }
764 }
765
766 return returnValues;
767 }
768
769 /**
770 * Returns true if and only if the value is matched by one or more of the supplied patterns.
771 *
772 * @param value the value to match
773 * @param patterns the patterns to try to match against
774 */
775 protected boolean matchesOneOf(String value, List<Pattern> patterns) {
776 boolean matches = false;
777
778 for (Pattern pattern : patterns) {
779 Matcher matcher = pattern.matcher(value);
780 if (matcher.matches()) {
781 matches = true;
782 break;
783 }
784 }
785
786 return matches;
787 }
788
789 /**
790 * Configures a {@code T} based on the related configuration options.
791 */
792 interface Configurer<T> {
793
794 /**
795 * Configures a {@code T} based on the related configuration options.
796 * The return value from this method may be {@code object} or it
797 * may be a decorated instance there of. Consequently, any subsequent
798 * actions on {@code object} must be performed using the returned value.
799 *
800 * @param object the object to configure
801 * @return {@code object} or a decorated instance there of
802 */
803 T configure(T object);
804 }
805
806 /**
807 * Makes a decorated {@link SSLContext} appear as a normal {@code SSLContext}.
808 */
809 protected static final class SSLContextDecorator extends SSLContext {
810
811 public SSLContextDecorator(SSLContextSpiDecorator decorator) {
812 super(decorator, decorator.getDelegate().getProvider(), decorator.getDelegate().getProtocol());
813 LOG.debug("SSLContextDecorator [{}] decorating SSLContext [{}].", this, decorator.getDelegate());
814 }
815
816 @Override
817 public String toString() {
818 return String.format("SSLContext[hash=%h, provider=%s, protocol=%s, needClientAuth=%s, "
819 + "wantClientAuth=%s\n\tdefaultProtocols=%s\n\tdefaultChiperSuites=%s\n\tsupportedProtocols=%s\n\tsupportedChiperSuites=%s\n]",
820 hashCode(), getProvider(), getProtocol(), getDefaultSSLParameters().getNeedClientAuth(), getDefaultSSLParameters().getWantClientAuth(),
821 collectionAsCommaDelimitedString(getDefaultSSLParameters().getProtocols()),
822 collectionAsCommaDelimitedString(getDefaultSSLParameters().getCipherSuites()),
823 collectionAsCommaDelimitedString(getSupportedSSLParameters().getProtocols()),
824 collectionAsCommaDelimitedString(getSupportedSSLParameters().getCipherSuites()));
825 }
826 }
827
828 /**
829 * Class needed to provide decoration of an existing {@link SSLContext}.
830 * Since {@code SSLContext} is an abstract class and requires an instance of
831 * {@link SSLContextSpi}, this class effectively wraps an
832 * {@code SSLContext} as if it were an {@code SSLContextSpi}, allowing us to
833 * achieve decoration.
834 */
835 protected static final class SSLContextSpiDecorator extends SSLContextSpi {
836
837 private final SSLContext context;
838
839 private final List<Configurer<SSLEngine>> sslEngineConfigurers;
840
841 private final List<Configurer<SSLSocketFactory>> sslSocketFactoryConfigurers;
842
843 private final List<Configurer<SSLServerSocketFactory>> sslServerSocketFactoryConfigurers;
844
845 public SSLContextSpiDecorator(SSLContext context,
846 List<Configurer<SSLEngine>> sslEngineConfigurers,
847 List<Configurer<SSLSocketFactory>> sslSocketFactoryConfigurers,
848 List<Configurer<SSLServerSocketFactory>> sslServerSocketFactoryConfigurers) {
849 this.context = context;
850 this.sslEngineConfigurers = sslEngineConfigurers;
851 this.sslSocketFactoryConfigurers = sslSocketFactoryConfigurers;
852 this.sslServerSocketFactoryConfigurers = sslServerSocketFactoryConfigurers;
853 }
854
855 @Override
856 protected SSLEngine engineCreateSSLEngine() {
857 SSLEngine engine = this.context.createSSLEngine();
858 LOG.debug("SSLEngine [{}] created from SSLContext [{}].", engine, context);
859 this.configureSSLEngine(engine);
860 return engine;
861 }
862
863 @Override
864 protected SSLEngine engineCreateSSLEngine(String peerHost, int peerPort) {
865 SSLEngine engine = this.context.createSSLEngine(peerHost, peerPort);
866 LOG.debug("SSLEngine [{}] created from SSLContext [{}].", engine, context);
867 return this.configureSSLEngine(engine);
868 }
869
870 @Override
871 protected SSLSessionContext engineGetClientSessionContext() {
872 return this.context.getClientSessionContext();
873 }
874
875 @Override
876 protected SSLSessionContext engineGetServerSessionContext() {
877 return this.context.getServerSessionContext();
878 }
879
880 @Override
881 protected SSLServerSocketFactory engineGetServerSocketFactory() {
882 SSLServerSocketFactory factory = this.context.getServerSocketFactory();
883 LOG.debug("SSLServerSocketFactoryEngine [{}] created from SSLContext [{}].", factory, context);
884 return this.configureSSLServerSocketFactory(factory);
885 }
886
887 @Override
888 protected SSLSocketFactory engineGetSocketFactory() {
889 SSLSocketFactory factory = this.context.getSocketFactory();
890 LOG.debug("SSLSocketFactory [{}] created from SSLContext [{}].", factory, context);
891 return this.configureSSLSocketFactory(factory);
892 }
893
894 @Override
895 protected void engineInit(KeyManager[] km,
896 TrustManager[] tm,
897 SecureRandom random) throws KeyManagementException {
898 this.context.init(km, tm, random);
899 }
900
901 protected SSLContext getDelegate() {
902 return this.context;
903 }
904
905 /**
906 * Configures an {@link SSLEngine} based on the configurers in instance.
907 * The return value from this method may be {@code engine} or it may be
908 * a decorated instance there of. Consequently, any subsequent actions
909 * on {@code engine} must be performed using the returned value.
910 *
911 * @param engine the engine to configure
912 * @return {@code engine} or a decorated instance there of
913 */
914 protected SSLEngine configureSSLEngine(SSLEngine engine) {
915 SSLEngine workingEngine = engine;
916
917 for (Configurer<SSLEngine> configurer : this.sslEngineConfigurers) {
918 workingEngine = configurer.configure(workingEngine);
919 }
920
921 return workingEngine;
922 }
923
924 /**
925 * Configures an {@link SSLSocketFactory} based on the configurers in
926 * this instance. The return value from this method may be
927 * {@code factory} or it may be a decorated instance there of.
928 * Consequently, any subsequent actions on {@code factory} must be
929 * performed using the returned value.
930 *
931 * @param factory the factory to configure
932 * @return {@code factory} or a decorated instance there of
933 */
934 protected SSLSocketFactory configureSSLSocketFactory(SSLSocketFactory factory) {
935 SSLSocketFactory workingFactory = factory;
936
937 for (Configurer<SSLSocketFactory> configurer : this.sslSocketFactoryConfigurers) {
938 workingFactory = configurer.configure(workingFactory);
939 }
940
941 return workingFactory;
942 }
943
944 /**
945 * Configures an {@link SSLServerSocketFactory} based on the
946 * configurers in this instance. The return value from this method may be
947 * {@code factory} or it may be a decorated instance there of.
948 * Consequently, any subsequent actions on {@code factory} must be
949 * performed using the returned value.
950 *
951 * @param factory the factory to configure
952 * @return {@code factory} or a decorated instance there of
953 */
954 protected SSLServerSocketFactory configureSSLServerSocketFactory(
955 SSLServerSocketFactory factory) {
956 SSLServerSocketFactory workingFactory = factory;
957
958 for (Configurer<SSLServerSocketFactory> configurer : this.sslServerSocketFactoryConfigurers) {
959 workingFactory = configurer.configure(workingFactory);
960 }
961
962 return workingFactory;
963 }
964 }
965
966 /**
967 * A decorator that enables the application of configuration options to be
968 * applied to created sockets even after this factory has been created and
969 * turned over to client code.
970 */
971 protected static final class SSLServerSocketFactoryDecorator extends SSLServerSocketFactory {
972
973 private final SSLServerSocketFactory sslServerSocketFactory;
974 private final List<Configurer<SSLServerSocket>> sslServerSocketConfigurers;
975
976 public SSLServerSocketFactoryDecorator(SSLServerSocketFactory sslServerSocketFactory,
977 List<Configurer<SSLServerSocket>> sslServerSocketConfigurers) {
978 this.sslServerSocketFactory = sslServerSocketFactory;
979 this.sslServerSocketConfigurers = sslServerSocketConfigurers;
980 }
981
982 @Override
983 public String[] getDefaultCipherSuites() {
984 return this.sslServerSocketFactory.getDefaultCipherSuites();
985 }
986
987 @Override
988 public String[] getSupportedCipherSuites() {
989 return this.sslServerSocketFactory.getSupportedCipherSuites();
990 }
991
992 @Override
993 public ServerSocket createServerSocket() throws IOException {
994 return this.configureSocket(this.sslServerSocketFactory.createServerSocket());
995 }
996
997 @Override
998 public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException {
999 return this.configureSocket(this.sslServerSocketFactory.createServerSocket(port, backlog, ifAddress));
1000 }
1001
1002 @Override
1003 public ServerSocket createServerSocket(int port, int backlog) throws IOException {
1004 return this.configureSocket(this.sslServerSocketFactory.createServerSocket(port, backlog));
1005 }
1006
1007 @Override
1008 public ServerSocket createServerSocket(int port) throws IOException {
1009 return this.configureSocket(this.sslServerSocketFactory.createServerSocket(port));
1010 }
1011
1012 public SSLServerSocketFactory getDelegate() {
1013 return this.sslServerSocketFactory;
1014 }
1015
1016 private ServerSocket configureSocket(ServerSocket s) {
1017 SSLServerSocket workingSocket = (SSLServerSocket) s;
1018
1019 LOG.debug("Created ServerSocket [{}] from SslServerSocketFactory [{}].", s, sslServerSocketFactory);
1020
1021 for (Configurer<SSLServerSocket> configurer : this.sslServerSocketConfigurers) {
1022 workingSocket = configurer.configure(workingSocket);
1023 }
1024
1025 return workingSocket;
1026 }
1027 }
1028
1029 /**
1030 * A decorator that enables the application of configuration options to be
1031 * applied to created sockets even after this factory has been created and
1032 * turned over to client code.
1033 */
1034 protected static final class SSLSocketFactoryDecorator extends SSLSocketFactory {
1035
1036 private final SSLSocketFactory sslSocketFactory;
1037 private final List<Configurer<SSLSocket>> sslSocketConfigurers;
1038
1039 public SSLSocketFactoryDecorator(SSLSocketFactory sslSocketFactory,
1040 List<Configurer<SSLSocket>> sslSocketConfigurers) {
1041 this.sslSocketFactory = sslSocketFactory;
1042 this.sslSocketConfigurers = sslSocketConfigurers;
1043 }
1044
1045 @Override
1046 public String[] getDefaultCipherSuites() {
1047 return sslSocketFactory.getDefaultCipherSuites();
1048 }
1049
1050 @Override
1051 public String[] getSupportedCipherSuites() {
1052 return sslSocketFactory.getSupportedCipherSuites();
1053 }
1054
1055 @Override
1056 public Socket createSocket() throws IOException {
1057 return configureSocket(sslSocketFactory.createSocket());
1058 }
1059
1060 @Override
1061 public Socket createSocket(Socket s, String host,
1062 int port, boolean autoClose) throws IOException, UnknownHostException {
1063 return configureSocket(sslSocketFactory.createSocket(s, host, port, autoClose));
1064 }
1065
1066 @Override
1067 public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
1068 return configureSocket(sslSocketFactory.createSocket(host, port));
1069 }
1070
1071 @Override
1072 public Socket createSocket(String host, int port,
1073 InetAddress localHost, int localPort) throws IOException, UnknownHostException {
1074 return configureSocket(sslSocketFactory.createSocket(host, port, localHost, localPort));
1075 }
1076
1077 @Override
1078 public Socket createSocket(InetAddress host, int port) throws IOException {
1079 return configureSocket(sslSocketFactory.createSocket(host, port));
1080 }
1081
1082 @Override
1083 public Socket createSocket(InetAddress address, int port,
1084 InetAddress localAddress, int localPort) throws IOException {
1085 return configureSocket(sslSocketFactory.createSocket(address, port, localAddress, localPort));
1086 }
1087
1088 public SSLSocketFactory getDelegate() {
1089 return this.sslSocketFactory;
1090 }
1091
1092 private Socket configureSocket(Socket s) {
1093 SSLSocket workingSocket = (SSLSocket) s;
1094
1095 LOG.debug("Created Socket [{}] from SocketFactory [{}].", s, sslSocketFactory);
1096
1097 for (Configurer<SSLSocket> configurer : this.sslSocketConfigurers) {
1098 workingSocket = configurer.configure(workingSocket);
1099 }
1100
1101 return workingSocket;
1102 }
1103 }
1104
1105 private static String createCipherSuiteLogMessage(String entityName) {
1106 return "Configuring " + entityName + " [{}] with " + LS
1107 + "\t explicitly set cipher suites [{}]," + LS
1108 + "\t cipher suite patterns [{}]," + LS
1109 + "\t available cipher suites [{}]," + LS
1110 + "\t currently enabled cipher suites [{}]," + LS
1111 + "\t and default cipher suite patterns [{}]." + LS
1112 + "\t Resulting enabled cipher suites are [{}].";
1113 }
1114
1115 private static String createProtocolLogMessage(String entityName) {
1116 return "Configuring " + entityName + " [{}] with " + LS
1117 + "\t explicitly set protocols [{}]," + LS
1118 + "\t protocol patterns [{}]," + LS
1119 + "\t available protocols [{}]," + LS
1120 + "\t currently enabled protocols [{}]," + LS
1121 + "\t and default protocol patterns [{}]." + LS
1122 + "\t Resulting enabled protocols are [{}].";
1123 }
1124 }