Blame winpr/libwinpr/sspi/NTLM/ntlm_message.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * NTLM Security Package (Message)
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include "ntlm.h"
Packit Service fa4841
#include "../sspi.h"
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/print.h>
Packit Service fa4841
#include <winpr/stream.h>
Packit Service fa4841
#include <winpr/sysinfo.h>
Packit Service fa4841
Packit Service fa4841
#include "ntlm_compute.h"
Packit Service fa4841
Packit Service fa4841
#include "ntlm_message.h"
Packit Service fa4841
Packit Service fa4841
#include "../log.h"
Packit Service fa4841
#define TAG WINPR_TAG("sspi.NTLM")
Packit Service fa4841
Packit Service fa4841
static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' };
Packit Service fa4841
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
static const char* const NTLM_NEGOTIATE_STRINGS[] = { "NTLMSSP_NEGOTIATE_56",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_KEY_EXCH",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_128",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED1",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED2",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED3",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_VERSION",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED4",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_TARGET_INFO",
Packit Service fa4841
	                                                  "NTLMSSP_REQUEST_NON_NT_SESSION_KEY",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED5",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_IDENTIFY",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED6",
Packit Service fa4841
	                                                  "NTLMSSP_TARGET_TYPE_SERVER",
Packit Service fa4841
	                                                  "NTLMSSP_TARGET_TYPE_DOMAIN",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_ALWAYS_SIGN",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED7",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_ANONYMOUS",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED8",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_NTLM",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED9",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_LM_KEY",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_DATAGRAM",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_SEAL",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_SIGN",
Packit Service fa4841
	                                                  "NTLMSSP_RESERVED10",
Packit Service fa4841
	                                                  "NTLMSSP_REQUEST_TARGET",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_OEM",
Packit Service fa4841
	                                                  "NTLMSSP_NEGOTIATE_UNICODE" };
Packit Service fa4841
Packit Service fa4841
static void ntlm_print_negotiate_flags(UINT32 flags)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	const char* str;
Packit Service fa4841
	WLog_INFO(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags);
Packit Service fa4841
Packit Service fa4841
	for (i = 31; i >= 0; i--)
Packit Service fa4841
	{
Packit Service fa4841
		if ((flags >> i) & 1)
Packit Service fa4841
		{
Packit Service fa4841
			str = NTLM_NEGOTIATE_STRINGS[(31 - i)];
Packit Service fa4841
			WLog_INFO(TAG, "\t%s (%d),", str, (31 - i));
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
Packit Service fa4841
{
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 12)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	Stream_Read(s, header->Signature, 8);
Packit Service fa4841
	Stream_Read_UINT32(s, header->MessageType);
Packit Service fa4841
Packit Service fa4841
	if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
Packit Service fa4841
{
Packit Service fa4841
	Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE));
Packit Service fa4841
	Stream_Write_UINT32(s, header->MessageType);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
Packit Service fa4841
{
Packit Service fa4841
	CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
Packit Service fa4841
	header->MessageType = MessageType;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
Packit Service fa4841
{
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 8)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT16(s, fields->Len);          /* Len (2 bytes) */
Packit Service fa4841
	Stream_Read_UINT16(s, fields->MaxLen);       /* MaxLen (2 bytes) */
Packit Service fa4841
	Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
Packit Service fa4841
{
Packit Service fa4841
	if (fields->MaxLen < 1)
Packit Service fa4841
		fields->MaxLen = fields->Len;
Packit Service fa4841
Packit Service fa4841
	Stream_Write_UINT16(s, fields->Len);          /* Len (2 bytes) */
Packit Service fa4841
	Stream_Write_UINT16(s, fields->MaxLen);       /* MaxLen (2 bytes) */
Packit Service fa4841
	Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
Packit Service fa4841
{
Packit Service fa4841
	if (fields->Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		const UINT32 offset = fields->BufferOffset + fields->Len;
Packit Service fa4841
Packit Service fa4841
		if (fields->BufferOffset > UINT32_MAX - fields->Len)
Packit Service fa4841
			return -1;
Packit Service fa4841
Packit Service fa4841
		if (offset > Stream_Length(s))
Packit Service fa4841
			return -1;
Packit Service fa4841
Packit Service fa4841
		fields->Buffer = (PBYTE)malloc(fields->Len);
Packit Service fa4841
Packit Service fa4841
		if (!fields->Buffer)
Packit Service fa4841
			return -1;
Packit Service fa4841
Packit Service fa4841
		Stream_SetPosition(s, fields->BufferOffset);
Packit Service fa4841
		Stream_Read(s, fields->Buffer, fields->Len);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
Packit Service fa4841
{
Packit Service fa4841
	if (fields->Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_SetPosition(s, fields->BufferOffset);
Packit Service fa4841
		Stream_Write(s, fields->Buffer, fields->Len);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
Packit Service fa4841
{
Packit Service fa4841
	if (fields)
Packit Service fa4841
	{
Packit Service fa4841
		if (fields->Buffer)
Packit Service fa4841
		{
Packit Service fa4841
			free(fields->Buffer);
Packit Service fa4841
			fields->Len = 0;
Packit Service fa4841
			fields->MaxLen = 0;
Packit Service fa4841
			fields->Buffer = NULL;
Packit Service fa4841
			fields->BufferOffset = 0;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)
Packit Service fa4841
{
Packit Service fa4841
	WLog_DBG(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name,
Packit Service fa4841
	         fields->Len, fields->MaxLen, fields->BufferOffset);
Packit Service fa4841
Packit Service fa4841
	if (fields->Len > 0)
Packit Service fa4841
		winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len);
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	NTLM_NEGOTIATE_MESSAGE* message;
Packit Service fa4841
	message = &context->NEGOTIATE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (message->MessageType != MESSAGE_TYPE_NEGOTIATE)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
Packit Service fa4841
	if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) &&
Packit Service fa4841
	      (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) &&
Packit Service fa4841
	      (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE)))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	context->NegotiateFlags = message->NegotiateFlags;
Packit Service fa4841
Packit Service fa4841
	/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INVALID_TOKEN;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
	{
Packit Service fa4841
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
Packit Service fa4841
		{
Packit Service fa4841
			Stream_Free(s, FALSE);
Packit Service fa4841
			return SEC_E_INVALID_TOKEN;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	length = Stream_GetPosition(s);
Packit Service fa4841
	buffer->cbBuffer = length;
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
	context->NegotiateMessage.BufferType = buffer->BufferType;
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", context->NegotiateMessage.cbBuffer);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer,
Packit Service fa4841
	              context->NegotiateMessage.cbBuffer);
Packit Service fa4841
	ntlm_print_negotiate_flags(message->NegotiateFlags);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_CHALLENGE;
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return SEC_I_CONTINUE_NEEDED;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	NTLM_NEGOTIATE_MESSAGE* message;
Packit Service fa4841
	message = &context->NEGOTIATE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_NEGOTIATE);
Packit Service fa4841
Packit Service fa4841
	if (context->NTLMv2)
Packit Service fa4841
	{
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
Packit Service fa4841
Packit Service fa4841
	if (context->confidentiality)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
Packit Service fa4841
Packit Service fa4841
	if (context->SendVersionInfo)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_get_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	context->NegotiateFlags = message->NegotiateFlags;
Packit Service fa4841
	/* Message Header (12 bytes) */
Packit Service fa4841
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message);
Packit Service fa4841
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
	/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
Packit Service fa4841
	/* DomainNameFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->DomainName));
Packit Service fa4841
	/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
Packit Service fa4841
	/* WorkstationFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->Workstation));
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_write_version_info(s, &(message->Version));
Packit Service fa4841
Packit Service fa4841
	length = Stream_GetPosition(s);
Packit Service fa4841
	buffer->cbBuffer = length;
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
	context->NegotiateMessage.BufferType = buffer->BufferType;
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_CHALLENGE;
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return SEC_I_CONTINUE_NEEDED;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	size_t StartOffset;
Packit Service fa4841
	size_t PayloadOffset;
Packit Service fa4841
	NTLM_AV_PAIR* AvTimestamp;
Packit Service fa4841
	NTLM_CHALLENGE_MESSAGE* message;
Packit Service fa4841
	if (!context || !buffer)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	ntlm_generate_client_challenge(context);
Packit Service fa4841
	message = &context->CHALLENGE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	StartOffset = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (message->MessageType != MESSAGE_TYPE_CHALLENGE)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
	context->NegotiateFlags = message->NegotiateFlags;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 8)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
Packit Service fa4841
	CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 8)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
	{
Packit Service fa4841
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* Payload (variable) */
Packit Service fa4841
	PayloadOffset = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	status = SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	if (message->TargetName.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (message->TargetInfo.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		size_t cbAvTimestamp;
Packit Service fa4841
Packit Service fa4841
		if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;
Packit Service fa4841
		context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
Packit Service fa4841
		AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*)message->TargetInfo.Buffer,
Packit Service fa4841
		                               message->TargetInfo.Len, MsvAvTimestamp, &cbAvTimestamp);
Packit Service fa4841
Packit Service fa4841
		if (AvTimestamp)
Packit Service fa4841
		{
Packit Service fa4841
			PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp);
Packit Service fa4841
Packit Service fa4841
			if (!ptr)
Packit Service fa4841
				goto fail;
Packit Service fa4841
Packit Service fa4841
			if (context->NTLMv2)
Packit Service fa4841
				context->UseMIC = TRUE;
Packit Service fa4841
Packit Service fa4841
			CopyMemory(context->ChallengeTimestamp, ptr, 8);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
Packit Service fa4841
	if (length > buffer->cbBuffer)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (context->ChallengeMessage.pvBuffer)
Packit Service fa4841
		CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length);
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer,
Packit Service fa4841
	              context->ChallengeMessage.cbBuffer);
Packit Service fa4841
	ntlm_print_negotiate_flags(context->NegotiateFlags);
Packit Service fa4841
Packit Service fa4841
	if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	ntlm_print_message_fields(&(message->TargetName), "TargetName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");
Packit Service fa4841
Packit Service fa4841
	if (context->ChallengeTargetInfo.cbBuffer > 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "ChallengeTargetInfo (%" PRIu32 "):", context->ChallengeTargetInfo.cbBuffer);
Packit Service fa4841
		ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer,
Packit Service fa4841
		                        context->ChallengeTargetInfo.cbBuffer);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	/* AV_PAIRs */
Packit Service fa4841
Packit Service fa4841
	if (context->NTLMv2)
Packit Service fa4841
	{
Packit Service fa4841
		if (ntlm_construct_authenticate_target_info(context) < 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		sspi_SecBufferFree(&context->ChallengeTargetInfo);
Packit Service fa4841
		context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
Packit Service fa4841
		context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	ntlm_generate_timestamp(context); /* Timestamp */
Packit Service fa4841
Packit Service fa4841
	if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	ntlm_generate_key_exchange_key(context);     /* KeyExchangeKey */
Packit Service fa4841
	ntlm_generate_random_session_key(context);   /* RandomSessionKey */
Packit Service fa4841
	ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
Packit Service fa4841
	ntlm_encrypt_random_session_key(context);    /* EncryptedRandomSessionKey */
Packit Service fa4841
	/* Generate signing keys */
Packit Service fa4841
	ntlm_generate_client_signing_key(context);
Packit Service fa4841
	ntlm_generate_server_signing_key(context);
Packit Service fa4841
	/* Generate sealing keys */
Packit Service fa4841
	ntlm_generate_client_sealing_key(context);
Packit Service fa4841
	ntlm_generate_server_sealing_key(context);
Packit Service fa4841
	/* Initialize RC4 seal state using client sealing key */
Packit Service fa4841
	ntlm_init_rc4_seal_states(context);
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "ClientChallenge");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8);
Packit Service fa4841
	WLog_DBG(TAG, "ServerChallenge");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8);
Packit Service fa4841
	WLog_DBG(TAG, "SessionBaseKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "KeyExchangeKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ExportedSessionKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "RandomSessionKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ClientSigningKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ClientSealingKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ServerSigningKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ServerSealingKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "Timestamp");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8);
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_AUTHENTICATE;
Packit Service fa4841
	status = SEC_I_CONTINUE_NEEDED;
Packit Service fa4841
fail:
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->TargetName));
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	UINT32 PayloadOffset;
Packit Service fa4841
	NTLM_CHALLENGE_MESSAGE* message;
Packit Service fa4841
	message = &context->CHALLENGE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	ntlm_get_version_info(&(message->Version)); /* Version */
Packit Service fa4841
	ntlm_generate_server_challenge(context);    /* Server Challenge */
Packit Service fa4841
	ntlm_generate_timestamp(context);           /* Timestamp */
Packit Service fa4841
Packit Service fa4841
	if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */
Packit Service fa4841
	message->NegotiateFlags = context->NegotiateFlags;
Packit Service fa4841
	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_CHALLENGE);
Packit Service fa4841
	/* Message Header (12 bytes) */
Packit Service fa4841
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
Packit Service fa4841
	{
Packit Service fa4841
		message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
Packit Service fa4841
		message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
Packit Service fa4841
	{
Packit Service fa4841
		message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
Packit Service fa4841
		message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	PayloadOffset = 48;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		PayloadOffset += 8;
Packit Service fa4841
Packit Service fa4841
	message->TargetName.BufferOffset = PayloadOffset;
Packit Service fa4841
	message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len;
Packit Service fa4841
	/* TargetNameFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->TargetName));
Packit Service fa4841
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
	Stream_Write(s, message->ServerChallenge, 8);    /* ServerChallenge (8 bytes) */
Packit Service fa4841
	Stream_Write(s, message->Reserved, 8);           /* Reserved (8 bytes), should be ignored */
Packit Service fa4841
	/* TargetInfoFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->TargetInfo));
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */
Packit Service fa4841
Packit Service fa4841
	/* Payload (variable) */
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
Packit Service fa4841
		ntlm_write_message_fields_buffer(s, &(message->TargetName));
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
Packit Service fa4841
		ntlm_write_message_fields_buffer(s, &(message->TargetInfo));
Packit Service fa4841
Packit Service fa4841
	length = Stream_GetPosition(s);
Packit Service fa4841
	buffer->cbBuffer = length;
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer,
Packit Service fa4841
	              context->ChallengeMessage.cbBuffer);
Packit Service fa4841
	ntlm_print_negotiate_flags(message->NegotiateFlags);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	ntlm_print_message_fields(&(message->TargetName), "TargetName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_AUTHENTICATE;
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return SEC_I_CONTINUE_NEEDED;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	UINT32 flags = 0;
Packit Service fa4841
	NTLM_AV_PAIR* AvFlags = NULL;
Packit Service fa4841
	UINT32 PayloadBufferOffset;
Packit Service fa4841
	NTLM_AUTHENTICATE_MESSAGE* message;
Packit Service fa4841
	SSPI_CREDENTIALS* credentials = context->credentials;
Packit Service fa4841
Packit Service fa4841
	message = &context->AUTHENTICATE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (message->MessageType != MESSAGE_TYPE_AUTHENTICATE)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) <
Packit Service fa4841
	    0) /* LmChallengeResponseFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) <
Packit Service fa4841
	    0) /* NtChallengeResponseFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) <
Packit Service fa4841
	    0) /* EncryptedRandomSessionKeyFields (8 bytes) */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		goto fail;
Packit Service fa4841
	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
	context->NegotiateKeyExchange =
Packit Service fa4841
	    (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
Packit Service fa4841
	    (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
	{
Packit Service fa4841
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	PayloadBufferOffset = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	status = SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) <
Packit Service fa4841
	    0) /* LmChallengeResponse */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) <
Packit Service fa4841
	    0) /* NtChallengeResponse */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (message->NtChallengeResponse.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		int rc;
Packit Service fa4841
		size_t cbAvFlags;
Packit Service fa4841
		wStream* snt =
Packit Service fa4841
		    Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len);
Packit Service fa4841
Packit Service fa4841
		if (!snt)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		status = SEC_E_INVALID_TOKEN;
Packit Service fa4841
		rc = ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response));
Packit Service fa4841
		Stream_Free(snt, FALSE);
Packit Service fa4841
		if (rc < 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
		status = SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
		context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
Packit Service fa4841
		context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
Packit Service fa4841
		sspi_SecBufferFree(&(context->ChallengeTargetInfo));
Packit Service fa4841
		context->ChallengeTargetInfo.pvBuffer = (void*)context->NTLMv2Response.Challenge.AvPairs;
Packit Service fa4841
		context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16);
Packit Service fa4841
		CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
Packit Service fa4841
		AvFlags =
Packit Service fa4841
		    ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
Packit Service fa4841
		                     context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);
Packit Service fa4841
Packit Service fa4841
		if (AvFlags)
Packit Service fa4841
			Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) <
Packit Service fa4841
	    0) /* EncryptedRandomSessionKey */
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (message->EncryptedRandomSessionKey.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		if (message->EncryptedRandomSessionKey.Len != 16)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
Packit Service fa4841
		           16);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	length = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
Packit Service fa4841
	buffer->cbBuffer = length;
Packit Service fa4841
	Stream_SetPosition(s, PayloadBufferOffset);
Packit Service fa4841
Packit Service fa4841
	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
Packit Service fa4841
	{
Packit Service fa4841
		context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
		status = SEC_E_INVALID_TOKEN;
Packit Service fa4841
		if (Stream_GetRemainingLength(s) < 16)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		Stream_Read(s, message->MessageIntegrityCheck, 16);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")",
Packit Service fa4841
	         context->AuthenticateMessage.cbBuffer);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer,
Packit Service fa4841
	              context->AuthenticateMessage.cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	ntlm_print_message_fields(&(message->DomainName), "DomainName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->UserName), "UserName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->Workstation), "Workstation");
Packit Service fa4841
	ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse");
Packit Service fa4841
	ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
Packit Service fa4841
	ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
Packit Service fa4841
	ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs,
Packit Service fa4841
	                        context->NTLMv2Response.Challenge.cbAvPairs);
Packit Service fa4841
Packit Service fa4841
	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "MessageIntegrityCheck:");
Packit Service fa4841
		winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (message->UserName.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		credentials->identity.User = (UINT16*)malloc(message->UserName.Len);
Packit Service fa4841
Packit Service fa4841
		if (!credentials->identity.User)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
Packit Service fa4841
		credentials->identity.UserLength = message->UserName.Len / 2;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (message->DomainName.Len > 0)
Packit Service fa4841
	{
Packit Service fa4841
		credentials->identity.Domain = (UINT16*)malloc(message->DomainName.Len);
Packit Service fa4841
Packit Service fa4841
		if (!credentials->identity.Domain)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
Packit Service fa4841
		           message->DomainName.Len);
Packit Service fa4841
		credentials->identity.DomainLength = message->DomainName.Len / 2;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	/* Computations beyond this point require the NTLM hash of the password */
Packit Service fa4841
	context->state = NTLM_STATE_COMPLETION;
Packit Service fa4841
	return SEC_I_COMPLETE_NEEDED;
Packit Service fa4841
Packit Service fa4841
fail:
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Send NTLMSSP AUTHENTICATE_MESSAGE.\n
Packit Service fa4841
 * AUTHENTICATE_MESSAGE @msdn{cc236643}
Packit Service fa4841
 * @param NTLM context
Packit Service fa4841
 * @param buffer
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
Packit Service fa4841
{
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	size_t length;
Packit Service fa4841
	UINT32 PayloadBufferOffset;
Packit Service fa4841
	NTLM_AUTHENTICATE_MESSAGE* message;
Packit Service fa4841
	SSPI_CREDENTIALS* credentials = context->credentials;
Packit Service fa4841
	message = &context->AUTHENTICATE_MESSAGE;
Packit Service fa4841
	ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
Packit Service fa4841
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	if (context->NTLMv2)
Packit Service fa4841
	{
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
Packit Service fa4841
Packit Service fa4841
		if (context->SendVersionInfo)
Packit Service fa4841
			message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
Packit Service fa4841
Packit Service fa4841
	if (context->SendWorkstationName)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
Packit Service fa4841
Packit Service fa4841
	if (context->confidentiality)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
Packit Service fa4841
Packit Service fa4841
	if (context->CHALLENGE_MESSAGE.NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
Packit Service fa4841
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
Packit Service fa4841
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_get_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
Packit Service fa4841
	{
Packit Service fa4841
		message->Workstation.Len = context->Workstation.Length;
Packit Service fa4841
		message->Workstation.Buffer = (BYTE*)context->Workstation.Buffer;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (credentials->identity.DomainLength > 0)
Packit Service fa4841
	{
Packit Service fa4841
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
Packit Service fa4841
		message->DomainName.Len = (UINT16)credentials->identity.DomainLength * 2;
Packit Service fa4841
		message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	message->UserName.Len = (UINT16)credentials->identity.UserLength * 2;
Packit Service fa4841
	message->UserName.Buffer = (BYTE*)credentials->identity.User;
Packit Service fa4841
	message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
Packit Service fa4841
	message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
Packit Service fa4841
	message->NtChallengeResponse.Len = (UINT16)context->NtChallengeResponse.cbBuffer;
Packit Service fa4841
	message->NtChallengeResponse.Buffer = (BYTE*)context->NtChallengeResponse.pvBuffer;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
Packit Service fa4841
	{
Packit Service fa4841
		message->EncryptedRandomSessionKey.Len = 16;
Packit Service fa4841
		message->EncryptedRandomSessionKey.Buffer = context->EncryptedRandomSessionKey;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	PayloadBufferOffset = 64;
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		PayloadBufferOffset += 8; /* Version (8 bytes) */
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
		PayloadBufferOffset += 16; /* Message Integrity Check (16 bytes) */
Packit Service fa4841
Packit Service fa4841
	message->DomainName.BufferOffset = PayloadBufferOffset;
Packit Service fa4841
	message->UserName.BufferOffset = message->DomainName.BufferOffset + message->DomainName.Len;
Packit Service fa4841
	message->Workstation.BufferOffset = message->UserName.BufferOffset + message->UserName.Len;
Packit Service fa4841
	message->LmChallengeResponse.BufferOffset =
Packit Service fa4841
	    message->Workstation.BufferOffset + message->Workstation.Len;
Packit Service fa4841
	message->NtChallengeResponse.BufferOffset =
Packit Service fa4841
	    message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len;
Packit Service fa4841
	message->EncryptedRandomSessionKey.BufferOffset =
Packit Service fa4841
	    message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len;
Packit Service fa4841
	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_AUTHENTICATE);
Packit Service fa4841
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); /* Message Header (12 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(
Packit Service fa4841
	    s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(
Packit Service fa4841
	    s, &(message->NtChallengeResponse));               /* NtChallengeResponseFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->DomainName));  /* DomainNameFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->UserName));    /* UserNameFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */
Packit Service fa4841
	ntlm_write_message_fields(
Packit Service fa4841
	    s, &(message->EncryptedRandomSessionKey));   /* EncryptedRandomSessionKeyFields (8 bytes) */
Packit Service fa4841
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
	{
Packit Service fa4841
		context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s);
Packit Service fa4841
		Stream_Zero(s, 16); /* Message Integrity Check (16 bytes) */
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
Packit Service fa4841
		ntlm_write_message_fields_buffer(s, &(message->DomainName)); /* DomainName */
Packit Service fa4841
Packit Service fa4841
	ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
Packit Service fa4841
		ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */
Packit Service fa4841
Packit Service fa4841
	ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */
Packit Service fa4841
	ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
Packit Service fa4841
		ntlm_write_message_fields_buffer(
Packit Service fa4841
		    s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */
Packit Service fa4841
Packit Service fa4841
	length = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
Packit Service fa4841
	buffer->cbBuffer = length;
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
	{
Packit Service fa4841
		/* Message Integrity Check */
Packit Service fa4841
		ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, 16);
Packit Service fa4841
		Stream_SetPosition(s, context->MessageIntegrityCheckOffset);
Packit Service fa4841
		Stream_Write(s, message->MessageIntegrityCheck, 16);
Packit Service fa4841
		Stream_SetPosition(s, length);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length);
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length);
Packit Service fa4841
	ntlm_print_negotiate_flags(message->NegotiateFlags);
Packit Service fa4841
Packit Service fa4841
	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
Packit Service fa4841
		ntlm_print_version_info(&(message->Version));
Packit Service fa4841
Packit Service fa4841
	if (context->AuthenticateTargetInfo.cbBuffer > 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG,
Packit Service fa4841
		         "AuthenticateTargetInfo (%" PRIu32 "):", context->AuthenticateTargetInfo.cbBuffer);
Packit Service fa4841
		ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer,
Packit Service fa4841
		                        context->AuthenticateTargetInfo.cbBuffer);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	ntlm_print_message_fields(&(message->DomainName), "DomainName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->UserName), "UserName");
Packit Service fa4841
	ntlm_print_message_fields(&(message->Workstation), "Workstation");
Packit Service fa4841
	ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse");
Packit Service fa4841
	ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
Packit Service fa4841
	ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
Packit Service fa4841
Packit Service fa4841
	if (context->UseMIC)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)");
Packit Service fa4841
		winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_FINAL;
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	return SEC_I_COMPLETE_NEEDED;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags = 0;
Packit Service fa4841
	size_t cbAvFlags;
Packit Service fa4841
	NTLM_AV_PAIR* AvFlags = NULL;
Packit Service fa4841
	NTLM_AUTHENTICATE_MESSAGE* message;
Packit Service fa4841
	BYTE messageIntegrityCheck[16];
Packit Service fa4841
Packit Service fa4841
	if (!context)
Packit Service fa4841
		return SEC_E_INVALID_PARAMETER;
Packit Service fa4841
Packit Service fa4841
	if (context->state != NTLM_STATE_COMPLETION)
Packit Service fa4841
		return SEC_E_OUT_OF_SEQUENCE;
Packit Service fa4841
Packit Service fa4841
	message = &context->AUTHENTICATE_MESSAGE;
Packit Service fa4841
	AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
Packit Service fa4841
	                           context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);
Packit Service fa4841
Packit Service fa4841
	if (AvFlags)
Packit Service fa4841
		Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags);
Packit Service fa4841
Packit Service fa4841
	if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
Packit Service fa4841
		return SEC_E_INTERNAL_ERROR;
Packit Service fa4841
Packit Service fa4841
	/* KeyExchangeKey */
Packit Service fa4841
	ntlm_generate_key_exchange_key(context);
Packit Service fa4841
	/* EncryptedRandomSessionKey */
Packit Service fa4841
	ntlm_decrypt_random_session_key(context);
Packit Service fa4841
	/* ExportedSessionKey */
Packit Service fa4841
	ntlm_generate_exported_session_key(context);
Packit Service fa4841
Packit Service fa4841
	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
Packit Service fa4841
	{
Packit Service fa4841
		ZeroMemory(
Packit Service fa4841
		    &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
Packit Service fa4841
		    16);
Packit Service fa4841
		ntlm_compute_message_integrity_check(context, messageIntegrityCheck,
Packit Service fa4841
		                                     sizeof(messageIntegrityCheck));
Packit Service fa4841
		CopyMemory(
Packit Service fa4841
		    &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
Packit Service fa4841
		    message->MessageIntegrityCheck, 16);
Packit Service fa4841
Packit Service fa4841
		if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!");
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
			WLog_ERR(TAG, "Expected MIC:");
Packit Service fa4841
			winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck, sizeof(messageIntegrityCheck));
Packit Service fa4841
			WLog_ERR(TAG, "Actual MIC:");
Packit Service fa4841
			winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
Packit Service fa4841
			              sizeof(message->MessageIntegrityCheck));
Packit Service fa4841
#endif
Packit Service fa4841
			return SEC_E_MESSAGE_ALTERED;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		/* no mic message was present
Packit Service fa4841
Packit Service fa4841
		   https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
Packit Service fa4841
		   the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
Packit Service fa4841
		   Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.
Packit Service fa4841
Packit Service fa4841
		   now check the NtProofString, to detect if the entered client password matches the
Packit Service fa4841
		   expected password.
Packit Service fa4841
		   */
Packit Service fa4841
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
		WLog_DBG(TAG, "No MIC present, using NtProofString for verification.");
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
		if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "NtProofString verification failed!");
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
			WLog_ERR(TAG, "Expected NtProofString:");
Packit Service fa4841
			winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, sizeof(context->NtProofString));
Packit Service fa4841
			WLog_ERR(TAG, "Actual NtProofString:");
Packit Service fa4841
			winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
Packit Service fa4841
			              sizeof(context->NTLMv2Response));
Packit Service fa4841
#endif
Packit Service fa4841
			return SEC_E_LOGON_DENIED;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* Generate signing keys */
Packit Service fa4841
	ntlm_generate_client_signing_key(context);
Packit Service fa4841
	ntlm_generate_server_signing_key(context);
Packit Service fa4841
	/* Generate sealing keys */
Packit Service fa4841
	ntlm_generate_client_sealing_key(context);
Packit Service fa4841
	ntlm_generate_server_sealing_key(context);
Packit Service fa4841
	/* Initialize RC4 seal state */
Packit Service fa4841
	ntlm_init_rc4_seal_states(context);
Packit Service fa4841
#ifdef WITH_DEBUG_NTLM
Packit Service fa4841
	WLog_DBG(TAG, "ClientChallenge");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8);
Packit Service fa4841
	WLog_DBG(TAG, "ServerChallenge");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8);
Packit Service fa4841
	WLog_DBG(TAG, "SessionBaseKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "KeyExchangeKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ExportedSessionKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "RandomSessionKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ClientSigningKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ClientSealingKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ServerSigningKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "ServerSealingKey");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16);
Packit Service fa4841
	WLog_DBG(TAG, "Timestamp");
Packit Service fa4841
	winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8);
Packit Service fa4841
#endif
Packit Service fa4841
	context->state = NTLM_STATE_FINAL;
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->DomainName));
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->UserName));
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->Workstation));
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->LmChallengeResponse));
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->NtChallengeResponse));
Packit Service fa4841
	ntlm_free_message_fields_buffer(&(message->EncryptedRandomSessionKey));
Packit Service fa4841
	return SEC_E_OK;
Packit Service fa4841
}