Coverage Report

Created: 2026-03-04 06:17

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