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