From 8d8afffc855657c41ae01d4372df5d09b9fe8f09 Mon Sep 17 00:00:00 2001
From: Matthew Vivian
Date: Tue, 19 Nov 2024 10:27:47 +0000
Subject: [PATCH 1/6] feat: Add option to enable certificate revocation checks
When enabled, certificates will be verified against Certificate Revocation Lists (CRL) and through Online Certificate Status Protocol (OCSP) to ensure they have not been revoked.
---
.../main/resources/openfire_i18n.properties | 1 +
.../keystore/OpenfireX509TrustManager.java | 16 ++++---
.../openfire/spi/ConnectionConfiguration.java | 18 ++++++-
.../openfire/spi/ConnectionListener.java | 47 +++++++++++++++++++
.../spi/EncryptionArtifactFactory.java | 10 ++--
.../webapp/connection-settings-advanced.jsp | 7 +++
.../keystore/CheckChainTrustedTest.java | 20 +++++---
.../OpenfireX509TrustManagerTest.java | 2 +-
.../LocalOutgoingServerSessionTest.java | 2 +-
9 files changed, 101 insertions(+), 22 deletions(-)
diff --git a/i18n/src/main/resources/openfire_i18n.properties b/i18n/src/main/resources/openfire_i18n.properties
index 7017cf18ff..19834d609c 100644
--- a/i18n/src/main/resources/openfire_i18n.properties
+++ b/i18n/src/main/resources/openfire_i18n.properties
@@ -1639,6 +1639,7 @@ connection.advanced.settings.certchain.boxtitle=Certificate chain checking
connection.advanced.settings.certchain.info=These options configure some aspects of the verification/validation of the certificates that are presented by peers while setting up encrypted connections.
connection.advanced.settings.certchain.label_selfsigned=Allow peer certificates to be self-signed.
connection.advanced.settings.certchain.label_validity=Verify that the certificate is currently valid (based on the 'notBefore' and 'notAfter' values of the certificate).
+connection.advanced.settings.certchain.label_revocation=Verify that certificates have not been revoked (by checking Certificate Revocation Lists and OCSP)
connection.advanced.settings.protocols.boxtitle=Encryption Protocols
connection.advanced.settings.protocols.info=These are all encryption protocols that this instance of Openfire supports. Those with a checked box are enabled, and can be used to establish an encrypted connection. Deselecting all values will cause a default to be restored.
connection.advanced.settings.protocols.sslv2hello.info=When setting up a new encrypted connection some encryption protocols allow you to have part of the handshake (the 'hello') encapsulated in an SSLv2 format. The SSLv2Hello option below controls this encapsulation. When enabled, incoming data may use the SSLv2 handshake format (but SSLv2 itself will never be allowed). When disabled, all incoming data must conform to the SSLv3/TLSv1 handshake format. All outgoing data (which applies to outbound server-to-server connections) will always conform to the SSLv3/TLSv1 format irrespective of this setting.
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java b/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java
index c5eacdfa59..cdf65a41f6 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java
@@ -30,8 +30,6 @@
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
-// TODO re-enable optional OCSP checking.
-// TODO re-enable CRL checking.
public class OpenfireX509TrustManager implements X509TrustManager
{
private static final Logger Log = LoggerFactory.getLogger( OpenfireX509TrustManager.class );
@@ -55,16 +53,22 @@ public class OpenfireX509TrustManager implements X509TrustManager
*/
private final boolean checkValidity;
+ /**
+ * A boolean that indicates if this trust manager will check revocation status of certificates.
+ */
+ private final boolean checkRevocation;
+
/**
* The set of trusted issuers from the trust store. Note that these certificates are not validated. It is assumed
* that this set can be long-lived. Time-based validation should occur close to the actual usage / invocation.
*/
protected final Set trustedIssuers;
- public OpenfireX509TrustManager( KeyStore trustStore, boolean acceptSelfSigned, boolean checkValidity ) throws NoSuchAlgorithmException, KeyStoreException
+ public OpenfireX509TrustManager( KeyStore trustStore, boolean acceptSelfSigned, boolean checkValidity, boolean checkRevocation ) throws NoSuchAlgorithmException, KeyStoreException
{
this.acceptSelfSigned = acceptSelfSigned;
this.checkValidity = checkValidity;
+ this.checkRevocation = checkRevocation;
// Retrieve all trusted certificates from the store, but don't validate them just yet!
final Set trusted = new HashSet<>();
@@ -85,7 +89,7 @@ public OpenfireX509TrustManager( KeyStore trustStore, boolean acceptSelfSigned,
trustedIssuers = Collections.unmodifiableSet( trusted );
- Log.debug( "Constructed trust manager. Number of trusted issuers: {}, accepts self-signed: {}, checks validity: {}", trustedIssuers.size(), acceptSelfSigned, checkValidity );
+ Log.debug( "Constructed trust manager. Number of trusted issuers: {}, accepts self-signed: {}, checks validity: {}, checks revocation: {}", trustedIssuers.size(), acceptSelfSigned, checkValidity, checkRevocation );
}
@Override
@@ -253,8 +257,8 @@ protected CertPath checkChainTrusted( CertSelector selector, X509Certificate...
// entire chain should now be in the store.
parameters.addCertStore( certificates );
- // When true, validation will fail if no CRLs are provided!
- parameters.setRevocationEnabled( false );
+ // When true, validation will fail if no OCSP staple, OCSP response, or CRLs, are provided
+ parameters.setRevocationEnabled(checkRevocation);
Log.debug( "Validating chain with {} certificates, using {} trust anchors.", chain.length, trustAnchors.size() );
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
index a5188f70e0..9984b1a69a 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
@@ -43,6 +43,7 @@ public class ConnectionConfiguration
private final CertificateStoreConfiguration trustStoreConfiguration;
private final boolean acceptSelfSignedCertificates;
private final boolean verifyCertificateValidity;
+ private final boolean verifyCertificateRevocation;
private final boolean strictCertificateValidation;
private final Set encryptionProtocols;
private final Set encryptionCipherSuites;
@@ -64,14 +65,15 @@ public class ConnectionConfiguration
* @param identityStoreConfiguration the certificates the server identify as
* @param trustStoreConfiguration the certificates the server trusts
* @param acceptSelfSignedCertificates {@code true} to accept self-signed certificates, otherwise {@code false}
- * @param verifyCertificateValidity {@code true} to accept self-signed certificates, otherwise {@code false}
+ * @param verifyCertificateValidity {@code true} to verify validity of certificates (based on their 'notBefore' and 'notAfter' property values), otherwise {@code false}
+ * @param verifyCertificateRevocation {@code true} to check certificate revocation status, otherwise {@code false}
* @param encryptionProtocols the set of protocols supported
* @param encryptionCipherSuites the set of ciphers supported
* @param compressionPolicy the compression policy
* @param strictCertificateValidation {@code true} to abort connections if certificate validation fails, otherwise {@code false}
*/
// TODO input validation
- public ConnectionConfiguration( ConnectionType type, boolean enabled, int maxThreadPoolSize, int maxBufferSize, Connection.ClientAuth clientAuth, InetAddress bindAddress, int port, Connection.TLSPolicy tlsPolicy, CertificateStoreConfiguration identityStoreConfiguration, CertificateStoreConfiguration trustStoreConfiguration, boolean acceptSelfSignedCertificates, boolean verifyCertificateValidity, Set encryptionProtocols, Set encryptionCipherSuites, Connection.CompressionPolicy compressionPolicy, boolean strictCertificateValidation )
+ public ConnectionConfiguration( ConnectionType type, boolean enabled, int maxThreadPoolSize, int maxBufferSize, Connection.ClientAuth clientAuth, InetAddress bindAddress, int port, Connection.TLSPolicy tlsPolicy, CertificateStoreConfiguration identityStoreConfiguration, CertificateStoreConfiguration trustStoreConfiguration, boolean acceptSelfSignedCertificates, boolean verifyCertificateValidity, boolean verifyCertificateRevocation, Set encryptionProtocols, Set encryptionCipherSuites, Connection.CompressionPolicy compressionPolicy, boolean strictCertificateValidation )
{
if ( maxThreadPoolSize <= 0 ) {
throw new IllegalArgumentException( "Argument 'maxThreadPoolSize' must be equal to or greater than one." );
@@ -92,6 +94,7 @@ public ConnectionConfiguration( ConnectionType type, boolean enabled, int maxThr
this.trustStoreConfiguration = trustStoreConfiguration;
this.acceptSelfSignedCertificates = acceptSelfSignedCertificates;
this.verifyCertificateValidity = verifyCertificateValidity;
+ this.verifyCertificateRevocation = verifyCertificateRevocation;
this.encryptionProtocols = Collections.unmodifiableSet( encryptionProtocols );
this.encryptionCipherSuites = Collections.unmodifiableSet( encryptionCipherSuites );
this.compressionPolicy = compressionPolicy;
@@ -173,6 +176,17 @@ public boolean isVerifyCertificateValidity()
return verifyCertificateValidity;
}
+ /**
+ * A boolean that indicates if the revocation status of certificates is checked when they are used to establish an
+ * encrypted connection.
+ *
+ * @return true when the revocation status of certificates is checked, otherwise false.
+ */
+ public boolean isVerifyCertificateRevocation()
+ {
+ return verifyCertificateRevocation;
+ }
+
/**
* A collection of protocol names that can be used for encryption of connections.
*
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionListener.java b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionListener.java
index 0dffd1528e..ada215029a 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionListener.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionListener.java
@@ -289,6 +289,7 @@ public ConnectionConfiguration generateConnectionConfiguration()
trustStoreConfiguration,
acceptSelfSignedCertificates(),
verifyCertificateValidity(),
+ verifyCertificateRevocation(),
getEncryptionProtocols(),
getEncryptionCipherSuites(),
getCompressionPolicy(),
@@ -803,6 +804,52 @@ public void setVerifyCertificateValidity( boolean verify )
restart();
}
+ /**
+ * Returns whether certificate revocation checking is enabled.
+ * When enabled, certificates will be verified against Certificate Revocation Lists (CRL)
+ * and through Online Certificate Status Protocol (OCSP) to ensure they have not been revoked.
+ *
+ * @return true if certificate revocation checking is enabled, false otherwise
+ */
+ public boolean verifyCertificateRevocation()
+ {
+ final String propertyName = type.getPrefix() + "certificate.verify.revocation";
+ final boolean defaultValue = true;
+
+ if ( type.getFallback() == null )
+ {
+ return JiveGlobals.getBooleanProperty( propertyName, defaultValue );
+ }
+ else
+ {
+ return JiveGlobals.getBooleanProperty( propertyName, getConnectionListener( type.getFallback() ).verifyCertificateRevocation() );
+ }
+ }
+
+ /**
+ * Sets whether certificate revocation checking should be enabled.
+ * When enabled, certificates will be verified against Certificate Revocation Lists (CRL)
+ * and through Online Certificate Status Protocol (OCSP) to ensure they have not been revoked.
+ *
+ * @param verify true to enable certificate revocation checking, false to disable it
+ */
+ public void setVerifyCertificateRevocation( boolean verify )
+ {
+ final boolean oldValue = verifyCertificateRevocation();
+
+ // Always set the property explicitly even if it appears the equal to the old value (the old value might be a fallback value).
+ JiveGlobals.setProperty( type.getPrefix() + "certificate.verify.revocation", Boolean.toString( verify ) );
+
+ if ( oldValue == verify )
+ {
+ Log.debug( "Ignoring certificate revocation verification configuration change request (to '{}'): listener already in this state.", verify );
+ return;
+ }
+
+ Log.debug( "Changing certificate revocation verification configuration from '{}' to '{}'.", oldValue, verify );
+ restart();
+ }
+
/**
* A collection of protocol names that can be used for encryption of connections.
*
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/EncryptionArtifactFactory.java b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/EncryptionArtifactFactory.java
index a070de30b1..b9247c43b1 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/EncryptionArtifactFactory.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/EncryptionArtifactFactory.java
@@ -152,15 +152,15 @@ public synchronized TrustManager[] getTrustManagers() throws KeyStoreException,
try
{
- Log.debug( "Attempting to instantiate '{}' using the three-argument constructor that is properietary to Openfire.", trustManagerClass );
- final Constructor constructor = trustManagerClass.getConstructor( KeyStore.class, Boolean.TYPE, Boolean.TYPE);
- final TrustManager trustManager = constructor.newInstance( configuration.getTrustStore().getStore(), configuration.isAcceptSelfSignedCertificates(), configuration.isVerifyCertificateValidity() );
+ Log.debug( "Attempting to instantiate '{}' using the four-argument constructor that is proprietary to Openfire.", trustManagerClass );
+ final Constructor constructor = trustManagerClass.getConstructor( KeyStore.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE );
+ final TrustManager trustManager = constructor.newInstance( configuration.getTrustStore().getStore(), configuration.isAcceptSelfSignedCertificates(), configuration.isVerifyCertificateValidity(), configuration.isVerifyCertificateRevocation() );
Log.debug( "Successfully instantiated '{}'.", trustManagerClass );
return new TrustManager[] { trustManager };
}
catch ( Exception e )
{
- Log.debug( "Unable to instantiate '{}' using the three-argument constructor that is properietary to Openfire. Trying to use a no-arg constructor instead...", trustManagerClass );
+ Log.debug( "Unable to instantiate '{}' using the four-argument constructor that is proprietary to Openfire. Trying to use a no-arg constructor instead...", trustManagerClass );
try
{
final TrustManager trustManager = trustManagerClass.newInstance();
@@ -171,7 +171,7 @@ public synchronized TrustManager[] getTrustManagers() throws KeyStoreException,
catch ( InstantiationException | IllegalAccessException ex )
{
Log.warn( "Unable to instantiate an instance of the configured Trust Manager implementation '{}'. Using {} instead.", trustManagerClass, OpenfireX509TrustManager.class, ex );
- return new TrustManager[] { new OpenfireX509TrustManager( configuration.getTrustStore().getStore(), configuration.isAcceptSelfSignedCertificates(), configuration.isVerifyCertificateValidity() )};
+ return new TrustManager[] { new OpenfireX509TrustManager( configuration.getTrustStore().getStore(), configuration.isAcceptSelfSignedCertificates(), configuration.isVerifyCertificateValidity(), configuration.isVerifyCertificateRevocation() )};
}
}
}
diff --git a/xmppserver/src/main/webapp/connection-settings-advanced.jsp b/xmppserver/src/main/webapp/connection-settings-advanced.jsp
index add878df30..3b396ea5b3 100644
--- a/xmppserver/src/main/webapp/connection-settings-advanced.jsp
+++ b/xmppserver/src/main/webapp/connection-settings-advanced.jsp
@@ -105,6 +105,7 @@
final int listenerMaxThreads = ParamUtils.getIntParameter( request, "maxThreads", configuration.getMaxThreadPoolSize() );
final boolean acceptSelfSignedCertificates = ParamUtils.getBooleanParameter( request, "accept-self-signed-certificates" );
final boolean verifyCertificateValidity = ParamUtils.getBooleanParameter( request, "verify-certificate-validity" );
+ final boolean verifyCertificateRevocation = ParamUtils.getBooleanParameter( request, "verify-certificate-revocation" );
final boolean strictCertificateValidation = ParamUtils.getBooleanParameter( request, "strict-certificate-validation" );
@@ -122,6 +123,7 @@
listener.setEncryptionCipherSuites( cipherSuites );
listener.setAcceptSelfSignedCertificates( acceptSelfSignedCertificates );
listener.setVerifyCertificateValidity( verifyCertificateValidity );
+ listener.setVerifyCertificateRevocation( verifyCertificateRevocation );
listener.setStrictCertificateValidation( strictCertificateValidation );
// Log the event
@@ -411,6 +413,11 @@
+
+
+
+
+
diff --git a/xmppserver/src/test/java/org/jivesoftware/openfire/keystore/CheckChainTrustedTest.java b/xmppserver/src/test/java/org/jivesoftware/openfire/keystore/CheckChainTrustedTest.java
index e8f8322436..080a0b4cad 100644
--- a/xmppserver/src/test/java/org/jivesoftware/openfire/keystore/CheckChainTrustedTest.java
+++ b/xmppserver/src/test/java/org/jivesoftware/openfire/keystore/CheckChainTrustedTest.java
@@ -39,14 +39,14 @@ public class CheckChainTrustedTest
* iterable returned here (its values are passed to the constructor of this class). This allows us to execute the
* same set of tests against a different configuration of the system under test.
*/
- @Parameterized.Parameters(name = "acceptSelfSignedCertificates={0},checkValidity={1}" )
+ @Parameterized.Parameters(name = "acceptSelfSignedCertificates={0},checkValidity={1},checkRevocation={2}")
public static Iterable
@@ -297,13 +298,178 @@
7. Configure Openfire
+
+
+
Certificate Revocation
+
+
This section covers the configuration of certificate revocation checking in Openfire, including OCSP
+ (Online Certificate Status Protocol) and CRL (Certificate Revocation List) mechanisms. This applies to
+ both roles that Openfire can assume in TLS connections:
Openfire supports three methods for checking certificate revocation status:
+
+
+
OCSP Stapling: The server attaches ("staples") the OCSP response to its certificate
+ during the TLS handshake.
+
+
Most efficient method
+
Reduces load on OCSP responders
+
Supported in both client and server roles
+
+
+
+
Client-driven OCSP: Direct OCSP responder queries to verify certificate status.
+
+
Real-time verification
+
Higher network overhead
+
Increased latency during TLS handshake
+
+
+
+
Certificate Revocation Lists (CRL): Downloadable lists of revoked certificates.
+
+
Periodic updates
+
Can be cached locally
+
Larger bandwidth requirements
+
Can be used as a fallback method
+
+
+
+
+
Configuring Revocation Checking
+
+
To enable certificate revocation checking:
+
+
+
Go to the Openfire admin console.
+
Navigate to "Server / Server Settings / Server to Server" or "Server / Server Settings / Client Connections".
+
In the "Certificate chain checking" section, locate the option labelled "Verify that certificates have not been revoked (by checking Certificate Revocation Lists and OCSP)".
+
Enable the option to verify certificates against Certificate Revocation Lists (CRL) and through Online Certificate Status Protocol (OCSP).
+
+
+
When this option is enabled, Openfire will check the revocation status of certificates used in server-to-server
+ (S2S) and client-to-server (C2S) connections to ensure they have not been revoked.
+
+
Fallback behavior when Openfire is the Client (S2S Connections)
+
+
When revocation checking is enabled, Openfire employs a multistep process to verify certificate validity
+ using both OCSP and CRLs. When Openfire acts as a client during the TLS handshake and receives certificates
+ from a server, it performs the following revocation checking process:
+
+
Check OCSP stapled response (if available)
+
Attempt client-driven OCSP query if no stapled response is present
+
Check CRL (if OCSP is unavailable)
+
Fail the connection if all methods fail
+
+
+
OCSP Stapling
+
+
Openfire, when operating as a TLS server and presenting its own certificate, will attempt to staple OCSP
+ responses when both of these conditions are met:
+
+
+
The certificate includes an OCSP responder URL in its Authority Info Access (AIA) extension.
+
The specified OCSP responder returns a valid (non-error) response.
+
+
+
If an OCSP response cannot be obtained, Openfire will present the certificate without an OCSP staple.
+ OCSP stapling improves performance by eliminating the need for clients to make separate requests to
+ verify certificate revocation status.
+
+
OCSP stapling is enabled by default. If you need to disable it for any reason, you can set the Java
+ system property jdk.tls.server.enableStatusRequestExtension to false.
+
+
+ The following configuration options allow you to customise OCSP stapling behavior:
+
+
+
+
+
Property
+
Description
+
Openfire Default Value
+
+
+
+
+
jdk.tls.server.enableStatusRequestExtension
+
Enables the server-side support for OCSP stapling.
+
True
+
+
+
jdk.tls.stapling.responseTimeout
+
+
Controls the maximum amount of time the server will use to obtain OCSP responses, whether from the cache or by contacting an OCSP responder.
+
The responses that are already received will be sent in a CertificateStatus message, if applicable based on the type of stapling being done.
+
+
5000 (integer value in milliseconds)
+
+
+
jdk.tls.stapling.cacheSize
+
+
Controls the maximum cache size in entries.
+
If the cache is full and a new response needs to be cached, then the least recently used cache entry will be replaced with the new one. A value of zero or less for this property means that the cache will have no upper bound on the number of responses it can contain.
+
+
256 objects
+
+
+
jdk.tls.stapling.cacheLifetime
+
+
Controls the maximum life of a cached response.
+
It is possible for responses to have shorter lifetimes than the value set with this property if the response has a nextUpdate field that expires sooner than the cache lifetime. A value of zero or less for this property disables the cache lifetime. If an object has no nextUpdate value and cache lifetimes are disabled, then the response will not be cached.
+
+
3600 seconds (1 hour)
+
+
+
jdk.tls.stapling.responderURI
+
+
Enables the administrator to set a default URI in the event that certificates used for TLS do not have the Authority Info Access (AIA) extension.
+
It will not override the Authority Info Access extension value unless the jdk.tls.stapling.responderOverride property is set.
+
+
Not set
+
+
+
jdk.tls.stapling.responderOverride
+
+
Enables a URI provided through the jdk.tls.stapling.responderURI property to override any AIA extension value.
+
+
False
+
+
+
jdk.tls.stapling.ignoreExtensions
+
+
Disables the forwarding of OCSP extensions specified in the status_request or status_request_v2 TLS extensions.
+
+
False
+
+
+
+
+
+
Other options
You can also use OpenSSL to create new private keys and generate certificate requests for your CA to issue new certificates.
Also, check out the new Certificate Manager plugin,
- which allows to setup a hotdeploy directory for new certificates deployment, which in turn combined with Let's Encrypt certbot
+ which allows to set up a hotdeploy directory for new certificates deployment, which in turn combined with Let's Encrypt certbot
allows dynamic certificates renewal without administrator intervention.
diff --git a/documentation/style.css b/documentation/style.css
index f7030e020e..78d7be49b1 100644
--- a/documentation/style.css
+++ b/documentation/style.css
@@ -338,6 +338,11 @@ fieldset {
right: .5em;
}
+table.general {
+ margin-top: 3em;
+ margin-left: 3em;
+ border : 1px #ccc solid;
+}
table.dbtable {
margin-top: 3em;
From 662c569bddaacdd4734cd5c06eb5e3cc70b0582a Mon Sep 17 00:00:00 2001
From: Matthew Vivian
Date: Fri, 22 Nov 2024 11:13:31 +0000
Subject: [PATCH 5/6] fix: Don't send error stanza for TLS handshake failures
Prior to this change, if the TLS handshake failed (e.g. if certificate validation did not succeed), an error stanza would be returned to the TLS client with the misleading message "An error occurred in XMPP Decoder".
---
.../openfire/nio/NettyXMPPDecoder.java | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyXMPPDecoder.java b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyXMPPDecoder.java
index f18c586005..77835e2e66 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyXMPPDecoder.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyXMPPDecoder.java
@@ -19,11 +19,12 @@
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.util.CharsetUtil;
+import io.netty.handler.codec.DecoderException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.StreamError;
+import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@@ -67,7 +68,22 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
final NettyConnection connection = ctx.channel().attr(CONNECTION).get();
+
+ if (isSslHandshakeError(cause)) {
+ connection.close();
+ return;
+ }
+
Log.warn("Error occurred while decoding XMPP stanza, closing connection: {}", connection, cause);
connection.close(new StreamError(StreamError.Condition.internal_server_error, "An error occurred in XMPP Decoder"), cause instanceof IOException);
}
+
+ private boolean isSslHandshakeError(Throwable t) {
+ // Unwrap DecoderException to check for potential SSLHandshakeException
+ if (t instanceof DecoderException) {
+ t = t.getCause();
+ }
+
+ return (t instanceof SSLHandshakeException);
+ }
}
From a2e3af55e3e500c413ae763fdbe3a860a9129dee Mon Sep 17 00:00:00 2001
From: Matthew Vivian
Date: Fri, 22 Nov 2024 11:18:01 +0000
Subject: [PATCH 6/6] feat: Add notice when revocation is enabled but
client-driven OCSP is not
If Openfire is configured to do revocation checking, but Java is configured to not support client-driven OCSP checking, we now inform the user.
---
i18n/src/main/resources/openfire_i18n.properties | 1 +
.../openfire/spi/ConnectionConfiguration.java | 16 ++++++++++++++++
.../main/webapp/connection-settings-advanced.jsp | 6 ++++++
3 files changed, 23 insertions(+)
diff --git a/i18n/src/main/resources/openfire_i18n.properties b/i18n/src/main/resources/openfire_i18n.properties
index 19834d609c..8ba35a229c 100644
--- a/i18n/src/main/resources/openfire_i18n.properties
+++ b/i18n/src/main/resources/openfire_i18n.properties
@@ -1635,6 +1635,7 @@ connection.advanced.settings.clientauth.label_disabled=Disabled - Peer ce
connection.advanced.settings.clientauth.label_wanted=Wanted - Peer certificates are verified, but only when they are presented by the peer.
connection.advanced.settings.clientauth.label_needed=Needed - A connection cannot be established if the peer does not present a valid certificate.
connection.advanced.settings.clientauth.label_strict_cert_validation=If attempting to validate a certificate fails, the connection is closed and not attempted via dialback authentication.
+connection.advanced.settings.certchain.ocsp.warning=Your server is configured with the Java security property ocsp.enable=false which disables client-driven OCSP certificate revocation checking. While OCSP stapling validation and CRL checking remain active, Openfire will not perform direct OCSP requests to verify certificate status.
connection.advanced.settings.certchain.boxtitle=Certificate chain checking
connection.advanced.settings.certchain.info=These options configure some aspects of the verification/validation of the certificates that are presented by peers while setting up encrypted connections.
connection.advanced.settings.certchain.label_selfsigned=Allow peer certificates to be self-signed.
diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
index 9984b1a69a..24bcf49272 100644
--- a/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
+++ b/xmppserver/src/main/java/org/jivesoftware/openfire/spi/ConnectionConfiguration.java
@@ -20,6 +20,7 @@
import org.jivesoftware.openfire.keystore.*;
import java.net.InetAddress;
+import java.security.Security;
import java.util.*;
/**
@@ -50,6 +51,7 @@ public class ConnectionConfiguration
private final Connection.CompressionPolicy compressionPolicy;
// derived
+ private final boolean isOcspEnabled;
private final IdentityStore identityStore;
private final TrustStore trustStore;
@@ -100,6 +102,7 @@ public ConnectionConfiguration( ConnectionType type, boolean enabled, int maxThr
this.compressionPolicy = compressionPolicy;
this.strictCertificateValidation = strictCertificateValidation;
+ this.isOcspEnabled = Boolean.parseBoolean(Security.getProperty("ocsp.enable"));
final CertificateStoreManager certificateStoreManager = XMPPServer.getInstance().getCertificateStoreManager();
this.identityStore = certificateStoreManager.getIdentityStore( type );
this.trustStore = certificateStoreManager.getTrustStore( type );
@@ -229,6 +232,19 @@ public TrustStore getTrustStore()
return trustStore;
}
+ /**
+ * Indicates if client-driven Online Certificate Status Protocol (OCSP) is enabled.
+ *
+ * This is a prerequisite to enable client-driven OCSP, it has no effect unless revocation
+ * checking is also enabled.
+ *
+ * @return true if client-driven OCSP is enabled, otherwise false.
+ */
+ public boolean isOcspEnabled()
+ {
+ return isOcspEnabled;
+ }
+
public boolean isEnabled()
{
return enabled;
diff --git a/xmppserver/src/main/webapp/connection-settings-advanced.jsp b/xmppserver/src/main/webapp/connection-settings-advanced.jsp
index 3b396ea5b3..1641d49d1e 100644
--- a/xmppserver/src/main/webapp/connection-settings-advanced.jsp
+++ b/xmppserver/src/main/webapp/connection-settings-advanced.jsp
@@ -310,6 +310,12 @@
+
+
+
+
+
+