20#include <winpr/config.h>
26#include <winpr/assert.h>
27#include <winpr/print.h>
28#include <winpr/stream.h>
29#include <winpr/sysinfo.h>
31#include "ntlm_compute.h"
33#include "ntlm_message.h"
36#define TAG WINPR_TAG("sspi.NTLM")
38#define NTLM_CheckAndLogRequiredCapacity(tag, s, nmemb, what) \
39 Stream_CheckAndLogRequiredCapacityEx(tag, WLOG_WARN, s, nmemb, 1, "%s(%s:%" PRIuz ") " what, \
40 __func__, __FILE__, (size_t)__LINE__)
42static const char NTLM_SIGNATURE[8] = {
'N',
'T',
'L',
'M',
'S',
'S',
'P',
'\0' };
51 ntlm_free_message_fields_buffer(&nego->Workstation);
52 ntlm_free_message_fields_buffer(&nego->DomainName);
59 ntlm_free_message_fields_buffer(&challenge->TargetName);
60 ntlm_free_message_fields_buffer(&challenge->TargetInfo);
67 ntlm_free_message_fields_buffer(&auth->DomainName);
68 ntlm_free_message_fields_buffer(&auth->UserName);
69 ntlm_free_message_fields_buffer(&auth->Workstation);
70 ntlm_free_message_fields_buffer(&auth->LmChallengeResponse);
71 ntlm_free_message_fields_buffer(&auth->EncryptedRandomSessionKey);
72 ntlm_free_message_fields_buffer(&(auth->NtChallengeResponse));
79 ntlm_free_negotiate_message(&context->NEGOTIATE_MESSAGE);
80 ntlm_free_challenge_message(&context->CHALLENGE_MESSAGE);
81 ntlm_free_authenticate_message(&context->AUTHENTICATE_MESSAGE);
88 SecBuffer buffer = { .cbBuffer = field->Len,
89 .pvBuffer = field->Buffer,
90 .BufferType = SECBUFFER_TOKEN };
92 field->Buffer =
nullptr;
93 field->BufferOffset = 0;
103 SecBuffer target = { .BufferType = in->BufferType,
104 .cbBuffer = in->cbBuffer,
105 .pvBuffer = in->pvBuffer };
107 in->pvBuffer =
nullptr;
111const char* ntlm_get_negotiate_string(UINT32 flag)
113 if (flag & NTLMSSP_NEGOTIATE_56)
114 return "NTLMSSP_NEGOTIATE_56";
115 if (flag & NTLMSSP_NEGOTIATE_KEY_EXCH)
116 return "NTLMSSP_NEGOTIATE_KEY_EXCH";
117 if (flag & NTLMSSP_NEGOTIATE_128)
118 return "NTLMSSP_NEGOTIATE_128";
119 if (flag & NTLMSSP_RESERVED1)
120 return "NTLMSSP_RESERVED1";
121 if (flag & NTLMSSP_RESERVED2)
122 return "NTLMSSP_RESERVED2";
123 if (flag & NTLMSSP_RESERVED3)
124 return "NTLMSSP_RESERVED3";
125 if (flag & NTLMSSP_NEGOTIATE_VERSION)
126 return "NTLMSSP_NEGOTIATE_VERSION";
127 if (flag & NTLMSSP_RESERVED4)
128 return "NTLMSSP_RESERVED4";
129 if (flag & NTLMSSP_NEGOTIATE_TARGET_INFO)
130 return "NTLMSSP_NEGOTIATE_TARGET_INFO";
131 if (flag & NTLMSSP_REQUEST_NON_NT_SESSION_KEY)
132 return "NTLMSSP_REQUEST_NON_NT_SESSION_KEY";
133 if (flag & NTLMSSP_RESERVED5)
134 return "NTLMSSP_RESERVED5";
135 if (flag & NTLMSSP_NEGOTIATE_IDENTIFY)
136 return "NTLMSSP_NEGOTIATE_IDENTIFY";
137 if (flag & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY)
138 return "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY";
139 if (flag & NTLMSSP_RESERVED6)
140 return "NTLMSSP_RESERVED6";
141 if (flag & NTLMSSP_TARGET_TYPE_SERVER)
142 return "NTLMSSP_TARGET_TYPE_SERVER";
143 if (flag & NTLMSSP_TARGET_TYPE_DOMAIN)
144 return "NTLMSSP_TARGET_TYPE_DOMAIN";
145 if (flag & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
146 return "NTLMSSP_NEGOTIATE_ALWAYS_SIGN";
147 if (flag & NTLMSSP_RESERVED7)
148 return "NTLMSSP_RESERVED7";
149 if (flag & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
150 return "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED";
151 if (flag & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
152 return "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED";
153 if (flag & NTLMSSP_NEGOTIATE_ANONYMOUS)
154 return "NTLMSSP_NEGOTIATE_ANONYMOUS";
155 if (flag & NTLMSSP_RESERVED8)
156 return "NTLMSSP_RESERVED8";
157 if (flag & NTLMSSP_NEGOTIATE_NTLM)
158 return "NTLMSSP_NEGOTIATE_NTLM";
159 if (flag & NTLMSSP_RESERVED9)
160 return "NTLMSSP_RESERVED9";
161 if (flag & NTLMSSP_NEGOTIATE_LM_KEY)
162 return "NTLMSSP_NEGOTIATE_LM_KEY";
163 if (flag & NTLMSSP_NEGOTIATE_DATAGRAM)
164 return "NTLMSSP_NEGOTIATE_DATAGRAM";
165 if (flag & NTLMSSP_NEGOTIATE_SEAL)
166 return "NTLMSSP_NEGOTIATE_SEAL";
167 if (flag & NTLMSSP_NEGOTIATE_SIGN)
168 return "NTLMSSP_NEGOTIATE_SIGN";
169 if (flag & NTLMSSP_RESERVED10)
170 return "NTLMSSP_RESERVED10";
171 if (flag & NTLMSSP_REQUEST_TARGET)
172 return "NTLMSSP_REQUEST_TARGET";
173 if (flag & NTLMSSP_NEGOTIATE_OEM)
174 return "NTLMSSP_NEGOTIATE_OEM";
175 if (flag & NTLMSSP_NEGOTIATE_UNICODE)
176 return "NTLMSSP_NEGOTIATE_UNICODE";
177 return "NTLMSSP_NEGOTIATE_UNKNOWN";
180#if defined(WITH_DEBUG_NTLM)
183 WINPR_ASSERT(fields);
186 WLog_VRB(TAG,
"%s (Len: %" PRIu16
" MaxLen: %" PRIu16
" BufferOffset: %" PRIu32
")", name,
187 fields->Len, fields->MaxLen, fields->BufferOffset);
190 winpr_HexDump(TAG, WLOG_TRACE, fields->Buffer, fields->Len);
193static void ntlm_print_negotiate_flags(UINT32 flags)
195 WLog_VRB(TAG,
"negotiateFlags \"0x%08" PRIX32
"\"", flags);
197 for (
int i = 31; i >= 0; i--)
199 if ((flags >> i) & 1)
201 const char* str = ntlm_get_negotiate_string(1u << i);
202 WLog_VRB(TAG,
"\t%s (%d),", str, (31 - i));
207static void ntlm_print_negotiate_message(
const SecBuffer* NegotiateMessage,
210 WINPR_ASSERT(NegotiateMessage);
211 WINPR_ASSERT(message);
213 WLog_VRB(TAG,
"NEGOTIATE_MESSAGE (length = %" PRIu32
")", NegotiateMessage->cbBuffer);
214 winpr_HexDump(TAG, WLOG_TRACE, NegotiateMessage->pvBuffer, NegotiateMessage->cbBuffer);
215 ntlm_print_negotiate_flags(message->NegotiateFlags);
217 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
218 ntlm_print_version_info(&(message->Version));
221static void ntlm_print_challenge_message(
const SecBuffer* ChallengeMessage,
225 WINPR_ASSERT(ChallengeMessage);
226 WINPR_ASSERT(message);
228 WLog_VRB(TAG,
"CHALLENGE_MESSAGE (length = %" PRIu32
")", ChallengeMessage->cbBuffer);
229 winpr_HexDump(TAG, WLOG_TRACE, ChallengeMessage->pvBuffer, ChallengeMessage->cbBuffer);
230 ntlm_print_negotiate_flags(message->NegotiateFlags);
232 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
233 ntlm_print_version_info(&(message->Version));
235 ntlm_print_message_fields(&(message->TargetName),
"TargetName");
236 ntlm_print_message_fields(&(message->TargetInfo),
"TargetInfo");
238 if (ChallengeTargetInfo && (ChallengeTargetInfo->cbBuffer > 0))
240 WLog_VRB(TAG,
"ChallengeTargetInfo (%" PRIu32
"):", ChallengeTargetInfo->cbBuffer);
241 ntlm_print_av_pair_list(ChallengeTargetInfo->pvBuffer, ChallengeTargetInfo->cbBuffer);
245static void ntlm_print_authenticate_message(
const SecBuffer* AuthenticateMessage,
249 WINPR_ASSERT(AuthenticateMessage);
250 WINPR_ASSERT(message);
252 WLog_VRB(TAG,
"AUTHENTICATE_MESSAGE (length = %" PRIu32
")", AuthenticateMessage->cbBuffer);
253 winpr_HexDump(TAG, WLOG_TRACE, AuthenticateMessage->pvBuffer, AuthenticateMessage->cbBuffer);
254 ntlm_print_negotiate_flags(message->NegotiateFlags);
256 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
257 ntlm_print_version_info(&(message->Version));
259 if (AuthenticateTargetInfo && (AuthenticateTargetInfo->cbBuffer > 0))
261 WLog_VRB(TAG,
"AuthenticateTargetInfo (%" PRIu32
"):", AuthenticateTargetInfo->cbBuffer);
262 ntlm_print_av_pair_list(AuthenticateTargetInfo->pvBuffer, AuthenticateTargetInfo->cbBuffer);
265 ntlm_print_message_fields(&(message->DomainName),
"DomainName");
266 ntlm_print_message_fields(&(message->UserName),
"UserName");
267 ntlm_print_message_fields(&(message->Workstation),
"Workstation");
268 ntlm_print_message_fields(&(message->LmChallengeResponse),
"LmChallengeResponse");
269 ntlm_print_message_fields(&(message->NtChallengeResponse),
"NtChallengeResponse");
270 ntlm_print_message_fields(&(message->EncryptedRandomSessionKey),
"EncryptedRandomSessionKey");
272 if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
274 WLog_VRB(TAG,
"MessageIntegrityCheck (length = 16)");
275 winpr_HexDump(TAG, WLOG_TRACE, message->MessageIntegrityCheck,
276 sizeof(message->MessageIntegrityCheck));
280static void ntlm_print_authentication_complete(
const NTLM_CONTEXT* context)
282 WINPR_ASSERT(context);
284 WLog_VRB(TAG,
"ClientChallenge");
285 winpr_HexDump(TAG, WLOG_TRACE, context->ClientChallenge, 8);
286 WLog_VRB(TAG,
"ServerChallenge");
287 winpr_HexDump(TAG, WLOG_TRACE, context->ServerChallenge, 8);
288 WLog_VRB(TAG,
"SessionBaseKey");
289 winpr_HexDump(TAG, WLOG_TRACE, context->SessionBaseKey, 16);
290 WLog_VRB(TAG,
"KeyExchangeKey");
291 winpr_HexDump(TAG, WLOG_TRACE, context->KeyExchangeKey, 16);
292 WLog_VRB(TAG,
"ExportedSessionKey");
293 winpr_HexDump(TAG, WLOG_TRACE, context->ExportedSessionKey, 16);
294 WLog_VRB(TAG,
"RandomSessionKey");
295 winpr_HexDump(TAG, WLOG_TRACE, context->RandomSessionKey, 16);
296 WLog_VRB(TAG,
"ClientSigningKey");
297 winpr_HexDump(TAG, WLOG_TRACE, context->ClientSigningKey, 16);
298 WLog_VRB(TAG,
"ClientSealingKey");
299 winpr_HexDump(TAG, WLOG_TRACE, context->ClientSealingKey, 16);
300 WLog_VRB(TAG,
"ServerSigningKey");
301 winpr_HexDump(TAG, WLOG_TRACE, context->ServerSigningKey, 16);
302 WLog_VRB(TAG,
"ServerSealingKey");
303 winpr_HexDump(TAG, WLOG_TRACE, context->ServerSealingKey, 16);
304 WLog_VRB(TAG,
"Timestamp");
305 winpr_HexDump(TAG, WLOG_TRACE, context->Timestamp, 8);
312 WINPR_ASSERT(header);
314 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
317 Stream_Read(s, header->Signature, 8);
318 Stream_Read_UINT32(s, header->MessageType);
320 if (strncmp((
char*)header->Signature, NTLM_SIGNATURE, 8) != 0)
322 char Signature[
sizeof(header->Signature) * 3 + 1] = WINPR_C_ARRAY_INIT;
323 winpr_BinToHexStringBuffer(header->Signature,
sizeof(header->Signature), Signature,
324 sizeof(Signature), TRUE);
326 WLog_ERR(TAG,
"NTLM_MESSAGE_HEADER Invalid signature, got %s, expected %s", Signature,
331 if (header->MessageType != expected)
333 WLog_ERR(TAG,
"NTLM_MESSAGE_HEADER Invalid message type, got %s, expected %s",
334 ntlm_message_type_string(header->MessageType), ntlm_message_type_string(expected));
344 WINPR_ASSERT(header);
346 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s,
sizeof(NTLM_SIGNATURE) + 4ull,
347 "NTLM_MESSAGE_HEADER::header"))
350 Stream_Write(s, header->Signature,
sizeof(NTLM_SIGNATURE));
351 Stream_Write_UINT32(s, header->MessageType);
358 WINPR_ASSERT(header);
360 CopyMemory(header->Signature, NTLM_SIGNATURE,
sizeof(NTLM_SIGNATURE));
361 header->MessageType = MessageType;
368 WINPR_ASSERT(fields);
370 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
373 ntlm_free_message_fields_buffer(fields);
375 Stream_Read_UINT16(s, fields->Len);
376 Stream_Read_UINT16(s, fields->MaxLen);
377 Stream_Read_UINT32(s, fields->BufferOffset);
385 WINPR_ASSERT(fields);
387 MaxLen = fields->MaxLen;
388 if (fields->MaxLen < 1)
389 MaxLen = fields->Len;
391 if (!NTLM_CheckAndLogRequiredCapacity(TAG, (s), 8,
"NTLM_MESSAGE_FIELDS::header"))
394 Stream_Write_UINT16(s, fields->Len);
395 Stream_Write_UINT16(s, MaxLen);
396 Stream_Write_UINT32(s, fields->BufferOffset);
403 WINPR_ASSERT(fields);
405 ntlm_free_message_fields_buffer(fields);
408 const size_t offset = 1ull * fields->BufferOffset + fields->Len;
410 if (fields->BufferOffset > UINT32_MAX - fields->Len)
413 "NTLM_MESSAGE_FIELDS::BufferOffset %" PRIu32
414 " too large, maximum allowed is %" PRIu32,
415 fields->BufferOffset, UINT32_MAX - fields->Len);
419 if (offset > Stream_Length(s))
422 "NTLM_MESSAGE_FIELDS::Buffer offset %" PRIuz
" beyond received data %" PRIuz,
423 offset, Stream_Length(s));
427 fields->Buffer = (PBYTE)malloc(fields->Len);
431 WLog_ERR(TAG,
"NTLM_MESSAGE_FIELDS::Buffer allocation of %" PRIu16
"bytes failed",
436 if (!Stream_SetPosition(s, fields->BufferOffset))
438 ntlm_free_message_fields_buffer(fields);
441 Stream_Read(s, fields->Buffer, fields->Len);
450 WINPR_ASSERT(fields);
454 if (!Stream_SetPosition(s, fields->BufferOffset))
456 if (!NTLM_CheckAndLogRequiredCapacity(TAG, (s), fields->Len,
"NTLM_MESSAGE_FIELDS::Len"))
459 Stream_Write(s, fields->Buffer, fields->Len);
471 free(fields->Buffer);
474 fields->Buffer =
nullptr;
475 fields->BufferOffset = 0;
478static BOOL ntlm_read_negotiate_flags(
wStream* s, UINT32* flags, UINT32 required,
const char* name)
480 UINT32 NegotiateFlags = 0;
481 char buffer[1024] = WINPR_C_ARRAY_INIT;
486 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
489 Stream_Read_UINT32(s, NegotiateFlags);
491 if ((NegotiateFlags & required) != required)
493 WLog_ERR(TAG,
"%s::NegotiateFlags invalid flags 0x08%" PRIx32
", 0x%08" PRIx32
" required",
494 name, NegotiateFlags, required);
498 WLog_DBG(TAG,
"Read flags %s",
499 ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags));
500 *flags = NegotiateFlags;
504static BOOL ntlm_write_negotiate_flags(
wStream* s, UINT32 flags,
const char* name)
506 char buffer[1024] = WINPR_C_ARRAY_INIT;
510 if (!Stream_CheckAndLogRequiredCapacityEx(TAG, WLOG_WARN, s, 4ull, 1ull,
511 "%s(%s:%" PRIuz
") %s::NegotiateFlags", __func__,
512 __FILE__, (
size_t)__LINE__, name))
515 WLog_DBG(TAG,
"Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags));
516 Stream_Write_UINT32(s, flags);
520static BOOL ntlm_read_message_integrity_check(
wStream* s,
size_t* offset, BYTE* data,
size_t size,
521 WINPR_ATTR_UNUSED
const char* name)
524 WINPR_ASSERT(offset);
526 WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
529 *offset = Stream_GetPosition(s);
531 if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
534 Stream_Read(s, data, size);
538static BOOL ntlm_write_message_integrity_check(
wStream* s,
size_t offset,
const BYTE* data,
539 size_t size, WINPR_ATTR_UNUSED
const char* name)
543 WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
546 const size_t pos = Stream_GetPosition(s);
548 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, offset,
"MessageIntegrityCheck::offset"))
551 if (!Stream_SetPosition(s, offset))
553 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, size,
"MessageIntegrityCheck::size"))
556 Stream_Write(s, data, size);
557 return Stream_SetPosition(s, pos);
562 wStream sbuffer = WINPR_C_ARRAY_INIT;
564 WINPR_ASSERT(context);
565 WINPR_ASSERT(buffer);
568 WINPR_ASSERT(message);
570 ntlm_free_negotiate_message(message);
572 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
574 wStream* s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
579 if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE))
582 if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags,
583 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
584 NTLMSSP_NEGOTIATE_UNICODE,
585 "NTLM_NEGOTIATE_MESSAGE"))
588 context->NegotiateFlags = message->NegotiateFlags;
593 if (!ntlm_read_message_fields(s, &(message->DomainName)))
600 if (!ntlm_read_message_fields(s, &(message->Workstation)))
604 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
606 if (!ntlm_read_version_info(s, &(message->Version)))
610 if (!ntlm_read_message_fields_buffer(s, &message->DomainName))
613 if (!ntlm_read_message_fields_buffer(s, &message->Workstation))
616 const size_t length = Stream_GetPosition(s);
617 WINPR_ASSERT(length <= UINT32_MAX);
618 if (buffer->cbBuffer < length)
619 return SEC_E_INVALID_PARAMETER;
621 status = SEC_E_INTERNAL_ERROR;
622 if (!ntlm_SecBufferRealloc(&context->NegotiateMessage, (ULONG)length))
625 CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, length);
626 context->NegotiateMessage.BufferType = buffer->BufferType;
627#if defined(WITH_DEBUG_NTLM)
628 ntlm_print_negotiate_message(&context->NegotiateMessage, message);
630 ntlm_change_state(context, NTLM_STATE_CHALLENGE);
631 return SEC_I_CONTINUE_NEEDED;
639 wStream sbuffer = WINPR_C_ARRAY_INIT;
643 WINPR_ASSERT(context);
644 WINPR_ASSERT(buffer);
648 wStream* s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
651 return SEC_E_INTERNAL_ERROR;
653 if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE))
654 return SEC_E_INTERNAL_ERROR;
658 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
659 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
660 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
661 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
664 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
665 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
666 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
667 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
668 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
669 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
670 message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
671 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
673 if (context->confidentiality)
674 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
676 if (context->SendVersionInfo)
677 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
679 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
681 if (!ntlm_get_version_info(&(message->Version)))
682 return SEC_E_INTERNAL_ERROR;
685 context->NegotiateFlags = message->NegotiateFlags;
687 if (!ntlm_write_message_header(s, &message->header))
688 return SEC_E_INTERNAL_ERROR;
690 if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags,
"NTLM_NEGOTIATE_MESSAGE"))
691 return SEC_E_INTERNAL_ERROR;
695 if (!ntlm_write_message_fields(s, &(message->DomainName)))
696 return SEC_E_INTERNAL_ERROR;
700 if (!ntlm_write_message_fields(s, &(message->Workstation)))
701 return SEC_E_INTERNAL_ERROR;
703 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
705 if (!ntlm_write_version_info(s, &(message->Version)))
706 return SEC_E_INTERNAL_ERROR;
709 length = Stream_GetPosition(s);
710 WINPR_ASSERT(length <= UINT32_MAX);
711 buffer->cbBuffer = (ULONG)length;
713 if (!ntlm_SecBufferRealloc(&context->NegotiateMessage, (ULONG)length))
714 return SEC_E_INTERNAL_ERROR;
716 CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
717 context->NegotiateMessage.BufferType = buffer->BufferType;
718#if defined(WITH_DEBUG_NTLM)
719 ntlm_print_negotiate_message(&context->NegotiateMessage, message);
721 ntlm_change_state(context, NTLM_STATE_CHALLENGE);
722 return SEC_I_CONTINUE_NEEDED;
727 SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
728 wStream sbuffer = WINPR_C_ARRAY_INIT;
730 size_t StartOffset = 0;
731 size_t PayloadOffset = 0;
733 if (!context || !buffer)
734 return SEC_E_INTERNAL_ERROR;
736 if (!ntlm_generate_client_challenge(context))
737 return SEC_E_INTERNAL_ERROR;
740 WINPR_ASSERT(message);
742 ntlm_free_challenge_message(message);
744 wStream* s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
747 return SEC_E_INTERNAL_ERROR;
749 StartOffset = Stream_GetPosition(s);
751 if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE))
754 if (!ntlm_read_message_fields(s, &(message->TargetName)))
757 if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0,
"NTLM_CHALLENGE_MESSAGE"))
760 context->NegotiateFlags = message->NegotiateFlags;
762 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
765 Stream_Read(s, message->ServerChallenge, 8);
766 CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);
767 Stream_Read(s, message->Reserved, 8);
769 if (!ntlm_read_message_fields(s, &(message->TargetInfo)))
772 if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
774 if (!ntlm_read_version_info(s, &(message->Version)))
779 PayloadOffset = Stream_GetPosition(s);
781 status = SEC_E_INTERNAL_ERROR;
782 if (message->TargetName.Len > 0)
784 if (!ntlm_read_message_fields_buffer(s, &(message->TargetName)))
788 if (message->TargetInfo.Len > 0)
790 size_t cbAvTimestamp = 0;
792 if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo)))
795 sspi_SecBufferFree(&context->ChallengeTargetInfo);
796 context->ChallengeTargetInfo = ntlm_move_buffer(&message->TargetInfo);
799 ntlm_av_pair_get((
NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer,
800 context->ChallengeTargetInfo.cbBuffer, MsvAvTimestamp, &cbAvTimestamp);
804 PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp, cbAvTimestamp);
806 if (!ptr || (AvTimestamp->AvLen < 8))
810 context->UseMIC = TRUE;
812 CopyMemory(context->ChallengeTimestamp, ptr, 8);
816 length = (PayloadOffset - StartOffset) + message->TargetName.Len +
817 context->ChallengeTargetInfo.cbBuffer;
818 if (length > buffer->cbBuffer)
821 if (!ntlm_SecBufferRealloc(&context->ChallengeMessage, (ULONG)length))
824 if (context->ChallengeMessage.pvBuffer)
825 CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length);
826#if defined(WITH_DEBUG_NTLM)
827 ntlm_print_challenge_message(&context->ChallengeMessage, message,
nullptr);
833 if (!ntlm_construct_authenticate_target_info(context))
836 sspi_SecBufferFree(&context->ChallengeTargetInfo);
837 context->ChallengeTargetInfo = ntlm_secbuffer_move(&context->AuthenticateTargetInfo);
840 ntlm_generate_timestamp(context);
843 const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context);
852 const SECURITY_STATUS rc2 =
853 ntlm_compute_ntlm_v2_response(context);
861 if (!ntlm_generate_key_exchange_key(context))
863 if (!ntlm_generate_random_session_key(context))
865 if (!ntlm_generate_exported_session_key(context))
867 if (!ntlm_encrypt_random_session_key(context))
871 status = SEC_E_ENCRYPT_FAILURE;
872 if (!ntlm_generate_client_signing_key(context))
874 if (!ntlm_generate_server_signing_key(context))
877 if (!ntlm_generate_client_sealing_key(context))
879 if (!ntlm_generate_server_sealing_key(context))
882 if (!ntlm_init_rc4_seal_states(context))
884#if defined(WITH_DEBUG_NTLM)
885 ntlm_print_authentication_complete(context);
887 ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
888 status = SEC_I_CONTINUE_NEEDED;
895 wStream sbuffer = WINPR_C_ARRAY_INIT;
897 UINT32 PayloadOffset = 0;
900 WINPR_ASSERT(context);
901 WINPR_ASSERT(buffer);
905 wStream* s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
908 return SEC_E_INTERNAL_ERROR;
910 if (!ntlm_get_version_info(&(message->Version)))
911 return SEC_E_INTERNAL_ERROR;
912 if (!ntlm_generate_server_challenge(context))
913 return SEC_E_INTERNAL_ERROR;
914 ntlm_generate_timestamp(context);
916 if (!ntlm_construct_challenge_target_info(context))
917 return SEC_E_INTERNAL_ERROR;
919 CopyMemory(message->ServerChallenge, context->ServerChallenge, 8);
920 message->NegotiateFlags = context->NegotiateFlags;
921 if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE))
922 return SEC_E_INTERNAL_ERROR;
925 if (!ntlm_write_message_header(s, &message->header))
926 return SEC_E_INTERNAL_ERROR;
928 if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
930 message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
931 message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
934 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
936 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
938 message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
939 message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
944 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
947 message->TargetName.BufferOffset = PayloadOffset;
948 message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len;
950 if (!ntlm_write_message_fields(s, &(message->TargetName)))
951 return SEC_E_INTERNAL_ERROR;
953 if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags,
"NTLM_CHALLENGE_MESSAGE"))
954 return SEC_E_INTERNAL_ERROR;
956 if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 16,
"NTLM_CHALLENGE_MESSAGE::ServerChallenge"))
957 return SEC_E_INTERNAL_ERROR;
959 Stream_Write(s, message->ServerChallenge, 8);
960 Stream_Write(s, message->Reserved, 8);
963 if (!ntlm_write_message_fields(s, &(message->TargetInfo)))
964 return SEC_E_INTERNAL_ERROR;
966 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
968 if (!ntlm_write_version_info(s, &(message->Version)))
969 return SEC_E_INTERNAL_ERROR;
973 if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
975 if (!ntlm_write_message_fields_buffer(s, &(message->TargetName)))
976 return SEC_E_INTERNAL_ERROR;
979 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
981 if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo)))
982 return SEC_E_INTERNAL_ERROR;
985 length = Stream_GetPosition(s);
986 WINPR_ASSERT(length <= UINT32_MAX);
987 buffer->cbBuffer = (ULONG)length;
989 if (!ntlm_SecBufferRealloc(&context->ChallengeMessage, (ULONG)length))
990 return SEC_E_INTERNAL_ERROR;
992 CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
993#if defined(WITH_DEBUG_NTLM)
994 ntlm_print_challenge_message(&context->ChallengeMessage, message,
995 &context->ChallengeTargetInfo);
997 ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
998 return SEC_I_CONTINUE_NEEDED;
1003 SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
1004 wStream sbuffer = WINPR_C_ARRAY_INIT;
1008 size_t PayloadBufferOffset = 0;
1010 WINPR_ASSERT(context);
1011 WINPR_ASSERT(buffer);
1014 WINPR_ASSERT(credentials);
1017 WINPR_ASSERT(message);
1019 ntlm_free_authenticate_message(message);
1021 wStream* s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
1024 return SEC_E_INTERNAL_ERROR;
1026 if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE))
1029 if (!ntlm_read_message_fields(
1030 s, &(message->LmChallengeResponse)))
1033 if (!ntlm_read_message_fields(
1034 s, &(message->NtChallengeResponse)))
1037 if (!ntlm_read_message_fields(s, &(message->DomainName)))
1040 if (!ntlm_read_message_fields(s, &(message->UserName)))
1043 if (!ntlm_read_message_fields(s, &(message->Workstation)))
1046 if (!ntlm_read_message_fields(
1048 &(message->EncryptedRandomSessionKey)))
1051 if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0,
"NTLM_AUTHENTICATE_MESSAGE"))
1054 context->NegotiateKeyExchange = (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0;
1056 if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
1057 (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
1060 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1062 if (!ntlm_read_version_info(s, &(message->Version)))
1066 PayloadBufferOffset = Stream_GetPosition(s);
1068 status = SEC_E_INTERNAL_ERROR;
1069 if (!ntlm_read_message_fields_buffer(s, &(message->DomainName)))
1072 if (!ntlm_read_message_fields_buffer(s, &(message->UserName)))
1075 if (!ntlm_read_message_fields_buffer(s, &(message->Workstation)))
1078 if (!ntlm_read_message_fields_buffer(s,
1079 &(message->LmChallengeResponse)))
1082 if (!ntlm_read_message_fields_buffer(s,
1083 &(message->NtChallengeResponse)))
1086 if (ntlm_SetContextWorkstationX(context, TRUE, message->Workstation.Buffer,
1087 message->Workstation.Len) != SEC_E_OK)
1090 if (message->NtChallengeResponse.Len > 0)
1092 size_t cbAvFlags = 0;
1094 wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer,
1095 message->NtChallengeResponse.Len);
1100 status = SEC_E_INVALID_TOKEN;
1101 if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)))
1103 status = SEC_E_INTERNAL_ERROR;
1105 sspi_SecBufferFree(&context->NtChallengeResponse);
1106 context->NtChallengeResponse = ntlm_move_buffer(&message->NtChallengeResponse);
1108 sspi_SecBufferFree(&(context->ChallengeTargetInfo));
1109 context->ChallengeTargetInfo.pvBuffer = (
void*)context->NTLMv2Response.Challenge.AvPairs;
1110 context->ChallengeTargetInfo.cbBuffer = context->NtChallengeResponse.cbBuffer - (28 + 16);
1111 CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
1113 ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
1114 context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);
1118 const BYTE* ptr = ntlm_av_pair_get_value_pointer(AvFlags, cbAvFlags);
1119 if (!ptr || (AvFlags->AvLen < 4))
1121 flags = winpr_Data_Get_UINT32(ptr);
1125 if (!ntlm_read_message_fields_buffer(
1126 s, &(message->EncryptedRandomSessionKey)))
1129 if (message->EncryptedRandomSessionKey.Len > 0)
1131 if (message->EncryptedRandomSessionKey.Len != 16)
1134 CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
1138 length = Stream_GetPosition(s);
1139 WINPR_ASSERT(length <= UINT32_MAX);
1141 if (!ntlm_SecBufferRealloc(&context->AuthenticateMessage, (ULONG)length))
1144 CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1145 buffer->cbBuffer = (ULONG)length;
1146 if (!Stream_SetPosition(s, PayloadBufferOffset))
1149 if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1151 status = SEC_E_INVALID_TOKEN;
1152 if (!ntlm_read_message_integrity_check(
1153 s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1154 sizeof(message->MessageIntegrityCheck),
"NTLM_AUTHENTICATE_MESSAGE"))
1158 status = SEC_E_INTERNAL_ERROR;
1160#if defined(WITH_DEBUG_NTLM)
1161 ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags,
nullptr);
1164 if (message->UserName.Len > 0)
1166 credentials->identity.User = (UINT16*)calloc(message->UserName.Len +
sizeof(WCHAR), 1);
1168 if (!credentials->identity.User)
1171 CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
1172 credentials->identity.UserLength = message->UserName.Len /
sizeof(WCHAR);
1175 if (message->DomainName.Len > 0)
1177 credentials->identity.Domain = (UINT16*)calloc(message->DomainName.Len +
sizeof(WCHAR), 1);
1179 if (!credentials->identity.Domain)
1182 CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
1183 message->DomainName.Len);
1184 credentials->identity.DomainLength = message->DomainName.Len /
sizeof(WCHAR);
1187 if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1189 const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context);
1198 const SECURITY_STATUS rc = ntlm_compute_ntlm_v2_response(context);
1207 if (!ntlm_generate_key_exchange_key(context))
1210 if (!ntlm_decrypt_random_session_key(context))
1213 if (!ntlm_generate_exported_session_key(context))
1216 if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1218 BYTE messageIntegrityCheck[16] = WINPR_C_ARRAY_INIT;
1220 if (!ntlm_compute_message_integrity_check(context, messageIntegrityCheck,
1221 sizeof(messageIntegrityCheck)))
1224 &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
1225 message->MessageIntegrityCheck,
sizeof(message->MessageIntegrityCheck));
1227 if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck,
1228 sizeof(message->MessageIntegrityCheck)) != 0)
1230 WLog_ERR(TAG,
"Message Integrity Check (MIC) verification failed!");
1231#ifdef WITH_DEBUG_NTLM
1232 WLog_ERR(TAG,
"Expected MIC:");
1233 winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck,
sizeof(messageIntegrityCheck));
1234 WLog_ERR(TAG,
"Actual MIC:");
1235 winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
1236 sizeof(message->MessageIntegrityCheck));
1238 status = SEC_E_MESSAGE_ALTERED;
1254#ifdef WITH_DEBUG_NTLM
1255 WLog_VRB(TAG,
"No MIC present, using NtProofString for verification.");
1258 if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
1260 WLog_ERR(TAG,
"NtProofString verification failed!");
1261#ifdef WITH_DEBUG_NTLM
1262 WLog_ERR(TAG,
"Expected NtProofString:");
1263 winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString,
sizeof(context->NtProofString));
1264 WLog_ERR(TAG,
"Actual NtProofString:");
1265 winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
1266 sizeof(context->NTLMv2Response));
1268 status = SEC_E_LOGON_DENIED;
1274 if (!ntlm_generate_client_signing_key(context))
1276 if (!ntlm_generate_server_signing_key(context))
1279 if (!ntlm_generate_client_sealing_key(context))
1281 if (!ntlm_generate_server_sealing_key(context))
1284 if (!ntlm_init_rc4_seal_states(context))
1286#if defined(WITH_DEBUG_NTLM)
1287 ntlm_print_authentication_complete(context);
1289 ntlm_change_state(context, NTLM_STATE_FINAL);
1305 wStream sbuffer = WINPR_C_ARRAY_INIT;
1307 UINT32 PayloadBufferOffset = 0;
1310 WINPR_ASSERT(context);
1311 WINPR_ASSERT(buffer);
1314 WINPR_ASSERT(credentials);
1318 wStream* s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
1321 return SEC_E_INTERNAL_ERROR;
1323 if (context->NTLMv2)
1325 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
1327 if (context->SendVersionInfo)
1328 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
1331 if (context->UseMIC)
1332 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
1334 if (context->SendWorkstationName)
1335 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
1337 if (context->confidentiality)
1338 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
1340 if (context->CHALLENGE_MESSAGE.NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1341 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
1343 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
1344 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
1345 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
1346 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
1347 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1348 message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
1349 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
1351 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1353 if (!ntlm_get_version_info(&(message->Version)))
1354 return SEC_E_INTERNAL_ERROR;
1357 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1359 message->Workstation.Len = context->Workstation.Length;
1360 message->Workstation.Buffer = (BYTE*)context->Workstation.Buffer;
1363 if (credentials->identity.DomainLength > 0)
1365 message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
1366 message->DomainName.Len = (UINT16)credentials->identity.DomainLength *
sizeof(WCHAR);
1367 message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
1370 message->UserName.Len = (UINT16)credentials->identity.UserLength *
sizeof(WCHAR);
1371 message->UserName.Buffer = (BYTE*)credentials->identity.User;
1372 message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
1373 message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
1374 message->NtChallengeResponse.Len = (UINT16)context->NtChallengeResponse.cbBuffer;
1375 message->NtChallengeResponse.Buffer = (BYTE*)context->NtChallengeResponse.pvBuffer;
1377 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1379 message->EncryptedRandomSessionKey.Len = 16;
1380 message->EncryptedRandomSessionKey.Buffer = context->EncryptedRandomSessionKey;
1383 PayloadBufferOffset = 64;
1385 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1386 PayloadBufferOffset += 8;
1388 if (context->UseMIC)
1389 PayloadBufferOffset += 16;
1391 message->DomainName.BufferOffset = PayloadBufferOffset;
1392 message->UserName.BufferOffset = message->DomainName.BufferOffset + message->DomainName.Len;
1393 message->Workstation.BufferOffset = message->UserName.BufferOffset + message->UserName.Len;
1394 message->LmChallengeResponse.BufferOffset =
1395 message->Workstation.BufferOffset + message->Workstation.Len;
1396 message->NtChallengeResponse.BufferOffset =
1397 message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len;
1398 message->EncryptedRandomSessionKey.BufferOffset =
1399 message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len;
1400 if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE))
1401 return SEC_E_INVALID_TOKEN;
1402 if (!ntlm_write_message_header(s, &message->header))
1403 return SEC_E_INTERNAL_ERROR;
1404 if (!ntlm_write_message_fields(
1405 s, &(message->LmChallengeResponse)))
1406 return SEC_E_INTERNAL_ERROR;
1407 if (!ntlm_write_message_fields(
1408 s, &(message->NtChallengeResponse)))
1409 return SEC_E_INTERNAL_ERROR;
1410 if (!ntlm_write_message_fields(s, &(message->DomainName)))
1411 return SEC_E_INTERNAL_ERROR;
1412 if (!ntlm_write_message_fields(s, &(message->UserName)))
1413 return SEC_E_INTERNAL_ERROR;
1414 if (!ntlm_write_message_fields(s, &(message->Workstation)))
1415 return SEC_E_INTERNAL_ERROR;
1416 if (!ntlm_write_message_fields(
1418 &(message->EncryptedRandomSessionKey)))
1419 return SEC_E_INTERNAL_ERROR;
1420 if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags,
"NTLM_AUTHENTICATE_MESSAGE"))
1421 return SEC_E_INTERNAL_ERROR;
1423 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1425 if (!ntlm_write_version_info(s, &(message->Version)))
1426 return SEC_E_INTERNAL_ERROR;
1429 if (context->UseMIC)
1431 const BYTE data[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1433 context->MessageIntegrityCheckOffset = Stream_GetPosition(s);
1434 if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data,
sizeof(data),
1435 "NTLM_AUTHENTICATE_MESSAGE"))
1436 return SEC_E_INTERNAL_ERROR;
1439 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
1441 if (!ntlm_write_message_fields_buffer(s, &(message->DomainName)))
1442 return SEC_E_INTERNAL_ERROR;
1445 if (!ntlm_write_message_fields_buffer(s, &(message->UserName)))
1446 return SEC_E_INTERNAL_ERROR;
1448 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1450 if (!ntlm_write_message_fields_buffer(s, &(message->Workstation)))
1451 return SEC_E_INTERNAL_ERROR;
1454 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1456 if (!ntlm_write_message_fields_buffer(
1457 s, &(message->LmChallengeResponse)))
1458 return SEC_E_INTERNAL_ERROR;
1460 if (!ntlm_write_message_fields_buffer(
1461 s, &(message->NtChallengeResponse)))
1462 return SEC_E_INTERNAL_ERROR;
1464 if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1466 if (!ntlm_write_message_fields_buffer(
1467 s, &(message->EncryptedRandomSessionKey)))
1468 return SEC_E_INTERNAL_ERROR;
1471 length = Stream_GetPosition(s);
1472 WINPR_ASSERT(length <= UINT32_MAX);
1474 if (!ntlm_SecBufferRealloc(&context->AuthenticateMessage, (ULONG)length))
1475 return SEC_E_INTERNAL_ERROR;
1477 CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1478 buffer->cbBuffer = (ULONG)length;
1480 if (context->UseMIC)
1483 if (!ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck,
1484 sizeof(message->MessageIntegrityCheck)))
1485 return SEC_E_INTERNAL_ERROR;
1486 if (!ntlm_write_message_integrity_check(
1487 s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1488 sizeof(message->MessageIntegrityCheck),
"NTLM_AUTHENTICATE_MESSAGE"))
1489 return SEC_E_INTERNAL_ERROR;
1492#if defined(WITH_DEBUG_NTLM)
1493 ntlm_print_authenticate_message(&context->AuthenticateMessage, message,
1494 context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0,
1495 &context->AuthenticateTargetInfo);
1497 ntlm_change_state(context, NTLM_STATE_FINAL);