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 <[email protected]>
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>

Reply via email to