mirror of https://github.com/FreeRDP/FreeRDP
Refactored WinPR::NTLM
* added assertions * added log messages * removed code duplication
This commit is contained in:
parent
e5b50c550b
commit
8d4332235e
|
@ -49,6 +49,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
|||
DWORD nSize = 0;
|
||||
CHAR* computerName;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!Workstation)
|
||||
{
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
|
||||
|
@ -91,6 +93,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
|||
|
||||
static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
|
@ -116,6 +120,8 @@ static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
|||
DWORD nSize = 0;
|
||||
CHAR* computerName = NULL;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
|
||||
|
@ -254,7 +260,7 @@ static NTLM_CONTEXT* ntlm_ContextNew(void)
|
|||
|
||||
context->NegotiateFlags = 0;
|
||||
context->LmCompatibilityLevel = 3;
|
||||
context->state = NTLM_STATE_INITIAL;
|
||||
ntlm_change_state(context, NTLM_STATE_INITIAL);
|
||||
FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA);
|
||||
|
||||
if (context->NTLMv2)
|
||||
|
@ -414,9 +420,11 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec
|
|||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
if (context->state == NTLM_STATE_INITIAL)
|
||||
switch (ntlm_get_state(context))
|
||||
{
|
||||
context->state = NTLM_STATE_NEGOTIATE;
|
||||
case NTLM_STATE_INITIAL:
|
||||
{
|
||||
ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
|
||||
|
||||
if (!pInput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
@ -433,8 +441,10 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec
|
|||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
status = ntlm_read_NegotiateMessage(context, input_buffer);
|
||||
if (status != SEC_I_CONTINUE_NEEDED)
|
||||
return status;
|
||||
|
||||
if (context->state == NTLM_STATE_CHALLENGE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
|
||||
{
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
@ -455,7 +465,8 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec
|
|||
|
||||
return SEC_E_OUT_OF_SEQUENCE;
|
||||
}
|
||||
else if (context->state == NTLM_STATE_AUTHENTICATE)
|
||||
break;
|
||||
case NTLM_STATE_AUTHENTICATE:
|
||||
{
|
||||
if (!pInput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
@ -486,7 +497,10 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SEC_E_OUT_OF_SEQUENCE;
|
||||
}
|
||||
|
||||
|
@ -540,7 +554,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
|||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
|
||||
if ((!pInput) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE))
|
||||
{
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
@ -556,10 +570,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
|||
if (output_buffer->cbBuffer < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (context->state == NTLM_STATE_INITIAL)
|
||||
context->state = NTLM_STATE_NEGOTIATE;
|
||||
if (ntlm_get_state(context) == NTLM_STATE_INITIAL)
|
||||
ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
|
||||
|
||||
if (context->state == NTLM_STATE_NEGOTIATE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE)
|
||||
return ntlm_write_NegotiateMessage(context, output_buffer);
|
||||
|
||||
return SEC_E_OUT_OF_SEQUENCE;
|
||||
|
@ -585,7 +599,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
|||
context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer;
|
||||
}
|
||||
|
||||
if (context->state == NTLM_STATE_CHALLENGE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
|
||||
{
|
||||
status = ntlm_read_ChallengeMessage(context, input_buffer);
|
||||
|
||||
|
@ -606,7 +620,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
|||
if (output_buffer->cbBuffer < 1)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->state == NTLM_STATE_AUTHENTICATE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)
|
||||
return ntlm_write_AuthenticateMessage(context, output_buffer);
|
||||
}
|
||||
|
||||
|
@ -675,7 +689,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContex
|
|||
SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
|
||||
{
|
||||
BYTE* blob;
|
||||
SecBuffer* target = &ntlm->ChallengeTargetInfo;
|
||||
SecBuffer* target;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
WINPR_ASSERT(ntproof);
|
||||
|
||||
target = &ntlm->ChallengeTargetInfo;
|
||||
|
||||
if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
@ -696,7 +715,12 @@ SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
|
|||
SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue)
|
||||
{
|
||||
BYTE* blob;
|
||||
ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
|
||||
ULONG msgSize;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
WINPR_ASSERT(micvalue);
|
||||
|
||||
msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
|
||||
ntlm->AuthenticateMessage.cbBuffer;
|
||||
|
||||
if (!sspi_SecBufferAlloc(micvalue, msgSize))
|
||||
|
@ -975,8 +999,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON
|
|||
void* data;
|
||||
UINT32 SeqNo;
|
||||
UINT32 value;
|
||||
BYTE digest[WINPR_MD5_DIGEST_LENGTH];
|
||||
BYTE checksum[8];
|
||||
BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
BYTE checksum[8] = { 0 };
|
||||
BYTE* signature;
|
||||
ULONG version = 1;
|
||||
WINPR_HMAC_CTX* hmac;
|
||||
|
@ -1072,12 +1096,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSec
|
|||
void* data;
|
||||
UINT32 SeqNo;
|
||||
UINT32 value;
|
||||
BYTE digest[WINPR_MD5_DIGEST_LENGTH];
|
||||
BYTE checksum[8];
|
||||
BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
BYTE checksum[8] = { 0 };
|
||||
UINT32 version = 1;
|
||||
WINPR_HMAC_CTX* hmac;
|
||||
NTLM_CONTEXT* context;
|
||||
BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH];
|
||||
BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
PSecBuffer data_buffer = NULL;
|
||||
PSecBuffer signature_buffer = NULL;
|
||||
SeqNo = (UINT32)MessageSeqNo;
|
||||
|
@ -1264,3 +1288,81 @@ const SecPkgInfoW NTLM_SecPkgInfoW = {
|
|||
NTLM_SecPkgInfoW_Name, /* Name */
|
||||
NTLM_SecPkgInfoW_Comment /* Comment */
|
||||
};
|
||||
|
||||
char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags)
|
||||
{
|
||||
int x;
|
||||
if (!buffer || (size == 0))
|
||||
return buffer;
|
||||
|
||||
for (x = 0; x < 31; x++)
|
||||
{
|
||||
size_t len = strnlen(buffer, size);
|
||||
if (flags & x)
|
||||
{
|
||||
const char* str = ntlm_get_negotiate_string(1 << x);
|
||||
size_t flen = strlen(str);
|
||||
if (len > 0)
|
||||
{
|
||||
if (size - len < 1)
|
||||
break;
|
||||
strcat(buffer, "|");
|
||||
len++;
|
||||
}
|
||||
|
||||
if (size - len < flen)
|
||||
break;
|
||||
strcat(buffer, str);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* ntlm_message_type_string(UINT32 messageType)
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case MESSAGE_TYPE_NEGOTIATE:
|
||||
return "MESSAGE_TYPE_NEGOTIATE";
|
||||
case MESSAGE_TYPE_CHALLENGE:
|
||||
return "MESSAGE_TYPE_CHALLENGE";
|
||||
case MESSAGE_TYPE_AUTHENTICATE:
|
||||
return "MESSAGE_TYPE_AUTHENTICATE";
|
||||
default:
|
||||
return "MESSAGE_TYPE_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char* ntlm_state_string(NTLM_STATE state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case NTLM_STATE_INITIAL:
|
||||
return "NTLM_STATE_INITIAL";
|
||||
case NTLM_STATE_NEGOTIATE:
|
||||
return "NTLM_STATE_NEGOTIATE";
|
||||
case NTLM_STATE_CHALLENGE:
|
||||
return "NTLM_STATE_CHALLENGE";
|
||||
case NTLM_STATE_AUTHENTICATE:
|
||||
return "NTLM_STATE_AUTHENTICATE";
|
||||
case NTLM_STATE_COMPLETION:
|
||||
return "NTLM_STATE_COMPLETION";
|
||||
case NTLM_STATE_FINAL:
|
||||
return "NTLM_STATE_FINAL";
|
||||
default:
|
||||
return "NTLM_STATE_UNKNOWN";
|
||||
}
|
||||
}
|
||||
void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state)
|
||||
{
|
||||
WINPR_ASSERT(ntlm);
|
||||
WLog_DBG(TAG, "change state from %s to %s", ntlm_state_string(ntlm->state),
|
||||
ntlm_state_string(state));
|
||||
ntlm->state = state;
|
||||
}
|
||||
|
||||
NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm)
|
||||
{
|
||||
WINPR_ASSERT(ntlm);
|
||||
return ntlm->state;
|
||||
}
|
||||
|
|
|
@ -186,8 +186,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
|
@ -196,8 +195,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
BYTE ServerChallenge[8];
|
||||
BYTE Reserved[8];
|
||||
|
@ -208,8 +206,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
|
@ -258,7 +255,7 @@ typedef struct
|
|||
NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE;
|
||||
NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE;
|
||||
NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE;
|
||||
UINT32 MessageIntegrityCheckOffset;
|
||||
size_t MessageIntegrityCheckOffset;
|
||||
SecBuffer NegotiateMessage;
|
||||
SecBuffer ChallengeMessage;
|
||||
SecBuffer AuthenticateMessage;
|
||||
|
@ -286,6 +283,13 @@ typedef struct
|
|||
void* HashCallbackArg;
|
||||
} NTLM_CONTEXT;
|
||||
|
||||
char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags);
|
||||
const char* ntlm_message_type_string(UINT32 messageType);
|
||||
|
||||
const char* ntlm_state_string(NTLM_STATE state);
|
||||
void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state);
|
||||
NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm);
|
||||
|
||||
SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof);
|
||||
SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "../sspi.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <winpr/tchar.h>
|
||||
|
@ -85,11 +86,13 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvP
|
|||
|
||||
static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
Data_Write_UINT16(&pAvPair->AvId, id);
|
||||
}
|
||||
|
||||
static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
Data_Write_UINT16(&pAvPair->AvLen, len);
|
||||
}
|
||||
|
||||
|
@ -183,6 +186,7 @@ static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength
|
|||
|
||||
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
|
||||
}
|
||||
|
||||
|
@ -301,6 +305,8 @@ static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FO
|
|||
DWORD nSize = 0;
|
||||
CHAR* computerName;
|
||||
|
||||
WINPR_ASSERT(pName);
|
||||
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA)
|
||||
return -1;
|
||||
|
||||
|
@ -398,6 +404,9 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
|
|||
BYTE* ChannelBindingToken;
|
||||
UINT32 ChannelBindingTokenLength;
|
||||
SEC_CHANNEL_BINDINGS* ChannelBindings;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
|
||||
ChannelBindings = context->Bindings.Bindings;
|
||||
|
||||
|
@ -440,6 +449,7 @@ out:
|
|||
|
||||
static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
/**
|
||||
* The Single_Host_Data structure allows a client to send machine-specific information
|
||||
* within an authentication exchange to services on the same machine. The client can
|
||||
|
@ -455,9 +465,9 @@ static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
|||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
int rc = -1;
|
||||
BOOL rc = FALSE;
|
||||
ULONG length;
|
||||
ULONG AvPairsCount;
|
||||
ULONG AvPairsLength;
|
||||
|
@ -468,6 +478,8 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
|||
UNICODE_STRING DnsDomainName = { 0 };
|
||||
UNICODE_STRING DnsComputerName = { 0 };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -520,7 +532,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
|||
sizeof(context->Timestamp)))
|
||||
goto fail;
|
||||
|
||||
rc = 1;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
ntlm_free_unicode_string(&NbDomainName);
|
||||
ntlm_free_unicode_string(&NbComputerName);
|
||||
|
@ -529,7 +541,7 @@ fail:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG size;
|
||||
ULONG AvPairsCount;
|
||||
|
@ -550,6 +562,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
|||
size_t cbAvDnsTreeName;
|
||||
size_t cbChallengeTargetInfo;
|
||||
size_t cbAuthenticateTargetInfo;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
AvPairsCount = 1;
|
||||
AvPairsValueLength = 0;
|
||||
ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
|
||||
|
@ -751,8 +766,8 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
|||
ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
fail:
|
||||
sspi_SecBufferFree(&context->AuthenticateTargetInfo);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair);
|
|||
NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
|
||||
size_t* pcbAvPairListRemaining);
|
||||
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */
|
||||
|
|
|
@ -50,16 +50,21 @@ static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0
|
|||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
OSVERSIONINFOA osVersionInfo;
|
||||
OSVERSIONINFOA osVersionInfo = { 0 };
|
||||
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||||
GetVersionExA(&osVersionInfo);
|
||||
if (!GetVersionExA(&osVersionInfo))
|
||||
return FALSE;
|
||||
versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion;
|
||||
versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion;
|
||||
versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber;
|
||||
ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved));
|
||||
versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,17 +73,24 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
|||
* @param s
|
||||
*/
|
||||
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz,
|
||||
Stream_GetRemainingLength(s), 8);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,13 +99,24 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
|||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 5 + sizeof(versionInfo->Reserved))
|
||||
{
|
||||
WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz,
|
||||
Stream_GetRemainingCapacity(s), 5 + sizeof(versionInfo->Reserved));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,8 +125,10 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
|||
* @param s
|
||||
*/
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
WLog_VRB(TAG, "VERSION ={");
|
||||
WLog_VRB(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion);
|
||||
WLog_VRB(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion);
|
||||
|
@ -114,11 +139,18 @@ void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
static BOOL ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
size_t size;
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(challenge);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 28)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, got %" PRIuz "bytes",
|
||||
Stream_GetRemainingLength(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, challenge->RespType);
|
||||
Stream_Read_UINT8(s, challenge->HiRespType);
|
||||
|
@ -130,21 +162,39 @@ static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENG
|
|||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
|
||||
if (size > UINT32_MAX)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz "bytes", size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
challenge->cbAvPairs = (UINT32)size;
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*)malloc(challenge->cbAvPairs);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32 "bytes",
|
||||
challenge->cbAvPairs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
static BOOL ntlm_write_ntlm_v2_client_challenge(wStream* s,
|
||||
const NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(challenge);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 28)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write_UINT8(s, challenge->RespType);
|
||||
Stream_Write_UINT8(s, challenge->HiRespType);
|
||||
Stream_Write_UINT16(s, challenge->Reserved1);
|
||||
|
@ -153,20 +203,44 @@ static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLEN
|
|||
Stream_Write(s, challenge->ClientChallenge, 8);
|
||||
Stream_Write_UINT32(s, challenge->Reserved3);
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs);
|
||||
if (Stream_GetRemainingCapacity(s) < length)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"NTLMv2_CLIENT_CHALLENGE::AvPairs expected %" PRIu32 "bytes, have %" PRIuz "bytes",
|
||||
length, Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 16)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingLength(s));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Read(s, response->Response, 16);
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 16)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write(s, response->Response, 16);
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
@ -178,8 +252,11 @@ int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
|||
|
||||
void ntlm_current_time(BYTE* timestamp)
|
||||
{
|
||||
FILETIME filetime;
|
||||
ULARGE_INTEGER time64;
|
||||
FILETIME filetime = { 0 };
|
||||
ULARGE_INTEGER time64 = { 0 };
|
||||
|
||||
WINPR_ASSERT(timestamp);
|
||||
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
time64.u.LowPart = filetime.dwLowDateTime;
|
||||
time64.u.HighPart = filetime.dwHighDateTime;
|
||||
|
@ -193,6 +270,8 @@ void ntlm_current_time(BYTE* timestamp)
|
|||
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0)
|
||||
CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8);
|
||||
else
|
||||
|
@ -203,7 +282,12 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
{
|
||||
WINPR_SAM* sam;
|
||||
WINPR_SAM_ENTRY* entry;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
sam = SamOpen(context->SamFile, TRUE);
|
||||
|
||||
if (!sam)
|
||||
|
@ -257,7 +341,12 @@ static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
int i;
|
||||
char* PasswordHash = NULL;
|
||||
INT64 PasswordHashLength = 0;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
/* Password contains a password hash of length (PasswordLength -
|
||||
* SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) */
|
||||
PasswordHashLength = credentials->identity.PasswordLength - SSPI_CREDENTIALS_HASH_LENGTH_OFFSET;
|
||||
|
@ -284,9 +373,14 @@ static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
|
||||
if (credentials)
|
||||
|
@ -311,10 +405,10 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
#endif
|
||||
|
||||
if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
return 1;
|
||||
return TRUE;
|
||||
|
||||
if (!credentials)
|
||||
return -1;
|
||||
return FALSE;
|
||||
else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
{
|
||||
NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
|
@ -325,7 +419,7 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
{
|
||||
/* Special case for WinPR: password hash */
|
||||
if (ntlm_convert_password_hash(context, context->NtlmHash) < 0)
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain,
|
||||
|
@ -344,55 +438,57 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
SecBuffer proofValue, micValue;
|
||||
|
||||
if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK)
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK)
|
||||
{
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = context->HashCallback(context->HashCallbackArg, &credentials->identity, &proofValue,
|
||||
context->EncryptedRandomSessionKey,
|
||||
(&context->AUTHENTICATE_MESSAGE)->MessageIntegrityCheck,
|
||||
&micValue, hash);
|
||||
context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck, &micValue,
|
||||
hash);
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
sspi_SecBufferFree(&micValue);
|
||||
return ret ? 1 : -1;
|
||||
return ret ? TRUE : FALSE;
|
||||
}
|
||||
else if (context->UseSamFileDatabase)
|
||||
{
|
||||
return ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* response;
|
||||
BYTE value[WINPR_MD5_DIGEST_LENGTH];
|
||||
BYTE value[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash))
|
||||
return FALSE;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
response = (BYTE*)context->LmChallengeResponse.pvBuffer;
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
|
@ -401,7 +497,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
|||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response
|
||||
* (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -411,13 +507,17 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* blob;
|
||||
SecBuffer ntlm_v2_temp = { 0 };
|
||||
SecBuffer ntlm_v2_temp_chal = { 0 };
|
||||
PSecBuffer TargetInfo = &context->ChallengeTargetInfo;
|
||||
int ret = -1;
|
||||
PSecBuffer TargetInfo;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
goto exit;
|
||||
|
@ -426,7 +526,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
|||
blob = (BYTE*)ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash) < 0)
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash))
|
||||
goto exit;
|
||||
|
||||
/* Construct temp */
|
||||
|
@ -467,7 +567,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
|||
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
|
||||
context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey,
|
||||
WINPR_MD5_DIGEST_LENGTH);
|
||||
ret = 1;
|
||||
ret = TRUE;
|
||||
exit:
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
|
@ -500,9 +600,11 @@ void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext)
|
|||
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
winpr_RAND(context->ClientChallenge, 8);
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, sizeof(context->ClientChallenge)) == 0)
|
||||
winpr_RAND(context->ClientChallenge, sizeof(context->ClientChallenge));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,8 +614,10 @@ void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
winpr_RAND(context->ServerChallenge, 8);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, sizeof(context->ServerChallenge)) == 0)
|
||||
winpr_RAND(context->ServerChallenge, sizeof(context->ServerChallenge));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -524,8 +628,11 @@ void ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(sizeof(context->KeyExchangeKey) == sizeof(context->SessionBaseKey));
|
||||
|
||||
/* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */
|
||||
CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, 16);
|
||||
CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, sizeof(context->KeyExchangeKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,7 +642,8 @@ void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
winpr_RAND(context->RandomSessionKey, 16);
|
||||
WINPR_ASSERT(context);
|
||||
winpr_RAND(context->RandomSessionKey, sizeof(context->RandomSessionKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -545,7 +653,11 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_exported_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, 16);
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(sizeof(context->ExportedSessionKey) == sizeof(context->RandomSessionKey));
|
||||
|
||||
CopyMemory(context->ExportedSessionKey, context->RandomSessionKey,
|
||||
sizeof(context->ExportedSessionKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -557,6 +669,7 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
|||
{
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
WINPR_ASSERT(context);
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey,
|
||||
context->EncryptedRandomSessionKey);
|
||||
}
|
||||
|
@ -568,6 +681,8 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
|
||||
|
@ -577,10 +692,18 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
|||
* AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey) else Set RandomSessionKey to KeyExchangeKey
|
||||
*/
|
||||
if (context->NegotiateKeyExchange)
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey,
|
||||
context->RandomSessionKey);
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->EncryptedRandomSessionKey) ==
|
||||
sizeof(context->RandomSessionKey));
|
||||
ntlm_rc4k(context->KeyExchangeKey, sizeof(context->EncryptedRandomSessionKey),
|
||||
context->EncryptedRandomSessionKey, context->RandomSessionKey);
|
||||
}
|
||||
else
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, 16);
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->RandomSessionKey) == sizeof(context->KeyExchangeKey));
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey,
|
||||
sizeof(context->RandomSessionKey));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -591,29 +714,32 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
|||
* @param signing_key Destination signing key
|
||||
*/
|
||||
|
||||
static int ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic,
|
||||
static BOOL ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic,
|
||||
BYTE* signing_key)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
size_t length;
|
||||
BYTE* value;
|
||||
BYTE* value = NULL;
|
||||
|
||||
WINPR_ASSERT(exported_session_key);
|
||||
WINPR_ASSERT(sign_magic);
|
||||
WINPR_ASSERT(signing_key);
|
||||
|
||||
length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer;
|
||||
value = (BYTE*)malloc(length);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
goto out;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
|
||||
if (!winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH))
|
||||
{
|
||||
free(value);
|
||||
return -1;
|
||||
}
|
||||
rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
out:
|
||||
free(value);
|
||||
return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -622,10 +748,13 @@ static int ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer signMagic = { sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC };
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey);
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
|
||||
context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -634,43 +763,13 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer signMagic = { sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC };
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate sealing key.
|
||||
* @msdn{cc236712}
|
||||
* @param exported_session_key ExportedSessionKey
|
||||
* @param seal_magic Seal magic string
|
||||
* @param sealing_key Destination sealing key
|
||||
*/
|
||||
|
||||
static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic,
|
||||
BYTE* sealing_key)
|
||||
{
|
||||
BYTE* p;
|
||||
SecBuffer buffer;
|
||||
|
||||
if (!sspi_SecBufferAlloc(&buffer, WINPR_MD5_DIGEST_LENGTH + seal_magic->cbBuffer))
|
||||
return -1;
|
||||
|
||||
p = (BYTE*)buffer.pvBuffer;
|
||||
/* Concatenate ExportedSessionKey with seal magic */
|
||||
CopyMemory(p, exported_session_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
CopyMemory(&p[WINPR_MD5_DIGEST_LENGTH], seal_magic->pvBuffer, seal_magic->cbBuffer);
|
||||
|
||||
if (!winpr_Digest(WINPR_MD_MD5, buffer.pvBuffer, buffer.cbBuffer, sealing_key,
|
||||
WINPR_MD5_DIGEST_LENGTH))
|
||||
{
|
||||
sspi_SecBufferFree(&buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sspi_SecBufferFree(&buffer);
|
||||
return 1;
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
|
||||
context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -679,10 +778,13 @@ static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC };
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey);
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -691,10 +793,13 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC };
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey);
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -704,14 +809,17 @@ void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
if (context->server)
|
||||
{
|
||||
context->SendSigningKey = context->ServerSigningKey;
|
||||
context->RecvSigningKey = context->ClientSigningKey;
|
||||
context->SendSealingKey = context->ClientSealingKey;
|
||||
context->RecvSealingKey = context->ServerSealingKey;
|
||||
context->SendRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16);
|
||||
context->RecvRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16);
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -719,22 +827,29 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context)
|
|||
context->RecvSigningKey = context->ServerSigningKey;
|
||||
context->SendSealingKey = context->ServerSealingKey;
|
||||
context->RecvSealingKey = context->ClientSealingKey;
|
||||
context->SendRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16);
|
||||
context->RecvRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16);
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
}
|
||||
}
|
||||
|
||||
void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
/*
|
||||
* Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE,
|
||||
* CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey
|
||||
*/
|
||||
WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(mic);
|
||||
WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
memset(mic, 0, size);
|
||||
if (!hmac)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
if (winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH))
|
||||
{
|
||||
|
@ -742,10 +857,27 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT
|
|||
context->NegotiateMessage.cbBuffer);
|
||||
winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer,
|
||||
context->ChallengeMessage.cbBuffer);
|
||||
|
||||
if (context->MessageIntegrityCheckOffset > 0)
|
||||
{
|
||||
const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer;
|
||||
const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
const size_t rest = context->MessageIntegrityCheckOffset + sizeof(data);
|
||||
|
||||
WINPR_ASSERT(rest <= context->AuthenticateMessage.cbBuffer);
|
||||
winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset);
|
||||
winpr_HMAC_Update(hmac, data, sizeof(data));
|
||||
winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest);
|
||||
}
|
||||
else
|
||||
{
|
||||
winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer,
|
||||
context->AuthenticateMessage.cbBuffer);
|
||||
}
|
||||
winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH);
|
||||
rc = TRUE;
|
||||
}
|
||||
|
||||
winpr_HMAC_Free(hmac);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -24,16 +24,16 @@
|
|||
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo);
|
||||
#endif
|
||||
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
|
@ -41,8 +41,8 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
|||
void ntlm_current_time(BYTE* timestamp);
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
|
@ -53,12 +53,12 @@ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context);
|
|||
void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size);
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size);
|
||||
|
||||
#endif /* WINPR_AUTH_NTLM_COMPUTE_H */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,12 +23,14 @@
|
|||
#include "ntlm.h"
|
||||
|
||||
SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, const PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer);
|
||||
|
||||
SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context);
|
||||
|
||||
const char* ntlm_get_negotiate_string(UINT32 flag);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_MESSAGE_H */
|
||||
|
|
|
@ -465,18 +465,15 @@ static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
|
|||
free(ntlm);
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
static BOOL test_default(void)
|
||||
{
|
||||
int status;
|
||||
int rc = -1;
|
||||
BOOL rc = FALSE;
|
||||
PSecBuffer pSecBuffer;
|
||||
TEST_NTLM_CLIENT* client = NULL;
|
||||
TEST_NTLM_SERVER* server = NULL;
|
||||
BOOL DynamicTest = TRUE;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
*/
|
||||
|
@ -682,7 +679,7 @@ int TestNTLM(int argc, char* argv[])
|
|||
goto fail;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
/**
|
||||
|
@ -692,3 +689,13 @@ fail:
|
|||
test_ntlm_server_free(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_default())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue