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