20#include <winpr/config.h>
22#include <winpr/assert.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#if defined(WITH_DEBUG_NTLM)
39#define TAG WINPR_TAG("sspi.NTLM")
42static BOOL ntlm_av_pair_get_next_offset(
const NTLM_AV_PAIR* pAvPair,
size_t size,
size_t* pOffset);
44static BOOL ntlm_av_pair_check_data(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair,
size_t size)
49 if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
51 return cbAvPair >= offset;
55static const char* get_av_pair_string(UINT16 pair)
61 case MsvAvNbComputerName:
62 return "MsvAvNbComputerName";
63 case MsvAvNbDomainName:
64 return "MsvAvNbDomainName";
65 case MsvAvDnsComputerName:
66 return "MsvAvDnsComputerName";
67 case MsvAvDnsDomainName:
68 return "MsvAvDnsDomainName";
69 case MsvAvDnsTreeName:
70 return "MsvAvDnsTreeName";
74 return "MsvAvTimestamp";
76 return "MsvAvSingleHost";
78 return "MsvAvTargetName";
79 case MsvAvChannelBindings:
80 return "MsvAvChannelBindings";
87static BOOL ntlm_av_pair_check(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair);
90static inline void ntlm_av_pair_set_id(
NTLM_AV_PAIR* pAvPair, UINT16
id)
92 WINPR_ASSERT(pAvPair);
93 winpr_Data_Write_UINT16(&pAvPair->AvId,
id);
96static inline void ntlm_av_pair_set_len(
NTLM_AV_PAIR* pAvPair, UINT16 len)
98 WINPR_ASSERT(pAvPair);
99 winpr_Data_Write_UINT16(&pAvPair->AvLen, len);
102static BOOL ntlm_av_pair_list_init(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
109 ntlm_av_pair_set_id(pAvPair, MsvAvEOL);
110 ntlm_av_pair_set_len(pAvPair, 0);
114WINPR_ATTR_NODISCARD
static inline BOOL ntlm_av_pair_get_id(
const NTLM_AV_PAIR* pAvPair,
115 size_t size, UINT16* pair)
117 if (!pAvPair || !pair)
123 const UINT16 AvId = winpr_Data_Get_UINT16(&pAvPair->AvId);
129ULONG ntlm_av_pair_list_length(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
134 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
138 if (pAvPair < pAvPairList)
141 const size_t size = WINPR_ASSERTING_INT_CAST(
size_t, ((PBYTE)pAvPair - (PBYTE)pAvPairList)) +
143 WINPR_ASSERT(size <= UINT32_MAX);
144 WINPR_ASSERT(size >= 0);
148WINPR_ATTR_NODISCARD
static inline BOOL ntlm_av_pair_get_len(
const NTLM_AV_PAIR* pAvPair,
149 size_t size,
size_t* pAvLen)
157 const UINT16 AvLen = winpr_Data_Get_UINT16(&pAvPair->AvLen);
163#ifdef WITH_DEBUG_NTLM
164void ntlm_print_av_pair_list(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList)
167 size_t cbAvPair = cbAvPairList;
170 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
173 WLog_VRB(TAG,
"AV_PAIRs =");
175 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
178 ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
180 WLog_VRB(TAG,
"\t%s AvId: %" PRIu16
" AvLen: %" PRIuz
"", get_av_pair_string(pair), pair,
182 winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
184 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
189static size_t ntlm_av_pair_list_size(
size_t AvPairsCount,
size_t AvPairsValueLength)
192 return ((AvPairsCount + 1) * 4ULL) + AvPairsValueLength;
195PBYTE ntlm_av_pair_get_value_pointer(
NTLM_AV_PAIR* pAvPair)
197 WINPR_ASSERT(pAvPair);
201static BOOL ntlm_av_pair_get_next_offset(
const NTLM_AV_PAIR* pAvPair,
size_t size,
size_t* pOffset)
207 if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
213static BOOL ntlm_av_pair_check(
const NTLM_AV_PAIR* pAvPair,
size_t cbAvPair)
215 return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
224 if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
227 if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
230 *pcbAvPair -= offset;
235 size_t* pcbAvPairListRemaining)
238 size_t cbAvPair = cbAvPairList;
241 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
244 while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &
id))
254 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
259 if (pcbAvPairListRemaining)
260 *pcbAvPairListRemaining = cbAvPair;
265static BOOL ntlm_av_pair_add(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList, NTLM_AV_ID AvId,
266 PBYTE Value, UINT16 AvLen)
271 pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
274 if (!pAvPair || cbAvPair < 2 *
sizeof(
NTLM_AV_PAIR) + AvLen)
277 ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
278 ntlm_av_pair_set_len(pAvPair, AvLen);
281 WINPR_ASSERT(Value !=
nullptr);
282 CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
285 pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
286 return ntlm_av_pair_list_init(pAvPair, cbAvPair);
289static BOOL ntlm_av_pair_valid(UINT16 pair)
294 case MsvAvNbComputerName:
295 case MsvAvNbDomainName:
296 case MsvAvDnsComputerName:
297 case MsvAvDnsDomainName:
298 case MsvAvDnsTreeName:
301 case MsvAvSingleHost:
302 case MsvAvTargetName:
303 case MsvAvChannelBindings:
310static BOOL ntlm_av_pair_add_copy(
NTLM_AV_PAIR* pAvPairList,
size_t cbAvPairList,
316 if (!ntlm_av_pair_check(pAvPair, cbAvPair))
319 if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
322 if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
325 if (!ntlm_av_pair_valid(pair))
328 WINPR_ASSERT(avLen <= UINT16_MAX);
329 return ntlm_av_pair_add(pAvPairList, cbAvPairList, WINPR_ASSERTING_INT_CAST(NTLM_AV_ID, pair),
330 ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
333static char* get_name(COMPUTER_NAME_FORMAT type)
337 if (GetComputerNameExA(type,
nullptr, &nSize))
340 if (GetLastError() != ERROR_MORE_DATA)
343 char* computerName = calloc(1, nSize);
348 if (!GetComputerNameExA(type, computerName, &nSize))
358 WINPR_ATTR_UNUSED COMPUTER_NAME_FORMAT type)
364 char* name = get_name(ComputerNameNetBIOS);
371 pName->Buffer = ConvertUtf8ToWCharAlloc(name, &len);
374 if (!pName->Buffer || (len == 0) || (len > UINT16_MAX /
sizeof(WCHAR)))
377 pName->Buffer =
nullptr;
381 pName->Length = (USHORT)((len) *
sizeof(WCHAR));
382 pName->MaximumLength = pName->Length;
390 if (string->Length > 0)
392 free(string->Buffer);
393 string->Buffer =
nullptr;
395 string->MaximumLength = 0;
428static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num)
431 be32[0] = (num >> 0) & 0xFF;
432 be32[1] = (num >> 8) & 0xFF;
433 be32[2] = (num >> 16) & 0xFF;
434 be32[3] = (num >> 24) & 0xFF;
435 return winpr_Digest_Update(md5, be32, 4);
438static void ntlm_compute_channel_bindings(
NTLM_CONTEXT* context)
440 WINPR_DIGEST_CTX* md5 =
nullptr;
441 BYTE* ChannelBindingToken =
nullptr;
442 UINT32 ChannelBindingTokenLength = 0;
445 WINPR_ASSERT(context);
447 ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
448 ChannelBindings = context->Bindings.Bindings;
450 if (!ChannelBindings)
453 if (!(md5 = winpr_Digest_New()))
456 if (!winpr_Digest_Init(md5, WINPR_MD_MD5))
460 ChannelBindingToken = &((BYTE*)ChannelBindings)[ChannelBindings->dwApplicationDataOffset];
462 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwInitiatorAddrType))
465 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbInitiatorLength))
468 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->dwAcceptorAddrType))
471 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbAcceptorLength))
474 if (!ntlm_md5_update_uint32_be(md5, ChannelBindings->cbApplicationDataLength))
477 if (!winpr_Digest_Update(md5, (
void*)ChannelBindingToken, ChannelBindingTokenLength))
480 if (!winpr_Digest_Final(md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH))
484 winpr_Digest_Free(md5);
487static void ntlm_compute_single_host_data(
NTLM_CONTEXT* context)
489 WINPR_ASSERT(context);
498 winpr_Data_Write_UINT32(&context->SingleHostData.Size, 48);
499 winpr_Data_Write_UINT32(&context->SingleHostData.Z4, 0);
500 winpr_Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
501 winpr_Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
502 FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
505BOOL ntlm_construct_challenge_target_info(
NTLM_CONTEXT* context)
508 ULONG AvPairsCount = 0;
509 ULONG AvPairsLength = 0;
511 size_t cbAvPairList = 0;
517 WINPR_ASSERT(context);
519 if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
522 NbComputerName.Buffer =
nullptr;
524 if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
527 DnsDomainName.Buffer =
nullptr;
529 if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
532 DnsComputerName.Buffer =
nullptr;
534 if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
538 AvPairsLength = NbDomainName.Length + NbComputerName.Length + DnsDomainName.Length +
539 DnsComputerName.Length + 8;
541 const size_t length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
542 if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo,
543 WINPR_ASSERTING_INT_CAST(uint32_t, length)))
547 pAvPairList = (
NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
548 cbAvPairList = context->ChallengeTargetInfo.cbBuffer;
550 if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList))
553 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE)NbDomainName.Buffer,
554 NbDomainName.Length))
557 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName,
558 (PBYTE)NbComputerName.Buffer, NbComputerName.Length))
561 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName,
562 (PBYTE)DnsDomainName.Buffer, DnsDomainName.Length))
565 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName,
566 (PBYTE)DnsComputerName.Buffer, DnsComputerName.Length))
569 if (!ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp,
570 sizeof(context->Timestamp)))
575 ntlm_free_unicode_string(&NbDomainName);
576 ntlm_free_unicode_string(&NbComputerName);
577 ntlm_free_unicode_string(&DnsDomainName);
578 ntlm_free_unicode_string(&DnsComputerName);
582BOOL ntlm_construct_authenticate_target_info(
NTLM_CONTEXT* context)
584 ULONG AvPairsCount = 0;
585 size_t AvPairsValueLength = 0;
594 size_t cbAvTimestamp = 0;
595 size_t cbAvNbDomainName = 0;
596 size_t cbAvNbComputerName = 0;
597 size_t cbAvDnsDomainName = 0;
598 size_t cbAvDnsComputerName = 0;
599 size_t cbAvDnsTreeName = 0;
600 size_t cbChallengeTargetInfo = 0;
601 size_t cbAuthenticateTargetInfo = 0;
603 WINPR_ASSERT(context);
606 ChallengeTargetInfo = (
NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
607 cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer;
608 AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName,
610 AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
611 MsvAvNbComputerName, &cbAvNbComputerName);
612 AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
613 MsvAvDnsDomainName, &cbAvDnsDomainName);
614 AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo,
615 MsvAvDnsComputerName, &cbAvDnsComputerName);
616 AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName,
618 AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp,
624 if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
627 AvPairsValueLength += avLen;
630 if (AvNbComputerName)
633 if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
636 AvPairsValueLength += avLen;
642 if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
645 AvPairsValueLength += avLen;
648 if (AvDnsComputerName)
651 if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
654 AvPairsValueLength += avLen;
660 if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
663 AvPairsValueLength += avLen;
667 AvPairsValueLength += 8;
672 AvPairsValueLength += 4;
675 if (context->SendSingleHostData)
678 ntlm_compute_single_host_data(context);
679 AvPairsValueLength += context->SingleHostData.Size;
687 if (!context->SuppressExtendedProtection)
694 AvPairsValueLength += 16;
695 ntlm_compute_channel_bindings(context);
697 if (context->ServicePrincipalName.Length > 0)
700 AvPairsValueLength += context->ServicePrincipalName.Length;
705 size_t size = ntlm_av_pair_list_size(AvPairsCount, AvPairsValueLength);
709 if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo,
710 WINPR_ASSERTING_INT_CAST(uint32_t, size)))
714 AuthenticateTargetInfo = (
NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
715 cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
717 if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
722 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
727 if (AvNbComputerName)
729 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
730 AvNbComputerName, cbAvNbComputerName))
736 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
737 AvDnsDomainName, cbAvDnsDomainName))
741 if (AvDnsComputerName)
743 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
744 AvDnsComputerName, cbAvDnsComputerName))
750 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
757 if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
765 winpr_Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK);
767 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
772 if (context->SendSingleHostData)
774 WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
775 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
776 (PBYTE)&context->SingleHostData,
777 (UINT16)context->SingleHostData.Size))
781 if (!context->SuppressExtendedProtection)
783 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
784 MsvAvChannelBindings, context->ChannelBindingsHash, 16))
787 if (context->ServicePrincipalName.Length > 0)
789 if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
790 (PBYTE)context->ServicePrincipalName.Buffer,
791 context->ServicePrincipalName.Length))
799 AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL,
nullptr);
809 sspi_SecBufferFree(&context->AuthenticateTargetInfo);