You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2025/10/10 18:32:28 UTC

(logging-log4j2) 01/01: Fix nullability issues in `SslConfiguration`

This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch fix/2.x/syslog-truststore
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit d19c9f9f8bd490de10615ea6bf7fb5c9785757df
Author: Matt Sicker <ms...@apple.com>
AuthorDate: Fri Oct 10 13:27:40 2025 -0500

    Fix nullability issues in `SslConfiguration`
    
    As discovered in issue #3947, an NPE can be thrown when an `SslConfiguration` returns `null` for its keystore, truststore, or `SSLContext`, in particular, in `SslSocketManager`.
---
 .../log4j/core/appender/TlsSyslogAppenderTest.java        |  4 +++-
 .../log4j/core/appender/HttpURLConnectionManager.java     | 10 +++++++---
 .../org/apache/logging/log4j/core/net/SmtpManager.java    |  9 ++++++---
 .../apache/logging/log4j/core/net/SslSocketManager.java   | 15 ++++++++-------
 .../logging/log4j/core/net/UrlConnectionFactory.java      | 10 +++++++---
 .../logging/log4j/core/net/ssl/SslConfiguration.java      | 12 ++++++++++--
 .../java/org/apache/logging/log4j/smtp/SmtpManager.java   |  9 ++++++---
 .../.2.x.x/3947_fix_SslSocketManager_null_keystore.xml    | 14 ++++++++++++++
 8 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
index b18673e4be..5c6adf8f71 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/TlsSyslogAppenderTest.java
@@ -83,7 +83,9 @@ class TlsSyslogAppenderTest extends SyslogAppenderTest {
         final TrustStoreConfiguration tsc = new TrustStoreConfiguration(
                 SslKeyStoreConstants.TRUSTSTORE_LOCATION, SslKeyStoreConstants::TRUSTSTORE_PWD, null, null);
         sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc);
-        serverSocketFactory = sslConfiguration.getSslContext().getServerSocketFactory();
+        serverSocketFactory = sslConfiguration.getSslContext() != null
+                ? sslConfiguration.getSslContext().getServerSocketFactory()
+                : (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
     }
 
     private void initTlsTestEnvironment(final int numberOfMessages, final TlsSyslogMessageFormat messageFormat)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
index a4e9858431..6a49f181c4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpURLConnectionManager.java
@@ -23,8 +23,10 @@ import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.LoggerContext;
@@ -37,7 +39,7 @@ import org.apache.logging.log4j.core.util.IOUtils;
 
 public class HttpURLConnectionManager extends HttpManager {
 
-    private static final Charset CHARSET = Charset.forName("US-ASCII");
+    private static final Charset CHARSET = StandardCharsets.US_ASCII;
 
     private final URL url;
     private final boolean isHttps;
@@ -100,8 +102,10 @@ public class HttpURLConnectionManager extends HttpManager {
                     header.getName(), header.evaluate(getConfiguration().getStrSubstitutor()));
         }
         if (sslConfiguration != null) {
-            ((HttpsURLConnection) urlConnection)
-                    .setSSLSocketFactory(sslConfiguration.getSslContext().getSocketFactory());
+            final SSLContext sslContext = sslConfiguration.getSslContext();
+            if (sslContext != null) {
+                ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslContext.getSocketFactory());
+            }
         }
         if (isHttps && !verifyHostname) {
             ((HttpsURLConnection) urlConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
index f129b80fe4..f44132df6d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
@@ -35,6 +35,7 @@ import javax.mail.internet.MimeMessage;
 import javax.mail.internet.MimeMultipart;
 import javax.mail.internet.MimeUtility;
 import javax.mail.util.ByteArrayDataSource;
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
 import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.core.Layout;
@@ -308,9 +309,11 @@ public class SmtpManager extends MailManager {
             if (smtpProtocol.equals("smtps")) {
                 final SslConfiguration sslConfiguration = data.getSslConfiguration();
                 if (sslConfiguration != null) {
-                    final SSLSocketFactory sslSocketFactory =
-                            sslConfiguration.getSslContext().getSocketFactory();
-                    properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
+                    final SSLContext sslContext = sslConfiguration.getSslContext();
+                    if (sslContext != null) {
+                        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+                        properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
+                    }
                     properties.setProperty(
                             prefix + ".ssl.checkserveridentity", Boolean.toString(sslConfiguration.isVerifyHostName()));
                 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
index 4f28e57502..994f11bbce 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SslSocketManager.java
@@ -27,8 +27,10 @@ import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import org.apache.logging.log4j.core.Layout;
@@ -245,6 +247,7 @@ public class SslSocketManager extends TcpSocketManager {
      */
     private static String createSslConfigurationId(final SslConfiguration sslConfig) {
         return String.valueOf(Stream.of(sslConfig.getKeyStoreConfig(), sslConfig.getTrustStoreConfig())
+                .filter(Objects::nonNull)
                 .flatMap(keyStoreConfig -> {
                     final Enumeration<String> aliases;
                     try {
@@ -289,15 +292,13 @@ public class SslSocketManager extends TcpSocketManager {
     }
 
     private static SSLSocketFactory createSslSocketFactory(final SslConfiguration sslConf) {
-        SSLSocketFactory socketFactory;
-
         if (sslConf != null) {
-            socketFactory = sslConf.getSslContext().getSocketFactory();
-        } else {
-            socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+            final SSLContext sslContext = sslConf.getSslContext();
+            if (sslContext != null) {
+                return sslContext.getSocketFactory();
+            }
         }
-
-        return socketFactory;
+        return (SSLSocketFactory) SSLSocketFactory.getDefault();
     }
 
     private static class SslSocketManagerFactory extends TcpSocketManagerFactory<SslSocketManager, SslFactoryData> {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
index e98d3d9a9d..fe57d821d9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
@@ -28,6 +28,7 @@ import java.net.URLConnection;
 import java.util.Arrays;
 import java.util.List;
 import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
@@ -120,10 +121,13 @@ public class UrlConnectionFactory {
                 httpURLConnection.setIfModifiedSince(lastModifiedMillis);
             }
             if (url.getProtocol().equals(HTTPS) && sslConfiguration != null) {
-                ((HttpsURLConnection) httpURLConnection)
-                        .setSSLSocketFactory(sslConfiguration.getSslContext().getSocketFactory());
+                final SSLContext sslContext = sslConfiguration.getSslContext();
+                final HttpsURLConnection httpsURLConnection = (HttpsURLConnection) httpURLConnection;
+                if (sslContext != null) {
+                    httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
+                }
                 if (!sslConfiguration.isVerifyHostName()) {
-                    ((HttpsURLConnection) httpURLConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
+                    httpsURLConnection.setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
                 }
             }
             urlConnection = httpURLConnection;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
index cb24113bd9..41e2fc1031 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/ssl/SslConfiguration.java
@@ -54,6 +54,7 @@ public class SslConfiguration {
     @Nullable
     private final TrustStoreConfiguration trustStoreConfig;
 
+    @Nullable
     private final transient SSLContext sslContext;
 
     private SslConfiguration(
@@ -88,8 +89,9 @@ public class SslConfiguration {
      * @deprecated Use {@link SSLContext#getSocketFactory()} on {@link #getSslContext()}
      */
     @Deprecated
+    @Nullable
     public SSLSocketFactory getSslSocketFactory() {
-        return sslContext.getSocketFactory();
+        return sslContext != null ? sslContext.getSocketFactory() : null;
     }
 
     /**
@@ -99,10 +101,12 @@ public class SslConfiguration {
      * @deprecated Use {@link SSLContext#getServerSocketFactory()} on {@link #getSslContext()}
      */
     @Deprecated
+    @Nullable
     public SSLServerSocketFactory getSslServerSocketFactory() {
-        return sslContext.getServerSocketFactory();
+        return sslContext != null ? sslContext.getServerSocketFactory() : null;
     }
 
+    @Nullable
     private static SSLContext createDefaultSslContext(final String protocol) {
         try {
             return SSLContext.getDefault();
@@ -121,6 +125,7 @@ public class SslConfiguration {
         }
     }
 
+    @Nullable
     private static SSLContext createSslContext(
             final String protocol,
             @Nullable final KeyStoreConfiguration keyStoreConfig,
@@ -242,14 +247,17 @@ public class SslConfiguration {
         return verifyHostName;
     }
 
+    @Nullable
     public KeyStoreConfiguration getKeyStoreConfig() {
         return keyStoreConfig;
     }
 
+    @Nullable
     public TrustStoreConfiguration getTrustStoreConfig() {
         return trustStoreConfig;
     }
 
+    @Nullable
     public SSLContext getSslContext() {
         return sslContext;
     }
diff --git a/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
index ab1963ea23..f98457a410 100644
--- a/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
+++ b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
@@ -36,6 +36,7 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Date;
 import java.util.Properties;
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
 import org.apache.logging.log4j.LoggingException;
 import org.apache.logging.log4j.core.Layout;
@@ -262,9 +263,11 @@ public class SmtpManager extends MailManager {
             if (smtpProtocol.equals("smtps")) {
                 final SslConfiguration sslConfiguration = data.getSslConfiguration();
                 if (sslConfiguration != null) {
-                    final SSLSocketFactory sslSocketFactory =
-                            sslConfiguration.getSslContext().getSocketFactory();
-                    properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
+                    final SSLContext sslContext = sslConfiguration.getSslContext();
+                    if (sslContext != null) {
+                        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+                        properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
+                    }
                     properties.setProperty(
                             prefix + ".ssl.checkserveridentity", Boolean.toString(sslConfiguration.isVerifyHostName()));
                 }
diff --git a/src/changelog/.2.x.x/3947_fix_SslSocketManager_null_keystore.xml b/src/changelog/.2.x.x/3947_fix_SslSocketManager_null_keystore.xml
new file mode 100644
index 0000000000..3b0610d403
--- /dev/null
+++ b/src/changelog/.2.x.x/3947_fix_SslSocketManager_null_keystore.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+           https://logging.apache.org/xml/ns
+           https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+       type="fixed">
+    <issue id="3947" link="https://github.com/apache/logging-log4j2/issues/3947"/>
+    <description format="asciidoc">
+        Corrected nullability annotations in `SslConfiguration` which lead to nullability problems in consuming code.
+        In particular, when configuring a syslog appender, if only a truststore is defined, an exception is thrown during configuration time.
+        This fixes that error along with various other potential null errors in related code.
+    </description>
+</entry>