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