diff --git a/distribution/src/bin/openfire.sh b/distribution/src/bin/openfire.sh index 1953f5a65e..77ed83b16f 100644 --- a/distribution/src/bin/openfire.sh +++ b/distribution/src/bin/openfire.sh @@ -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 diff --git a/distribution/src/security/java.security b/distribution/src/security/java.security index a7cb6b7a44..8a1a6f7feb 100644 --- a/distribution/src/security/java.security +++ b/distribution/src/security/java.security @@ -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 diff --git a/documentation/ssl-guide.html b/documentation/ssl-guide.html index db7e4903e2..81b223be68 100644 --- a/documentation/ssl-guide.html +++ b/documentation/ssl-guide.html @@ -374,10 +374,20 @@

Fallback behavior when Openfire is the Client (S2S Connections)

  1. Check OCSP stapled response (if available)
  2. Attempt client-driven OCSP query if no stapled response is present
  3. -
  4. Check CRL (if OCSP is unavailable)
  5. -
  6. Fail the connection if all methods fail
  7. +
  8. Check CRL (if OCSP is unavailable, and CRL is available)
  9. +
  10. Allow the connection to succeed if the revocation status cannot be determined
+

The system property xmpp.socket.ssl.certificate.revocation.soft-fail controls the behavior when + revocation status cannot be determined. The default value of this property is false 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 true. When set to true, the + connection will be allowed if a certificate's revocation status cannot be established.

+ +

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 xmpp.socket.ssl.certificate.revocation.only-end-entity to true.

+

OCSP Stapling

Openfire, when operating as a TLS server and presenting its own certificate, will attempt to staple OCSP diff --git a/i18n/src/main/resources/openfire_i18n.properties b/i18n/src/main/resources/openfire_i18n.properties index 1cca96b52a..ca3d8b648f 100644 --- a/i18n/src/main/resources/openfire_i18n.properties +++ b/i18n/src/main/resources/openfire_i18n.properties @@ -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. 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 cdf65a41f6..924b7a79d8 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/keystore/OpenfireX509TrustManager.java @@ -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. * @@ -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 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); + } + try { // Finally, construct (and implicitly validate) the certificate path. diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/session/ConnectionSettings.java b/xmppserver/src/main/java/org/jivesoftware/openfire/session/ConnectionSettings.java index 4b13cc8617..13f652987d 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/session/ConnectionSettings.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/session/ConnectionSettings.java @@ -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 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 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";