FreeRDP
ntlm_message.c
1 
20 #include <winpr/config.h>
21 
22 #include "ntlm.h"
23 #include "../sspi.h"
24 
25 #include <winpr/crt.h>
26 #include <winpr/assert.h>
27 #include <winpr/print.h>
28 #include <winpr/stream.h>
29 #include <winpr/sysinfo.h>
30 
31 #include "ntlm_compute.h"
32 
33 #include "ntlm_message.h"
34 
35 #include "../../log.h"
36 #define TAG WINPR_TAG("sspi.NTLM")
37 
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__)
41 
42 static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' };
43 
44 static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields);
45 
46 const char* ntlm_get_negotiate_string(UINT32 flag)
47 {
48  if (flag & NTLMSSP_NEGOTIATE_56)
49  return "NTLMSSP_NEGOTIATE_56";
50  if (flag & NTLMSSP_NEGOTIATE_KEY_EXCH)
51  return "NTLMSSP_NEGOTIATE_KEY_EXCH";
52  if (flag & NTLMSSP_NEGOTIATE_128)
53  return "NTLMSSP_NEGOTIATE_128";
54  if (flag & NTLMSSP_RESERVED1)
55  return "NTLMSSP_RESERVED1";
56  if (flag & NTLMSSP_RESERVED2)
57  return "NTLMSSP_RESERVED2";
58  if (flag & NTLMSSP_RESERVED3)
59  return "NTLMSSP_RESERVED3";
60  if (flag & NTLMSSP_NEGOTIATE_VERSION)
61  return "NTLMSSP_NEGOTIATE_VERSION";
62  if (flag & NTLMSSP_RESERVED4)
63  return "NTLMSSP_RESERVED4";
64  if (flag & NTLMSSP_NEGOTIATE_TARGET_INFO)
65  return "NTLMSSP_NEGOTIATE_TARGET_INFO";
66  if (flag & NTLMSSP_REQUEST_NON_NT_SESSION_KEY)
67  return "NTLMSSP_REQUEST_NON_NT_SESSION_KEY";
68  if (flag & NTLMSSP_RESERVED5)
69  return "NTLMSSP_RESERVED5";
70  if (flag & NTLMSSP_NEGOTIATE_IDENTIFY)
71  return "NTLMSSP_NEGOTIATE_IDENTIFY";
72  if (flag & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY)
73  return "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY";
74  if (flag & NTLMSSP_RESERVED6)
75  return "NTLMSSP_RESERVED6";
76  if (flag & NTLMSSP_TARGET_TYPE_SERVER)
77  return "NTLMSSP_TARGET_TYPE_SERVER";
78  if (flag & NTLMSSP_TARGET_TYPE_DOMAIN)
79  return "NTLMSSP_TARGET_TYPE_DOMAIN";
80  if (flag & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
81  return "NTLMSSP_NEGOTIATE_ALWAYS_SIGN";
82  if (flag & NTLMSSP_RESERVED7)
83  return "NTLMSSP_RESERVED7";
84  if (flag & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
85  return "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED";
86  if (flag & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
87  return "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED";
88  if (flag & NTLMSSP_NEGOTIATE_ANONYMOUS)
89  return "NTLMSSP_NEGOTIATE_ANONYMOUS";
90  if (flag & NTLMSSP_RESERVED8)
91  return "NTLMSSP_RESERVED8";
92  if (flag & NTLMSSP_NEGOTIATE_NTLM)
93  return "NTLMSSP_NEGOTIATE_NTLM";
94  if (flag & NTLMSSP_RESERVED9)
95  return "NTLMSSP_RESERVED9";
96  if (flag & NTLMSSP_NEGOTIATE_LM_KEY)
97  return "NTLMSSP_NEGOTIATE_LM_KEY";
98  if (flag & NTLMSSP_NEGOTIATE_DATAGRAM)
99  return "NTLMSSP_NEGOTIATE_DATAGRAM";
100  if (flag & NTLMSSP_NEGOTIATE_SEAL)
101  return "NTLMSSP_NEGOTIATE_SEAL";
102  if (flag & NTLMSSP_NEGOTIATE_SIGN)
103  return "NTLMSSP_NEGOTIATE_SIGN";
104  if (flag & NTLMSSP_RESERVED10)
105  return "NTLMSSP_RESERVED10";
106  if (flag & NTLMSSP_REQUEST_TARGET)
107  return "NTLMSSP_REQUEST_TARGET";
108  if (flag & NTLMSSP_NEGOTIATE_OEM)
109  return "NTLMSSP_NEGOTIATE_OEM";
110  if (flag & NTLMSSP_NEGOTIATE_UNICODE)
111  return "NTLMSSP_NEGOTIATE_UNICODE";
112  return "NTLMSSP_NEGOTIATE_UNKNOWN";
113 }
114 
115 #if defined(WITH_DEBUG_NTLM)
116 static void ntlm_print_message_fields(const NTLM_MESSAGE_FIELDS* fields, const char* name)
117 {
118  WINPR_ASSERT(fields);
119  WINPR_ASSERT(name);
120 
121  WLog_VRB(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name,
122  fields->Len, fields->MaxLen, fields->BufferOffset);
123 
124  if (fields->Len > 0)
125  winpr_HexDump(TAG, WLOG_TRACE, fields->Buffer, fields->Len);
126 }
127 
128 static void ntlm_print_negotiate_flags(UINT32 flags)
129 {
130  WLog_VRB(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags);
131 
132  for (int i = 31; i >= 0; i--)
133  {
134  if ((flags >> i) & 1)
135  {
136  const char* str = ntlm_get_negotiate_string(1 << i);
137  WLog_VRB(TAG, "\t%s (%d),", str, (31 - i));
138  }
139  }
140 }
141 
142 static void ntlm_print_negotiate_message(const SecBuffer* NegotiateMessage,
143  const NTLM_NEGOTIATE_MESSAGE* message)
144 {
145  WINPR_ASSERT(NegotiateMessage);
146  WINPR_ASSERT(message);
147 
148  WLog_VRB(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", NegotiateMessage->cbBuffer);
149  winpr_HexDump(TAG, WLOG_TRACE, NegotiateMessage->pvBuffer, NegotiateMessage->cbBuffer);
150  ntlm_print_negotiate_flags(message->NegotiateFlags);
151 
152  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
153  ntlm_print_version_info(&(message->Version));
154 }
155 
156 static void ntlm_print_challenge_message(const SecBuffer* ChallengeMessage,
157  const NTLM_CHALLENGE_MESSAGE* message,
158  const SecBuffer* ChallengeTargetInfo)
159 {
160  WINPR_ASSERT(ChallengeMessage);
161  WINPR_ASSERT(message);
162 
163  WLog_VRB(TAG, "CHALLENGE_MESSAGE (length = %" PRIu32 ")", ChallengeMessage->cbBuffer);
164  winpr_HexDump(TAG, WLOG_TRACE, ChallengeMessage->pvBuffer, ChallengeMessage->cbBuffer);
165  ntlm_print_negotiate_flags(message->NegotiateFlags);
166 
167  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
168  ntlm_print_version_info(&(message->Version));
169 
170  ntlm_print_message_fields(&(message->TargetName), "TargetName");
171  ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");
172 
173  if (ChallengeTargetInfo && (ChallengeTargetInfo->cbBuffer > 0))
174  {
175  WLog_VRB(TAG, "ChallengeTargetInfo (%" PRIu32 "):", ChallengeTargetInfo->cbBuffer);
176  ntlm_print_av_pair_list(ChallengeTargetInfo->pvBuffer, ChallengeTargetInfo->cbBuffer);
177  }
178 }
179 
180 static void ntlm_print_authenticate_message(const SecBuffer* AuthenticateMessage,
181  const NTLM_AUTHENTICATE_MESSAGE* message, UINT32 flags,
182  const SecBuffer* AuthenticateTargetInfo)
183 {
184  WINPR_ASSERT(AuthenticateMessage);
185  WINPR_ASSERT(message);
186 
187  WLog_VRB(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", AuthenticateMessage->cbBuffer);
188  winpr_HexDump(TAG, WLOG_TRACE, AuthenticateMessage->pvBuffer, AuthenticateMessage->cbBuffer);
189  ntlm_print_negotiate_flags(message->NegotiateFlags);
190 
191  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
192  ntlm_print_version_info(&(message->Version));
193 
194  if (AuthenticateTargetInfo && (AuthenticateTargetInfo->cbBuffer > 0))
195  {
196  WLog_VRB(TAG, "AuthenticateTargetInfo (%" PRIu32 "):", AuthenticateTargetInfo->cbBuffer);
197  ntlm_print_av_pair_list(AuthenticateTargetInfo->pvBuffer, AuthenticateTargetInfo->cbBuffer);
198  }
199 
200  ntlm_print_message_fields(&(message->DomainName), "DomainName");
201  ntlm_print_message_fields(&(message->UserName), "UserName");
202  ntlm_print_message_fields(&(message->Workstation), "Workstation");
203  ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse");
204  ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse");
205  ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey");
206 
207  if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
208  {
209  WLog_VRB(TAG, "MessageIntegrityCheck (length = 16)");
210  winpr_HexDump(TAG, WLOG_TRACE, message->MessageIntegrityCheck,
211  sizeof(message->MessageIntegrityCheck));
212  }
213 }
214 
215 static void ntlm_print_authentication_complete(const NTLM_CONTEXT* context)
216 {
217  WINPR_ASSERT(context);
218 
219  WLog_VRB(TAG, "ClientChallenge");
220  winpr_HexDump(TAG, WLOG_TRACE, context->ClientChallenge, 8);
221  WLog_VRB(TAG, "ServerChallenge");
222  winpr_HexDump(TAG, WLOG_TRACE, context->ServerChallenge, 8);
223  WLog_VRB(TAG, "SessionBaseKey");
224  winpr_HexDump(TAG, WLOG_TRACE, context->SessionBaseKey, 16);
225  WLog_VRB(TAG, "KeyExchangeKey");
226  winpr_HexDump(TAG, WLOG_TRACE, context->KeyExchangeKey, 16);
227  WLog_VRB(TAG, "ExportedSessionKey");
228  winpr_HexDump(TAG, WLOG_TRACE, context->ExportedSessionKey, 16);
229  WLog_VRB(TAG, "RandomSessionKey");
230  winpr_HexDump(TAG, WLOG_TRACE, context->RandomSessionKey, 16);
231  WLog_VRB(TAG, "ClientSigningKey");
232  winpr_HexDump(TAG, WLOG_TRACE, context->ClientSigningKey, 16);
233  WLog_VRB(TAG, "ClientSealingKey");
234  winpr_HexDump(TAG, WLOG_TRACE, context->ClientSealingKey, 16);
235  WLog_VRB(TAG, "ServerSigningKey");
236  winpr_HexDump(TAG, WLOG_TRACE, context->ServerSigningKey, 16);
237  WLog_VRB(TAG, "ServerSealingKey");
238  winpr_HexDump(TAG, WLOG_TRACE, context->ServerSealingKey, 16);
239  WLog_VRB(TAG, "Timestamp");
240  winpr_HexDump(TAG, WLOG_TRACE, context->Timestamp, 8);
241 }
242 #endif
243 
244 static BOOL ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header, UINT32 expected)
245 {
246  WINPR_ASSERT(s);
247  WINPR_ASSERT(header);
248 
249  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
250  return FALSE;
251 
252  Stream_Read(s, header->Signature, 8);
253  Stream_Read_UINT32(s, header->MessageType);
254 
255  if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0)
256  {
257  char Signature[sizeof(header->Signature) * 3 + 1] = { 0 };
258  winpr_BinToHexStringBuffer(header->Signature, sizeof(header->Signature), Signature,
259  sizeof(Signature), TRUE);
260 
261  WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid signature, got %s, expected %s", Signature,
262  NTLM_SIGNATURE);
263  return FALSE;
264  }
265 
266  if (header->MessageType != expected)
267  {
268  WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid message tyep, got %s, expected %s",
269  ntlm_message_type_string(header->MessageType), ntlm_message_type_string(expected));
270  return FALSE;
271  }
272 
273  return TRUE;
274 }
275 
276 static BOOL ntlm_write_message_header(wStream* s, const NTLM_MESSAGE_HEADER* header)
277 {
278  WINPR_ASSERT(s);
279  WINPR_ASSERT(header);
280 
281  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, sizeof(NTLM_SIGNATURE) + 4ull,
282  "NTLM_MESSAGE_HEADER::header"))
283  return FALSE;
284 
285  Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE));
286  Stream_Write_UINT32(s, header->MessageType);
287 
288  return TRUE;
289 }
290 
291 static BOOL ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType)
292 {
293  WINPR_ASSERT(header);
294 
295  CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE));
296  header->MessageType = MessageType;
297  return TRUE;
298 }
299 
300 static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields)
301 {
302  WINPR_ASSERT(s);
303  WINPR_ASSERT(fields);
304 
305  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
306  return FALSE;
307 
308  ntlm_free_message_fields_buffer(fields);
309 
310  Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */
311  Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */
312  Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
313  return TRUE;
314 }
315 
316 static BOOL ntlm_write_message_fields(wStream* s, const NTLM_MESSAGE_FIELDS* fields)
317 {
318  UINT16 MaxLen = 0;
319  WINPR_ASSERT(s);
320  WINPR_ASSERT(fields);
321 
322  MaxLen = fields->MaxLen;
323  if (fields->MaxLen < 1)
324  MaxLen = fields->Len;
325 
326  if (!NTLM_CheckAndLogRequiredCapacity(TAG, (s), 8, "NTLM_MESSAGE_FIELDS::header"))
327  return FALSE;
328 
329  Stream_Write_UINT16(s, fields->Len); /* Len (2 bytes) */
330  Stream_Write_UINT16(s, MaxLen); /* MaxLen (2 bytes) */
331  Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */
332  return TRUE;
333 }
334 
335 static BOOL ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields)
336 {
337  WINPR_ASSERT(s);
338  WINPR_ASSERT(fields);
339 
340  if (fields->Len > 0)
341  {
342  const UINT32 offset = fields->BufferOffset + fields->Len;
343 
344  if (fields->BufferOffset > UINT32_MAX - fields->Len)
345  {
346  WLog_ERR(TAG,
347  "NTLM_MESSAGE_FIELDS::BufferOffset %" PRIu32
348  " too large, maximum allowed is %" PRIu32,
349  fields->BufferOffset, UINT32_MAX - fields->Len);
350  return FALSE;
351  }
352 
353  if (offset > Stream_Length(s))
354  {
355  WLog_ERR(TAG,
356  "NTLM_MESSAGE_FIELDS::Buffer offset %" PRIu32 " beyond received data %" PRIuz,
357  offset, Stream_Length(s));
358  return FALSE;
359  }
360 
361  fields->Buffer = (PBYTE)malloc(fields->Len);
362 
363  if (!fields->Buffer)
364  {
365  WLog_ERR(TAG, "NTLM_MESSAGE_FIELDS::Buffer allocation of %" PRIu16 "bytes failed",
366  fields->Len);
367  return FALSE;
368  }
369 
370  Stream_SetPosition(s, fields->BufferOffset);
371  Stream_Read(s, fields->Buffer, fields->Len);
372  }
373 
374  return TRUE;
375 }
376 
377 static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIELDS* fields)
378 {
379  WINPR_ASSERT(s);
380  WINPR_ASSERT(fields);
381 
382  if (fields->Len > 0)
383  {
384  Stream_SetPosition(s, fields->BufferOffset);
385  if (!NTLM_CheckAndLogRequiredCapacity(TAG, (s), fields->Len, "NTLM_MESSAGE_FIELDS::Len"))
386  return FALSE;
387 
388  Stream_Write(s, fields->Buffer, fields->Len);
389  }
390  return TRUE;
391 }
392 
393 void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
394 {
395  if (fields)
396  {
397  if (fields->Buffer)
398  {
399  free(fields->Buffer);
400  fields->Len = 0;
401  fields->MaxLen = 0;
402  fields->Buffer = NULL;
403  fields->BufferOffset = 0;
404  }
405  }
406 }
407 
408 static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name)
409 {
410  UINT32 NegotiateFlags = 0;
411  char buffer[1024] = { 0 };
412  WINPR_ASSERT(s);
413  WINPR_ASSERT(flags);
414  WINPR_ASSERT(name);
415 
416  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
417  return FALSE;
418 
419  Stream_Read_UINT32(s, NegotiateFlags); /* NegotiateFlags (4 bytes) */
420 
421  if ((NegotiateFlags & required) != required)
422  {
423  WLog_ERR(TAG, "%s::NegotiateFlags invalid flags 0x08%" PRIx32 ", 0x%08" PRIx32 " required",
424  name, NegotiateFlags, required);
425  return FALSE;
426  }
427 
428  WLog_DBG(TAG, "Read flags %s",
429  ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags));
430  *flags = NegotiateFlags;
431  return TRUE;
432 }
433 
434 static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name)
435 {
436  char buffer[1024] = { 0 };
437  WINPR_ASSERT(s);
438  WINPR_ASSERT(name);
439 
440  if (!Stream_CheckAndLogRequiredCapacityEx(TAG, WLOG_WARN, s, 4ull, 1ull,
441  "%s(%s:%" PRIuz ") %s::NegotiateFlags", __func__,
442  __FILE__, (size_t)__LINE__, name))
443  return FALSE;
444 
445  WLog_DBG(TAG, "Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags));
446  Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */
447  return TRUE;
448 }
449 
450 static BOOL ntlm_read_message_integrity_check(wStream* s, size_t* offset, BYTE* data, size_t size,
451  const char* name)
452 {
453  WINPR_ASSERT(s);
454  WINPR_ASSERT(offset);
455  WINPR_ASSERT(data);
456  WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
457  WINPR_ASSERT(name);
458 
459  *offset = Stream_GetPosition(s);
460 
461  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
462  return FALSE;
463 
464  Stream_Read(s, data, size);
465  return TRUE;
466 }
467 
468 static BOOL ntlm_write_message_integrity_check(wStream* s, size_t offset, const BYTE* data,
469  size_t size, const char* name)
470 {
471  size_t pos = 0;
472 
473  WINPR_ASSERT(s);
474  WINPR_ASSERT(data);
475  WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
476  WINPR_ASSERT(name);
477 
478  pos = Stream_GetPosition(s);
479 
480  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, offset, "MessageIntegrityCheck::offset"))
481  return FALSE;
482 
483  Stream_SetPosition(s, offset);
484  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, size, "MessageIntegrityCheck::size"))
485  return FALSE;
486 
487  Stream_Write(s, data, size);
488  Stream_SetPosition(s, pos);
489  return TRUE;
490 }
491 
492 SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
493 {
494  wStream sbuffer;
495  wStream* s = NULL;
496  size_t length = 0;
497  const NTLM_NEGOTIATE_MESSAGE empty = { 0 };
498  NTLM_NEGOTIATE_MESSAGE* message = NULL;
499 
500  WINPR_ASSERT(context);
501  WINPR_ASSERT(buffer);
502 
503  message = &context->NEGOTIATE_MESSAGE;
504  WINPR_ASSERT(message);
505 
506  *message = empty;
507 
508  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
509 
510  if (!s)
511  return SEC_E_INTERNAL_ERROR;
512 
513  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE))
514  return SEC_E_INVALID_TOKEN;
515 
516  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags,
517  NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
518  NTLMSSP_NEGOTIATE_UNICODE,
519  "NTLM_NEGOTIATE_MESSAGE"))
520  return SEC_E_INVALID_TOKEN;
521 
522  context->NegotiateFlags = message->NegotiateFlags;
523 
524  /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
525  // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
526  {
527  if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
528  return SEC_E_INVALID_TOKEN;
529  }
530 
531  /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
532  // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
533  {
534  if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
535  return SEC_E_INVALID_TOKEN;
536  }
537 
538  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
539  {
540  if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
541  return SEC_E_INVALID_TOKEN;
542  }
543 
544  if (!ntlm_read_message_fields_buffer(s, &message->DomainName))
545  return SEC_E_INVALID_TOKEN;
546 
547  if (!ntlm_read_message_fields_buffer(s, &message->Workstation))
548  return SEC_E_INVALID_TOKEN;
549 
550  length = Stream_GetPosition(s);
551  WINPR_ASSERT(length <= UINT32_MAX);
552  buffer->cbBuffer = (ULONG)length;
553 
554  if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length))
555  return SEC_E_INTERNAL_ERROR;
556 
557  CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
558  context->NegotiateMessage.BufferType = buffer->BufferType;
559 #if defined(WITH_DEBUG_NTLM)
560  ntlm_print_negotiate_message(&context->NegotiateMessage, message);
561 #endif
562  ntlm_change_state(context, NTLM_STATE_CHALLENGE);
563  return SEC_I_CONTINUE_NEEDED;
564 }
565 
566 SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer)
567 {
568  wStream sbuffer;
569  wStream* s = NULL;
570  size_t length = 0;
571  const NTLM_NEGOTIATE_MESSAGE empty = { 0 };
572  NTLM_NEGOTIATE_MESSAGE* message = NULL;
573 
574  WINPR_ASSERT(context);
575  WINPR_ASSERT(buffer);
576 
577  message = &context->NEGOTIATE_MESSAGE;
578  WINPR_ASSERT(message);
579 
580  *message = empty;
581 
582  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
583 
584  if (!s)
585  return SEC_E_INTERNAL_ERROR;
586 
587  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE))
588  return SEC_E_INTERNAL_ERROR;
589 
590  if (context->NTLMv2)
591  {
592  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
593  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
594  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
595  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
596  }
597 
598  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
599  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
600  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
601  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
602  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
603  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
604  message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
605  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
606 
607  if (context->confidentiality)
608  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
609 
610  if (context->SendVersionInfo)
611  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
612 
613  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
614  ntlm_get_version_info(&(message->Version));
615 
616  context->NegotiateFlags = message->NegotiateFlags;
617  /* Message Header (12 bytes) */
618  if (!ntlm_write_message_header(s, &message->header))
619  return SEC_E_INTERNAL_ERROR;
620 
621  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_NEGOTIATE_MESSAGE"))
622  return SEC_E_INTERNAL_ERROR;
623 
624  /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
625  /* DomainNameFields (8 bytes) */
626  if (!ntlm_write_message_fields(s, &(message->DomainName)))
627  return SEC_E_INTERNAL_ERROR;
628 
629  /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
630  /* WorkstationFields (8 bytes) */
631  if (!ntlm_write_message_fields(s, &(message->Workstation)))
632  return SEC_E_INTERNAL_ERROR;
633 
634  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
635  {
636  if (!ntlm_write_version_info(s, &(message->Version)))
637  return SEC_E_INTERNAL_ERROR;
638  }
639 
640  length = Stream_GetPosition(s);
641  WINPR_ASSERT(length <= UINT32_MAX);
642  buffer->cbBuffer = (ULONG)length;
643 
644  if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length))
645  return SEC_E_INTERNAL_ERROR;
646 
647  CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
648  context->NegotiateMessage.BufferType = buffer->BufferType;
649 #if defined(WITH_DEBUG_NTLM)
650  ntlm_print_negotiate_message(&context->NegotiateMessage, message);
651 #endif
652  ntlm_change_state(context, NTLM_STATE_CHALLENGE);
653  return SEC_I_CONTINUE_NEEDED;
654 }
655 
656 SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
657 {
658  SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
659  wStream sbuffer;
660  wStream* s = NULL;
661  size_t length = 0;
662  size_t StartOffset = 0;
663  size_t PayloadOffset = 0;
664  NTLM_AV_PAIR* AvTimestamp = NULL;
665  const NTLM_CHALLENGE_MESSAGE empty = { 0 };
666  NTLM_CHALLENGE_MESSAGE* message = NULL;
667 
668  if (!context || !buffer)
669  return SEC_E_INTERNAL_ERROR;
670 
671  ntlm_generate_client_challenge(context);
672  message = &context->CHALLENGE_MESSAGE;
673  WINPR_ASSERT(message);
674 
675  *message = empty;
676 
677  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
678 
679  if (!s)
680  return SEC_E_INTERNAL_ERROR;
681 
682  StartOffset = Stream_GetPosition(s);
683 
684  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE))
685  goto fail;
686 
687  if (!ntlm_read_message_fields(s, &(message->TargetName))) /* TargetNameFields (8 bytes) */
688  goto fail;
689 
690  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE"))
691  goto fail;
692 
693  context->NegotiateFlags = message->NegotiateFlags;
694 
695  if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
696  goto fail;
697 
698  Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
699  CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);
700  Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */
701 
702  if (!ntlm_read_message_fields(s, &(message->TargetInfo))) /* TargetInfoFields (8 bytes) */
703  goto fail;
704 
705  if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
706  {
707  if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
708  goto fail;
709  }
710 
711  /* Payload (variable) */
712  PayloadOffset = Stream_GetPosition(s);
713 
714  status = SEC_E_INTERNAL_ERROR;
715  if (message->TargetName.Len > 0)
716  {
717  if (!ntlm_read_message_fields_buffer(s, &(message->TargetName)))
718  goto fail;
719  }
720 
721  if (message->TargetInfo.Len > 0)
722  {
723  size_t cbAvTimestamp = 0;
724 
725  if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo)))
726  goto fail;
727 
728  context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;
729  context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
730  AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*)message->TargetInfo.Buffer,
731  message->TargetInfo.Len, MsvAvTimestamp, &cbAvTimestamp);
732 
733  if (AvTimestamp)
734  {
735  PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp);
736 
737  if (!ptr)
738  goto fail;
739 
740  if (context->NTLMv2)
741  context->UseMIC = TRUE;
742 
743  CopyMemory(context->ChallengeTimestamp, ptr, 8);
744  }
745  }
746 
747  length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
748  if (length > buffer->cbBuffer)
749  goto fail;
750 
751  if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length))
752  goto fail;
753 
754  if (context->ChallengeMessage.pvBuffer)
755  CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length);
756 #if defined(WITH_DEBUG_NTLM)
757  ntlm_print_challenge_message(&context->ChallengeMessage, message, NULL);
758 #endif
759  /* AV_PAIRs */
760 
761  if (context->NTLMv2)
762  {
763  if (!ntlm_construct_authenticate_target_info(context))
764  goto fail;
765 
766  sspi_SecBufferFree(&context->ChallengeTargetInfo);
767  context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
768  context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
769  }
770 
771  ntlm_generate_timestamp(context); /* Timestamp */
772 
773  const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
774  if (rc != SEC_E_OK)
775  {
776  status = rc;
777  goto fail;
778  }
779 
780  const SECURITY_STATUS rc2 = ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
781  if (rc2 != SEC_E_OK)
782  {
783  status = rc2;
784  goto fail;
785  }
786 
787  ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */
788  ntlm_generate_random_session_key(context); /* RandomSessionKey */
789  ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
790  ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */
791 
792  /* Generate signing keys */
793  status = SEC_E_ENCRYPT_FAILURE;
794  if (!ntlm_generate_client_signing_key(context))
795  goto fail;
796  if (!ntlm_generate_server_signing_key(context))
797  goto fail;
798  /* Generate sealing keys */
799  if (!ntlm_generate_client_sealing_key(context))
800  goto fail;
801  if (!ntlm_generate_server_sealing_key(context))
802  goto fail;
803  /* Initialize RC4 seal state using client sealing key */
804  if (!ntlm_init_rc4_seal_states(context))
805  goto fail;
806 #if defined(WITH_DEBUG_NTLM)
807  ntlm_print_authentication_complete(context);
808 #endif
809  ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
810  status = SEC_I_CONTINUE_NEEDED;
811 fail:
812  ntlm_free_message_fields_buffer(&(message->TargetName));
813  return status;
814 }
815 
816 SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, const PSecBuffer buffer)
817 {
818  wStream sbuffer;
819  wStream* s = NULL;
820  size_t length = 0;
821  UINT32 PayloadOffset = 0;
822  const NTLM_CHALLENGE_MESSAGE empty = { 0 };
823  NTLM_CHALLENGE_MESSAGE* message = NULL;
824 
825  WINPR_ASSERT(context);
826  WINPR_ASSERT(buffer);
827 
828  message = &context->CHALLENGE_MESSAGE;
829  WINPR_ASSERT(message);
830 
831  *message = empty;
832 
833  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
834 
835  if (!s)
836  return SEC_E_INTERNAL_ERROR;
837 
838  ntlm_get_version_info(&(message->Version)); /* Version */
839  ntlm_generate_server_challenge(context); /* Server Challenge */
840  ntlm_generate_timestamp(context); /* Timestamp */
841 
842  if (!ntlm_construct_challenge_target_info(context)) /* TargetInfo */
843  return SEC_E_INTERNAL_ERROR;
844 
845  CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */
846  message->NegotiateFlags = context->NegotiateFlags;
847  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE))
848  return SEC_E_INTERNAL_ERROR;
849 
850  /* Message Header (12 bytes) */
851  if (!ntlm_write_message_header(s, &message->header))
852  return SEC_E_INTERNAL_ERROR;
853 
854  if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
855  {
856  message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
857  message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
858  }
859 
860  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
861 
862  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
863  {
864  message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
865  message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
866  }
867 
868  PayloadOffset = 48;
869 
870  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
871  PayloadOffset += 8;
872 
873  message->TargetName.BufferOffset = PayloadOffset;
874  message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len;
875  /* TargetNameFields (8 bytes) */
876  if (!ntlm_write_message_fields(s, &(message->TargetName)))
877  return SEC_E_INTERNAL_ERROR;
878 
879  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE"))
880  return SEC_E_INTERNAL_ERROR;
881 
882  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 16, "NTLM_CHALLENGE_MESSAGE::ServerChallenge"))
883  return SEC_E_INTERNAL_ERROR;
884 
885  Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
886  Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */
887 
888  /* TargetInfoFields (8 bytes) */
889  if (!ntlm_write_message_fields(s, &(message->TargetInfo)))
890  return SEC_E_INTERNAL_ERROR;
891 
892  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
893  {
894  if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */
895  return SEC_E_INTERNAL_ERROR;
896  }
897 
898  /* Payload (variable) */
899  if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
900  {
901  if (!ntlm_write_message_fields_buffer(s, &(message->TargetName)))
902  return SEC_E_INTERNAL_ERROR;
903  }
904 
905  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
906  {
907  if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo)))
908  return SEC_E_INTERNAL_ERROR;
909  }
910 
911  length = Stream_GetPosition(s);
912  WINPR_ASSERT(length <= UINT32_MAX);
913  buffer->cbBuffer = (ULONG)length;
914 
915  if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length))
916  return SEC_E_INTERNAL_ERROR;
917 
918  CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
919 #if defined(WITH_DEBUG_NTLM)
920  ntlm_print_challenge_message(&context->ChallengeMessage, message,
921  &context->ChallengeTargetInfo);
922 #endif
923  ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
924  return SEC_I_CONTINUE_NEEDED;
925 }
926 
927 SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
928 {
929  SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
930  wStream sbuffer;
931  wStream* s = NULL;
932  size_t length = 0;
933  UINT32 flags = 0;
934  NTLM_AV_PAIR* AvFlags = NULL;
935  size_t PayloadBufferOffset = 0;
936  const NTLM_AUTHENTICATE_MESSAGE empty = { 0 };
937  NTLM_AUTHENTICATE_MESSAGE* message = NULL;
938  SSPI_CREDENTIALS* credentials = NULL;
939 
940  WINPR_ASSERT(context);
941  WINPR_ASSERT(buffer);
942 
943  credentials = context->credentials;
944  WINPR_ASSERT(credentials);
945 
946  message = &context->AUTHENTICATE_MESSAGE;
947  WINPR_ASSERT(message);
948 
949  *message = empty;
950 
951  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
952 
953  if (!s)
954  return SEC_E_INTERNAL_ERROR;
955 
956  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE))
957  goto fail;
958 
959  if (!ntlm_read_message_fields(
960  s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */
961  goto fail;
962 
963  if (!ntlm_read_message_fields(
964  s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */
965  goto fail;
966 
967  if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
968  goto fail;
969 
970  if (!ntlm_read_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */
971  goto fail;
972 
973  if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
974  goto fail;
975 
976  if (!ntlm_read_message_fields(
977  s,
978  &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */
979  goto fail;
980 
981  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_AUTHENTICATE_MESSAGE"))
982  goto fail;
983 
984  context->NegotiateKeyExchange =
985  (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE;
986 
987  if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
988  (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
989  goto fail;
990 
991  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
992  {
993  if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
994  goto fail;
995  }
996 
997  PayloadBufferOffset = Stream_GetPosition(s);
998 
999  status = SEC_E_INTERNAL_ERROR;
1000  if (!ntlm_read_message_fields_buffer(s, &(message->DomainName))) /* DomainName */
1001  goto fail;
1002 
1003  if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */
1004  goto fail;
1005 
1006  if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
1007  goto fail;
1008 
1009  if (!ntlm_read_message_fields_buffer(s,
1010  &(message->LmChallengeResponse))) /* LmChallengeResponse */
1011  goto fail;
1012 
1013  if (!ntlm_read_message_fields_buffer(s,
1014  &(message->NtChallengeResponse))) /* NtChallengeResponse */
1015  goto fail;
1016 
1017  if (message->NtChallengeResponse.Len > 0)
1018  {
1019  size_t cbAvFlags = 0;
1020  wStream ssbuffer;
1021  wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer,
1022  message->NtChallengeResponse.Len);
1023 
1024  if (!snt)
1025  goto fail;
1026 
1027  status = SEC_E_INVALID_TOKEN;
1028  if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)))
1029  goto fail;
1030  status = SEC_E_INTERNAL_ERROR;
1031 
1032  context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
1033  context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
1034  sspi_SecBufferFree(&(context->ChallengeTargetInfo));
1035  context->ChallengeTargetInfo.pvBuffer = (void*)context->NTLMv2Response.Challenge.AvPairs;
1036  context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16);
1037  CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
1038  AvFlags =
1039  ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
1040  context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);
1041 
1042  if (AvFlags)
1043  Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags);
1044  }
1045 
1046  if (!ntlm_read_message_fields_buffer(
1047  s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */
1048  goto fail;
1049 
1050  if (message->EncryptedRandomSessionKey.Len > 0)
1051  {
1052  if (message->EncryptedRandomSessionKey.Len != 16)
1053  goto fail;
1054 
1055  CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
1056  16);
1057  }
1058 
1059  length = Stream_GetPosition(s);
1060  WINPR_ASSERT(length <= UINT32_MAX);
1061 
1062  if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length))
1063  goto fail;
1064 
1065  CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1066  buffer->cbBuffer = (ULONG)length;
1067  Stream_SetPosition(s, PayloadBufferOffset);
1068 
1069  if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1070  {
1071  status = SEC_E_INVALID_TOKEN;
1072  if (!ntlm_read_message_integrity_check(
1073  s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1074  sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE"))
1075  goto fail;
1076  }
1077 
1078  status = SEC_E_INTERNAL_ERROR;
1079 
1080 #if defined(WITH_DEBUG_NTLM)
1081  ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags, NULL);
1082 #endif
1083 
1084  if (message->UserName.Len > 0)
1085  {
1086  credentials->identity.User = (UINT16*)malloc(message->UserName.Len);
1087 
1088  if (!credentials->identity.User)
1089  goto fail;
1090 
1091  CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
1092  credentials->identity.UserLength = message->UserName.Len / 2;
1093  }
1094 
1095  if (message->DomainName.Len > 0)
1096  {
1097  credentials->identity.Domain = (UINT16*)malloc(message->DomainName.Len);
1098 
1099  if (!credentials->identity.Domain)
1100  goto fail;
1101 
1102  CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
1103  message->DomainName.Len);
1104  credentials->identity.DomainLength = message->DomainName.Len / 2;
1105  }
1106 
1107  if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1108  {
1109  const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
1110  if (rc != SEC_E_OK)
1111  return rc;
1112  }
1113 
1114  const SECURITY_STATUS rc = ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
1115  if (rc != SEC_E_OK)
1116  return rc;
1117 
1118  /* KeyExchangeKey */
1119  ntlm_generate_key_exchange_key(context);
1120  /* EncryptedRandomSessionKey */
1121  ntlm_decrypt_random_session_key(context);
1122  /* ExportedSessionKey */
1123  ntlm_generate_exported_session_key(context);
1124 
1125  if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1126  {
1127  BYTE messageIntegrityCheck[16] = { 0 };
1128 
1129  ntlm_compute_message_integrity_check(context, messageIntegrityCheck,
1130  sizeof(messageIntegrityCheck));
1131  CopyMemory(
1132  &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
1133  message->MessageIntegrityCheck, sizeof(message->MessageIntegrityCheck));
1134 
1135  if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck,
1136  sizeof(message->MessageIntegrityCheck)) != 0)
1137  {
1138  WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!");
1139 #ifdef WITH_DEBUG_NTLM
1140  WLog_ERR(TAG, "Expected MIC:");
1141  winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck, sizeof(messageIntegrityCheck));
1142  WLog_ERR(TAG, "Actual MIC:");
1143  winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
1144  sizeof(message->MessageIntegrityCheck));
1145 #endif
1146  return SEC_E_MESSAGE_ALTERED;
1147  }
1148  }
1149  else
1150  {
1151  /* no mic message was present
1152 
1153  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
1154  the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
1155  Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.
1156 
1157  now check the NtProofString, to detect if the entered client password matches the
1158  expected password.
1159  */
1160 
1161 #ifdef WITH_DEBUG_NTLM
1162  WLog_VRB(TAG, "No MIC present, using NtProofString for verification.");
1163 #endif
1164 
1165  if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
1166  {
1167  WLog_ERR(TAG, "NtProofString verification failed!");
1168 #ifdef WITH_DEBUG_NTLM
1169  WLog_ERR(TAG, "Expected NtProofString:");
1170  winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, sizeof(context->NtProofString));
1171  WLog_ERR(TAG, "Actual NtProofString:");
1172  winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
1173  sizeof(context->NTLMv2Response));
1174 #endif
1175  return SEC_E_LOGON_DENIED;
1176  }
1177  }
1178 
1179  /* Generate signing keys */
1180  if (!ntlm_generate_client_signing_key(context))
1181  return SEC_E_INTERNAL_ERROR;
1182  if (!ntlm_generate_server_signing_key(context))
1183  return SEC_E_INTERNAL_ERROR;
1184  /* Generate sealing keys */
1185  if (!ntlm_generate_client_sealing_key(context))
1186  return SEC_E_INTERNAL_ERROR;
1187  if (!ntlm_generate_server_sealing_key(context))
1188  return SEC_E_INTERNAL_ERROR;
1189  /* Initialize RC4 seal state */
1190  if (!ntlm_init_rc4_seal_states(context))
1191  return SEC_E_INTERNAL_ERROR;
1192 #if defined(WITH_DEBUG_NTLM)
1193  ntlm_print_authentication_complete(context);
1194 #endif
1195  ntlm_change_state(context, NTLM_STATE_FINAL);
1196  ntlm_free_message_fields_buffer(&(message->DomainName));
1197  ntlm_free_message_fields_buffer(&(message->UserName));
1198  ntlm_free_message_fields_buffer(&(message->Workstation));
1199  ntlm_free_message_fields_buffer(&(message->LmChallengeResponse));
1200  ntlm_free_message_fields_buffer(&(message->NtChallengeResponse));
1201  ntlm_free_message_fields_buffer(&(message->EncryptedRandomSessionKey));
1202  return SEC_E_OK;
1203 
1204 fail:
1205  return status;
1206 }
1207 
1215 SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer)
1216 {
1217  wStream sbuffer;
1218  wStream* s = NULL;
1219  size_t length = 0;
1220  UINT32 PayloadBufferOffset = 0;
1221  const NTLM_AUTHENTICATE_MESSAGE empty = { 0 };
1222  NTLM_AUTHENTICATE_MESSAGE* message = NULL;
1223  SSPI_CREDENTIALS* credentials = NULL;
1224 
1225  WINPR_ASSERT(context);
1226  WINPR_ASSERT(buffer);
1227 
1228  credentials = context->credentials;
1229  WINPR_ASSERT(credentials);
1230 
1231  message = &context->AUTHENTICATE_MESSAGE;
1232  WINPR_ASSERT(message);
1233 
1234  *message = empty;
1235 
1236  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
1237 
1238  if (!s)
1239  return SEC_E_INTERNAL_ERROR;
1240 
1241  if (context->NTLMv2)
1242  {
1243  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
1244 
1245  if (context->SendVersionInfo)
1246  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
1247  }
1248 
1249  if (context->UseMIC)
1250  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
1251 
1252  if (context->SendWorkstationName)
1253  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
1254 
1255  if (context->confidentiality)
1256  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
1257 
1258  if (context->CHALLENGE_MESSAGE.NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1259  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
1260 
1261  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
1262  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
1263  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
1264  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
1265  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1266  message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
1267  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
1268 
1269  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1270  ntlm_get_version_info(&(message->Version));
1271 
1272  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1273  {
1274  message->Workstation.Len = context->Workstation.Length;
1275  message->Workstation.Buffer = (BYTE*)context->Workstation.Buffer;
1276  }
1277 
1278  if (credentials->identity.DomainLength > 0)
1279  {
1280  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
1281  message->DomainName.Len = (UINT16)credentials->identity.DomainLength * 2;
1282  message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
1283  }
1284 
1285  message->UserName.Len = (UINT16)credentials->identity.UserLength * 2;
1286  message->UserName.Buffer = (BYTE*)credentials->identity.User;
1287  message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
1288  message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
1289  message->NtChallengeResponse.Len = (UINT16)context->NtChallengeResponse.cbBuffer;
1290  message->NtChallengeResponse.Buffer = (BYTE*)context->NtChallengeResponse.pvBuffer;
1291 
1292  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1293  {
1294  message->EncryptedRandomSessionKey.Len = 16;
1295  message->EncryptedRandomSessionKey.Buffer = context->EncryptedRandomSessionKey;
1296  }
1297 
1298  PayloadBufferOffset = 64;
1299 
1300  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1301  PayloadBufferOffset += 8; /* Version (8 bytes) */
1302 
1303  if (context->UseMIC)
1304  PayloadBufferOffset += 16; /* Message Integrity Check (16 bytes) */
1305 
1306  message->DomainName.BufferOffset = PayloadBufferOffset;
1307  message->UserName.BufferOffset = message->DomainName.BufferOffset + message->DomainName.Len;
1308  message->Workstation.BufferOffset = message->UserName.BufferOffset + message->UserName.Len;
1309  message->LmChallengeResponse.BufferOffset =
1310  message->Workstation.BufferOffset + message->Workstation.Len;
1311  message->NtChallengeResponse.BufferOffset =
1312  message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len;
1313  message->EncryptedRandomSessionKey.BufferOffset =
1314  message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len;
1315  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE))
1316  return SEC_E_INVALID_TOKEN;
1317  if (!ntlm_write_message_header(s, &message->header)) /* Message Header (12 bytes) */
1318  return SEC_E_INTERNAL_ERROR;
1319  if (!ntlm_write_message_fields(
1320  s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */
1321  return SEC_E_INTERNAL_ERROR;
1322  if (!ntlm_write_message_fields(
1323  s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */
1324  return SEC_E_INTERNAL_ERROR;
1325  if (!ntlm_write_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
1326  return SEC_E_INTERNAL_ERROR;
1327  if (!ntlm_write_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */
1328  return SEC_E_INTERNAL_ERROR;
1329  if (!ntlm_write_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
1330  return SEC_E_INTERNAL_ERROR;
1331  if (!ntlm_write_message_fields(
1332  s,
1333  &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */
1334  return SEC_E_INTERNAL_ERROR;
1335  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_AUTHENTICATE_MESSAGE"))
1336  return SEC_E_INTERNAL_ERROR;
1337 
1338  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1339  {
1340  if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */
1341  return SEC_E_INTERNAL_ERROR;
1342  }
1343 
1344  if (context->UseMIC)
1345  {
1346  const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 };
1347 
1348  context->MessageIntegrityCheckOffset = Stream_GetPosition(s);
1349  if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data, sizeof(data),
1350  "NTLM_AUTHENTICATE_MESSAGE"))
1351  return SEC_E_INTERNAL_ERROR;
1352  }
1353 
1354  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
1355  {
1356  if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */
1357  return SEC_E_INTERNAL_ERROR;
1358  }
1359 
1360  if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */
1361  return SEC_E_INTERNAL_ERROR;
1362 
1363  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1364  {
1365  if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
1366  return SEC_E_INTERNAL_ERROR;
1367  }
1368 
1369  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1370  {
1371  if (!ntlm_write_message_fields_buffer(
1372  s, &(message->LmChallengeResponse))) /* LmChallengeResponse */
1373  return SEC_E_INTERNAL_ERROR;
1374  }
1375  if (!ntlm_write_message_fields_buffer(
1376  s, &(message->NtChallengeResponse))) /* NtChallengeResponse */
1377  return SEC_E_INTERNAL_ERROR;
1378 
1379  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1380  {
1381  if (!ntlm_write_message_fields_buffer(
1382  s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */
1383  return SEC_E_INTERNAL_ERROR;
1384  }
1385 
1386  length = Stream_GetPosition(s);
1387  WINPR_ASSERT(length <= UINT32_MAX);
1388 
1389  if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length))
1390  return SEC_E_INTERNAL_ERROR;
1391 
1392  CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1393  buffer->cbBuffer = (ULONG)length;
1394 
1395  if (context->UseMIC)
1396  {
1397  /* Message Integrity Check */
1398  ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck,
1399  sizeof(message->MessageIntegrityCheck));
1400  if (!ntlm_write_message_integrity_check(
1401  s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1402  sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE"))
1403  return SEC_E_INTERNAL_ERROR;
1404  }
1405 
1406 #if defined(WITH_DEBUG_NTLM)
1407  ntlm_print_authenticate_message(&context->AuthenticateMessage, message,
1408  context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0,
1409  &context->AuthenticateTargetInfo);
1410 #endif
1411  ntlm_change_state(context, NTLM_STATE_FINAL);
1412  return SEC_E_OK;
1413 }