Skip to content

Implement channel binding support on Unix - #130758

Merged
rzikm merged 21 commits into
dotnet:mainfrom
rzikm:feature/gssapi-server-channel-bindings
Jul 23, 2026
Merged

Implement channel binding support on Unix#130758
rzikm merged 21 commits into
dotnet:mainfrom
rzikm:feature/gssapi-server-channel-bindings

Conversation

@rzikm

@rzikm rzikm commented Jul 15, 2026

Copy link
Copy Markdown
Member

Adds a new NetSecurityNative_AcceptSecContextEx native shim that takes a
channel binding token (the application data portion of the SecChannelBindings
buffer) and forwards it to gss_accept_sec_context via a
gss_channel_bindings_struct.

The managed NegotiateAuthenticationPal.Unix server path now passes
_channelBinding into AcceptSecurityContext, which dispatches to the
cbt-aware overload when bindings are present. GSSAPI surfaces a binding
mismatch as GSS_S_BAD_BINDINGS so no additional validation is required
on the managed side, matching the existing client (initiator) behavior.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

rzikm and others added 2 commits April 28, 2026 12:08
…Unix

Adds a new `NetSecurityNative_AcceptSecContextEx` native shim that takes a
channel binding token (the application data portion of the `SecChannelBindings`
buffer) and forwards it to `gss_accept_sec_context` via a
`gss_channel_bindings_struct`. The pre-existing `NetSecurityNative_AcceptSecContext`
shim now delegates to the new entry point with NULL bindings to preserve
backward compatibility for in-place servicing.

The managed `NegotiateAuthenticationPal.Unix` server path now passes
`_channelBinding` into `AcceptSecurityContext`, which dispatches to the
cbt-aware overload when bindings are present. GSSAPI surfaces a binding
mismatch as `GSS_S_BAD_BINDINGS` so no additional validation is required
on the managed side, matching the existing client (initiator) behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds four functional tests using KerberosExecutor (in-process KDC) that
verify GSSAPI server-side channel binding token enforcement:

* ChannelBindings_Matching_{Endpoint,Unique}_Succeeds confirm authentication
  succeeds when client and server present matching bindings.
* ChannelBindings_Mismatched_{Endpoint,Unique}_FailsWithBadBinding confirm
  the server returns NegotiateAuthenticationStatusCode.BadBinding when the
  bindings differ.

Without the prior implementation change the mismatch tests fail with
status=Completed (no enforcement); with the fix they observe BadBinding.

The new file is conditionally compiled for non-Windows targets only,
matching the visibility of SafeChannelBindingHandle. The companion sources
(SafeChannelBindingHandle.cs, SecChannelBindings.cs) are added as Compile
items to the test csproj for the same target conditions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 15, 2026 08:10
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/ncl, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends Unix (GSSAPI) Negotiate/Kerberos server-side authentication to support TLS channel bindings by plumbing a channel binding token (CBT) from managed NegotiateAuthenticationPal.Unix into a new native shim (NetSecurityNative_AcceptSecContextEx) that forwards bindings to gss_accept_sec_context.

Changes:

  • Add a new native export NetSecurityNative_AcceptSecContextEx and keep the existing NetSecurityNative_AcceptSecContext as a compatibility wrapper.
  • Update the Unix managed server path to pass _channelBinding into AcceptSecurityContext, dispatching to the CBT-aware native entrypoint when present.
  • Add Unix-only functional tests validating matching vs. mismatched channel bindings for Kerberos (endpoint/unique).

Reviewed changes

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

Show a summary per file
File Description
src/native/libs/System.Net.Security.Native/pal_gssapi.h Declares the new CBT-aware AcceptSecContext native shim.
src/native/libs/System.Net.Security.Native/pal_gssapi.c Implements NetSecurityNative_AcceptSecContextEx and makes the legacy entrypoint delegate to it with no bindings.
src/native/libs/System.Net.Security.Native/entrypoints.c Exposes the new native export via the resolver table.
src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs Adds LibraryImport for NetSecurityNative_AcceptSecContextEx and an internal wrapper overload.
src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs Plumbs server-side channel binding into AcceptSecurityContext; maps GSS_S_BAD_BINDINGS to BadBinding.
src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj Includes the new Unix-only channel binding test file and links production CBT helper types for tests.
src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateAuthenticationKerberosTest.cs Makes the Kerberos test class partial to allow adding a new test file.
src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateAuthenticationKerberosTest.ChannelBindings.cs Adds functional tests for matching/mismatched channel bindings (endpoint/unique).

Comment thread src/native/libs/System.Net.Security.Native/pal_gssapi.c
- Protect the ChannelBinding SafeHandle with DangerousAddRef/DangerousRelease
  around the native AcceptSecContext call to avoid a use-after-free if the
  binding is disposed concurrently.
- Fail fast with GSS_S_BAD_BINDINGS in NetSecurityNative_AcceptSecContextEx
  when cbtSize is negative, preventing a negative-to-size_t cast that could
  make gss_accept_sec_context read past the buffer in Release builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 331f6905-5e70-4f82-9c67-63a939a13117
Copilot AI review requested due to automatic review settings July 15, 2026 11:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 8 out of 8 changed files in this pull request and generated 1 comment.

Instead of adding a separate NetSecurityNative_AcceptSecContextEx export,
add the cbt/cbtSize parameters directly to NetSecurityNative_AcceptSecContext.
Callers that don't use a channel binding token pass NULL/0. These native
shims are only consumed by the in-repo managed interop layer, so there is no
ABI compatibility concern that would require a separate entry point.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 331f6905-5e70-4f82-9c67-63a939a13117
Copilot AI review requested due to automatic review settings July 15, 2026 11:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (3)

src/native/libs/System.Net.Security.Native/pal_gssapi.h:156

  • NetSecurityNative_AcceptSecContext has its exported signature changed (adds cbt/cbtSize). This contradicts the PR description (which says a new ...AcceptSecContextEx shim is added and the existing entry point delegates for backwards compatibility) and can break in-place servicing scenarios where older managed code calls the old signature against a newer native library. Consider restoring the original NetSecurityNative_AcceptSecContext signature and introducing a new NetSecurityNative_AcceptSecContextEx export for channel bindings, with the old entry point delegating to the new one with NULL/0 bindings.
PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,
                                                      uint32_t inputLength,
                                                      PAL_GssBuffer* outBuffer,
                                                      uint32_t* retFlags,
                                                      int32_t* isNtlmUsed);

src/native/libs/System.Net.Security.Native/pal_gssapi.c:414

  • This implementation updates the NetSecurityNative_AcceptSecContext export to take cbt/cbtSize. If the intent is to preserve backward compatibility (as described in the PR), the existing export should keep its original signature and delegate to a new NetSecurityNative_AcceptSecContextEx export instead. As-is, a managed/native mismatch would be a hard runtime failure.
uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                            GssCredId* acceptorCredHandle,
                                            GssCtxId** contextHandle,
                                            void* cbt,
                                            int32_t cbtSize,
                                            uint8_t* inputBytes,
                                            uint32_t inputLength,
                                            PAL_GssBuffer* outBuffer,
                                            uint32_t* retFlags,
                                            int32_t* isNtlmUsed)

src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs:173

  • The managed LibraryImport for NetSecurityNative_AcceptSecContext now includes cbt/cbtSize, which relies on the native export’s signature having changed. If the goal is in-place servicing compatibility, consider keeping the old NetSecurityNative_AcceptSecContext P/Invoke signature and adding a new AcceptSecContextEx P/Invoke that includes channel bindings, mirroring the existing InitSecContext/InitSecContextEx pattern.
        [LibraryImport(Interop.Libraries.NetSecurityNative, EntryPoint = "NetSecurityNative_AcceptSecContext")]
        private static partial Status AcceptSecContext(
            out Status minorStatus,
            SafeGssCredHandle acceptorCredHandle,
            ref SafeGssContextHandle acceptContextHandle,
            IntPtr cbt,
            int cbtSize,
            ref byte inputBytes,
            int inputLength,
            ref GssBuffer token,
            out uint retFlags,
            [MarshalAs(UnmanagedType.Bool)] out bool isNtlmUsed);

Comment thread src/native/libs/System.Net.Security.Native/pal_gssapi.c
@rzikm
rzikm requested review from a team and filipnavara July 15, 2026 11:51
…ive path

- Reject a malformed ChannelBinding (Size smaller than the SecChannelBindings
  header) in both the initiator and acceptor managed paths before doing pointer
  arithmetic, returning BadBinding instead of passing a negative size to interop.
- Mirror the acceptor's cbtSize < 0 fail-fast guard in
  NetSecurityNative_InitSecContextEx so the initiator native path is equally
  protected against an out-of-bounds read on malformed input.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 331f6905-5e70-4f82-9c67-63a939a13117
Copilot AI review requested due to automatic review settings July 15, 2026 11:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/native/libs/System.Net.Security.Native/pal_gssapi.h:156

  • The PR description says a new NetSecurityNative_AcceptSecContextEx entry point is added and the existing NetSecurityNative_AcceptSecContext delegates to it to preserve backward compatibility. In this header, the existing exported NetSecurityNative_AcceptSecContext signature is being extended with cbt/cbtSize, and there is no ...AcceptSecContextEx entry point. Extending an existing export changes the native ABI and does not preserve the old signature for in-place servicing / mixed-version scenarios.

Consider introducing a new export (e.g. NetSecurityNative_AcceptSecContextEx) and keeping NetSecurityNative_AcceptSecContext with its original signature as a wrapper that passes NULL/0 for CBT.

PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,
                                                      uint32_t inputLength,
                                                      PAL_GssBuffer* outBuffer,
                                                      uint32_t* retFlags,
                                                      int32_t* isNtlmUsed);

Comment thread src/native/libs/System.Net.Security.Native/pal_gssapi.c
Comment thread src/native/libs/System.Net.Security.Native/pal_gssapi.c

@filipnavara filipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generally LGTM, there was just one small thing I noticed which could be pre-existing bug.

…nt binding in initiator

- Initialize outBuffer/retFlags/isNtlmUsed to safe defaults on the cbtSize<0
  fast-fail path in both NetSecurityNative_InitSecContextEx and
  NetSecurityNative_AcceptSecContext so no uninitialized data propagates back
  to managed code.
- Bracket the initiator InitSecContext interop call with DangerousAddRef/
  DangerousRelease on the ChannelBinding handle, mirroring the acceptor path,
  to avoid a use-after-free on concurrent dispose.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a829d7e2-feca-4d23-ac34-8e07b2bd71a5

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

src/native/libs/System.Net.Security.Native/pal_gssapi.h:152

  • The PR description says a new NetSecurityNative_AcceptSecContextEx shim was added, but the code here changes the existing exported NetSecurityNative_AcceptSecContext signature to include CBT parameters. Given the existing InitSecContext/InitSecContextEx pattern in this same header, consider keeping the old AcceptSecContext ABI (no CBT) and adding an AcceptSecContextEx entrypoint instead (with the old one forwarding cbt = NULL, cbtSize = 0). This avoids native/managed version-skew issues and keeps the shim surface consistent.
PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,

src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs:154

  • OSSupportsExtendedProtection is now true on Linux, but the comment still says "Managed implements only client-side", which is misleading now that the Unix server path flows channel bindings into AcceptSecContext. Please update the comment to match the actual supported platforms/behavior (and fix the macOS casing/punctuation while here).
                // ExtendedProtection is supported on all Windows versions supported by current .NET version.
                // Linux is supported via GSSAPI (Managed implements only client-side).
                // MacOS's Heimdal-derived GSS.framework does not reject a channel binding mismatch (the exchange completes successfully)
                return OperatingSystem.IsWindows() || OperatingSystem.IsLinux();

src/libraries/System.Net.Security/tests/UnitTests/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicyTest.cs:60

  • The unit tests validating ExtendedProtectionPolicy.OSSupportsExtendedProtection were removed, but the property’s semantics changed (Linux is now supported). Please keep a small platform-gated assertion in this test file so regressions in the platform matrix get caught (Windows/Linux => true; everything else => false).

        [Fact]
        public void ExtendedProtectionPolicy_Properties()

@wfurt wfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@rzikm
rzikm requested review from Copilot and wfurt July 22, 2026 14:01
@rzikm
rzikm enabled auto-merge (squash) July 22, 2026 14:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/libraries/System.Net.Security/tests/UnitTests/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicyTest.cs:61

  • Unit coverage for ExtendedProtectionPolicy.OSSupportsExtendedProtection was removed, but the property’s semantics changed (Linux now returns true). The remaining tests only use the property as a condition, so they won’t catch accidental regressions in its value. Add a cross-platform assertion that verifies the property matches the intended OS matrix (Windows/Linux => true; other OSes => false).
        [Fact]
        public void ExtendedProtectionPolicy_Properties()
        {

src/native/libs/System.Net.Security.Native/pal_gssapi.h:152

  • The PR description says a new NetSecurityNative_AcceptSecContextEx shim was added, but the code changes the existing NetSecurityNative_AcceptSecContext export signature instead. If the intent is to keep the native ABI additive (and match the description), consider keeping the old export as a wrapper (no CBT) and adding a new ...Ex entrypoint that takes CBT/size, updating managed interop to call the new symbol.
PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs:154

  • The comment on OSSupportsExtendedProtection looks outdated/misleading now that Linux server-side channel binding support exists in the Unix PAL. Consider updating the wording (and macOS capitalization/punctuation) to describe the actual supported platforms without referencing managed-only behavior.
                // ExtendedProtection is supported on all Windows versions supported by current .NET version.
                // Linux is supported via GSSAPI (Managed implements only client-side).
                // MacOS's Heimdal-derived GSS.framework does not reject a channel binding mismatch (the exchange completes successfully)
                return OperatingSystem.IsWindows() || OperatingSystem.IsLinux();

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 14:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateAuthenticationKerberosTest.ChannelBindings.cs:83

  • RunMismatch is missing braces, so the using statements are not inside a method body and this file will not compile. Wrap the body in { ... }.
        private static void RunMismatch(ChannelBindingKind kind)
            using SafeChannelBindingHandle clientBinding = CreateChannelBinding(kind, hashSeed: 0x42);
            using SafeChannelBindingHandle serverBinding = CreateChannelBinding(kind, hashSeed: 0x99);

src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicy.cs:154

  • The comment says Linux support is client-side only, but this PR adds server-side channel binding support on Unix via AcceptSecContext. Please update the comment to avoid misleading future readers, and use the standard "macOS" casing / add punctuation.
                // ExtendedProtection is supported on all Windows versions supported by current .NET version.
                // Linux is supported via GSSAPI (Managed implements only client-side).
                // MacOS's Heimdal-derived GSS.framework does not reject a channel binding mismatch (the exchange completes successfully)
                return OperatingSystem.IsWindows() || OperatingSystem.IsLinux();

src/libraries/System.Net.Security/tests/UnitTests/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicyTest.cs:61

  • The unit tests no longer cover the platform contract of ExtendedProtectionPolicy.OSSupportsExtendedProtection. Since this PR changes the behavior to include Linux, it would be good to keep a simple regression test here to prevent accidental reverts.
        [Fact]
        public void ExtendedProtectionPolicy_Properties()
        {

src/native/libs/System.Net.Security.Native/pal_gssapi.h:152

  • The PR description mentions adding a new NetSecurityNative_AcceptSecContextEx shim, but the native export being changed here is NetSecurityNative_AcceptSecContext (signature extended with CBT pointer/size). Please update the PR description (or rename/add an ...Ex export) so the implementation matches the stated approach.
/*
Shims the gss_accept_sec_context method.
*/
PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,

Copilot AI review requested due to automatic review settings July 22, 2026 15:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/libraries/System.Net.Security/tests/UnitTests/System/Security/Authentication/ExtendedProtection/ExtendedProtectionPolicyTest.cs:58

  • The PR changes ExtendedProtectionPolicy.OSSupportsExtendedProtection semantics (Linux now supported), but the unit tests that validated OSSupportsExtendedProtection were removed rather than updated. This loses direct coverage of a public, behavior-affecting property and makes it easier for future changes to accidentally regress platform gating.
    src/native/libs/System.Net.Security.Native/pal_gssapi.h:152
  • The PR description says a new NetSecurityNative_AcceptSecContextEx shim is added, but the actual change extends the existing NetSecurityNative_AcceptSecContext export/signature. This mismatch makes it harder to understand the intended compatibility story and can confuse future maintainers when searching for the "Ex" entrypoint.
PALEXPORT uint32_t NetSecurityNative_AcceptSecContext(uint32_t* minorStatus,
                                                      GssCredId* acceptorCredHandle,
                                                      GssCtxId** contextHandle,
                                                      void* cbt,
                                                      int32_t cbtSize,
                                                      uint8_t* inputBytes,

@rzikm

rzikm commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

/ba-g Test failures are unrelated

@rzikm
rzikm merged commit 3e64752 into dotnet:main Jul 23, 2026
99 of 104 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants