PHP can open TLS connections, but it can't read one piece of data that some login protocols need: the TLS channel binding. Sjoerd Langkemper's RFC adds openssl_get_channel_binding() to fill that gap.

Channel binding ties a login to the TLS connection it runs over. If an attacker relays your TLS connection, they can't relay the login along with it. SASL, the login layer used by mail, XMPP and database servers, uses it in the SCRAM-SHA-*-PLUS mechanisms. PHP libraries already speak SCRAM, but only the versions without -PLUS, because PHP gives them no way to get the binding data. The RFC names PEAR's Auth_SASL, Roundcube, SnappyMail and Horde among the code that would use it. The request started as php-src issue #16766.

How it works

You pass a connected TLS stream and the binding type you want:

$binding = openssl_get_channel_binding(
    $stream,
    Openssl\ChannelBindingType::TlsUnique,
);

if ($binding === null) {
    // tls-unique is not defined for TLS 1.3; use tls-exporter instead.
    $binding = openssl_get_channel_binding(
        $stream,
        Openssl\ChannelBindingType::TlsExporter,
    );
}

// SCRAM sends the binding data base64-encoded.
$cb = base64_encode($binding);

The new Openssl\ChannelBindingType enum has one case for each type the TLS standards define:

  • TlsUnique (tls-unique) is for TLS 1.2 and earlier. On TLS 1.3, where it isn't defined, the function returns null.
  • TlsServerEndPoint (tls-server-end-point) is a digest of the server's certificate.
  • TlsExporter (tls-exporter) is the TLS 1.3 type. It also works on TLS 1.2 when OpenSSL supports it.

The enum is backed by the official IANA names, so $type->value can go straight into SASL code, and ChannelBindingType::from() turns a name from your config into a case. The function returns raw bytes. Calling it on a stream without TLS throws an Openssl\OpensslException.

It takes a connected stream, not a stream context, because one context can open many connections. It works on both the client and the server side.

What it means for existing code

Nothing changes for existing code. The function and the enum are new, and they only exist when ext/openssl is loaded. Code that declares its own openssl_get_channel_binding() would clash, but none is known. You can't polyfill it in plain PHP, since only the TLS library has the data.

Where it stands

Sjoerd Langkemper announced the RFC on internals on October 27, 2026 (thread), targeting PHP 8.7. Pull request #24035 has tests for TLS 1.2 and 1.3. It still takes a string for the type and will switch to the enum before a vote. In the discussion, Tim Düsterhus asked whether an unsupported type should throw instead of returning null. Sjoerd said he sees the appeal of a dedicated exception, so that detail may change. Acceptance needs a two-thirds majority. No vote has been scheduled yet.