-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Native shims for libheimntlm #5728
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // 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.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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: there's an extra space after |
||
| } | ||
| } | ||
|
|
||
| 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
|
||
| { | ||
| 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")] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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")] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR is using a prefix of |
||
| 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| int inl); | ||
|
|
||
| } | ||
| } | ||
There was a problem hiding this comment.
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.