Commit message: Fixed GHSL-2020-100: oob read in ntlm_read_ChallengeMessage

* Added length checks for data read from stream
* Unified function resource cleanup

(cherry picked from commit 8357dedbbf7213b7d0d18f1026145b9a5b92235a)
CVE: CVE-2020-13396
CWE: CWE-125
Vulnerability description: An issue was discovered in FreeRDP before 2.1.1. An out-of-bounds (OOB) read vulnerability has been detected in ntlm_read_ChallengeMessage in winpr/libwinpr/sspi/NTLM/ntlm_message.c.

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	wStream* s;
	size_t length;
	NTLM_NEGOTIATE_MESSAGE* message;
	message = &context->NEGOTIATE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}

	if (message->MessageType != MESSAGE_TYPE_NEGOTIATE)
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}

	if (Stream_GetRemainingLength(s) < 4)
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}
	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */

	if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) &&
	      (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) &&
	      (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE)))
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}

	context->NegotiateFlags = message->NegotiateFlags;

	/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */

	if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}

	/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */

	if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
	{
		Stream_Free(s, FALSE);
		return SEC_E_INVALID_TOKEN;
	}

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
	{
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
		{
			Stream_Free(s, FALSE);
			return SEC_E_INVALID_TOKEN;
		}
	}

	length = Stream_GetPosition(s);
	buffer->cbBuffer = length;

	if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
	{
		Stream_Free(s, FALSE);
		return SEC_E_INTERNAL_ERROR;
	}

	CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
	context->NegotiateMessage.BufferType = buffer->BufferType;
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", context->NegotiateMessage.cbBuffer);
	winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer,
	              context->NegotiateMessage.cbBuffer);
	ntlm_print_negotiate_flags(message->NegotiateFlags);

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

#endif
	context->state = NTLM_STATE_CHALLENGE;
	Stream_Free(s, FALSE);
	return SEC_I_CONTINUE_NEEDED;
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name)
{
	WLog_DBG(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name,
	         fields->Len, fields->MaxLen, fields->BufferOffset);

	if (fields->Len > 0)
		winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len);
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	wStream* s;
	size_t length;
	UINT32 PayloadBufferOffset;
	NTLM_AUTHENTICATE_MESSAGE* message;
	SSPI_CREDENTIALS* credentials = context->credentials;
	message = &context->AUTHENTICATE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	if (context->NTLMv2)
	{
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;

		if (context->SendVersionInfo)
			message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
	}

	if (context->UseMIC)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;

	if (context->SendWorkstationName)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;

	if (context->confidentiality)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;

	if (context->CHALLENGE_MESSAGE.NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;

	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
	message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_get_version_info(&(message->Version));

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
	{
		message->Workstation.Len = context->Workstation.Length;
		message->Workstation.Buffer = (BYTE*)context->Workstation.Buffer;
	}

	if (credentials->identity.DomainLength > 0)
	{
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
		message->DomainName.Len = (UINT16)credentials->identity.DomainLength * 2;
		message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
	}

	message->UserName.Len = (UINT16)credentials->identity.UserLength * 2;
	message->UserName.Buffer = (BYTE*)credentials->identity.User;
	message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
	message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
	message->NtChallengeResponse.Len = (UINT16)context->NtChallengeResponse.cbBuffer;
	message->NtChallengeResponse.Buffer = (BYTE*)context->NtChallengeResponse.pvBuffer;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
	{
		message->EncryptedRandomSessionKey.Len = 16;
		message->EncryptedRandomSessionKey.Buffer = context->EncryptedRandomSessionKey;
	}

	PayloadBufferOffset = 64;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		PayloadBufferOffset += 8; /* Version (8 bytes) */

	if (context->UseMIC)
		PayloadBufferOffset += 16; /* Message Integrity Check (16 bytes) */

	message->DomainName.BufferOffset = PayloadBufferOffset;
	message->UserName.BufferOffset = message->DomainName.BufferOffset + message->DomainName.Len;
	message->Workstation.BufferOffset = message->UserName.BufferOffset + message->UserName.Len;
	message->LmChallengeResponse.BufferOffset =
	    message->Workstation.BufferOffset + message->Workstation.Len;
	message->NtChallengeResponse.BufferOffset =
	    message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len;
	message->EncryptedRandomSessionKey.BufferOffset =
	    message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len;
	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_AUTHENTICATE);
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); /* Message Header (12 bytes) */
	ntlm_write_message_fields(
	    s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */
	ntlm_write_message_fields(
	    s, &(message->NtChallengeResponse));               /* NtChallengeResponseFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->DomainName));  /* DomainNameFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->UserName));    /* UserNameFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */
	ntlm_write_message_fields(
	    s, &(message->EncryptedRandomSessionKey));   /* EncryptedRandomSessionKeyFields (8 bytes) */
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */

	if (context->UseMIC)
	{
		context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s);
		Stream_Zero(s, 16); /* Message Integrity Check (16 bytes) */
	}

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
		ntlm_write_message_fields_buffer(s, &(message->DomainName)); /* DomainName */

	ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
		ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */

	ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */
	ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
		ntlm_write_message_fields_buffer(
		    s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */

	length = Stream_GetPosition(s);

	if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
	{
		Stream_Free(s, FALSE);
		return SEC_E_INTERNAL_ERROR;
	}

	CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
	buffer->cbBuffer = length;

	if (context->UseMIC)
	{
		/* Message Integrity Check */
		ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, 16);
		Stream_SetPosition(s, context->MessageIntegrityCheckOffset);
		Stream_Write(s, message->MessageIntegrityCheck, 16);
		Stream_SetPosition(s, length);
	}

#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length);
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length);
	ntlm_print_negotiate_flags(message->NegotiateFlags);

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

	if (context->AuthenticateTargetInfo.cbBuffer > 0)
	{
		WLog_DBG(TAG,
		         "AuthenticateTargetInfo (%" PRIu32 "):", context->AuthenticateTargetInfo.cbBuffer);
		ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer,
		                        context->AuthenticateTargetInfo.cbBuffer);
	}

	ntlm_print_message_fields(&(message->DomainName), "DomainName");
	ntlm_print_message_fields(&(message->UserName), "UserName");
	ntlm_print_message_fields(&(message->Workstation), "Workstation");
	ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse");
	ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
	ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");

	if (context->UseMIC)
	{
		WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)");
		winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16);
	}

#endif
	context->state = NTLM_STATE_FINAL;
	Stream_Free(s, FALSE);
	return SEC_I_COMPLETE_NEEDED;
}

Project: FreeRDP
File: ntlm_message.c

static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
{
	if (Stream_GetRemainingLength(s) < 8)
		return -1;

	Stream_Read_UINT16(s, fields->Len);          /* Len (2 bytes) */
	Stream_Read_UINT16(s, fields->MaxLen);       /* MaxLen (2 bytes) */
	Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
	return 1;
}

Project: FreeRDP
File: ntlm_message.c

static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
{
	if (Stream_GetRemainingLength(s) < 12)
		return -1;

	Stream_Read(s, header->Signature, 8);
	Stream_Read_UINT32(s, header->MessageType);

	if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0)
		return -1;

	return 1;
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header)
{
	Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE));
	Stream_Write_UINT32(s, header->MessageType);
}

Project: FreeRDP
File: ntlm_message.c

static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
{
	if (fields->Len > 0)
	{
		const UINT32 offset = fields->BufferOffset + fields->Len;

		if (fields->BufferOffset > UINT32_MAX - fields->Len)
			return -1;

		if (offset > Stream_Length(s))
			return -1;

		fields->Buffer = (PBYTE)malloc(fields->Len);

		if (!fields->Buffer)
			return -1;

		Stream_SetPosition(s, fields->BufferOffset);
		Stream_Read(s, fields->Buffer, fields->Len);
	}

	return 1;
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
{
	if (fields->MaxLen < 1)
		fields->MaxLen = fields->Len;

	Stream_Write_UINT16(s, fields->Len);          /* Len (2 bytes) */
	Stream_Write_UINT16(s, fields->MaxLen);       /* MaxLen (2 bytes) */
	Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	wStream* s;
	size_t length;
	UINT32 PayloadOffset;
	NTLM_CHALLENGE_MESSAGE* message;
	message = &context->CHALLENGE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	ntlm_get_version_info(&(message->Version)); /* Version */
	ntlm_generate_server_challenge(context);    /* Server Challenge */
	ntlm_generate_timestamp(context);           /* Timestamp */

	if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */
	{
		Stream_Free(s, FALSE);
		return SEC_E_INTERNAL_ERROR;
	}

	CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */
	message->NegotiateFlags = context->NegotiateFlags;
	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_CHALLENGE);
	/* Message Header (12 bytes) */
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message);

	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
	{
		message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
		message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
	}

	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
	{
		message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
		message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
	}

	PayloadOffset = 48;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		PayloadOffset += 8;

	message->TargetName.BufferOffset = PayloadOffset;
	message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len;
	/* TargetNameFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->TargetName));
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
	Stream_Write(s, message->ServerChallenge, 8);    /* ServerChallenge (8 bytes) */
	Stream_Write(s, message->Reserved, 8);           /* Reserved (8 bytes), should be ignored */
	/* TargetInfoFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->TargetInfo));

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */

	/* Payload (variable) */

	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
		ntlm_write_message_fields_buffer(s, &(message->TargetName));

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
		ntlm_write_message_fields_buffer(s, &(message->TargetInfo));

	length = Stream_GetPosition(s);
	buffer->cbBuffer = length;

	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
	{
		Stream_Free(s, FALSE);
		return SEC_E_INTERNAL_ERROR;
	}

	CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length);
	winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer,
	              context->ChallengeMessage.cbBuffer);
	ntlm_print_negotiate_flags(message->NegotiateFlags);

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

	ntlm_print_message_fields(&(message->TargetName), "TargetName");
	ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");
#endif
	context->state = NTLM_STATE_AUTHENTICATE;
	Stream_Free(s, FALSE);
	return SEC_I_CONTINUE_NEEDED;
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
	wStream* s;
	size_t length;
	UINT32 flags = 0;
	NTLM_AV_PAIR* AvFlags = NULL;
	UINT32 PayloadBufferOffset;
	NTLM_AUTHENTICATE_MESSAGE* message;
	SSPI_CREDENTIALS* credentials = context->credentials;

	message = &context->AUTHENTICATE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
		goto fail;

	if (message->MessageType != MESSAGE_TYPE_AUTHENTICATE)
		goto fail;

	if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) <
	    0) /* LmChallengeResponseFields (8 bytes) */
		goto fail;

	if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) <
	    0) /* NtChallengeResponseFields (8 bytes) */
		goto fail;

	if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */
		goto fail;

	if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */
		goto fail;

	if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */
		goto fail;

	if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) <
	    0) /* EncryptedRandomSessionKeyFields (8 bytes) */
		goto fail;

	if (Stream_GetRemainingLength(s) < 4)
		goto fail;
	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
	context->NegotiateKeyExchange =
	    (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE;

	if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
	    (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
		goto fail;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
	{
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
			goto fail;
	}

	PayloadBufferOffset = Stream_GetPosition(s);

	status = SEC_E_INTERNAL_ERROR;
	if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */
		goto fail;

	if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */
		goto fail;

	if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */
		goto fail;

	if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) <
	    0) /* LmChallengeResponse */
		goto fail;

	if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) <
	    0) /* NtChallengeResponse */
		goto fail;

	if (message->NtChallengeResponse.Len > 0)
	{
		int rc;
		size_t cbAvFlags;
		wStream* snt =
		    Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len);

		if (!snt)
			goto fail;

		status = SEC_E_INVALID_TOKEN;
		rc = ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response));
		Stream_Free(snt, FALSE);
		if (rc < 0)
			goto fail;
		status = SEC_E_INTERNAL_ERROR;

		context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
		context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
		sspi_SecBufferFree(&(context->ChallengeTargetInfo));
		context->ChallengeTargetInfo.pvBuffer = (void*)context->NTLMv2Response.Challenge.AvPairs;
		context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16);
		CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
		AvFlags =
		    ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
		                     context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);

		if (AvFlags)
			Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags);
	}

	if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) <
	    0) /* EncryptedRandomSessionKey */
		goto fail;

	if (message->EncryptedRandomSessionKey.Len > 0)
	{
		if (message->EncryptedRandomSessionKey.Len != 16)
			goto fail;

		CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
		           16);
	}

	length = Stream_GetPosition(s);

	if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
		goto fail;

	CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
	buffer->cbBuffer = length;
	Stream_SetPosition(s, PayloadBufferOffset);

	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
	{
		context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s);

		status = SEC_E_INVALID_TOKEN;
		if (Stream_GetRemainingLength(s) < 16)
			goto fail;

		Stream_Read(s, message->MessageIntegrityCheck, 16);
	}

	status = SEC_E_INTERNAL_ERROR;

#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")",
	         context->AuthenticateMessage.cbBuffer);
	winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer,
	              context->AuthenticateMessage.cbBuffer);

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

	ntlm_print_message_fields(&(message->DomainName), "DomainName");
	ntlm_print_message_fields(&(message->UserName), "UserName");
	ntlm_print_message_fields(&(message->Workstation), "Workstation");
	ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse");
	ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
	ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
	ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs,
	                        context->NTLMv2Response.Challenge.cbAvPairs);

	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
	{
		WLog_DBG(TAG, "MessageIntegrityCheck:");
		winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16);
	}

#endif

	if (message->UserName.Len > 0)
	{
		credentials->identity.User = (UINT16*)malloc(message->UserName.Len);

		if (!credentials->identity.User)
			goto fail;

		CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
		credentials->identity.UserLength = message->UserName.Len / 2;
	}

	if (message->DomainName.Len > 0)
	{
		credentials->identity.Domain = (UINT16*)malloc(message->DomainName.Len);

		if (!credentials->identity.Domain)
			goto fail;

		CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
		           message->DomainName.Len);
		credentials->identity.DomainLength = message->DomainName.Len / 2;
	}

	Stream_Free(s, FALSE);
	/* Computations beyond this point require the NTLM hash of the password */
	context->state = NTLM_STATE_COMPLETION;
	return SEC_I_COMPLETE_NEEDED;

fail:
	Stream_Free(s, FALSE);
	return status;
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
	wStream* s;
	size_t length;
	size_t StartOffset;
	size_t PayloadOffset;
	NTLM_AV_PAIR* AvTimestamp;
	NTLM_CHALLENGE_MESSAGE* message;
	if (!context || !buffer)
		return SEC_E_INTERNAL_ERROR;

	ntlm_generate_client_challenge(context);
	message = &context->CHALLENGE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	StartOffset = Stream_GetPosition(s);

	if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0)
		goto fail;

	if (message->MessageType != MESSAGE_TYPE_CHALLENGE)
		goto fail;

	if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */
		goto fail;

	if (Stream_GetRemainingLength(s) < 4)
		goto fail;

	Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
	context->NegotiateFlags = message->NegotiateFlags;

	if (Stream_GetRemainingLength(s) < 8)
		goto fail;

	Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
	CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);

	if (Stream_GetRemainingLength(s) < 8)
		goto fail;

	Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */

	if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */
		goto fail;

	if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
	{
		if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */
			goto fail;
	}

	/* Payload (variable) */
	PayloadOffset = Stream_GetPosition(s);

	status = SEC_E_INTERNAL_ERROR;
	if (message->TargetName.Len > 0)
	{
		if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0)
			goto fail;
	}

	if (message->TargetInfo.Len > 0)
	{
		size_t cbAvTimestamp;

		if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0)
			goto fail;

		context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;
		context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
		AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*)message->TargetInfo.Buffer,
		                               message->TargetInfo.Len, MsvAvTimestamp, &cbAvTimestamp);

		if (AvTimestamp)
		{
			PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp);

			if (!ptr)
				goto fail;

			if (context->NTLMv2)
				context->UseMIC = TRUE;

			CopyMemory(context->ChallengeTimestamp, ptr, 8);
		}
	}

	length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
	if (length > buffer->cbBuffer)
		goto fail;

	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
		goto fail;

	if (context->ChallengeMessage.pvBuffer)
		CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length);
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length);
	winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer,
	              context->ChallengeMessage.cbBuffer);
	ntlm_print_negotiate_flags(context->NegotiateFlags);

	if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

	ntlm_print_message_fields(&(message->TargetName), "TargetName");
	ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");

	if (context->ChallengeTargetInfo.cbBuffer > 0)
	{
		WLog_DBG(TAG, "ChallengeTargetInfo (%" PRIu32 "):", context->ChallengeTargetInfo.cbBuffer);
		ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer,
		                        context->ChallengeTargetInfo.cbBuffer);
	}

#endif
	/* AV_PAIRs */

	if (context->NTLMv2)
	{
		if (ntlm_construct_authenticate_target_info(context) < 0)
			goto fail;

		sspi_SecBufferFree(&context->ChallengeTargetInfo);
		context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
		context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
	}

	ntlm_generate_timestamp(context); /* Timestamp */

	if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
		goto fail;

	if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
		goto fail;

	ntlm_generate_key_exchange_key(context);     /* KeyExchangeKey */
	ntlm_generate_random_session_key(context);   /* RandomSessionKey */
	ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
	ntlm_encrypt_random_session_key(context);    /* EncryptedRandomSessionKey */
	/* Generate signing keys */
	ntlm_generate_client_signing_key(context);
	ntlm_generate_server_signing_key(context);
	/* Generate sealing keys */
	ntlm_generate_client_sealing_key(context);
	ntlm_generate_server_sealing_key(context);
	/* Initialize RC4 seal state using client sealing key */
	ntlm_init_rc4_seal_states(context);
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "ClientChallenge");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8);
	WLog_DBG(TAG, "ServerChallenge");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8);
	WLog_DBG(TAG, "SessionBaseKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16);
	WLog_DBG(TAG, "KeyExchangeKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16);
	WLog_DBG(TAG, "ExportedSessionKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16);
	WLog_DBG(TAG, "RandomSessionKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16);
	WLog_DBG(TAG, "ClientSigningKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16);
	WLog_DBG(TAG, "ClientSealingKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16);
	WLog_DBG(TAG, "ServerSigningKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16);
	WLog_DBG(TAG, "ServerSealingKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16);
	WLog_DBG(TAG, "Timestamp");
	winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8);
#endif
	context->state = NTLM_STATE_AUTHENTICATE;
	ntlm_free_message_fields_buffer(&(message->TargetName));
	status = SEC_I_CONTINUE_NEEDED;
fail:
	Stream_Free(s, FALSE);
	return status;
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_print_negotiate_flags(UINT32 flags)
{
	int i;
	const char* str;
	WLog_INFO(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags);

	for (i = 31; i >= 0; i--)
	{
		if ((flags >> i) & 1)
		{
			str = NTLM_NEGOTIATE_STRINGS[(31 - i)];
			WLog_INFO(TAG, "\t%s (%d),", str, (31 - i));
		}
	}
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
{
	CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
	header->MessageType = MessageType;
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
{
	wStream* s;
	size_t length;
	NTLM_NEGOTIATE_MESSAGE* message;
	message = &context->NEGOTIATE_MESSAGE;
	ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE));
	s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer);

	if (!s)
		return SEC_E_INTERNAL_ERROR;

	ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_NEGOTIATE);

	if (context->NTLMv2)
	{
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
	}

	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
	message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;

	if (context->confidentiality)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;

	if (context->SendVersionInfo)
		message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_get_version_info(&(message->Version));

	context->NegotiateFlags = message->NegotiateFlags;
	/* Message Header (12 bytes) */
	ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message);
	Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */
	/* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
	/* DomainNameFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->DomainName));
	/* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
	/* WorkstationFields (8 bytes) */
	ntlm_write_message_fields(s, &(message->Workstation));

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_write_version_info(s, &(message->Version));

	length = Stream_GetPosition(s);
	buffer->cbBuffer = length;

	if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length))
	{
		Stream_Free(s, FALSE);
		return SEC_E_INTERNAL_ERROR;
	}

	CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
	context->NegotiateMessage.BufferType = buffer->BufferType;
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length);
	winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length);

	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
		ntlm_print_version_info(&(message->Version));

#endif
	context->state = NTLM_STATE_CHALLENGE;
	Stream_Free(s, FALSE);
	return SEC_I_CONTINUE_NEEDED;
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
{
	if (fields->Len > 0)
	{
		Stream_SetPosition(s, fields->BufferOffset);
		Stream_Write(s, fields->Buffer, fields->Len);
	}
}

Project: FreeRDP
File: ntlm_message.c

static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
{
	if (fields)
	{
		if (fields->Buffer)
		{
			free(fields->Buffer);
			fields->Len = 0;
			fields->MaxLen = 0;
			fields->Buffer = NULL;
			fields->BufferOffset = 0;
		}
	}
}

Project: FreeRDP
File: ntlm_message.c

SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context)
{
	UINT32 flags = 0;
	size_t cbAvFlags;
	NTLM_AV_PAIR* AvFlags = NULL;
	NTLM_AUTHENTICATE_MESSAGE* message;
	BYTE messageIntegrityCheck[16];

	if (!context)
		return SEC_E_INVALID_PARAMETER;

	if (context->state != NTLM_STATE_COMPLETION)
		return SEC_E_OUT_OF_SEQUENCE;

	message = &context->AUTHENTICATE_MESSAGE;
	AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
	                           context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);

	if (AvFlags)
		Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags);

	if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */
		return SEC_E_INTERNAL_ERROR;

	if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */
		return SEC_E_INTERNAL_ERROR;

	/* KeyExchangeKey */
	ntlm_generate_key_exchange_key(context);
	/* EncryptedRandomSessionKey */
	ntlm_decrypt_random_session_key(context);
	/* ExportedSessionKey */
	ntlm_generate_exported_session_key(context);

	if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
	{
		ZeroMemory(
		    &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
		    16);
		ntlm_compute_message_integrity_check(context, messageIntegrityCheck,
		                                     sizeof(messageIntegrityCheck));
		CopyMemory(
		    &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
		    message->MessageIntegrityCheck, 16);

		if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0)
		{
			WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!");
#ifdef WITH_DEBUG_NTLM
			WLog_ERR(TAG, "Expected MIC:");
			winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck, sizeof(messageIntegrityCheck));
			WLog_ERR(TAG, "Actual MIC:");
			winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
			              sizeof(message->MessageIntegrityCheck));
#endif
			return SEC_E_MESSAGE_ALTERED;
		}
	}
	else
	{
		/* no mic message was present

		   https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
		   the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
		   Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.

		   now check the NtProofString, to detect if the entered client password matches the
		   expected password.
		   */

#ifdef WITH_DEBUG_NTLM
		WLog_DBG(TAG, "No MIC present, using NtProofString for verification.");
#endif

		if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
		{
			WLog_ERR(TAG, "NtProofString verification failed!");
#ifdef WITH_DEBUG_NTLM
			WLog_ERR(TAG, "Expected NtProofString:");
			winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, sizeof(context->NtProofString));
			WLog_ERR(TAG, "Actual NtProofString:");
			winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
			              sizeof(context->NTLMv2Response));
#endif
			return SEC_E_LOGON_DENIED;
		}
	}

	/* Generate signing keys */
	ntlm_generate_client_signing_key(context);
	ntlm_generate_server_signing_key(context);
	/* Generate sealing keys */
	ntlm_generate_client_sealing_key(context);
	ntlm_generate_server_sealing_key(context);
	/* Initialize RC4 seal state */
	ntlm_init_rc4_seal_states(context);
#ifdef WITH_DEBUG_NTLM
	WLog_DBG(TAG, "ClientChallenge");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8);
	WLog_DBG(TAG, "ServerChallenge");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8);
	WLog_DBG(TAG, "SessionBaseKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16);
	WLog_DBG(TAG, "KeyExchangeKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16);
	WLog_DBG(TAG, "ExportedSessionKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16);
	WLog_DBG(TAG, "RandomSessionKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16);
	WLog_DBG(TAG, "ClientSigningKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16);
	WLog_DBG(TAG, "ClientSealingKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16);
	WLog_DBG(TAG, "ServerSigningKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16);
	WLog_DBG(TAG, "ServerSealingKey");
	winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16);
	WLog_DBG(TAG, "Timestamp");
	winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8);
#endif
	context->state = NTLM_STATE_FINAL;
	ntlm_free_message_fields_buffer(&(message->DomainName));
	ntlm_free_message_fields_buffer(&(message->UserName));
	ntlm_free_message_fields_buffer(&(message->Workstation));
	ntlm_free_message_fields_buffer(&(message->LmChallengeResponse));
	ntlm_free_message_fields_buffer(&(message->NtChallengeResponse));
	ntlm_free_message_fields_buffer(&(message->EncryptedRandomSessionKey));
	return SEC_E_OK;
}