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