20 #include <winpr/config.h>
22 #include <winpr/assert.h>
27 #include <winpr/crt.h>
28 #include <winpr/print.h>
29 #include <winpr/sysinfo.h>
30 #include <winpr/tchar.h>
31 #include <winpr/crypto.h>
33 #include "ntlm_compute.h"
35 #include "ntlm_av_pairs.h"
37 #include "../../log.h"
38 #define TAG WINPR_TAG("sspi.NTLM")
40 static BOOL ntlm_av_pair_get_next_offset(
const NTLM_AV_PAIR* pAvPair,
size_t size,
size_t* pOffset);
42 static BOOL ntlm_av_pair_check_data(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair,
size_t size)
47 if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
49 return cbAvPair >= offset;
52 static const char* get_av_pair_string(UINT16 pair)
58 case MsvAvNbComputerName:
59 return "MsvAvNbComputerName";
60 case MsvAvNbDomainName:
61 return "MsvAvNbDomainName";
62 case MsvAvDnsComputerName:
63 return "MsvAvDnsComputerName";
64 case MsvAvDnsDomainName:
65 return "MsvAvDnsDomainName";
66 case MsvAvDnsTreeName:
67 return "MsvAvDnsTreeName";
71 return "MsvAvTimestamp";
73 return "MsvAvSingleHost";
75 return "MsvAvTargetName";
76 case MsvAvChannelBindings:
77 return "MsvAvChannelBindings";
83 static BOOL ntlm_av_pair_check(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair);
86 static INLINE
void ntlm_av_pair_set_id(
NTLM_AV_PAIR* pAvPair, UINT16
id)
88 WINPR_ASSERT(pAvPair);
89 winpr_Data_Write_UINT16(&pAvPair->AvId,
id);
92 static INLINE
void ntlm_av_pair_set_len(
NTLM_AV_PAIR* pAvPair, UINT16 len)
94 WINPR_ASSERT(pAvPair);
95 winpr_Data_Write_UINT16(&pAvPair->AvLen, len);
98 static BOOL ntlm_av_pair_list_init(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
105 ntlm_av_pair_set_id(pAvPair, MsvAvEOL);
106 ntlm_av_pair_set_len(pAvPair, 0);
110 static INLINE BOOL ntlm_av_pair_get_id(
const NTLM_AV_PAIR* pAvPair,
size_t size, UINT16* pair)
112 if (!pAvPair || !pair)
118 const UINT16 AvId = winpr_Data_Get_UINT16(&pAvPair->AvId);
124 ULONG ntlm_av_pair_list_length(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
129 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
133 if (pAvPair < pAvPairList)
136 const size_t size = WINPR_ASSERTING_INT_CAST(
size_t, ((PBYTE)pAvPair - (PBYTE)pAvPairList)) +
138 WINPR_ASSERT(size <= UINT32_MAX);
139 WINPR_ASSERT(size >= 0);
143 static INLINE BOOL ntlm_av_pair_get_len(
const NTLM_AV_PAIR* pAvPair,
size_t size,
size_t* pAvLen)
151 const UINT16 AvLen = winpr_Data_Get_UINT16(&pAvPair->AvLen);
157 #ifdef WITH_DEBUG_NTLM
158 void ntlm_print_av_pair_list(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
161 size_t cbAvPair = cbAvPairList;
164 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
167 WLog_VRB(TAG,
"AV_PAIRs =");
169 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
172 ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
174 WLog_VRB(TAG,
"\t%s AvId: %" PRIu16
" AvLen: %" PRIu16
"", get_av_pair_string(pair), pair);
175 winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
177 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
182 static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
185 return ((AvPairsCount + 1) * 4) + AvPairsValueLength;
188 PBYTE ntlm_av_pair_get_value_pointer(
NTLM_AV_PAIR* pAvPair)
190 WINPR_ASSERT(pAvPair);
194 static BOOL ntlm_av_pair_get_next_offset(
const NTLM_AV_PAIR* pAvPair,
size_t size,
size_t* pOffset)
200 if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
206 static BOOL ntlm_av_pair_check(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair)
208 return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
217 if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
220 if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
223 *pcbAvPair -= offset;
228 size_t* pcbAvPairListRemaining)
231 size_t cbAvPair = cbAvPairList;
234 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
237 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &
id))
247 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
252 if (pcbAvPairListRemaining)
253 *pcbAvPairListRemaining = cbAvPair;
258 static BOOL ntlm_av_pair_add(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList, NTLM_AV_ID AvId,
259 PBYTE Value, UINT16 AvLen)
264 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
267 if (!pAvPair || cbAvPair < 2 *
sizeof(
NTLM_AV_PAIR) + AvLen)
270 ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
271 ntlm_av_pair_set_len(pAvPair, AvLen);
274 WINPR_ASSERT(Value != NULL);
275 CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
278 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
279 return ntlm_av_pair_list_init(pAvPair, cbAvPair);
282 static BOOL ntlm_av_pair_add_copy(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList,
288 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
291 if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
294 if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
297 WINPR_ASSERT(avLen <= UINT16_MAX);
298 return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
299 ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
302 static char* get_name(COMPUTER_NAME_FORMAT type)
306 if (GetComputerNameExA(type, NULL, &nSize))
309 if (GetLastError() != ERROR_MORE_DATA)
312 char* computerName = calloc(1, nSize);
317 if (!GetComputerNameExA(type, computerName, &nSize))
326 static int ntlm_get_target_computer_name(
PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
332 char* name = get_name(ComputerNameNetBIOS);
339 pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
342 if (!pName->Buffer || (len == 0) || (len > UINT16_MAX /
sizeof(WCHAR)))
345 pName->Buffer = NULL;
349 pName->Length = (USHORT)((len) *
sizeof(WCHAR));
350 pName->MaximumLength = pName->Length;
358 if (string->Length > 0)
360 free(string->Buffer);
361 string->Buffer = NULL;
363 string->MaximumLength = 0;
396 static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
399 be32[0] = (num >> 0) & 0xFF;
400 be32[1] = (num >> 8) & 0xFF;
401 be32[2] = (num >> 16) & 0xFF;
402 be32[3] = (num >> 24) & 0xFF;
403 return winpr_Digest_Update(md5, be32, 4);
406 static void ntlm_compute_channel_bindings(
NTLM_CONTEXT* context)
408 WINPR_DIGEST_CTX* md5 = NULL;
409 BYTE* ChannelBindingToken = NULL;
410 UINT32 ChannelBindingTokenLength = 0;
413 WINPR_ASSERT(context);
415 ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
416 ChannelBindings = context->Bindings.Bindings;
418 if (!ChannelBindings)
421 if (!(md5 = winpr_Digest_New()))
424 if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
428 ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
430 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
433 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
436 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
439 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
442 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
445 if (!winpr_Digest_Update(md5, (
void*)ChannelBindingToken, ChannelBindingTokenLength))
448 if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
452 winpr_Digest_Free(md5);
455 static void ntlm_compute_single_host_data(
NTLM_CONTEXT* context)
457 WINPR_ASSERT(context);
466 winpr_Data_Write_UINT32(&context->SingleHostData.Size, 48);
467 winpr_Data_Write_UINT32(&context->SingleHostData.Z4, 0);
468 winpr_Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
469 winpr_Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
470 FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
473 BOOL ntlm_construct_challenge_target_info(
NTLM_CONTEXT* context)
477 ULONG AvPairsCount = 0;
478 ULONG AvPairsLength = 0;
480 size_t cbAvPairList = 0;
486 WINPR_ASSERT(context);
488 if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
491 NbComputerName.Buffer = NULL;
493 if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
496 DnsDomainName.Buffer = NULL;
498 if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
501 DnsComputerName.Buffer = NULL;
503 if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
507 AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
508 DnsComputerName.Length + 8;
509 length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
511 if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length))
514 pAvPairList = (
NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
515 cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
517 if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
520 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
521 NbDomainName.Length))
524 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
525 (PBYTE)NbComputerName.Buffer, NbComputerName.Length))
528 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
529 (PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
532 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
533 (PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
536 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
537 sizeof(context->Timestamp)))
542 ntlm_free_unicode_string(&NbDomainName);
543 ntlm_free_unicode_string(&NbComputerName);
544 ntlm_free_unicode_string(&DnsDomainName);
545 ntlm_free_unicode_string(&DnsComputerName);
549 BOOL ntlm_construct_authenticate_target_info(
NTLM_CONTEXT* context)
552 ULONG AvPairsCount = 0;
553 ULONG AvPairsValueLength = 0;
562 size_t cbAvTimestamp = 0;
563 size_t cbAvNbDomainName = 0;
564 size_t cbAvNbComputerName = 0;
565 size_t cbAvDnsDomainName = 0;
566 size_t cbAvDnsComputerName = 0;
567 size_t cbAvDnsTreeName = 0;
568 size_t cbChallengeTargetInfo = 0;
569 size_t cbAuthenticateTargetInfo = 0;
571 WINPR_ASSERT(context);
574 AvPairsValueLength = 0;
575 ChallengeTargetInfo = (
NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
576 cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
577 AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
579 AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
580 MsvAvNbComputerName, &cbAvNbComputerName);
581 AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
582 MsvAvDnsDomainName, &cbAvDnsDomainName);
583 AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
584 MsvAvDnsComputerName, &cbAvDnsComputerName);
585 AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
587 AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
593 if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
596 AvPairsValueLength += avLen;
599 if (AvNbComputerName)
602 if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
605 AvPairsValueLength += avLen;
611 if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
614 AvPairsValueLength += avLen;
617 if (AvDnsComputerName)
620 if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
623 AvPairsValueLength += avLen;
629 if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
632 AvPairsValueLength += avLen;
636 AvPairsValueLength += 8;
641 AvPairsValueLength += 4;
644 if (context->SendSingleHostData)
647 ntlm_compute_single_host_data(context);
648 AvPairsValueLength += context->SingleHostData.Size;
656 if (!context->SuppressExtendedProtection)
663 AvPairsValueLength += 16;
664 ntlm_compute_channel_bindings(context);
666 if (context->ServicePrincipalName.Length > 0)
669 AvPairsValueLength += context->ServicePrincipalName.Length;
673 size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
678 if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size))
681 AuthenticateTargetInfo = (
NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
682 cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
684 if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
689 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
694 if (AvNbComputerName)
696 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
697 AvNbComputerName, cbAvNbComputerName))
703 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
704 AvDnsDomainName, cbAvDnsDomainName))
708 if (AvDnsComputerName)
710 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
711 AvDnsComputerName, cbAvDnsComputerName))
717 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
724 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
732 winpr_Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
734 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
739 if (context->SendSingleHostData)
741 WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
742 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
743 (PBYTE)&context->SingleHostData,
744 (UINT16)context->SingleHostData.Size))
748 if (!context->SuppressExtendedProtection)
750 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
751 MsvAvChannelBindings, context->ChannelBindingsHash, 16))
754 if (context->ServicePrincipalName.Length > 0)
756 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
757 (PBYTE)context->ServicePrincipalName.Buffer,
758 context->ServicePrincipalName.Length))
766 AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);
776 sspi_SecBufferFree(&context->AuthenticateTargetInfo);