diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedNtlm.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedNtlm.cs index 95be2c7fc8984e..147dd35e4e194c 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedNtlm.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.ManagedNtlm.cs @@ -424,10 +424,23 @@ private unsafe void WriteChannelBindingHash(Span hashBuffer) { if (_channelBinding != null) { - IntPtr cbtData = _channelBinding.DangerousGetHandle(); - int cbtDataSize = _channelBinding.Size; - int written = MD5.HashData(new Span((void*)cbtData, cbtDataSize), hashBuffer); - Debug.Assert(written == MD5.HashSizeInBytes); + int appDataOffset = sizeof(SecChannelBindings); + IntPtr cbtData = (nint)_channelBinding.DangerousGetHandle() + appDataOffset; + int cbtDataSize = _channelBinding.Size - appDataOffset; + + // Channel bindings are calculated according to RFC 4121, section 4.1.1.2, + // so we need to include zeroed initiator fields and length prefix for the + // application data. + Span prefix = stackalloc byte[sizeof(uint) * 5]; + prefix.Clear(); + BinaryPrimitives.WriteInt32LittleEndian(prefix.Slice(sizeof(uint) * 4), cbtDataSize); + using (var md5 = IncrementalHash.CreateHash(HashAlgorithmName.MD5)) + { + md5.AppendData(prefix); + md5.AppendData(new Span((void*)cbtData, cbtDataSize)); + int written = md5.GetHashAndReset(hashBuffer); + Debug.Assert(written == MD5.HashSizeInBytes); + } } else { diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs index d3b39321b12bf2..e1735a65a6f97e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs @@ -543,7 +543,7 @@ Interop.NetSecurityNative.Status status } } - private NegotiateAuthenticationStatusCode InitializeSecurityContext( + private unsafe NegotiateAuthenticationStatusCode InitializeSecurityContext( ref SafeGssCredHandle credentialsHandle, ref SafeGssContextHandle? contextHandle, ref SafeGssNameHandle? targetNameHandle, @@ -587,7 +587,7 @@ private NegotiateAuthenticationStatusCode InitializeSecurityContext( { // If a TLS channel binding token (cbt) is available then get the pointer // to the application specific data. - int appDataOffset = Marshal.SizeOf(); + int appDataOffset = sizeof(SecChannelBindings); Debug.Assert(appDataOffset < channelBinding.Size); IntPtr cbtAppData = channelBinding.DangerousGetHandle() + appDataOffset; int cbtAppDataSize = channelBinding.Size - appDataOffset; diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs index 35daf739b88af8..0b8699fd0eaa04 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs @@ -11,7 +11,7 @@ namespace System.Net.Security internal sealed class SafeChannelBindingHandle : ChannelBinding { private const int CertHashMaxSize = 128; - private static readonly int s_secChannelBindingSize = Marshal.SizeOf(); + private static unsafe int SecChannelBindingSize => sizeof(SecChannelBindings); private readonly int _cbtPrefixByteArraySize; internal int Length { get; private set; } @@ -36,8 +36,8 @@ internal unsafe SafeChannelBindingHandle(ChannelBindingKind kind) "tls-unique:"u8; _cbtPrefixByteArraySize = cbtPrefix.Length; - handle = Marshal.AllocHGlobal(s_secChannelBindingSize + _cbtPrefixByteArraySize + CertHashMaxSize); - IntPtr cbtPrefixPtr = handle + s_secChannelBindingSize; + handle = Marshal.AllocHGlobal(SecChannelBindingSize + _cbtPrefixByteArraySize + CertHashMaxSize); + IntPtr cbtPrefixPtr = handle + SecChannelBindingSize; cbtPrefix.CopyTo(new Span((byte*)cbtPrefixPtr, cbtPrefix.Length)); CertHashPtr = cbtPrefixPtr + _cbtPrefixByteArraySize; Length = CertHashMaxSize; @@ -46,12 +46,12 @@ internal unsafe SafeChannelBindingHandle(ChannelBindingKind kind) internal void SetCertHashLength(int certHashLength) { int cbtLength = _cbtPrefixByteArraySize + certHashLength; - Length = s_secChannelBindingSize + cbtLength; + Length = SecChannelBindingSize + cbtLength; SecChannelBindings channelBindings = new SecChannelBindings() { ApplicationDataLength = cbtLength, - ApplicationDataOffset = s_secChannelBindingSize + ApplicationDataOffset = SecChannelBindingSize }; Marshal.StructureToPtr(channelBindings, handle, true); }