Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows Extended Protection support #366

Open
techmikal opened this issue Mar 12, 2024 · 4 comments
Open

Windows Extended Protection support #366

techmikal opened this issue Mar 12, 2024 · 4 comments

Comments

@techmikal
Copy link

Is your feature request related to a problem? Please describe.
When using the library together the sample code provided to create a "Negotiate" header and then using that header with httpClient to make a request to a website, it fails if the receiving IIS has Windows Extended Protection set to required.

Describe the solution you'd like
It would be great if there was a way to add channel binding information when the apReq (i think) is created.

@SteveSyfuhs
Copy link
Collaborator

Yeah, good feature. In theory this could be built out by an application directly by filling in the DelegationInfo object during AP-REQ creation, but that's certainly a pain.

@techmikal
Copy link
Author

First of all, thanks for taking the time to answer and to point me in the right direction.
I did give it a go (well, a lot of go's actually) but unfortunately I wasn't able to get it working. While this is not a support channel perhaps you can easily see where i went wrong.

By your direction I made the changes to DelegationInfo.cs

I started with declaring:

public const int ChannelBindingLength = 0x10;
            public readonly byte[] cbt_zeros = new byte[] {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            };
            public readonly byte[] tls_server_end_point = new byte[] {
                0x74, 0x6c, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2d, 0x65, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x3a
            };

And then I attempted to change the Encode method like below but when i add "Negotiate " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray()) to the Authorization: header of a http request the binding fails.

public ReadOnlyMemory<byte> Encode()
        {
            using (var stream = new MemoryStream())
            using (var writer = new BinaryWriter(stream))
            {
                X509Certificate cert = new X509Certificate("C:\\Temp\\cert\\test\\publicKey.cer");

                using (var hasher = SHA256.Create())
                {
                    var hash = hasher.ComputeHash(cert.GetRawCertData());
                    int cbtLength = cbt_zeros.Length + tls_server_end_point.Length + hash.Length + 4;
                    var cbt = new byte[cbtLength];

                    int pos = 0;
                    //first 16 bytes zeros
                    Array.Copy(cbt_zeros, 0, cbt, pos, cbt_zeros.Length);

                    //add 4 bytes of app data length (tls prefix + cert hash)
                    byte[] dataLength = new byte[] { (byte)(tls_server_end_point.Length + hash.Length), 0, 0, 0 };
                    pos += cbt_zeros.Length;
                    Array.Copy(dataLength, 0, cbt, pos, 4);

                    //add tls prefix
                    pos += 4;
                    Array.Copy(tls_server_end_point, 0, cbt, pos, tls_server_end_point.Length);

                    //add cert hash
                    pos += tls_server_end_point.Length;
                    Array.Copy(hash, 0, cbt, pos, hash.Length);

                    this.ChannelBinding = cbt;
                }

                if (this.ChannelBinding.Length == 0)
                {
                    this.ChannelBinding = new byte[ChannelBindingLength];
                }

                writer.Write(this.ChannelBinding.Length);
                writer.Write(this.ChannelBinding.ToArray());

                if (this.DelegationTicket != null)
                {
                    this.Flags |= GssContextEstablishmentFlag.GSS_C_DELEG_FLAG;
                }

                writer.Write((int)this.Flags);

                if (this.DelegationTicket != null)
                {
                    writer.Write((short)this.DelegationOption);

                    var deleg = this.DelegationTicket.EncodeApplication();

                    writer.Write((short)deleg.Length);

                    writer.Write(deleg.ToArray());
                }

                return stream.ToArray();
            }
        }

@SteveSyfuhs
Copy link
Collaborator

SteveSyfuhs commented Mar 14, 2024 via email

@techmikal
Copy link
Author

Hi, you were absolutely right about the MD5 hash. For some reason I thought that part was only for NTLM. Thanks a ton for taking the time to help out. Hopefully this helps someone else.

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

No branches or pull requests

2 participants