Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2a45658
Reload key and certs in SockerAppender reconnector
MichaelMorrisEst Jul 24, 2024
580ec20
Evict old connections during reconfiguration
MichaelMorrisEst Aug 21, 2024
575f8f7
Reload key and certs in SockerAppender reconnector
MichaelMorrisEst Jul 24, 2024
1ef19d1
Evict old connections during reconfiguration
MichaelMorrisEst Aug 21, 2024
9ccac2d
Avoid caching configuration in `SslConfigurationFactory`
vy Aug 29, 2024
6e90862
Overhaul `SslConfiguration` to improve reload support
vy Aug 29, 2024
799abc4
Avoid `Thread.sleep()` in `SocketAppenderReconnectTest`
vy Aug 29, 2024
c39d865
Overhaul SSL tests
vy Aug 30, 2024
9519457
Use distinct passwords for SSL key stores in tests
vy Aug 30, 2024
0bbf3c5
Extend `SocketAppenderReconnectTest` to test key & trust store reloads
vy Sep 3, 2024
4b81792
Merge remote-tracking branch 'origin/2.x' into ssl-cfg
vy Sep 3, 2024
2060e83
Merge branch 'ssl-cfg' into nordix-log4j2-2988
vy Sep 3, 2024
c58e6d2
Minor corrections
vy Sep 3, 2024
9121978
Add changelog entry
vy Sep 3, 2024
75503e3
Fix `bnd-baseline:baseline` failures
vy Sep 3, 2024
7c81318
Merge branch '2.x' into nordix-log4j2-2988
vy Sep 3, 2024
68e8c23
Replace `Configurator.initialize()` with `LoggerContext::new`
vy Sep 6, 2024
1c2165c
Remove country from the CA certificate
vy Sep 6, 2024
132cdd9
Fix `@Version` in `o.a.l.l.core.net.ssl`
vy Sep 6, 2024
8528e89
Improve creation of the default `SSLContext`
vy Sep 6, 2024
6676e5d
Remove complicated fallback logic in `SslConfiguration`
vy Sep 6, 2024
34eb0ef
Improve changelog
vy Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ public static KeyStoreConfiguration createKeyStoreConfiguration(
location, (password == null ? null : password.toCharArray()), keyStoreType, keyManagerFactoryAlgorithm);
}

/**
* @deprecated Planned to be removed in the next major release
*/
@Deprecated
public KeyManagerFactory initKeyManagerFactory()
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
final KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(this.keyManagerFactoryAlgorithm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
*/
package org.apache.logging.log4j.core.net.ssl;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.Objects;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
Expand All @@ -34,10 +31,14 @@
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.status.StatusLogger;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;

/**
* SSL Configuration
*/
@NullMarked
@Plugin(name = "Ssl", category = Core.CATEGORY_NAME, printObject = true)
public class SslConfiguration {

Expand All @@ -47,23 +48,25 @@ public class SslConfiguration {

private final boolean verifyHostName;

@Nullable
private final KeyStoreConfiguration keyStoreConfig;

@Nullable
private final TrustStoreConfiguration trustStoreConfig;

private final transient SSLContext sslContext;

private SslConfiguration(
final String protocol,
@Nullable final String protocol,
final boolean verifyHostName,
final KeyStoreConfiguration keyStoreConfig,
final TrustStoreConfiguration trustStoreConfig) {
@Nullable final KeyStoreConfiguration keyStoreConfig,
@Nullable final TrustStoreConfiguration trustStoreConfig) {
this.keyStoreConfig = keyStoreConfig;
this.trustStoreConfig = trustStoreConfig;
final String effectiveProtocol = protocol == null ? SslConfigurationDefaults.PROTOCOL : protocol;
this.protocol = effectiveProtocol;
this.verifyHostName = verifyHostName;
this.sslContext = createSslContextWithFallbacks(effectiveProtocol, keyStoreConfig, trustStoreConfig);
this.sslContext = createSslContext(effectiveProtocol, keyStoreConfig, trustStoreConfig);
}

/**
Expand Down Expand Up @@ -100,74 +103,13 @@ public SSLServerSocketFactory getSslServerSocketFactory() {
return sslContext.getServerSocketFactory();
}

private static SSLContext createSslContextWithFallbacks(
final String protocol,
final KeyStoreConfiguration keyStoreConfig,
final TrustStoreConfiguration trustStoreConfig) {
SSLContext context;
try {
context = createSslContext(protocol, keyStoreConfig, trustStoreConfig);
LOGGER.debug("Creating SSLContext with the given parameters");
} catch (final TrustStoreConfigurationException e) {
context = createSslContextWithTrustStoreFailure(protocol, trustStoreConfig);
} catch (final KeyStoreConfigurationException e) {
context = createSslContextWithKeyStoreFailure(protocol, keyStoreConfig);
}
return context;
}

private static SSLContext createSslContextWithTrustStoreFailure(
final String protocol, final TrustStoreConfiguration trustStoreConfig) {
SSLContext context;
try {
context = createSslContextWithDefaultTrustManagerFactory(protocol, trustStoreConfig);
LOGGER.debug("Creating SSLContext with default truststore");
} catch (final KeyStoreConfigurationException e) {
context = createDefaultSslContext(protocol);
LOGGER.debug("Creating SSLContext with default configuration");
}
return context;
}

private static SSLContext createSslContextWithKeyStoreFailure(
final String protocol, final KeyStoreConfiguration keyStoreConfig) {
SSLContext context;
try {
context = createSslContextWithDefaultKeyManagerFactory(protocol, keyStoreConfig);
LOGGER.debug("Creating SSLContext with default keystore");
} catch (final TrustStoreConfigurationException e) {
context = createDefaultSslContext(protocol);
LOGGER.debug("Creating SSLContext with default configuration");
}
return context;
}

private static SSLContext createSslContextWithDefaultKeyManagerFactory(
final String protocol, final KeyStoreConfiguration keyStoreConfig) throws TrustStoreConfigurationException {
try {
return createSslContext(protocol, keyStoreConfig, null);
} catch (final KeyStoreConfigurationException dummy) {
LOGGER.debug("Exception occurred while using default keystore. This should be a BUG");
return null;
}
}

private static SSLContext createSslContextWithDefaultTrustManagerFactory(
final String protocol, final TrustStoreConfiguration trustStoreConfig)
throws KeyStoreConfigurationException {
try {
return createSslContext(protocol, null, trustStoreConfig);
} catch (final TrustStoreConfigurationException dummy) {
LOGGER.debug("Exception occurred while using default truststore. This should be a BUG");
return null;
}
}

private static SSLContext createDefaultSslContext(final String protocol) {
try {
return SSLContext.getDefault();
} catch (final NoSuchAlgorithmException defaultContextError) {
LOGGER.error("Failed to create an `SSLContext` using the default configuration, falling back to creating an empty one", defaultContextError);
LOGGER.error(
"Failed to create an `SSLContext` using the default configuration, falling back to creating an empty one",
defaultContextError);
try {
final SSLContext emptyContext = SSLContext.getInstance(protocol);
emptyContext.init(new KeyManager[0], new TrustManager[0], null);
Expand All @@ -181,61 +123,43 @@ private static SSLContext createDefaultSslContext(final String protocol) {

private static SSLContext createSslContext(
final String protocol,
final KeyStoreConfiguration keyStoreConfig,
final TrustStoreConfiguration trustStoreConfig)
throws KeyStoreConfigurationException, TrustStoreConfigurationException {
@Nullable final KeyStoreConfiguration keyStoreConfig,
@Nullable final TrustStoreConfiguration trustStoreConfig) {
try {
KeyManager[] kManagers = null;
TrustManager[] tManagers = null;

final SSLContext newSslContext = SSLContext.getInstance(protocol);
if (keyStoreConfig != null) {
final KeyManagerFactory kmFactory = loadKeyManagerFactory(keyStoreConfig);
kManagers = kmFactory.getKeyManagers();
}
if (trustStoreConfig != null) {
final TrustManagerFactory tmFactory = loadTrustManagerFactory(trustStoreConfig);
tManagers = tmFactory.getTrustManagers();
}

newSslContext.init(kManagers, tManagers, null);
return newSslContext;
} catch (final NoSuchAlgorithmException e) {
LOGGER.error("No Provider supports a TrustManagerFactorySpi implementation for the specified protocol", e);
throw new TrustStoreConfigurationException(e);
} catch (final KeyManagementException e) {
LOGGER.error("Failed to initialize the SSLContext", e);
throw new KeyStoreConfigurationException(e);
final SSLContext sslContext = SSLContext.getInstance(protocol);
final KeyManager[] keyManagers = loadKeyManagers(keyStoreConfig);
final TrustManager[] trustManagers = loadTrustManagers(trustStoreConfig);
sslContext.init(keyManagers, trustManagers, null);
return sslContext;
} catch (final Exception error) {
LOGGER.error(
"Failed to create an `SSLContext` using the provided configuration, falling back to a default instance",
error);
return createDefaultSslContext(protocol);
}
}

private static TrustManagerFactory loadTrustManagerFactory(final TrustStoreConfiguration trustStoreConfig)
throws TrustStoreConfigurationException {
private static KeyManager[] loadKeyManagers(@Nullable final KeyStoreConfiguration config) throws Exception {
if (config == null) {
return new KeyManager[0];
}
final KeyManagerFactory factory = KeyManagerFactory.getInstance(config.getKeyManagerFactoryAlgorithm());
final char[] password = config.getPasswordAsCharArray();
try {
return trustStoreConfig.initTrustManagerFactory();
} catch (final NoSuchAlgorithmException e) {
LOGGER.error("The specified algorithm is not available from the specified provider", e);
throw new TrustStoreConfigurationException(e);
} catch (final KeyStoreException e) {
LOGGER.error("Failed to initialize the TrustManagerFactory", e);
throw new TrustStoreConfigurationException(e);
factory.init(config.getKeyStore(), password);
} finally {
config.clearSecrets();
}
return factory.getKeyManagers();
}

private static KeyManagerFactory loadKeyManagerFactory(final KeyStoreConfiguration keyStoreConfig)
throws KeyStoreConfigurationException {
try {
return keyStoreConfig.initKeyManagerFactory();
} catch (final NoSuchAlgorithmException e) {
LOGGER.error("The specified algorithm is not available from the specified provider", e);
throw new KeyStoreConfigurationException(e);
} catch (final KeyStoreException e) {
LOGGER.error("Failed to initialize the TrustManagerFactory", e);
throw new KeyStoreConfigurationException(e);
} catch (final UnrecoverableKeyException e) {
LOGGER.error("The key cannot be recovered (e.g. the given password is wrong)", e);
throw new KeyStoreConfigurationException(e);
private static TrustManager[] loadTrustManagers(@Nullable final TrustStoreConfiguration config) throws Exception {
if (config == null) {
return new TrustManager[0];
}
final TrustManagerFactory factory = TrustManagerFactory.getInstance(config.getTrustManagerFactoryAlgorithm());
factory.init(config.getKeyStore());
return factory.getTrustManagers();
}

/**
Expand All @@ -246,6 +170,7 @@ private static KeyManagerFactory loadKeyManagerFactory(final KeyStoreConfigurati
* @param trustStoreConfig The TrustStoreConfiguration.
* @return a new SslConfiguration
*/
@NullUnmarked
@PluginFactory
public static SslConfiguration createSSLConfiguration(
// @formatter:off
Expand All @@ -266,6 +191,7 @@ public static SslConfiguration createSSLConfiguration(
* @return a new SslConfiguration
* @since 2.12
*/
@NullUnmarked
public static SslConfiguration createSSLConfiguration(
// @formatter:off
@PluginAttribute("protocol") final String protocol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public StoreConfiguration(final String location, final String password) {
*/
public void clearSecrets() {
this.location = null;
this.passwordProvider = null;
this.passwordProvider = new MemoryPasswordProvider(new char[0]);
}

public String getLocation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ public static TrustStoreConfiguration createKeyStoreConfiguration(
trustManagerFactoryAlgorithm);
}

/**
* @deprecated Planned to be removed in the next major release
*/
@Deprecated
public TrustManagerFactory initTrustManagerFactory() throws NoSuchAlgorithmException, KeyStoreException {
final TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(this.trustManagerFactoryAlgorithm);
tmFactory.init(this.getKeyStore());
Expand Down