Add GSS channel binding support per RFC 4121 section 4.1.1.2 for AP-REQ and TGS-REQ#422
Add GSS channel binding support per RFC 4121 section 4.1.1.2 for AP-REQ and TGS-REQ#422thadumi wants to merge 3 commits intodotnet:developfrom
Conversation
|
@dotnet-policy-service agree company="Microsoft" |
| /// Accepts a raw SEC_CHANNEL_BINDINGS buffer | ||
| /// and converts it to <see cref="ExpectedChannelBindings"/>. | ||
| /// </summary> | ||
| public ReadOnlyMemory<byte> ExpectedRawChannelBindings |
There was a problem hiding this comment.
Nit: I feel like intention might be clearer with a setter method instead of a setter-only field. Or you could just make the caller call GssChannelBindings.FromSecChannelBindings. But no strong opinion on this.
|
|
||
| protected abstract MessageType MessageType { get; } | ||
|
|
||
| protected KdcMessageHandlerBase(ReadOnlyMemory<byte> message, KdcServerOptions options) |
There was a problem hiding this comment.
Would it make sense to add expected channel bindings here? That way, it's harder to miss passing it in
|
|
||
| protected virtual void ValidateChannelBinding() | ||
| { | ||
| if (this.ExpectedChannelBindings == null) |
There was a problem hiding this comment.
If you passed ValidationActions.ChannelBinding but forgot to pass ExpectedChannelBindings -- should this be an exception? Or maybe it's not a wise idea -- but just trying to see if there's a way to not fail silently
There was a problem hiding this comment.
Or maybe you could make ExpectedChannelBindings a mandatory param of Validate?
|
|
||
| public int Length { get; set; } | ||
|
|
||
| public ReadOnlyMemory<byte> ChannelBinding { get; set; } |
There was a problem hiding this comment.
Rename to ChannelBindingHash to avoid confusion?
|
|
||
| using System; | ||
| using System.Globalization; | ||
| using System.Runtime.Versioning; |
| /// <summary> | ||
| /// Expected channel bindings for this request's TGS-REQ validation. | ||
| /// </summary> | ||
| public GssChannelBindings ExpectedChannelBindings { get; set; } |
There was a problem hiding this comment.
Maybe makes sense to just store the hash, instead of the full object? Seems like you just need the hash
What's the problem?
TLS Channel Binding Tokens solve authentication relay attacks (MITM).
Without CBT attacker intercepts a client's connection, terminates the TLS session, and establishes a separate TLS session to the real server. The attacker then relays the client's Kerberos AP-REQ (which is valid and properly encrypted) to the server. The server accepts it because the Kerberos ticket itself is perfectly legitimate and it has no knowledge that it arrived through an intermediary.
RFC 4121 describes Channel Binding Tokens for Kerberos.
What's the solution?
CBT ties the Kerberos authentication to the specific TLS channel it was intended for:
application_dataof thegss_channel_bindings_struct, computes the MD5 Bnd hash, and embeds it inside the authenticator checksum of the AP-REQ (encrypted, so the attacker can't modify it).If an attacker is relaying, the two TLS sessions have different certificates, the attacker's certificate on the client side vs. the real server's certificate on the server side. The hashes won't match, and the server rejects the request.
As such we are introducing:
DecryptedKrbApReq.ExpectedChannelBindingsto allow the server to specify the expected Channel Binding information in the AP-REQKerberosValidator.ExpectedChannelBindingswhich is symmetrical toDecryptedKrbApReqto facilitate the usage of this featureValidationActions.ChannelBindingthat triggersValidateChannelBinding()duringValidate()ValidateChannelBinding()uses the propertyDecryptedKrbApReq.ExpectedChannelBindingsto ensure that the unique material present in the AP-REQ.On server side the intended usage is
On client side
As of this PR, Channel Binding validation is enabled by default and follow an opt‑out model. Validation is bypassed only when ExpectedChannelBindings is unset, or when Channel Bindings are explicitly excluded through flags:
decrypted.Validate(ValidationActions.All & ~ValidationActions.ChannelBinding);Describe the solution here.