Coverage Report

Created: 2026-01-09 06:49

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] = { 0 };
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
    Stream_SetPosition(s, fields->BufferOffset);
371
0
    Stream_Read(s, fields->Buffer, fields->Len);
372
0
  }
373
374
0
  return TRUE;
375
0
}
376
377
static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIELDS* fields)
378
0
{
379
0
  WINPR_ASSERT(s);
380
0
  WINPR_ASSERT(fields);
381
382
0
  if (fields->Len > 0)
383
0
  {
384
0
    Stream_SetPosition(s, fields->BufferOffset);
385
0
    if (!NTLM_CheckAndLogRequiredCapacity(TAG, (s), fields->Len, "NTLM_MESSAGE_FIELDS::Len"))
386
0
      return FALSE;
387
388
0
    Stream_Write(s, fields->Buffer, fields->Len);
389
0
  }
390
0
  return TRUE;
391
0
}
392
393
void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
394
0
{
395
0
  if (fields)
396
0
  {
397
0
    if (fields->Buffer)
398
0
    {
399
0
      free(fields->Buffer);
400
0
      fields->Len = 0;
401
0
      fields->MaxLen = 0;
402
0
      fields->Buffer = NULL;
403
0
      fields->BufferOffset = 0;
404
0
    }
405
0
  }
406
0
}
407
408
static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name)
409
0
{
410
0
  UINT32 NegotiateFlags = 0;
411
0
  char buffer[1024] = { 0 };
412
0
  WINPR_ASSERT(s);
413
0
  WINPR_ASSERT(flags);
414
0
  WINPR_ASSERT(name);
415
416
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
417
0
    return FALSE;
418
419
0
  Stream_Read_UINT32(s, NegotiateFlags); /* NegotiateFlags (4 bytes) */
420
421
0
  if ((NegotiateFlags & required) != required)
422
0
  {
423
0
    WLog_ERR(TAG, "%s::NegotiateFlags invalid flags 0x08%" PRIx32 ", 0x%08" PRIx32 " required",
424
0
             name, NegotiateFlags, required);
425
0
    return FALSE;
426
0
  }
427
428
0
  WLog_DBG(TAG, "Read flags %s",
429
0
           ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags));
430
0
  *flags = NegotiateFlags;
431
0
  return TRUE;
432
0
}
433
434
static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name)
435
0
{
436
0
  char buffer[1024] = { 0 };
437
0
  WINPR_ASSERT(s);
438
0
  WINPR_ASSERT(name);
439
440
0
  if (!Stream_CheckAndLogRequiredCapacityEx(TAG, WLOG_WARN, s, 4ull, 1ull,
441
0
                                            "%s(%s:%" PRIuz ") %s::NegotiateFlags", __func__,
442
0
                                            __FILE__, (size_t)__LINE__, name))
443
0
    return FALSE;
444
445
0
  WLog_DBG(TAG, "Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags));
446
0
  Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */
447
0
  return TRUE;
448
0
}
449
450
static BOOL ntlm_read_message_integrity_check(wStream* s, size_t* offset, BYTE* data, size_t size,
451
                                              WINPR_ATTR_UNUSED const char* name)
452
0
{
453
0
  WINPR_ASSERT(s);
454
0
  WINPR_ASSERT(offset);
455
0
  WINPR_ASSERT(data);
456
0
  WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
457
0
  WINPR_ASSERT(name);
458
459
0
  *offset = Stream_GetPosition(s);
460
461
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
462
0
    return FALSE;
463
464
0
  Stream_Read(s, data, size);
465
0
  return TRUE;
466
0
}
467
468
static BOOL ntlm_write_message_integrity_check(wStream* s, size_t offset, const BYTE* data,
469
                                               size_t size, WINPR_ATTR_UNUSED const char* name)
470
0
{
471
0
  size_t pos = 0;
472
473
0
  WINPR_ASSERT(s);
474
0
  WINPR_ASSERT(data);
475
0
  WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH);
476
0
  WINPR_ASSERT(name);
477
478
0
  pos = Stream_GetPosition(s);
479
480
0
  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, offset, "MessageIntegrityCheck::offset"))
481
0
    return FALSE;
482
483
0
  Stream_SetPosition(s, offset);
484
0
  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, size, "MessageIntegrityCheck::size"))
485
0
    return FALSE;
486
487
0
  Stream_Write(s, data, size);
488
0
  Stream_SetPosition(s, pos);
489
0
  return TRUE;
490
0
}
491
492
SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
493
0
{
494
0
  wStream sbuffer;
495
0
  wStream* s = NULL;
496
0
  size_t length = 0;
497
0
  const NTLM_NEGOTIATE_MESSAGE empty = { 0 };
498
0
  NTLM_NEGOTIATE_MESSAGE* message = NULL;
499
500
0
  WINPR_ASSERT(context);
501
0
  WINPR_ASSERT(buffer);
502
503
0
  message = &context->NEGOTIATE_MESSAGE;
504
0
  WINPR_ASSERT(message);
505
506
0
  *message = empty;
507
508
0
  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
509
510
0
  if (!s)
511
0
    return SEC_E_INTERNAL_ERROR;
512
513
0
  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE))
514
0
    return SEC_E_INVALID_TOKEN;
515
516
0
  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags,
517
0
                                 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
518
0
                                     NTLMSSP_NEGOTIATE_UNICODE,
519
0
                                 "NTLM_NEGOTIATE_MESSAGE"))
520
0
    return SEC_E_INVALID_TOKEN;
521
522
0
  context->NegotiateFlags = message->NegotiateFlags;
523
524
  /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
525
  // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
526
0
  {
527
0
    if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
528
0
      return SEC_E_INVALID_TOKEN;
529
0
  }
530
531
  /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
532
  // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
533
0
  {
534
0
    if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
535
0
      return SEC_E_INVALID_TOKEN;
536
0
  }
537
538
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
539
0
  {
540
0
    if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
541
0
      return SEC_E_INVALID_TOKEN;
542
0
  }
543
544
0
  if (!ntlm_read_message_fields_buffer(s, &message->DomainName))
545
0
    return SEC_E_INVALID_TOKEN;
546
547
0
  if (!ntlm_read_message_fields_buffer(s, &message->Workstation))
548
0
    return SEC_E_INVALID_TOKEN;
549
550
0
  length = Stream_GetPosition(s);
551
0
  WINPR_ASSERT(length <= UINT32_MAX);
552
0
  buffer->cbBuffer = (ULONG)length;
553
554
0
  if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length))
555
0
    return SEC_E_INTERNAL_ERROR;
556
557
0
  CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
558
0
  context->NegotiateMessage.BufferType = buffer->BufferType;
559
#if defined(WITH_DEBUG_NTLM)
560
  ntlm_print_negotiate_message(&context->NegotiateMessage, message);
561
#endif
562
0
  ntlm_change_state(context, NTLM_STATE_CHALLENGE);
563
0
  return SEC_I_CONTINUE_NEEDED;
564
0
}
565
566
SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SecBuffer* buffer)
567
0
{
568
0
  wStream sbuffer;
569
0
  wStream* s = NULL;
570
0
  size_t length = 0;
571
0
  const NTLM_NEGOTIATE_MESSAGE empty = { 0 };
572
0
  NTLM_NEGOTIATE_MESSAGE* message = NULL;
573
574
0
  WINPR_ASSERT(context);
575
0
  WINPR_ASSERT(buffer);
576
577
0
  message = &context->NEGOTIATE_MESSAGE;
578
0
  WINPR_ASSERT(message);
579
580
0
  *message = empty;
581
582
0
  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
583
584
0
  if (!s)
585
0
    return SEC_E_INTERNAL_ERROR;
586
587
0
  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE))
588
0
    return SEC_E_INTERNAL_ERROR;
589
590
0
  if (context->NTLMv2)
591
0
  {
592
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
593
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
594
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY;
595
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_OEM;
596
0
  }
597
598
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
599
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
600
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
601
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
602
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
603
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
604
0
  message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
605
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
606
607
0
  if (context->confidentiality)
608
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
609
610
0
  if (context->SendVersionInfo)
611
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
612
613
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
614
0
    ntlm_get_version_info(&(message->Version));
615
616
0
  context->NegotiateFlags = message->NegotiateFlags;
617
  /* Message Header (12 bytes) */
618
0
  if (!ntlm_write_message_header(s, &message->header))
619
0
    return SEC_E_INTERNAL_ERROR;
620
621
0
  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_NEGOTIATE_MESSAGE"))
622
0
    return SEC_E_INTERNAL_ERROR;
623
624
  /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */
625
  /* DomainNameFields (8 bytes) */
626
0
  if (!ntlm_write_message_fields(s, &(message->DomainName)))
627
0
    return SEC_E_INTERNAL_ERROR;
628
629
  /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */
630
  /* WorkstationFields (8 bytes) */
631
0
  if (!ntlm_write_message_fields(s, &(message->Workstation)))
632
0
    return SEC_E_INTERNAL_ERROR;
633
634
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
635
0
  {
636
0
    if (!ntlm_write_version_info(s, &(message->Version)))
637
0
      return SEC_E_INTERNAL_ERROR;
638
0
  }
639
640
0
  length = Stream_GetPosition(s);
641
0
  WINPR_ASSERT(length <= UINT32_MAX);
642
0
  buffer->cbBuffer = (ULONG)length;
643
644
0
  if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length))
645
0
    return SEC_E_INTERNAL_ERROR;
646
647
0
  CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer);
648
0
  context->NegotiateMessage.BufferType = buffer->BufferType;
649
#if defined(WITH_DEBUG_NTLM)
650
  ntlm_print_negotiate_message(&context->NegotiateMessage, message);
651
#endif
652
0
  ntlm_change_state(context, NTLM_STATE_CHALLENGE);
653
0
  return SEC_I_CONTINUE_NEEDED;
654
0
}
655
656
SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
657
0
{
658
0
  SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
659
0
  wStream sbuffer;
660
0
  wStream* s = NULL;
661
0
  size_t length = 0;
662
0
  size_t StartOffset = 0;
663
0
  size_t PayloadOffset = 0;
664
0
  NTLM_AV_PAIR* AvTimestamp = NULL;
665
0
  const NTLM_CHALLENGE_MESSAGE empty = { 0 };
666
0
  NTLM_CHALLENGE_MESSAGE* message = NULL;
667
668
0
  if (!context || !buffer)
669
0
    return SEC_E_INTERNAL_ERROR;
670
671
0
  ntlm_generate_client_challenge(context);
672
0
  message = &context->CHALLENGE_MESSAGE;
673
0
  WINPR_ASSERT(message);
674
675
0
  *message = empty;
676
677
0
  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
678
679
0
  if (!s)
680
0
    return SEC_E_INTERNAL_ERROR;
681
682
0
  StartOffset = Stream_GetPosition(s);
683
684
0
  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE))
685
0
    goto fail;
686
687
0
  if (!ntlm_read_message_fields(s, &(message->TargetName))) /* TargetNameFields (8 bytes) */
688
0
    goto fail;
689
690
0
  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE"))
691
0
    goto fail;
692
693
0
  context->NegotiateFlags = message->NegotiateFlags;
694
695
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
696
0
    goto fail;
697
698
0
  Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
699
0
  CopyMemory(context->ServerChallenge, message->ServerChallenge, 8);
700
0
  Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */
701
702
0
  if (!ntlm_read_message_fields(s, &(message->TargetInfo))) /* TargetInfoFields (8 bytes) */
703
0
    goto fail;
704
705
0
  if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
706
0
  {
707
0
    if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
708
0
      goto fail;
709
0
  }
710
711
  /* Payload (variable) */
712
0
  PayloadOffset = Stream_GetPosition(s);
713
714
0
  status = SEC_E_INTERNAL_ERROR;
715
0
  if (message->TargetName.Len > 0)
716
0
  {
717
0
    if (!ntlm_read_message_fields_buffer(s, &(message->TargetName)))
718
0
      goto fail;
719
0
  }
720
721
0
  if (message->TargetInfo.Len > 0)
722
0
  {
723
0
    size_t cbAvTimestamp = 0;
724
725
0
    if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo)))
726
0
      goto fail;
727
728
0
    context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer;
729
0
    context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
730
0
    AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*)message->TargetInfo.Buffer,
731
0
                                   message->TargetInfo.Len, MsvAvTimestamp, &cbAvTimestamp);
732
733
0
    if (AvTimestamp)
734
0
    {
735
0
      PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp);
736
737
0
      if (!ptr)
738
0
        goto fail;
739
740
0
      if (context->NTLMv2)
741
0
        context->UseMIC = TRUE;
742
743
0
      CopyMemory(context->ChallengeTimestamp, ptr, 8);
744
0
    }
745
0
  }
746
747
0
  length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
748
0
  if (length > buffer->cbBuffer)
749
0
    goto fail;
750
751
0
  if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length))
752
0
    goto fail;
753
754
0
  if (context->ChallengeMessage.pvBuffer)
755
0
    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
0
  if (context->NTLMv2)
762
0
  {
763
0
    if (!ntlm_construct_authenticate_target_info(context))
764
0
      goto fail;
765
766
0
    sspi_SecBufferFree(&context->ChallengeTargetInfo);
767
0
    context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
768
0
    context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
769
0
  }
770
771
0
  ntlm_generate_timestamp(context); /* Timestamp */
772
773
0
  {
774
0
    const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
775
0
    if (rc != SEC_E_OK)
776
0
    {
777
0
      status = rc;
778
0
      goto fail;
779
0
    }
780
0
  }
781
782
0
  {
783
0
    const SECURITY_STATUS rc2 =
784
0
        ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
785
0
    if (rc2 != SEC_E_OK)
786
0
    {
787
0
      status = rc2;
788
0
      goto fail;
789
0
    }
790
0
  }
791
792
0
  ntlm_generate_key_exchange_key(context);     /* KeyExchangeKey */
793
0
  ntlm_generate_random_session_key(context);   /* RandomSessionKey */
794
0
  ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
795
0
  ntlm_encrypt_random_session_key(context);    /* EncryptedRandomSessionKey */
796
797
  /* Generate signing keys */
798
0
  status = SEC_E_ENCRYPT_FAILURE;
799
0
  if (!ntlm_generate_client_signing_key(context))
800
0
    goto fail;
801
0
  if (!ntlm_generate_server_signing_key(context))
802
0
    goto fail;
803
  /* Generate sealing keys */
804
0
  if (!ntlm_generate_client_sealing_key(context))
805
0
    goto fail;
806
0
  if (!ntlm_generate_server_sealing_key(context))
807
0
    goto fail;
808
  /* Initialize RC4 seal state using client sealing key */
809
0
  if (!ntlm_init_rc4_seal_states(context))
810
0
    goto fail;
811
#if defined(WITH_DEBUG_NTLM)
812
  ntlm_print_authentication_complete(context);
813
#endif
814
0
  ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
815
0
  status = SEC_I_CONTINUE_NEEDED;
816
0
fail:
817
0
  ntlm_free_message_fields_buffer(&(message->TargetName));
818
0
  return status;
819
0
}
820
821
SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, SecBuffer* buffer)
822
0
{
823
0
  wStream sbuffer;
824
0
  wStream* s = NULL;
825
0
  size_t length = 0;
826
0
  UINT32 PayloadOffset = 0;
827
0
  const NTLM_CHALLENGE_MESSAGE empty = { 0 };
828
0
  NTLM_CHALLENGE_MESSAGE* message = NULL;
829
830
0
  WINPR_ASSERT(context);
831
0
  WINPR_ASSERT(buffer);
832
833
0
  message = &context->CHALLENGE_MESSAGE;
834
0
  WINPR_ASSERT(message);
835
836
0
  *message = empty;
837
838
0
  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
839
840
0
  if (!s)
841
0
    return SEC_E_INTERNAL_ERROR;
842
843
0
  ntlm_get_version_info(&(message->Version)); /* Version */
844
0
  ntlm_generate_server_challenge(context);    /* Server Challenge */
845
0
  ntlm_generate_timestamp(context);           /* Timestamp */
846
847
0
  if (!ntlm_construct_challenge_target_info(context)) /* TargetInfo */
848
0
    return SEC_E_INTERNAL_ERROR;
849
850
0
  CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */
851
0
  message->NegotiateFlags = context->NegotiateFlags;
852
0
  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE))
853
0
    return SEC_E_INTERNAL_ERROR;
854
855
  /* Message Header (12 bytes) */
856
0
  if (!ntlm_write_message_header(s, &message->header))
857
0
    return SEC_E_INTERNAL_ERROR;
858
859
0
  if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
860
0
  {
861
0
    message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
862
0
    message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
863
0
  }
864
865
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
866
867
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
868
0
  {
869
0
    message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
870
0
    message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
871
0
  }
872
873
0
  PayloadOffset = 48;
874
875
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
876
0
    PayloadOffset += 8;
877
878
0
  message->TargetName.BufferOffset = PayloadOffset;
879
0
  message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len;
880
  /* TargetNameFields (8 bytes) */
881
0
  if (!ntlm_write_message_fields(s, &(message->TargetName)))
882
0
    return SEC_E_INTERNAL_ERROR;
883
884
0
  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE"))
885
0
    return SEC_E_INTERNAL_ERROR;
886
887
0
  if (!NTLM_CheckAndLogRequiredCapacity(TAG, s, 16, "NTLM_CHALLENGE_MESSAGE::ServerChallenge"))
888
0
    return SEC_E_INTERNAL_ERROR;
889
890
0
  Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */
891
0
  Stream_Write(s, message->Reserved, 8);        /* Reserved (8 bytes), should be ignored */
892
893
  /* TargetInfoFields (8 bytes) */
894
0
  if (!ntlm_write_message_fields(s, &(message->TargetInfo)))
895
0
    return SEC_E_INTERNAL_ERROR;
896
897
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
898
0
  {
899
0
    if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */
900
0
      return SEC_E_INTERNAL_ERROR;
901
0
  }
902
903
  /* Payload (variable) */
904
0
  if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
905
0
  {
906
0
    if (!ntlm_write_message_fields_buffer(s, &(message->TargetName)))
907
0
      return SEC_E_INTERNAL_ERROR;
908
0
  }
909
910
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
911
0
  {
912
0
    if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo)))
913
0
      return SEC_E_INTERNAL_ERROR;
914
0
  }
915
916
0
  length = Stream_GetPosition(s);
917
0
  WINPR_ASSERT(length <= UINT32_MAX);
918
0
  buffer->cbBuffer = (ULONG)length;
919
920
0
  if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length))
921
0
    return SEC_E_INTERNAL_ERROR;
922
923
0
  CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
924
#if defined(WITH_DEBUG_NTLM)
925
  ntlm_print_challenge_message(&context->ChallengeMessage, message,
926
                               &context->ChallengeTargetInfo);
927
#endif
928
0
  ntlm_change_state(context, NTLM_STATE_AUTHENTICATE);
929
0
  return SEC_I_CONTINUE_NEEDED;
930
0
}
931
932
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer)
933
0
{
934
0
  SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
935
0
  wStream sbuffer;
936
0
  wStream* s = NULL;
937
0
  size_t length = 0;
938
0
  UINT32 flags = 0;
939
0
  NTLM_AV_PAIR* AvFlags = NULL;
940
0
  size_t PayloadBufferOffset = 0;
941
0
  const NTLM_AUTHENTICATE_MESSAGE empty = { 0 };
942
0
  NTLM_AUTHENTICATE_MESSAGE* message = NULL;
943
0
  SSPI_CREDENTIALS* credentials = NULL;
944
945
0
  WINPR_ASSERT(context);
946
0
  WINPR_ASSERT(buffer);
947
948
0
  credentials = context->credentials;
949
0
  WINPR_ASSERT(credentials);
950
951
0
  message = &context->AUTHENTICATE_MESSAGE;
952
0
  WINPR_ASSERT(message);
953
954
0
  *message = empty;
955
956
0
  s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
957
958
0
  if (!s)
959
0
    return SEC_E_INTERNAL_ERROR;
960
961
0
  if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE))
962
0
    goto fail;
963
964
0
  if (!ntlm_read_message_fields(
965
0
          s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */
966
0
    goto fail;
967
968
0
  if (!ntlm_read_message_fields(
969
0
          s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */
970
0
    goto fail;
971
972
0
  if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
973
0
    goto fail;
974
975
0
  if (!ntlm_read_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */
976
0
    goto fail;
977
978
0
  if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
979
0
    goto fail;
980
981
0
  if (!ntlm_read_message_fields(
982
0
          s,
983
0
          &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */
984
0
    goto fail;
985
986
0
  if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_AUTHENTICATE_MESSAGE"))
987
0
    goto fail;
988
989
0
  context->NegotiateKeyExchange =
990
0
      (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE;
991
992
0
  if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
993
0
      (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
994
0
    goto fail;
995
996
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
997
0
  {
998
0
    if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */
999
0
      goto fail;
1000
0
  }
1001
1002
0
  PayloadBufferOffset = Stream_GetPosition(s);
1003
1004
0
  status = SEC_E_INTERNAL_ERROR;
1005
0
  if (!ntlm_read_message_fields_buffer(s, &(message->DomainName))) /* DomainName */
1006
0
    goto fail;
1007
1008
0
  if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */
1009
0
    goto fail;
1010
1011
0
  if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
1012
0
    goto fail;
1013
1014
0
  if (!ntlm_read_message_fields_buffer(s,
1015
0
                                       &(message->LmChallengeResponse))) /* LmChallengeResponse */
1016
0
    goto fail;
1017
1018
0
  if (!ntlm_read_message_fields_buffer(s,
1019
0
                                       &(message->NtChallengeResponse))) /* NtChallengeResponse */
1020
0
    goto fail;
1021
1022
0
  if (message->NtChallengeResponse.Len > 0)
1023
0
  {
1024
0
    size_t cbAvFlags = 0;
1025
0
    wStream ssbuffer;
1026
0
    wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer,
1027
0
                                          message->NtChallengeResponse.Len);
1028
1029
0
    if (!snt)
1030
0
      goto fail;
1031
1032
0
    status = SEC_E_INVALID_TOKEN;
1033
0
    if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)))
1034
0
      goto fail;
1035
0
    status = SEC_E_INTERNAL_ERROR;
1036
1037
0
    context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
1038
0
    context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
1039
0
    sspi_SecBufferFree(&(context->ChallengeTargetInfo));
1040
0
    context->ChallengeTargetInfo.pvBuffer = (void*)context->NTLMv2Response.Challenge.AvPairs;
1041
0
    context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16);
1042
0
    CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
1043
0
    AvFlags =
1044
0
        ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs,
1045
0
                         context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags);
1046
1047
0
    if (AvFlags)
1048
0
      flags = winpr_Data_Get_UINT32(ntlm_av_pair_get_value_pointer(AvFlags));
1049
0
  }
1050
1051
0
  if (!ntlm_read_message_fields_buffer(
1052
0
          s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */
1053
0
    goto fail;
1054
1055
0
  if (message->EncryptedRandomSessionKey.Len > 0)
1056
0
  {
1057
0
    if (message->EncryptedRandomSessionKey.Len != 16)
1058
0
      goto fail;
1059
1060
0
    CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
1061
0
               16);
1062
0
  }
1063
1064
0
  length = Stream_GetPosition(s);
1065
0
  WINPR_ASSERT(length <= UINT32_MAX);
1066
1067
0
  if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length))
1068
0
    goto fail;
1069
1070
0
  CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1071
0
  buffer->cbBuffer = (ULONG)length;
1072
0
  Stream_SetPosition(s, PayloadBufferOffset);
1073
1074
0
  if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1075
0
  {
1076
0
    status = SEC_E_INVALID_TOKEN;
1077
0
    if (!ntlm_read_message_integrity_check(
1078
0
            s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1079
0
            sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE"))
1080
0
      goto fail;
1081
0
  }
1082
1083
0
  status = SEC_E_INTERNAL_ERROR;
1084
1085
#if defined(WITH_DEBUG_NTLM)
1086
  ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags, NULL);
1087
#endif
1088
1089
0
  if (message->UserName.Len > 0)
1090
0
  {
1091
0
    credentials->identity.User = (UINT16*)malloc(message->UserName.Len);
1092
1093
0
    if (!credentials->identity.User)
1094
0
      goto fail;
1095
1096
0
    CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
1097
0
    credentials->identity.UserLength = message->UserName.Len / 2;
1098
0
  }
1099
1100
0
  if (message->DomainName.Len > 0)
1101
0
  {
1102
0
    credentials->identity.Domain = (UINT16*)malloc(message->DomainName.Len);
1103
1104
0
    if (!credentials->identity.Domain)
1105
0
      goto fail;
1106
1107
0
    CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
1108
0
               message->DomainName.Len);
1109
0
    credentials->identity.DomainLength = message->DomainName.Len / 2;
1110
0
  }
1111
1112
0
  if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1113
0
  {
1114
0
    const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
1115
0
    if (rc != SEC_E_OK)
1116
0
      return rc;
1117
0
  }
1118
1119
0
  {
1120
0
    const SECURITY_STATUS rc = ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
1121
0
    if (rc != SEC_E_OK)
1122
0
      return rc;
1123
0
  }
1124
1125
  /* KeyExchangeKey */
1126
0
  ntlm_generate_key_exchange_key(context);
1127
  /* EncryptedRandomSessionKey */
1128
0
  ntlm_decrypt_random_session_key(context);
1129
  /* ExportedSessionKey */
1130
0
  ntlm_generate_exported_session_key(context);
1131
1132
0
  if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK)
1133
0
  {
1134
0
    BYTE messageIntegrityCheck[16] = { 0 };
1135
1136
0
    ntlm_compute_message_integrity_check(context, messageIntegrityCheck,
1137
0
                                         sizeof(messageIntegrityCheck));
1138
0
    CopyMemory(
1139
0
        &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset],
1140
0
        message->MessageIntegrityCheck, sizeof(message->MessageIntegrityCheck));
1141
1142
0
    if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck,
1143
0
               sizeof(message->MessageIntegrityCheck)) != 0)
1144
0
    {
1145
0
      WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!");
1146
#ifdef WITH_DEBUG_NTLM
1147
      WLog_ERR(TAG, "Expected MIC:");
1148
      winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck, sizeof(messageIntegrityCheck));
1149
      WLog_ERR(TAG, "Actual MIC:");
1150
      winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
1151
                    sizeof(message->MessageIntegrityCheck));
1152
#endif
1153
0
      return SEC_E_MESSAGE_ALTERED;
1154
0
    }
1155
0
  }
1156
0
  else
1157
0
  {
1158
    /* no mic message was present
1159
1160
       https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
1161
       the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
1162
       Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.
1163
1164
       now check the NtProofString, to detect if the entered client password matches the
1165
       expected password.
1166
       */
1167
1168
#ifdef WITH_DEBUG_NTLM
1169
    WLog_VRB(TAG, "No MIC present, using NtProofString for verification.");
1170
#endif
1171
1172
0
    if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0)
1173
0
    {
1174
0
      WLog_ERR(TAG, "NtProofString verification failed!");
1175
#ifdef WITH_DEBUG_NTLM
1176
      WLog_ERR(TAG, "Expected NtProofString:");
1177
      winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, sizeof(context->NtProofString));
1178
      WLog_ERR(TAG, "Actual NtProofString:");
1179
      winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
1180
                    sizeof(context->NTLMv2Response));
1181
#endif
1182
0
      return SEC_E_LOGON_DENIED;
1183
0
    }
1184
0
  }
1185
1186
  /* Generate signing keys */
1187
0
  if (!ntlm_generate_client_signing_key(context))
1188
0
    return SEC_E_INTERNAL_ERROR;
1189
0
  if (!ntlm_generate_server_signing_key(context))
1190
0
    return SEC_E_INTERNAL_ERROR;
1191
  /* Generate sealing keys */
1192
0
  if (!ntlm_generate_client_sealing_key(context))
1193
0
    return SEC_E_INTERNAL_ERROR;
1194
0
  if (!ntlm_generate_server_sealing_key(context))
1195
0
    return SEC_E_INTERNAL_ERROR;
1196
  /* Initialize RC4 seal state */
1197
0
  if (!ntlm_init_rc4_seal_states(context))
1198
0
    return SEC_E_INTERNAL_ERROR;
1199
#if defined(WITH_DEBUG_NTLM)
1200
  ntlm_print_authentication_complete(context);
1201
#endif
1202
0
  ntlm_change_state(context, NTLM_STATE_FINAL);
1203
0
  ntlm_free_message_fields_buffer(&(message->DomainName));
1204
0
  ntlm_free_message_fields_buffer(&(message->UserName));
1205
0
  ntlm_free_message_fields_buffer(&(message->Workstation));
1206
0
  ntlm_free_message_fields_buffer(&(message->LmChallengeResponse));
1207
0
  ntlm_free_message_fields_buffer(&(message->NtChallengeResponse));
1208
0
  ntlm_free_message_fields_buffer(&(message->EncryptedRandomSessionKey));
1209
0
  return SEC_E_OK;
1210
1211
0
fail:
1212
0
  return status;
1213
0
}
1214
1215
/**
1216
 * Send NTLMSSP AUTHENTICATE_MESSAGE. msdn{cc236643}
1217
 *
1218
 * @param context Pointer to the NTLM context
1219
 * @param buffer The buffer to write
1220
 */
1221
1222
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, SecBuffer* buffer)
1223
0
{
1224
0
  wStream sbuffer;
1225
0
  wStream* s = NULL;
1226
0
  size_t length = 0;
1227
0
  UINT32 PayloadBufferOffset = 0;
1228
0
  const NTLM_AUTHENTICATE_MESSAGE empty = { 0 };
1229
0
  NTLM_AUTHENTICATE_MESSAGE* message = NULL;
1230
0
  SSPI_CREDENTIALS* credentials = NULL;
1231
1232
0
  WINPR_ASSERT(context);
1233
0
  WINPR_ASSERT(buffer);
1234
1235
0
  credentials = context->credentials;
1236
0
  WINPR_ASSERT(credentials);
1237
1238
0
  message = &context->AUTHENTICATE_MESSAGE;
1239
0
  WINPR_ASSERT(message);
1240
1241
0
  *message = empty;
1242
1243
0
  s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
1244
1245
0
  if (!s)
1246
0
    return SEC_E_INTERNAL_ERROR;
1247
1248
0
  if (context->NTLMv2)
1249
0
  {
1250
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_56;
1251
1252
0
    if (context->SendVersionInfo)
1253
0
      message->NegotiateFlags |= NTLMSSP_NEGOTIATE_VERSION;
1254
0
  }
1255
1256
0
  if (context->UseMIC)
1257
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
1258
1259
0
  if (context->SendWorkstationName)
1260
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
1261
1262
0
  if (context->confidentiality)
1263
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
1264
1265
0
  if (context->CHALLENGE_MESSAGE.NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1266
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
1267
1268
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_128;
1269
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
1270
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
1271
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLM;
1272
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1273
0
  message->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
1274
0
  message->NegotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE;
1275
1276
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1277
0
    ntlm_get_version_info(&(message->Version));
1278
1279
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1280
0
  {
1281
0
    message->Workstation.Len = context->Workstation.Length;
1282
0
    message->Workstation.Buffer = (BYTE*)context->Workstation.Buffer;
1283
0
  }
1284
1285
0
  if (credentials->identity.DomainLength > 0)
1286
0
  {
1287
0
    message->NegotiateFlags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
1288
0
    message->DomainName.Len = (UINT16)credentials->identity.DomainLength * 2;
1289
0
    message->DomainName.Buffer = (BYTE*)credentials->identity.Domain;
1290
0
  }
1291
1292
0
  message->UserName.Len = (UINT16)credentials->identity.UserLength * 2;
1293
0
  message->UserName.Buffer = (BYTE*)credentials->identity.User;
1294
0
  message->LmChallengeResponse.Len = (UINT16)context->LmChallengeResponse.cbBuffer;
1295
0
  message->LmChallengeResponse.Buffer = (BYTE*)context->LmChallengeResponse.pvBuffer;
1296
0
  message->NtChallengeResponse.Len = (UINT16)context->NtChallengeResponse.cbBuffer;
1297
0
  message->NtChallengeResponse.Buffer = (BYTE*)context->NtChallengeResponse.pvBuffer;
1298
1299
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1300
0
  {
1301
0
    message->EncryptedRandomSessionKey.Len = 16;
1302
0
    message->EncryptedRandomSessionKey.Buffer = context->EncryptedRandomSessionKey;
1303
0
  }
1304
1305
0
  PayloadBufferOffset = 64;
1306
1307
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1308
0
    PayloadBufferOffset += 8; /* Version (8 bytes) */
1309
1310
0
  if (context->UseMIC)
1311
0
    PayloadBufferOffset += 16; /* Message Integrity Check (16 bytes) */
1312
1313
0
  message->DomainName.BufferOffset = PayloadBufferOffset;
1314
0
  message->UserName.BufferOffset = message->DomainName.BufferOffset + message->DomainName.Len;
1315
0
  message->Workstation.BufferOffset = message->UserName.BufferOffset + message->UserName.Len;
1316
0
  message->LmChallengeResponse.BufferOffset =
1317
0
      message->Workstation.BufferOffset + message->Workstation.Len;
1318
0
  message->NtChallengeResponse.BufferOffset =
1319
0
      message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len;
1320
0
  message->EncryptedRandomSessionKey.BufferOffset =
1321
0
      message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len;
1322
0
  if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE))
1323
0
    return SEC_E_INVALID_TOKEN;
1324
0
  if (!ntlm_write_message_header(s, &message->header)) /* Message Header (12 bytes) */
1325
0
    return SEC_E_INTERNAL_ERROR;
1326
0
  if (!ntlm_write_message_fields(
1327
0
          s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */
1328
0
    return SEC_E_INTERNAL_ERROR;
1329
0
  if (!ntlm_write_message_fields(
1330
0
          s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */
1331
0
    return SEC_E_INTERNAL_ERROR;
1332
0
  if (!ntlm_write_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */
1333
0
    return SEC_E_INTERNAL_ERROR;
1334
0
  if (!ntlm_write_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */
1335
0
    return SEC_E_INTERNAL_ERROR;
1336
0
  if (!ntlm_write_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */
1337
0
    return SEC_E_INTERNAL_ERROR;
1338
0
  if (!ntlm_write_message_fields(
1339
0
          s,
1340
0
          &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */
1341
0
    return SEC_E_INTERNAL_ERROR;
1342
0
  if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_AUTHENTICATE_MESSAGE"))
1343
0
    return SEC_E_INTERNAL_ERROR;
1344
1345
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
1346
0
  {
1347
0
    if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */
1348
0
      return SEC_E_INTERNAL_ERROR;
1349
0
  }
1350
1351
0
  if (context->UseMIC)
1352
0
  {
1353
0
    const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 };
1354
1355
0
    context->MessageIntegrityCheckOffset = Stream_GetPosition(s);
1356
0
    if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data, sizeof(data),
1357
0
                                            "NTLM_AUTHENTICATE_MESSAGE"))
1358
0
      return SEC_E_INTERNAL_ERROR;
1359
0
  }
1360
1361
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
1362
0
  {
1363
0
    if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */
1364
0
      return SEC_E_INTERNAL_ERROR;
1365
0
  }
1366
1367
0
  if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */
1368
0
    return SEC_E_INTERNAL_ERROR;
1369
1370
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
1371
0
  {
1372
0
    if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
1373
0
      return SEC_E_INTERNAL_ERROR;
1374
0
  }
1375
1376
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
1377
0
  {
1378
0
    if (!ntlm_write_message_fields_buffer(
1379
0
            s, &(message->LmChallengeResponse))) /* LmChallengeResponse */
1380
0
      return SEC_E_INTERNAL_ERROR;
1381
0
  }
1382
0
  if (!ntlm_write_message_fields_buffer(
1383
0
          s, &(message->NtChallengeResponse))) /* NtChallengeResponse */
1384
0
    return SEC_E_INTERNAL_ERROR;
1385
1386
0
  if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
1387
0
  {
1388
0
    if (!ntlm_write_message_fields_buffer(
1389
0
            s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */
1390
0
      return SEC_E_INTERNAL_ERROR;
1391
0
  }
1392
1393
0
  length = Stream_GetPosition(s);
1394
0
  WINPR_ASSERT(length <= UINT32_MAX);
1395
1396
0
  if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length))
1397
0
    return SEC_E_INTERNAL_ERROR;
1398
1399
0
  CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length);
1400
0
  buffer->cbBuffer = (ULONG)length;
1401
1402
0
  if (context->UseMIC)
1403
0
  {
1404
    /* Message Integrity Check */
1405
0
    ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck,
1406
0
                                         sizeof(message->MessageIntegrityCheck));
1407
0
    if (!ntlm_write_message_integrity_check(
1408
0
            s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck,
1409
0
            sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE"))
1410
0
      return SEC_E_INTERNAL_ERROR;
1411
0
  }
1412
1413
#if defined(WITH_DEBUG_NTLM)
1414
  ntlm_print_authenticate_message(&context->AuthenticateMessage, message,
1415
                                  context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0,
1416
                                  &context->AuthenticateTargetInfo);
1417
#endif
1418
0
  ntlm_change_state(context, NTLM_STATE_FINAL);
1419
0
  return SEC_E_OK;
1420
0
}