Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these files are using the old license header.

// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
internal static class HeimdalNtlm
{
internal static byte[] CreateNegotiateMessage(uint flags)
{
SafeNtlmBufferHandle data;
int dataLen;
int status = NetSecurity.HeimNtlmEncodeType1(flags, out data, out dataLen);
NetSecurity.HeimdalNtlmException.AssertOrThrowIfError("HeimNtlmEncodeType1 failed", status);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be moved to inside of the using so that the SafeNtlmBufferHandle is disposed even if the operation fails? Or is data guaranteed to be null in the event of a failure? (If it's not-null but IsInvalid, we should still dispose of it.)

using (data)
{
return data.ToByteArray(dataLen,0);
}
}

internal static byte[] CreateAuthenticateMessage(uint flags, string username, string password, string domain,
byte[] type2Data, int offset, int count, out byte[] sessionKey)
{
using (SafeNtlmType3Handle challengeMessage = new SafeNtlmType3Handle(type2Data, offset, count))
{
return challengeMessage.GetResponse(flags, username, password, domain, out sessionKey);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: there's an extra space after return

}
}

internal static void CreateKeys(byte[] sessionKey, out SafeNtlmKeyHandle serverSignKey, out SafeNtlmKeyHandle serverSealKey, out SafeNtlmKeyHandle clientSignKey, out SafeNtlmKeyHandle clientSealKey)
{
serverSignKey = new SafeNtlmKeyHandle(sessionKey, false, false);
serverSealKey = new SafeNtlmKeyHandle(sessionKey, false, true);
clientSignKey = new SafeNtlmKeyHandle(sessionKey, true, false);
clientSealKey = new SafeNtlmKeyHandle(sessionKey, true, true);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could you use named arguments for the Booleans so that it's clear what each of the false and true arguments mean? e.g.

serverSignKey = new SafeNtlmKeyHandle(sessionKey, isClient: false, isSealKey: false);

}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class NetSecurity
{
internal sealed class HeimdalNtlmException : Exception
{
public HeimdalNtlmException(string message) : base(message)
{
}

public HeimdalNtlmException(int error)
: base(SR.Format(SR.net_generic_heimntlm_operation_failed, error))
{
HResult = error;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any string-based description of the error we can retrieve from the library? Or if these errors are standard errno values, can we use the existing infrastructure we have for getting exceptions/strings for such errors?

}

public static void AssertOrThrowIfError(string message, int error)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we just make this Throw. Often Debug.Assert/Fail is used in situations where we're not throwing, but since we are here, you could just throw, and if you want extra debugging information, use Debug.WriteLine. Additionally, it's strange that the message is being used only for the assert but not for the exception; that could be confusing for a developer calling this method, especially since it looks like there's useful information being captured in those messages and not conveyed via the exception. So, I suggest:

  1. Replace the Debug.Fail with Debug.WriteLine.
  2. Either incorporate the message into the exception or remove the message parameter.
  3. Change the name of the method to ThrowIfError.

{
if (error != 0)
{
var ex = new HeimdalNtlmException(error);
Debug.Fail(message + ": " + ex);
throw ex;
}
}
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
internal static partial class NetSecurity
{
// The following constant is used in calculation of NTOWF2
// ref: https://msdn.microsoft.com/en-us/library/cc236700.aspx
public const int MD5DigestLength = 16;
[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmFreeBuf")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please add a blank line after the constant

internal static extern int HeimNtlmFreeBuf(IntPtr bufferHandle);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_ExtractNtlmBuffer")]
internal static extern int ExtractNtlmBuffer(SafeNtlmBufferHandle data, byte[] buffer, int capacity, int offset);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signature parity: capacity and offset are declared here as signed integers, in the native code as unsigned integers.


[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmEncodeType1")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is using a prefix of NetSecurity. #5774 is using one of NetSecurityNative.

internal static extern int HeimNtlmEncodeType1(uint flags, out SafeNtlmBufferHandle data, out int length);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmDecodeType2")]
internal static extern int HeimNtlmDecodeType2(byte[] data, int offset, int count, out SafeNtlmType2Handle type2Handle);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmFreeType2")]
internal static extern int HeimNtlmFreeType2(IntPtr type2Handle);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmNtKey", CharSet = CharSet.Ansi)]
internal static extern int HeimNtlmNtKey(string password, out SafeNtlmBufferHandle key, out int length);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_HeimNtlmCalculateResponse", CharSet = CharSet.Ansi)]
internal static extern int HeimNtlmCalculateResponse(
bool isLM,
SafeNtlmBufferHandle key,
SafeNtlmType2Handle type2Handle,
string username,
string target,
byte[] baseSessionKey,
int baseSessionKeyLen,
out SafeNtlmBufferHandle answer,
out int ansLength);

[DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurity_CreateType3Message", CharSet = CharSet.Ansi)]
internal static extern int CreateType3Message(
SafeNtlmBufferHandle key,
SafeNtlmType2Handle type2Handle,
string username,
string domain,
uint flags,
SafeNtlmBufferHandle lmResponse,
SafeNtlmBufferHandle ntlmResponse,
byte [] baseSessionKey,
int baseSessionKeyLen,
out SafeNtlmBufferHandle sessionKey,
out int sessionKeyLen,
out SafeNtlmBufferHandle data,
out int dataLen
);

internal partial class NtlmFlags
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a [Flags] enum?

{
internal const uint NTLMSSP_NEGOTIATE_UNICODE = 0x1;
internal const uint NTLMSSP_REQUEST_TARGET = 0x4;
internal const uint NTLMSSP_NEGOTIATE_SIGN = 0x10;
internal const uint NTLMSSP_NEGOTIATE_SEAL = 0x20;
internal const uint NTLMSSP_NEGOTIATE_NTLM = 0x200;
internal const uint NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x8000;
internal const uint NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x80000;
internal const uint NTLMSSP_NEGOTIATE_128 = 0x20000000;
internal const uint NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000;
}
}
}
1 change: 1 addition & 0 deletions src/Common/src/Interop/Unix/Interop.Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ private static partial class Libraries
// Shims
internal const string SystemNative = "System.Native";
internal const string HttpNative = "System.Net.Http.Native";
internal const string NetSecurityNative = "System.Net.Security.Native";
internal const string CryptoNative = "System.Security.Cryptography.Native";
internal const string GlobalizationNative = "System.Globalization.Native";
internal const string CompressionNative = "System.IO.Compression.Native";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,16 @@ internal static extern unsafe bool EvpCipherFinalEx(

[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDes3Cbc")]
internal static extern IntPtr EvpDes3Cbc();

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpRc4")]
internal static extern IntPtr EvpRc4();

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpCipher")]
internal static unsafe extern int EvpCipher(
SafeEvpCipherCtxHandle ctx,
byte[] output,
byte* input,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's strange to me that input comes after output in the argument ordering. Also, what's the reason one is a byte[] and the other is a byte*, rather than both being the same type?

int inl);

}
}
Loading