Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libraries/Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,20 @@ internal static unsafe partial int DecryptMessage(
uint sequenceNumber,
uint* qualityOfProtection);

[LibraryImport(Interop.Libraries.SspiCli, SetLastError = true)]
internal static partial int MakeSignature(
ref CredHandle contextHandle,
uint qualityOfProtection,
ref SecBufferDesc inputOutput,
uint sequenceNumber);

[LibraryImport(Interop.Libraries.SspiCli, SetLastError = true)]
internal static unsafe partial int VerifySignature(
ref CredHandle contextHandle,
in SecBufferDesc input,
uint sequenceNumber,
uint *qualityOfProtection);

[LibraryImport(Interop.Libraries.SspiCli, SetLastError = true)]
internal static partial int QuerySecurityContextToken(
ref CredHandle phContext,
Expand Down
30 changes: 10 additions & 20 deletions src/libraries/Common/src/System/Net/NTAuthentication.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ internal NegotiateAuthenticationStatusCode UnwrapInPlace(Span<byte> input, out i
return NegotiateStreamPal.UnwrapInPlace(_securityContext!, input, out unwrappedOffset, out unwrappedLength, out wasEncrypted);
}

internal bool VerifyMIC(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature)
{
return NegotiateStreamPal.VerifyMIC(_securityContext!, (_contextFlags & ContextFlagsPal.Confidentiality) != 0, message, signature);
}

internal void GetMIC(ReadOnlySpan<byte> message, IBufferWriter<byte> signature)
{
NegotiateStreamPal.GetMIC(_securityContext!, (_contextFlags & ContextFlagsPal.Confidentiality) != 0, message, signature);
}

internal string? GetOutgoingBlob(string? incomingBlob)
{
return GetOutgoingBlob(incomingBlob, throwOnError: true, out _);
Expand Down Expand Up @@ -329,25 +339,5 @@ internal NegotiateAuthenticationStatusCode UnwrapInPlace(Span<byte> input, out i

return spn;
}

internal int Encrypt(ReadOnlySpan<byte> buffer, [NotNull] ref byte[]? output)
{
return NegotiateStreamPal.Encrypt(
_securityContext!,
buffer,
(_contextFlags & ContextFlagsPal.Confidentiality) != 0,
IsNTLM,
ref output);
}

internal int Decrypt(Span<byte> payload, out int newOffset)
{
return NegotiateStreamPal.Decrypt(
_securityContext!,
payload,
(_contextFlags & ContextFlagsPal.Confidentiality) != 0,
IsNTLM,
out newOffset);
}
}
}
31 changes: 16 additions & 15 deletions src/libraries/Common/src/System/Net/NTAuthentication.Managed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ private void CalculateSignature(
}
}

private bool VerifyMIC(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature)
internal bool VerifyMIC(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature)
{
// Check length and version
if (signature.Length != SignatureLength ||
Expand All @@ -815,10 +815,21 @@ private bool VerifyMIC(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature)
return signature.SequenceEqual(expectedSignature);
}

internal void GetMIC(ReadOnlySpan<byte> message, IBufferWriter<byte> signature)
{
Debug.Assert(_clientSeal is not null);
Debug.Assert(_clientSigningKey is not null);

Span<byte> signatureBuffer = signature.GetSpan(SignatureLength);
CalculateSignature(message, _clientSequenceNumber, _clientSigningKey, _clientSeal, signatureBuffer);
_clientSequenceNumber++;
signature.Advance(SignatureLength);
}

private byte[] GetMIC(ReadOnlySpan<byte> message)
{
Debug.Assert(_clientSeal != null);
Debug.Assert(_clientSigningKey != null);
Debug.Assert(_clientSeal is not null);
Debug.Assert(_clientSigningKey is not null);

byte[] signature = new byte[SignatureLength];
CalculateSignature(message, _clientSequenceNumber, _clientSigningKey, _clientSeal, signature);
Expand Down Expand Up @@ -1084,28 +1095,18 @@ internal NegotiateAuthenticationStatusCode UnwrapInPlace(Span<byte> input, out i
return NegotiateAuthenticationStatusCode.Completed;
}

#pragma warning disable CA1822, IDE0060
internal int Encrypt(ReadOnlySpan<byte> buffer, [NotNull] ref byte[]? output)
{
throw new PlatformNotSupportedException();
}

internal int Decrypt(Span<byte> payload, out int newOffset)
{
throw new PlatformNotSupportedException();
}

internal string ProtocolName => _isSpNego ? NegotiationInfoClass.Negotiate : NegotiationInfoClass.NTLM;

#pragma warning disable CA1822, IDE0060
internal bool IsNTLM => true;

internal bool IsKerberos => false;

internal bool IsServer { get; set; }

internal bool IsValidContext => true;
#pragma warning restore CA1822, IDE0060

internal string? ClientSpecifiedSpn => _spn;
#pragma warning restore CA1822, IDE0060
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -499,100 +499,6 @@ internal static SecurityStatusPal CompleteAuthToken(
}
#pragma warning restore IDE0060

internal static int Encrypt(
SafeDeleteContext securityContext,
ReadOnlySpan<byte> buffer,
bool isConfidential,
bool isNtlm,
[NotNull] ref byte[]? output)
{
SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext!;
int resultSize;

if (isNtlm && !isConfidential)
{
Interop.NetSecurityNative.GssBuffer micBuffer = default;
try
{
Interop.NetSecurityNative.Status minorStatus;
Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.GetMic(
out minorStatus,
gssContext,
buffer,
ref micBuffer);
if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
{
throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
}

resultSize = micBuffer.Span.Length + buffer.Length;
if (output == null || output.Length < resultSize + 4)
{
output = new byte[resultSize + 4];
}

micBuffer.Span.CopyTo(output.AsSpan(4));
buffer.CopyTo(output.AsSpan(micBuffer.Span.Length + 4));
BinaryPrimitives.WriteInt32LittleEndian(output, resultSize);

return resultSize + 4;
}
finally
{
micBuffer.Dispose();
}
}

byte[] tempOutput = GssWrap(gssContext, ref isConfidential, buffer);

// Create space for prefixing with the length
const int prefixLength = 4;
output = new byte[tempOutput.Length + prefixLength];
Array.Copy(tempOutput, 0, output, prefixLength, tempOutput.Length);
resultSize = tempOutput.Length;
BinaryPrimitives.WriteInt32LittleEndian(output, resultSize);

return resultSize + 4;
}

internal static int Decrypt(
SafeDeleteContext securityContext,
Span<byte> buffer,
bool isConfidential,
bool isNtlm,
out int newOffset)
{
SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext!;

if (isNtlm && !isConfidential)
{
const int NtlmSignatureLength = 16;

if (buffer.Length < NtlmSignatureLength)
{
Debug.Fail("Argument 'count' out of range.");
throw new Interop.NetSecurityNative.GssApiException(Interop.NetSecurityNative.Status.GSS_S_DEFECTIVE_TOKEN, 0);
}

Interop.NetSecurityNative.Status minorStatus;
Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.VerifyMic(
out minorStatus,
gssContext,
buffer.Slice(NtlmSignatureLength),
buffer.Slice(0, NtlmSignatureLength));
if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
{
throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
}

newOffset = NtlmSignatureLength;
return buffer.Length - NtlmSignatureLength;
}

newOffset = 0;
return GssUnwrap(gssContext, out _, buffer);
}

internal static NegotiateAuthenticationStatusCode Unwrap(
SafeDeleteContext securityContext,
ReadOnlySpan<byte> input,
Expand Down Expand Up @@ -692,7 +598,52 @@ internal static NegotiateAuthenticationStatusCode Wrap(
{
encryptedBuffer.Dispose();
}
}

internal static bool VerifyMIC(
SafeDeleteContext securityContext,
bool isConfidential,
ReadOnlySpan<byte> message,
ReadOnlySpan<byte> signature)
{
_ = isConfidential;
SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext!;
Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.VerifyMic(
out _,
gssContext,
message,
signature);
return status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE;
}

internal static void GetMIC(
SafeDeleteContext securityContext,
bool isConfidential,
ReadOnlySpan<byte> message,
IBufferWriter<byte> signature)
{
_ = isConfidential;
SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext!;
Interop.NetSecurityNative.GssBuffer micBuffer = default;
try
{
Interop.NetSecurityNative.Status minorStatus;
Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.GetMic(
out minorStatus,
gssContext,
message,
ref micBuffer);
if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
{
throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
}

signature.Write(micBuffer.Span);
}
finally
{
micBuffer.Dispose();
}
}
}
}
Loading