Skip to content

OF-2694 & OF-2879: Add Channel binding support & implement XEP-0440#3282

Open
guusdk wants to merge 9 commits intoigniterealtime:mainfrom
guusdk:OF-2694_Channel-Binding
Open

OF-2694 & OF-2879: Add Channel binding support & implement XEP-0440#3282
guusdk wants to merge 9 commits intoigniterealtime:mainfrom
guusdk:OF-2694_Channel-Binding

Conversation

@guusdk
Copy link
Copy Markdown
Member

@guusdk guusdk commented Apr 21, 2026

Please refer to individual commit messages, but this adds an implementation for Channel Binding support, by:

  • making available a pluggable manager/provider mechanism (like Openfire has for various other bits of functionality
  • an implementation for tls-server-end-point
  • very basic integration into NettyConnection

This still lacks actual SASL support, and probably a couple of other things. I'm creating this PR as I'm looking for feedback (after churning way to much time on this).

After much experimentation, I've given up on tls-exporter as a native thing in Openfire. The Java-native route requires Java 25 (where Openfire can go as low as 17), and BouncyCastle is giving me more nightmares.

With this manager/provider mechanism, you can create a plugin that implements tls-exporter. As plugins can define a minimum Java version of their own, that can be leveraged to get tls-exporter in deployments that run on Java 25. I've got a simple plugin in the works (not included here). I have tried implementing tls-exporter in Openfire directly, by using Java reflection to dynamically detect support for the API that was added in Java 25 (in an attempt to be able to include code that would be compatible yet not functional with Java 17), but I ran into problems with that approach. Notably, the added security layers with Java modules, made it all more messy than I am comfortable with.

The tls-server-end-point implementation was trickier than I thought, but at least we can do that in Openfire directly. I've refactored my earlier implementation to make use of that same provider mechanism, for consistency. That's included in this PR.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a pluggable channel-binding mechanism to Openfire, including a built-in tls-server-end-point implementation and initial wiring into Netty-based connections.

Changes:

  • Introduces ChannelBindingProvider + ChannelBindingProviderManager to register and resolve channel binding data by RFC-defined prefix.
  • Implements tls-server-end-point channel binding (RFC 5929) based on the server certificate hash, including RSASSA-PSS parameter parsing.
  • Exposes channel binding retrieval via Connection#getChannelBindingData(...) and implements it in NettyConnection, with unit tests for both manager and provider.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
xmppserver/src/main/java/org/jivesoftware/util/channelbinding/ChannelBindingProvider.java New SPI for channel binding extraction (per type/prefix).
xmppserver/src/main/java/org/jivesoftware/util/channelbinding/ChannelBindingProviderManager.java New singleton manager for registering and querying providers.
xmppserver/src/main/java/org/jivesoftware/util/channelbinding/ChannelBindingType.java New enum for well-known channel binding prefixes.
xmppserver/src/main/java/org/jivesoftware/util/channelbinding/TlsServerEndPointChannelBindingProvider.java Implements RFC 5929 tls-server-end-point computation.
xmppserver/src/main/java/org/jivesoftware/openfire/Connection.java Adds default getChannelBindingData(cbPrefix) API.
xmppserver/src/main/java/org/jivesoftware/openfire/nio/NettyConnection.java Implements channel binding retrieval using the Netty SslHandler SSLEngine.
xmppserver/src/test/java/org/jivesoftware/util/channelbinding/ChannelBindingProviderManagerTest.java Tests provider registration/ordering and lookup behavior.
xmppserver/src/test/java/org/jivesoftware/util/channelbinding/TlsServerEndPointChannelBindingProviderTest.java Tests hashing behavior and algorithm resolution/normalization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@guusdk guusdk force-pushed the OF-2694_Channel-Binding branch from 95566f9 to 18c31e9 Compare April 21, 2026 20:08
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented Apr 21, 2026

The first round of copilot's reviews were all pretty minor: unused import, input validation and white space changes, things like that. I've applied the changes to the original commit, and force-pushed those.

@guusdk guusdk changed the title OF-2694: Add Channel binding support OF-2694 & OF-2879: Add Channel binding support & implement XEP-0440 Apr 22, 2026
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented Apr 22, 2026

I have now added support for exposing channel binding capable mechanisms through Openfire's SASL mechanism, and added one such mechanism: SCRAM-SHA-1-PLUS.

The new mechanism is advertised by default (unless configured otherwise, through preexisting options in the admin console).

Additionally, I've added support for XEP-0440: SASL Channel-Binding Type Capability as tracked by OF-2879.

I have tested the native support in Openfire of the tls-server-endpoint channel binding type with the Conversations client, which seems to work. Removing the mechanism causes the client to warn about downgrades, which is expected. I've also tested with a plugin (not included in this PR) that implements tls-exporter - that was successful, too.

image image

I'm unmarking this PR as draft. It is ready for review.

@guusdk guusdk marked this pull request as ready for review April 22, 2026 16:34
@akrherz akrherz requested a review from Copilot April 22, 2026 16:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread xmppserver/src/main/java/org/jivesoftware/openfire/net/SASLAuthentication.java Outdated
Comment thread xmppserver/src/main/java/org/jivesoftware/openfire/sasl/ScramSha1SaslServer.java Outdated
Comment thread i18n/src/main/resources/openfire_i18n_nl.properties Outdated
@guusdk guusdk force-pushed the OF-2694_Channel-Binding branch 2 times, most recently from a8d2268 to 79cce45 Compare April 22, 2026 18:30
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented Apr 23, 2026

I have added a companion plugin to this work, here: https://github.com/igniterealtime/openfire-tlsexportercb-plugin

This plugin uses the framework that is introduced in this PR. It adds the tls-exporter channel binding, making that available to Openfire if it is running with Java 25 or later.

@guusdk guusdk changed the title OF-2694 & OF-2879: Add Channel binding support & implement XEP-0440 OF-2694, OF-2879, OF-3257: Add Channel binding support & implement XEP-0440 Apr 23, 2026
@guusdk guusdk changed the title OF-2694, OF-2879, OF-3257: Add Channel binding support & implement XEP-0440 OF-2694 & OF-2879: Add Channel binding support & implement XEP-0440 Apr 23, 2026
@guusdk guusdk force-pushed the OF-2694_Channel-Binding branch from 64891a7 to ce2d1a5 Compare April 23, 2026 19:18
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented Apr 23, 2026

This PR briefly had a commit that improves the reesilience of the SCARM-SHA-1 SASL implementation. I have now separated out those changes into distinct PRs:

Copy link
Copy Markdown
Member

@Fishbowler Fishbowler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ace! The comments are enough to put all the pieces together, even for a muggle like me.

A few comments, but all typographical in nature.

I've read every line, it all makes sense, but I've not run any tests on this yet.

Comment thread i18n/src/main/resources/openfire_i18n.properties
Comment thread xmppserver/src/main/java/org/jivesoftware/openfire/net/SASLAuthentication.java Outdated
Comment thread xmppserver/src/main/java/org/jivesoftware/openfire/net/SASLAuthentication.java Outdated
Comment thread xmppserver/src/main/java/org/jivesoftware/openfire/sasl/ScramSha1SaslServer.java Outdated
@guusdk guusdk force-pushed the OF-2694_Channel-Binding branch from ce2d1a5 to f790903 Compare April 27, 2026 07:00
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented Apr 27, 2026

I have addressed all suggestions from @Fishbowler (which were mostly spelling/text changes). I have also rebased this on Main now that #3288 was merged there.

guusdk added 7 commits May 5, 2026 12:05
Add a channel binding abstraction consisting of:

- ChannelBindingProvider interface for extracting channel binding data from an SSLEngine
- ChannelBindingProviderManager to register, manage, and resolve providers per channel binding type
- ChannelBindingType enum defining RFC-aligned binding identifiers
- Comprehensive unit tests covering provider registration, ordering, resolution, and failure handling

This introduces a best-effort mechanism to obtain channel binding data (as defined in RFC 5705, RFC 5929, and RFC 9266) without introducing hard dependencies on a specific TLS implementation or JDK version.

The manager maintains an ordered list of providers per channel binding type and iterates through them until one successfully produces a value. Failures are isolated per provider, ensuring graceful degradation.

Why this is needed

Channel binding support is highly dependent on the capabilities of the underlying TLS stack and JDK version. Some mechanisms (notably newer exporter-based bindings) are difficult or effectively impossible to implement on older Java versions (e.g., Java 17), even when using reflection.

At the same time, increasing the minimum required Java version for Openfire is undesirable, as it would negatively impact existing deployments.

This change introduces a "manager/provider" pattern that:

- Aligns with existing extensibility mechanisms used elsewhere in the codebase
- Enables runtime discovery and prioritization of multiple implementations
- Allows third parties to contribute additional providers via plugins

Crucially, this design decouples channel binding support from the core runtime:

- Core Openfire can remain compatible with Java 17
- Optional plugins can provide advanced implementations that depend on newer Java versions (e.g., Java 25+)

These plugins can register their providers with the manager at runtime, seamlessly extending functionality without impacting baseline compatibility
…tion

Introduce TlsServerEndPointChannelBindingProvider, an implementation of ChannelBindingProvider for the tls-server-end-point channel binding type as defined in RFC 5929.

Implements logic to select the appropriate hash algorithm based on certificate signature algorithm, with special handling for RSASSA-PSS and weak hashes.
Expose per-connection channel binding data retrieval for SASL.
…ault

This registers the corresponding provider without any ceremony. Future modifications could introduce configurability, but as support for this channel binding is mandatory per XEP, hard-coding seems acceptable.
Introduces SCRAM-SHA-1-PLUS SASL mechanism, implementing RFC 5802 channel binding for TLS.

Advertise SCRAM-SHA-1-PLUS by default, but only when channel binding is available and session is encrypted.
With Channel Binding now available (as this commit follows commits that implements these under OF-2694), Openfire should announce what type of channel binding types it supports. The mechanism for this is define in XEP-0440. This commit implements this mechanism.

Additionally, the channel binding type that is used for a session (if any) is now shown on its 'session details' page on the admin console.
…rage

This adds more validation of the exchanged data in the SASL handshake, and adds more unit test coverage.

Small refactorings have been applied to make ScramSha1SaslServer easier to unit-test. It now no longer unconditionally uses static calls to other classes. Such classes can be provided via a `@VisibleForTesting` constructor.
guusdk added 2 commits May 5, 2026 12:08
…when channel binding is supported

Refactored SASL mechanism advertisement logic to ensure that -PLUS mechanisms (e.g., SCRAM-SHA-1-PLUS) are only offered when the current connection supports channel binding. The check now relies on Connection#getSupportedChannelBindingTypes(), which must return a non-empty set for -PLUS mechanisms to be advertised.

Updated all relevant connection implementations (only NettyConnection, and the default method in the Connection interface) to ensure correct reporting of supported channel binding types.

This change prevents authentication failures caused by advertising -PLUS mechanisms on connections that cannot provide channel binding data (e.g., WebSocket connections).
This addresses various typos and spelling issues. None of these are functionally changing anything.
@guusdk guusdk force-pushed the OF-2694_Channel-Binding branch from f790903 to b292378 Compare May 5, 2026 10:09
@guusdk
Copy link
Copy Markdown
Member Author

guusdk commented May 5, 2026

I've rebased this to HEAD of Main, after merging changes for OF-3257 and OF-3258.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants