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