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 d8909a897dbef6..56dfe4a80edcce 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 @@ -124,15 +124,25 @@ private enum AvId } [StructLayout(LayoutKind.Sequential)] - private unsafe struct MessageField + private struct MessageField { - public ushort Length; - public ushort MaximumLength; + private ushort _length; + private ushort _maximumLength; private int _payloadOffset; + public ushort Length + { + readonly get => BitConverter.IsLittleEndian ? _length : BinaryPrimitives.ReverseEndianness(_length); + set => _length = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); + } + public ushort MaximumLength + { + readonly get => BitConverter.IsLittleEndian ? _maximumLength : BinaryPrimitives.ReverseEndianness(_maximumLength); + set => _maximumLength = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); + } public int PayloadOffset { - readonly get =>BitConverter.IsLittleEndian? _payloadOffset: BinaryPrimitives.ReverseEndianness(_payloadOffset); - set =>_payloadOffset = BitConverter.IsLittleEndian? value: BinaryPrimitives.ReverseEndianness(value); + readonly get => BitConverter.IsLittleEndian ? _payloadOffset : BinaryPrimitives.ReverseEndianness(_payloadOffset); + set => _payloadOffset = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); } } @@ -158,8 +168,8 @@ private unsafe struct Version public byte CurrentRevision; public ushort ProductBuild { - readonly get =>BitConverter.IsLittleEndian? _productBuild: BinaryPrimitives.ReverseEndianness(_productBuild); - set =>_productBuild = BitConverter.IsLittleEndian? value: BinaryPrimitives.ReverseEndianness(value); + readonly get => BitConverter.IsLittleEndian ? _productBuild : BinaryPrimitives.ReverseEndianness(_productBuild); + set => _productBuild = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); } } @@ -174,8 +184,8 @@ private unsafe struct NegotiateMessage public Version Version; public Flags Flags { - readonly get =>BitConverter.IsLittleEndian? _flags: (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags); - set =>_flags = BitConverter.IsLittleEndian? value: (Flags)BinaryPrimitives.ReverseEndianness((uint)value); + readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags); + set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value); } } @@ -185,11 +195,16 @@ private unsafe struct ChallengeMessage { public MessageHeader Header; public MessageField TargetName; - public Flags Flags; + private Flags _flags; public fixed byte ServerChallenge[ChallengeLength]; private ulong _unused; public MessageField TargetInfo; public Version Version; + public Flags Flags + { + readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags); + set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value); + } } // TYPE 3 message @@ -203,9 +218,14 @@ private unsafe struct AuthenticateMessage public MessageField UserName; public MessageField Workstation; public MessageField EncryptedRandomSessionKey; - public Flags Flags; + private Flags _flags; public Version Version; public fixed byte Mic[16]; + public Flags Flags + { + readonly get => BitConverter.IsLittleEndian ? _flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)_flags); + set => _flags = BitConverter.IsLittleEndian ? value : (Flags)BinaryPrimitives.ReverseEndianness((uint)value); + } } // Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), Time, ClientChallenge, Z(4), ServerName, Z(4)) @@ -218,10 +238,15 @@ private unsafe struct NtChallengeResponse private byte _reserved1; private byte _reserved2; private int _reserved3; - public long Time; + private long _time; public fixed byte ClientChallenge[ChallengeLength]; private int _reserved4; public fixed byte ServerInfo[4]; // Has to be non-zero size, so set it to the Z(4) padding + public long Time + { + readonly get => BitConverter.IsLittleEndian ? _time : BinaryPrimitives.ReverseEndianness(_time); + set => _time = BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); + } } public override bool IsAuthenticated => _isAuthenticated; @@ -321,42 +346,29 @@ private static unsafe void CreateNtlmNegotiateMessage(Span asBytes, Flags message.Version = s_version; } - private static unsafe int GetFieldLength(MessageField field) - { - ReadOnlySpan span = new ReadOnlySpan(&field, sizeof(MessageField)); - return BinaryPrimitives.ReadInt16LittleEndian(span); - } - - private static unsafe int GetFieldOffset(MessageField field) - { - ReadOnlySpan span = new ReadOnlySpan(&field, sizeof(MessageField)); - return BinaryPrimitives.ReadInt16LittleEndian(span.Slice(4)); - } - private static ReadOnlySpan GetField(MessageField field, ReadOnlySpan payload) { - int offset = GetFieldOffset(field); - int length = GetFieldLength(field); + int offset = field.PayloadOffset; + int length = field.Length; if (length == 0 || offset + length > payload.Length) { return ReadOnlySpan.Empty; } - return payload.Slice(GetFieldOffset(field), GetFieldLength(field)); + return payload.Slice(offset, length); } - private static unsafe void SetField(ref MessageField field, int length, int offset) + private static void SetField(ref MessageField field, int length, int offset) { if (length is < 0 or > short.MaxValue) { throw new Win32Exception(NTE_FAIL); } - Span span = MemoryMarshal.AsBytes(new Span(ref field)); - BinaryPrimitives.WriteInt16LittleEndian(span, (short)length); - BinaryPrimitives.WriteInt16LittleEndian(span.Slice(2), (short)length); - BinaryPrimitives.WriteInt32LittleEndian(span.Slice(4), offset); + field.Length = (ushort)length; + field.MaximumLength = (ushort)length; + field.PayloadOffset = offset; } private static void AddToPayload(ref MessageField field, ReadOnlySpan data, Span payload, ref int offset) @@ -589,7 +601,7 @@ private static byte[] DeriveKey(ReadOnlySpan exportedSessionKey, ReadOnlyS return null; } - Flags flags = BitConverter.IsLittleEndian ? challengeMessage.Flags : (Flags)BinaryPrimitives.ReverseEndianness((uint)challengeMessage.Flags); + Flags flags = challengeMessage.Flags; ReadOnlySpan targetName = GetField(challengeMessage.TargetName, blob); // Only NTLMv2 with MIC is supported