Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Improve certificate revocation checking #2626

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions distribution/src/bin/openfire.sh
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ OPENFIRE_OPTS="${OPENFIRE_OPTS} -Djava.security.properties=${OPENFIRE_HOME}/reso
# Enable OCSP Stapling
OPENFIRE_OPTS="${OPENFIRE_OPTS} -Djdk.tls.server.enableStatusRequestExtension=true"

# Enable the CRL Distribution Points extension
OPENFIRE_OPTS="${OPENFIRE_OPTS} -Dcom.sun.security.enableCRLDP=true"

JAVACMD="${JAVACMD} -Dlog4j.configurationFile=${OPENFIRE_LIB}/log4j2.xml -Dlog4j2.formatMsgNoLookups=true -Djdk.tls.ephemeralDHKeySize=matched -Djsse.SSLEngine.acceptLargeFragments=true -Djava.net.preferIPv6Addresses=system"

if [ -z "$LOCALCLASSPATH" ] ; then
Expand Down
3 changes: 3 additions & 0 deletions distribution/src/security/java.security
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# Permit client-driven OCSP (has no effect unless revocation checking is also enabled)
ocsp.enable=true

# Enable CRL Distribution Points extension in certificates (download CRL from URL in certificate)
org.bouncycastle.x509.enableCRLDP=true
14 changes: 12 additions & 2 deletions documentation/ssl-guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,20 @@ <h4>Fallback behavior when Openfire is the Client (S2S Connections)</h4>
<ol>
<li>Check OCSP stapled response (if available)</li>
<li>Attempt client-driven OCSP query if no stapled response is present</li>
<li>Check CRL (if OCSP is unavailable)</li>
<li>Fail the connection if all methods fail</li>
<li>Check CRL (if OCSP is unavailable, and CRL is available)</li>
<li>Allow the connection to succeed if the revocation status cannot be determined</li>
</ol>

<p>The system property <code>xmpp.socket.ssl.certificate.revocation.soft-fail</code> controls the behavior when
revocation status cannot be determined. The default value of this property is <code>false</code> which fails
the connection if the revocation status of a certificate cannot be determined. If you want to relax
revocation checking, you can set this property to <code>true</code>. When set to <code>true</code>, the
connection will be allowed if a certificate's revocation status cannot be established.</p>

<p>By default, revocation checking considers the entire certificate chain. If you want to limit revocation
checking to only the leaf certificate in a chain you can set the system
property <code>xmpp.socket.ssl.certificate.revocation.only-end-entity</code> to <code>true</code>.</p>

<h4>OCSP Stapling</h4>

<p>Openfire, when operating as a TLS server and presenting its own certificate, will attempt to staple OCSP
Expand Down
2 changes: 2 additions & 0 deletions i18n/src/main/resources/openfire_i18n.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,8 @@ system_property.xmpp.auth.ssl.context_protocol=The TLS protocol to use for encry
system_property.xmpp.parser.buffer.size=Maximum size of an XMPP stanza. Larger stanzas will cause a connection to be closed.
system_property.xmpp.auth.ssl.enforce_sni=Controls if the server enforces the use of SNI (Server Name Indication) when clients connect using TLS.
system_property.xmpp.socket.ssl.active=Set to true to enable Direct TLS encrypted connections for clients, otherwise false
system_property.xmpp.socket.ssl.certificate.revocation.only-end-entity=Only verify revocation status of end-entity (leaf) certificates
system_property.xmpp.socket.ssl.certificate.revocation.soft-fail=Allow validation to continue if revocation information is unavailable
system_property.xmpp.socket.write-timeout-seconds=The write timeout time in seconds to handle stalled sessions and prevent DoS
system_property.xmpp.component.ssl.active=Set to true to enable Direct TLS encrypted connections for external components, otherwise false
system_property.xmpp.server.startup.retry.delay=Set to a positive value to allow a retry of a failed startup after the specified duration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import java.security.cert.Certificate;
import java.util.*;

import static org.jivesoftware.openfire.session.ConnectionSettings.Server.REVOCATION_CHECK_ONLY_END_ENTITY;
import static org.jivesoftware.openfire.session.ConnectionSettings.Server.REVOCATION_SOFT_FAIL;

/**
* A Trust Manager implementation that adds Openfire-proprietary functionality.
*
Expand Down Expand Up @@ -274,6 +277,31 @@ protected CertPath checkChainTrusted( CertSelector selector, X509Certificate...
pathBuilder = CertPathBuilder.getInstance( "PKIX" );
}

if (checkRevocation) {
// Configure revocation checking - using default OCSP preference (OCSP before CRL)
PKIXRevocationChecker revChecker = (PKIXRevocationChecker)pathBuilder.getRevocationChecker();

EnumSet<PKIXRevocationChecker.Option> options = EnumSet.noneOf(PKIXRevocationChecker.Option.class);

// When enabled, only validates revocation status for end-entity (leaf) certificates
// and skips intermediate/root certificate checks. This helps avoid validation failures
// when Certificate Revocation Lists (CRLs) or OCSP responders are unavailable or unreachable
// for CA certificates in the chain.
if (REVOCATION_CHECK_ONLY_END_ENTITY.getValue()) {
options.add(PKIXRevocationChecker.Option.ONLY_END_ENTITY);
}

// Allow validation to continue if revocation information is unavailable, if configured
// This prevents failures when OCSP/CRL servers are unreachable or when revocation
// information isn't available for some certificates
if (REVOCATION_SOFT_FAIL.getValue()) {
options.add(PKIXRevocationChecker.Option.SOFT_FAIL);
}

revChecker.setOptions(options);
parameters.addCertPathChecker(revChecker);
guusdk marked this conversation as resolved.
Show resolved Hide resolved
}

try
{
// Finally, construct (and implicitly validate) the certificate path.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,30 @@ public static final class Server {
public static final String TLS_CERTIFICATE_CHAIN_VERIFY = "xmpp.server.certificate.verify.chain";
public static final String TLS_ON_PLAIN_DETECTION_ALLOW_NONDIRECTTLS_FALLBACK = "xmpp.server.tls.on-plain-detection-allow-nondirecttls-fallback";

/**
* Only verify revocation status of end-entity (leaf) certificates.
*
* This avoids issues with chains where CRL information isn't accessible
* for intermediate certificates.
*/
public static final SystemProperty<Boolean> REVOCATION_CHECK_ONLY_END_ENTITY = SystemProperty.Builder.ofType(Boolean.class)
.setKey("xmpp.socket.ssl.certificate.revocation.only-end-entity")
.setDefaultValue(false)
.setDynamic(true)
.build();

/**
* Allow validation to continue if revocation information is unavailable.
*
* This prevents failures when OCSP/CRL servers are unreachable or when revocation
* information isn't available for some certificates.
*/
public static final SystemProperty<Boolean> REVOCATION_SOFT_FAIL = SystemProperty.Builder.ofType(Boolean.class)
.setKey("xmpp.socket.ssl.certificate.revocation.soft-fail")
.setDefaultValue(false)
.setDynamic(true)
.build();

public static final String COMPRESSION_SETTINGS = "xmpp.server.compression.policy";

public static final String PERMISSION_SETTINGS = "xmpp.server.permission";
Expand Down
Loading