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 }