All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.ssl.SSLContextBuilder Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2015 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.security.ssl;

import static org.wildfly.security.provider.util.ProviderUtil.INSTALLED_PROVIDERS;

import java.security.Provider;
import java.security.Security;
import java.util.function.Supplier;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;

import org.wildfly.common.Assert;
import org.wildfly.security.FixedSecurityFactory;
import org.wildfly.security.OneTimeSecurityFactory;
import org.wildfly.security.SecurityFactory;
import org.wildfly.security.auth.server.MechanismConfiguration;
import org.wildfly.security.auth.server.MechanismConfigurationSelector;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.PrincipalDecoder;
import org.wildfly.security.auth.server.ServerAuthenticationContext;
import org.wildfly.security.evidence.X509PeerCertificateChainEvidence;

/**
 * A class which allows building and configuration of a single client- or server-side SSL context.  The builder requires, at a
 * minimum, that a key manager be set; all other parameters have default values as follows:
 * 
    *
  • The security domain defaults to being empty (no client authentication possible)
  • *
  • The principal decoder defaults to the {@linkplain PrincipalDecoder#DEFAULT default principal decoder}
  • *
  • The cipher suite selector defaults to {@link CipherSuiteSelector#openSslDefault()}
  • *
  • The protocol suite selector defaults to {@link ProtocolSelector#DEFAULT_SELECTOR}
  • *
  • The "require client authentication" flag defaults to {@code false}
  • *
  • The provider supplier defaults to {@link Security#getProviders() Security::getProviders}
  • *
* * @author David M. Lloyd */ public final class SSLContextBuilder { private SecurityDomain securityDomain; // ELY-1917: This should be changed to CipherSuiteSelector.openSslCombinedDefault once we are ready to enable // TLS 1.3 by default private CipherSuiteSelector cipherSuiteSelector = CipherSuiteSelector.openSslDefault(); private ProtocolSelector protocolSelector = ProtocolSelector.DEFAULT_SELECTOR; private boolean useCipherSuitesOrder = true; private boolean wantClientAuth; private boolean needClientAuth; private boolean authenticationOptional; private boolean clientMode; private int sessionCacheSize; private int sessionTimeout; private SecurityFactory keyManagerSecurityFactory; private SecurityFactory trustManagerSecurityFactory = SSLUtils.getDefaultX509TrustManagerSecurityFactory(); private Supplier providerSupplier = INSTALLED_PROVIDERS; private String providerName; private boolean wrap = true; private MechanismConfigurationSelector mechanismConfigurationSelector; /** * Set the security domain to use to authenticate clients. * * @param securityDomain the security domain to use to authenticate clients, or {@code null} to disable client * certificate authentication */ public SSLContextBuilder setSecurityDomain(final SecurityDomain securityDomain) { if (securityDomain != null && securityDomain.getEvidenceVerifySupport(X509PeerCertificateChainEvidence.class).isNotSupported()) { throw ElytronMessages.tls.securityDomainOfSSLContextDoesNotSupportX509(); } this.securityDomain = securityDomain; return this; } /** * Set the cipher suite selector to use for this context. * * @param cipherSuiteSelector the cipher suite selector (not {@code null}) */ public SSLContextBuilder setCipherSuiteSelector(final CipherSuiteSelector cipherSuiteSelector) { Assert.checkNotNullParam("cipherSuiteSelector", cipherSuiteSelector); this.cipherSuiteSelector = cipherSuiteSelector; return this; } /** * Set the protocol selector to use for this context. * * @param protocolSelector the protocol selector to use for this context (not {@code null}) */ public SSLContextBuilder setProtocolSelector(final ProtocolSelector protocolSelector) { Assert.checkNotNullParam("protocolSelector", protocolSelector); this.protocolSelector = protocolSelector; return this; } /** * Sets whether the local cipher suites preference should be honored. * * @param useCipherSuitesOrder whether the local cipher suites preference should be honored. */ public SSLContextBuilder setUseCipherSuitesOrder(final boolean useCipherSuitesOrder) { Assert.checkNotNullParam("useCipherSuitesOrder", useCipherSuitesOrder); this.useCipherSuitesOrder = useCipherSuitesOrder; return this; } /** * Force the SSLContext created by this builder to want client authentication. * * The SSLContext returned by this builder will be configured to want client authentication if this value is set to true OR * of a SecurityDomain is associated. * * @param wantClientAuth should the SSLContext be forced to want client authentication. */ public SSLContextBuilder setWantClientAuth(final boolean wantClientAuth) { this.wantClientAuth = wantClientAuth; return this; } /** * Force the SSLContext created by this builder to need client authentication. * * The SSLContext returned by this builder will be configured to need client authentication if this value is set to true. * * @param needClientAuth should the SSLContext be forced to need client authentication. */ public SSLContextBuilder setNeedClientAuth(final boolean needClientAuth) { this.needClientAuth = needClientAuth; return this; } /** * Where a SecurityDomain is associated with this Builder if the client presents a certificate an attempt will be made to * obtain a SecurityIdentity by using the certificate for authentication, setting this flag to {@code true} allows for a * failed authentication to be silently ignored. * * This setting does not bypass any certificate checking performed by the underlying TrustManager so failure there will still cause the connection attempt to be aborted. * * The reason this setting would be used would be to enable a fallback to another authentication mechanism after the connection is established. * * Note: Where this is no security domain associated there is no authentication step so this value will be ignored. * * @param authenticationOptional should the authentication step be allowed to silently fail. */ public SSLContextBuilder setAuthenticationOptional(final boolean authenticationOptional) { this.authenticationOptional = authenticationOptional; return this; } /** * Sets the size of the cache used for storing SSLSession objects. * * @param sessionCacheSize the size of the cache used for storing SSLSession objects. * @return The {@link SSLContextBuilder} to allow chaining of method calls. */ public SSLContextBuilder setSessionCacheSize(final int sessionCacheSize) { this.sessionCacheSize = sessionCacheSize; return this; } /** * Sets the timeout limit for SSLSession objects. * * @param sessionTimeout the timeout limit for SSLSession objects. * @return The {@link SSLContextBuilder} to allow chaining of method calls. */ public SSLContextBuilder setSessionTimeout(final int sessionTimeout) { this.sessionTimeout = sessionTimeout; return this; } /** * Set the factory for the key manager which should be used to hold identities for this context. * * @param keyManagerSecurityFactory the security factory which produces the key manager (not {@code null}) */ public SSLContextBuilder setKeyManagerSecurityFactory(final SecurityFactory keyManagerSecurityFactory) { Assert.checkNotNullParam("keyManagerSecurityFactory", keyManagerSecurityFactory); this.keyManagerSecurityFactory = keyManagerSecurityFactory; return this; } /** * Set the key manager which should be used to hold identities for this context. * * @param keyManager the security factory which produces the key manager (not {@code null}) */ public SSLContextBuilder setKeyManager(final X509ExtendedKeyManager keyManager) { Assert.checkNotNullParam("keyManager", keyManager); this.keyManagerSecurityFactory = new FixedSecurityFactory<>(keyManager); return this; } /** * Set the factory for the trust manager which should be used for the initial trust decisions during connection. * * @param trustManagerSecurityFactory the factory for the trust manager which should be used for the initial trust decisions during connection (not {@code null}). */ public SSLContextBuilder setTrustManagerSecurityFactory(final SecurityFactory trustManagerSecurityFactory) { this.trustManagerSecurityFactory = Assert.checkNotNullParam("trustManagerSecurityFactory", trustManagerSecurityFactory); return this; } /** * Set the trust manager which should be used to hold identities for this context. * * @param trustManager the trust manager which should be used to hold identities for this context (not {@code null}). */ public SSLContextBuilder setTrustManager(final X509TrustManager trustManager) { Assert.checkNotNullParam("trustManager", trustManager); this.trustManagerSecurityFactory = new FixedSecurityFactory<>(trustManager); return this; } // todo: add a setter which simply accepts a single org.wildfly.security.ssl.X500CertificateChainPrivateCredential instance /** * Set the provider supplier. * * @param providerSupplier the provider supplier (not {@code null}) */ public SSLContextBuilder setProviderSupplier(final Supplier providerSupplier) { Assert.checkNotNullParam("providerSupplier", providerSupplier); this.providerSupplier = providerSupplier; return this; } /** * Set the provider name. * * @param name the provider name (if {@code null} and provider is allowed) * @return this builder */ public SSLContextBuilder setProviderName(final String name) { this.providerName = name; return this; } /** * Set the client mode of the target SSL context. * * @param clientMode {@code true} to use client mode, {@code false} otherwise * @return this builder */ public SSLContextBuilder setClientMode(final boolean clientMode) { this.clientMode = clientMode; return this; } /** * Set if the configured SSL engine and sockets created using the SSL context should be wrapped to prevent modification to the configuration. * * Defaults to {@code true}. * * @param wrap should the engine or socket created by the SSL context be wrapped to prevent modification to the configuration. * @return this builder */ public SSLContextBuilder setWrap(final boolean wrap) { this.wrap = wrap; return this; } /** * Set selector of mechanism configuration for {@link ServerAuthenticationContext}, which will be used for SSL client authentication. * * @param mechanismConfigurationSelector mechanism configuration selector to be used by {@link ServerAuthenticationContext} in SSL authentication. * @return this builder */ public SSLContextBuilder setMechanismConfigurationSelector(final MechanismConfigurationSelector mechanismConfigurationSelector) { this.mechanismConfigurationSelector = mechanismConfigurationSelector; return this; } /** * Build a security factory for the new context. The factory will cache the constructed instance. * * @return the security factory */ public SecurityFactory build() { final SecurityDomain securityDomain = this.securityDomain; final CipherSuiteSelector cipherSuiteSelector = this.cipherSuiteSelector; final ProtocolSelector protocolSelector = this.protocolSelector; final SecurityFactory trustManagerSecurityFactory = this.trustManagerSecurityFactory; final SecurityFactory keyManagerSecurityFactory = this.keyManagerSecurityFactory; final Supplier providerSupplier = this.providerSupplier; final boolean clientMode = this.clientMode; final boolean authenticationOptional = this.authenticationOptional; final int sessionCacheSize = this.sessionCacheSize; final int sessionTimeout = this.sessionTimeout; final boolean wantClientAuth = this.wantClientAuth; final boolean needClientAuth = this.needClientAuth; final boolean useCipherSuitesOrder = this.useCipherSuitesOrder; final boolean wrap = this.wrap; final MechanismConfigurationSelector mechanismConfigurationSelector = this.mechanismConfigurationSelector != null ? this.mechanismConfigurationSelector : MechanismConfigurationSelector.constantSelector(MechanismConfiguration.EMPTY); return new OneTimeSecurityFactory<>(() -> { final SecurityFactory sslContextFactory = SSLUtils.createSslContextFactory(protocolSelector, providerSupplier, providerName); // construct the original context final SSLContext sslContext = sslContextFactory.create(); final X509KeyManager x509KeyManager = keyManagerSecurityFactory == null ? null : keyManagerSecurityFactory.create(); final X509TrustManager x509TrustManager = trustManagerSecurityFactory.create(); final boolean canAuthPeers = securityDomain != null && securityDomain.getEvidenceVerifySupport(X509PeerCertificateChainEvidence.class).mayBeSupported(); if (ElytronMessages.tls.isTraceEnabled()) { ElytronMessages.tls.tracef("SSLContext initialization:%n" + " securityDomain = %s%n" + " canAuthPeers = %s%n" + " cipherSuiteSelector = %s%n" + " protocolSelector = %s%n" + " x509TrustManager = %s%n" + " x509KeyManager = %s%n" + " providerSupplier = %s%n" + " clientMode = %s%n" + " authenticationOptional = %s%n" + " sessionCacheSize = %s%n" + " sessionTimeout = %s%n" + " wantClientAuth = %s%n" + " needClientAuth = %s%n" + " useCipherSuitesOrder = %s%n" + " wrap = %s%n", securityDomain, canAuthPeers, cipherSuiteSelector, protocolSelector, x509TrustManager, x509KeyManager, providerSupplier, clientMode, authenticationOptional, sessionCacheSize, sessionTimeout, wantClientAuth, needClientAuth, useCipherSuitesOrder, wrap); } sslContext.init(x509KeyManager == null ? null : new KeyManager[]{ x509KeyManager }, new TrustManager[]{ canAuthPeers ? new SecurityDomainTrustManager(x509TrustManager, securityDomain, authenticationOptional, mechanismConfigurationSelector) : x509TrustManager }, null); SSLSessionContext sessionContext = clientMode ? sslContext.getClientSessionContext() : sslContext.getServerSessionContext(); if (sessionContext != null) { if (sessionCacheSize >= 0) sessionContext.setSessionCacheSize(sessionCacheSize); if (sessionTimeout >= 0) sessionContext.setSessionTimeout(sessionTimeout); } // now, set up the wrapping configuration final SSLConfigurator sslConfigurator = clientMode ? new SSLConfiguratorImpl(protocolSelector, cipherSuiteSelector, useCipherSuitesOrder) : new SSLConfiguratorImpl(protocolSelector, cipherSuiteSelector, wantClientAuth || canAuthPeers, needClientAuth, useCipherSuitesOrder); final ConfiguredSSLContextSpi contextSpi = new ConfiguredSSLContextSpi(sslContext, sslConfigurator, wrap); return new DelegatingSSLContext(contextSpi); }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy