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