20#include <winpr/config.h>
23#include <winpr/assert.h>
24#include <winpr/sspi.h>
25#include <winpr/print.h>
26#include <winpr/string.h>
27#include <winpr/tchar.h>
28#include <winpr/sysinfo.h>
29#include <winpr/registry.h>
30#include <winpr/endian.h>
31#include <winpr/build-config.h>
34#include "ntlm_export.h"
37#include "ntlm_message.h"
39#include "../../utils.h"
42#define TAG WINPR_TAG("sspi.NTLM")
45#define MIN(a, b) ((a) < (b)) ? (a) : (b)
48#define WINPR_KEY "Software\\%s\\WinPR\\NTLM"
50static char* NTLM_PACKAGE_NAME =
"NTLM";
52#define check_context(ctx) check_context_((ctx), __FILE__, __func__, __LINE__)
55static BOOL check_context_(
NTLM_CONTEXT* context,
const char* file,
const char* fkt,
size_t line)
58 wLog* log = WLog_Get(TAG);
59 const DWORD log_level = WLOG_ERROR;
63 if (WLog_IsLevelActive(log, log_level))
64 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context");
69 if (!context->RecvRc4Seal)
71 if (WLog_IsLevelActive(log, log_level))
72 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->RecvRc4Seal");
75 if (!context->SendRc4Seal)
77 if (WLog_IsLevelActive(log, log_level))
78 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->SendRc4Seal");
82 if (!context->SendSigningKey)
84 if (WLog_IsLevelActive(log, log_level))
85 WLog_PrintTextMessage(log, log_level, line, file, fkt,
86 "invalid context->SendSigningKey");
89 if (!context->RecvSigningKey)
91 if (WLog_IsLevelActive(log, log_level))
92 WLog_PrintTextMessage(log, log_level, line, file, fkt,
93 "invalid context->RecvSigningKey");
96 if (!context->SendSealingKey)
98 if (WLog_IsLevelActive(log, log_level))
99 WLog_PrintTextMessage(log, log_level, line, file, fkt,
100 "invalid context->SendSealingKey");
103 if (!context->RecvSealingKey)
105 if (WLog_IsLevelActive(log, log_level))
106 WLog_PrintTextMessage(log, log_level, line, file, fkt,
107 "invalid context->RecvSealingKey");
113WINPR_ATTR_MALLOC(free, 1)
114static
char* get_computer_name(COMPUTER_NAME_FORMAT type,
size_t* pSize)
121 if (GetComputerNameExA(type,
nullptr, &nSize))
124 if (GetLastError() != ERROR_MORE_DATA)
127 char* computerName = calloc(1, nSize);
132 if (!GetComputerNameExA(type, computerName, &nSize))
144SECURITY_STATUS ntlm_SetContextWorkstationX(
NTLM_CONTEXT* context, BOOL unicode,
const void* data,
147 WINPR_ASSERT(context);
148 ntlm_free_unicode_string(&context->Workstation);
155 context->Workstation = ntlm_from_unicode_string_w(data, length /
sizeof(WCHAR));
157 context->Workstation = ntlm_from_unicode_string_utf8(data, length);
159 if (ntlm_is_unicode_string_empty(&context->Workstation))
160 return SEC_E_INSUFFICIENT_MEMORY;
166static int ntlm_SetContextWorkstation(
NTLM_CONTEXT* context,
const char* Workstation)
168 const char* ws = Workstation;
169 CHAR* computerName =
nullptr;
173 computerName = get_computer_name(ComputerNameNetBIOS,
nullptr);
179 const size_t len = strlen(ws);
180 const SECURITY_STATUS status = ntlm_SetContextWorkstationX(context, FALSE, ws, len);
183 return (status == SEC_E_OK) ? 1 : -1;
187static int ntlm_SetContextServicePrincipalNameW(
NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
189 WINPR_ASSERT(context);
191 ntlm_free_unicode_string(&context->ServicePrincipalName);
192 if (!ServicePrincipalName)
195 const size_t len = _wcslen(ServicePrincipalName);
196 context->ServicePrincipalName = ntlm_from_unicode_string_w(ServicePrincipalName, len);
197 if (ntlm_is_unicode_string_empty(&context->ServicePrincipalName))
204static int ntlm_SetContextTargetName(
NTLM_CONTEXT* context,
char* TargetName)
206 char* name = TargetName;
207 WINPR_ASSERT(context);
212 char* computerName = get_computer_name(ComputerNameNetBIOS, &nSize);
217 if (nSize > MAX_COMPUTERNAME_LENGTH)
218 computerName[MAX_COMPUTERNAME_LENGTH] =
'\0';
229 sspi_SecBufferFree(&context->TargetName);
230 context->TargetName.pvBuffer = ConvertUtf8ToWCharAlloc(name, &len);
232 if (!context->TargetName.pvBuffer || (len > UINT16_MAX /
sizeof(WCHAR)))
234 free(context->TargetName.pvBuffer);
235 context->TargetName.pvBuffer =
nullptr;
243 context->TargetName.cbBuffer = (USHORT)(len *
sizeof(WCHAR));
256 winpr_RC4_Free(context->SendRc4Seal);
257 winpr_RC4_Free(context->RecvRc4Seal);
258 sspi_SecBufferFree(&context->NegotiateMessage);
259 sspi_SecBufferFree(&context->ChallengeMessage);
260 sspi_SecBufferFree(&context->AuthenticateMessage);
261 sspi_SecBufferFree(&context->ChallengeTargetInfo);
262 sspi_SecBufferFree(&context->AuthenticateTargetInfo);
263 sspi_SecBufferFree(&context->TargetName);
264 sspi_SecBufferFree(&context->NtChallengeResponse);
265 sspi_SecBufferFree(&context->LmChallengeResponse);
266 ntlm_free_unicode_string(&context->ServicePrincipalName);
267 ntlm_free_unicode_string(&context->Workstation);
268 ntlm_free_unicode_string(&context->NbComputerName);
269 ntlm_free_unicode_string(&context->NbDomainName);
270 ntlm_free_unicode_string(&context->DnsComputerName);
271 ntlm_free_unicode_string(&context->DnsDomainName);
273 ntlm_free_messages(context);
276 memset(context->NtlmHash, 0,
sizeof(context->NtlmHash));
277 memset(context->NtlmV2Hash, 0,
sizeof(context->NtlmV2Hash));
278 memset(context->SessionBaseKey, 0,
sizeof(context->SessionBaseKey));
279 memset(context->KeyExchangeKey, 0,
sizeof(context->KeyExchangeKey));
280 memset(context->RandomSessionKey, 0,
sizeof(context->RandomSessionKey));
281 memset(context->ExportedSessionKey, 0,
sizeof(context->ExportedSessionKey));
282 memset(context->EncryptedRandomSessionKey, 0,
sizeof(context->EncryptedRandomSessionKey));
283 memset(context->NtProofString, 0,
sizeof(context->NtProofString));
289 WINPR_ATTR_UNUSED COMPUTER_NAME_FORMAT type)
292 ntlm_free_unicode_string(pName);
295 char* name = get_computer_name(ComputerNameNetBIOS, &len);
301 *pName = ntlm_from_unicode_string_utf8(name, len);
304 return !ntlm_is_unicode_string_empty(pName);
308static BOOL ntlm_ContextFillDefaultNames(
NTLM_CONTEXT* context)
310 WINPR_ASSERT(context);
312 if (ntlm_SetContextWorkstation(context,
nullptr) < 0)
315 if (ntlm_get_target_computer_name(&context->NbDomainName, ComputerNameNetBIOS) < 0)
318 if (ntlm_get_target_computer_name(&context->NbComputerName, ComputerNameNetBIOS) < 0)
321 if (ntlm_get_target_computer_name(&context->DnsDomainName, ComputerNameDnsDomain) < 0)
324 if (ntlm_get_target_computer_name(&context->DnsComputerName, ComputerNameDnsHostname) < 0)
330static BOOL ntlm_try_set_from_registry(HKEY hKey,
const char* key,
UNICODE_STRING* ustr)
337 WCHAR wkey[64] = WINPR_C_ARRAY_INIT;
338 const SSIZE_T res = ConvertUtf8ToWChar(key, wkey, ARRAYSIZE(wkey));
341 WINPR_ASSERT((
size_t)res < ARRAYSIZE(wkey));
345 if (RegQueryValueExW(hKey, wkey,
nullptr, &dwType,
nullptr, &dwSize) != ERROR_SUCCESS)
348 if ((dwSize > UINT16_MAX) || ((dwSize % 2) != 0))
351 str.Buffer = calloc(dwSize /
sizeof(WCHAR) + 1,
sizeof(WCHAR));
354 str.Length = WINPR_ASSERTING_INT_CAST(UINT16, dwSize);
355 str.MaximumLength = WINPR_ASSERTING_INT_CAST(UINT16, dwSize);
357 const LONG rc = RegQueryValueExW(hKey, wkey,
nullptr, &dwType, (BYTE*)str.Buffer, &dwSize);
358 if (rc != ERROR_SUCCESS)
360 ntlm_free_unicode_string(ustr);
365 ntlm_free_unicode_string(&str);
370static BOOL ntlm_ContextFromConfig(
NTLM_CONTEXT* context)
373 WINPR_ASSERT(context);
375 char* key = winpr_getApplicatonDetailsRegKey(WINPR_KEY);
381 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
384 if (status == ERROR_SUCCESS)
390 if (RegQueryValueEx(hKey, _T(
"NTLMv2"),
nullptr, &dwType, (BYTE*)&dwValue,
391 &dwSize) == ERROR_SUCCESS)
392 context->NTLMv2 = dwValue ? 1 : 0;
394 if (RegQueryValueEx(hKey, _T(
"UseMIC"),
nullptr, &dwType, (BYTE*)&dwValue,
395 &dwSize) == ERROR_SUCCESS)
396 context->UseMIC = dwValue ? 1 : 0;
398 if (RegQueryValueEx(hKey, _T(
"SendVersionInfo"),
nullptr, &dwType, (BYTE*)&dwValue,
399 &dwSize) == ERROR_SUCCESS)
400 context->SendVersionInfo = dwValue ? 1 : 0;
402 if (RegQueryValueEx(hKey, _T(
"SendSingleHostData"),
nullptr, &dwType,
403 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
404 context->SendSingleHostData = dwValue ? 1 : 0;
406 if (RegQueryValueEx(hKey, _T(
"SendWorkstationName"),
nullptr, &dwType,
407 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
408 context->SendWorkstationName = dwValue ? 1 : 0;
410 (void)ntlm_try_set_from_registry(hKey,
"WorkstationName", &context->Workstation);
411 (void)ntlm_try_set_from_registry(hKey,
"NbDomainName", &context->NbDomainName);
412 (void)ntlm_try_set_from_registry(hKey,
"NbComputerName", &context->NbComputerName);
413 (void)ntlm_try_set_from_registry(hKey,
"DnsDomainName", &context->DnsDomainName);
414 (void)ntlm_try_set_from_registry(hKey,
"DnsComputerName",
415 &context->DnsComputerName);
424 RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"System\\CurrentControlSet\\Control\\LSA"), 0,
425 KEY_READ | KEY_WOW64_64KEY, &hKey);
427 if (status == ERROR_SUCCESS)
432 if (RegQueryValueEx(hKey, _T(
"SuppressExtendedProtection"),
nullptr, &dwType,
433 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
434 context->SuppressExtendedProtection = dwValue ? 1 : 0;
443 context->SuppressExtendedProtection = FALSE;
447WINPR_ATTR_MALLOC(ntlm_ContextFree, 1)
455 context->NTLMv2 = TRUE;
456 context->UseMIC = FALSE;
457 context->SendVersionInfo = TRUE;
458 context->SendSingleHostData = FALSE;
459 context->SendWorkstationName = TRUE;
460 context->NegotiateKeyExchange = TRUE;
461 context->UseSamFileDatabase = TRUE;
463 context->NegotiateFlags = 0;
464 context->LmCompatibilityLevel = 3;
465 ntlm_change_state(context, NTLM_STATE_INITIAL);
466 FillMemory(context->MachineID,
sizeof(context->MachineID), 0xAA);
469 context->UseMIC = TRUE;
471 if (!ntlm_ContextFillDefaultNames(context))
473 if (!ntlm_ContextFromConfig(context))
479 ntlm_ContextFree(context);
484static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
485 WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
486 ULONG fCredentialUse, WINPR_ATTR_UNUSED
void* pvLogonID,
void* pAuthData,
487 SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
492 if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
493 (fCredentialUse != SECPKG_CRED_BOTH))
495 return SEC_E_INVALID_PARAMETER;
501 return SEC_E_INTERNAL_ERROR;
503 credentials->fCredentialUse = fCredentialUse;
504 credentials->pGetKeyFn = pGetKeyFn;
505 credentials->pvGetKeyArgument = pvGetKeyArgument;
509 UINT32 identityFlags = sspi_GetAuthIdentityFlags(pAuthData);
511 if (sspi_CopyAuthIdentity(&(credentials->identity),
514 sspi_CredentialsFree(credentials);
515 return SEC_E_INVALID_PARAMETER;
518 if (identityFlags & SEC_WINNT_AUTH_IDENTITY_EXTENDED)
527 if (!credentials->ntlmSettings.
samFile)
529 sspi_CredentialsFree(credentials);
530 return SEC_E_INSUFFICIENT_MEMORY;
537 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)credentials);
538 sspi_SecureHandleSetUpperPointer(phCredential, (
void*)NTLM_PACKAGE_NAME);
543static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
544 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
545 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
548 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
549 SEC_WCHAR* principal =
nullptr;
550 SEC_WCHAR*
package = nullptr;
554 principal = ConvertUtf8ToWCharAlloc(pszPrincipal,
nullptr);
560 package = ConvertUtf8ToWCharAlloc(pszPackage, nullptr);
566 ntlm_AcquireCredentialsHandleW(principal, package, fCredentialUse, pvLogonID, pAuthData,
567 pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
577static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
PCredHandle phCredential)
580 return SEC_E_INVALID_HANDLE;
584 sspi_SecureHandleInvalidate(phCredential);
586 return SEC_E_INVALID_HANDLE;
588 sspi_CredentialsFree(credentials);
593static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
594 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
595 WINPR_ATTR_UNUSED
void* pBuffer)
597 if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
602 WLog_ERR(TAG,
"TODO: Implement");
603 return SEC_E_UNSUPPORTED_FUNCTION;
607static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
PCredHandle phCredential,
608 ULONG ulAttribute,
void* pBuffer)
610 return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
617static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
620 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsTimeStamp)
622 SECURITY_STATUS status = 0;
628 if (phContext && !phContext->dwLower && !phContext->dwUpper)
629 return SEC_E_INVALID_HANDLE;
635 context = ntlm_ContextNew();
638 return SEC_E_INSUFFICIENT_MEMORY;
640 context->server = TRUE;
642 if (fContextReq & ASC_REQ_CONFIDENTIALITY)
643 context->confidentiality = TRUE;
645 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
646 context->credentials = credentials;
647 context->SamFile = credentials->ntlmSettings.
samFile;
648 context->HashCallback = credentials->ntlmSettings.
hashCallback;
651 if (!ntlm_SetContextTargetName(context,
nullptr))
652 return SEC_E_INVALID_HANDLE;
653 sspi_SecureHandleSetLowerPointer(phNewContext, context);
654 sspi_SecureHandleSetUpperPointer(phNewContext, (
void*)NTLM_PACKAGE_NAME);
657 switch (ntlm_get_state(context))
659 case NTLM_STATE_INITIAL:
661 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
664 return SEC_E_INVALID_TOKEN;
666 if (pInput->cBuffers < 1)
667 return SEC_E_INVALID_TOKEN;
669 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
672 return SEC_E_INVALID_TOKEN;
674 if (input_buffer->cbBuffer < 1)
675 return SEC_E_INVALID_TOKEN;
677 status = ntlm_read_NegotiateMessage(context, input_buffer);
678 if (status != SEC_I_CONTINUE_NEEDED)
681 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
684 return SEC_E_INVALID_TOKEN;
686 if (pOutput->cBuffers < 1)
687 return SEC_E_INVALID_TOKEN;
689 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
691 if (!output_buffer->BufferType)
692 return SEC_E_INVALID_TOKEN;
694 if (output_buffer->cbBuffer < 1)
695 return SEC_E_INSUFFICIENT_MEMORY;
697 return ntlm_write_ChallengeMessage(context, output_buffer);
700 return SEC_E_OUT_OF_SEQUENCE;
703 case NTLM_STATE_AUTHENTICATE:
706 return SEC_E_INVALID_TOKEN;
708 if (pInput->cBuffers < 1)
709 return SEC_E_INVALID_TOKEN;
711 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
714 return SEC_E_INVALID_TOKEN;
716 if (input_buffer->cbBuffer < 1)
717 return SEC_E_INVALID_TOKEN;
719 status = ntlm_read_AuthenticateMessage(context, input_buffer);
723 for (ULONG i = 0; i < pOutput->cBuffers; i++)
725 pOutput->pBuffers[i].cbBuffer = 0;
726 pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
734 return SEC_E_OUT_OF_SEQUENCE;
739static SECURITY_STATUS SEC_ENTRY
740ntlm_ImpersonateSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
746static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
748 WINPR_ATTR_UNUSED ULONG Reserved1, WINPR_ATTR_UNUSED ULONG TargetDataRep,
PSecBufferDesc pInput,
750 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsExpiry)
752 SECURITY_STATUS status = 0;
758 if (phContext && !phContext->dwLower && !phContext->dwUpper)
759 return SEC_E_INVALID_HANDLE;
765 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
770 context = ntlm_ContextNew();
773 return SEC_E_INSUFFICIENT_MEMORY;
775 if (fContextReq & ISC_REQ_CONFIDENTIALITY)
776 context->confidentiality = TRUE;
778 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
779 context->credentials = credentials;
781 if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
783 ntlm_ContextFree(context);
784 return SEC_E_INTERNAL_ERROR;
787 sspi_SecureHandleSetLowerPointer(phNewContext, context);
788 sspi_SecureHandleSetUpperPointer(phNewContext, NTLM_SSP_NAME);
791 if ((!input_buffer) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE))
794 return SEC_E_INVALID_TOKEN;
796 if (pOutput->cBuffers < 1)
797 return SEC_E_INVALID_TOKEN;
799 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
802 return SEC_E_INVALID_TOKEN;
804 if (output_buffer->cbBuffer < 1)
805 return SEC_E_INVALID_TOKEN;
807 if (ntlm_get_state(context) == NTLM_STATE_INITIAL)
808 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
810 if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE)
811 return ntlm_write_NegotiateMessage(context, output_buffer);
813 return SEC_E_OUT_OF_SEQUENCE;
818 return SEC_E_INVALID_TOKEN;
820 if (input_buffer->cbBuffer < 1)
821 return SEC_E_INVALID_TOKEN;
823 PSecBuffer channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
825 if (channel_bindings)
827 context->Bindings.BindingsLength = channel_bindings->cbBuffer;
831 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
833 status = ntlm_read_ChallengeMessage(context, input_buffer);
835 if (status != SEC_I_CONTINUE_NEEDED)
839 return SEC_E_INVALID_TOKEN;
841 if (pOutput->cBuffers < 1)
842 return SEC_E_INVALID_TOKEN;
844 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
847 return SEC_E_INVALID_TOKEN;
849 if (output_buffer->cbBuffer < 1)
850 return SEC_E_INSUFFICIENT_MEMORY;
852 if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)
853 return ntlm_write_AuthenticateMessage(context, output_buffer);
856 return SEC_E_OUT_OF_SEQUENCE;
859 return SEC_E_OUT_OF_SEQUENCE;
866static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
868 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
871 SECURITY_STATUS status = 0;
872 SEC_WCHAR* pszTargetNameW =
nullptr;
876 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName,
nullptr);
878 return SEC_E_INTERNAL_ERROR;
881 status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
882 Reserved1, TargetDataRep, pInput, Reserved2,
883 phNewContext, pOutput, pfContextAttr, ptsExpiry);
884 free(pszTargetNameW);
890static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(
PCtxtHandle phContext)
893 sspi_SecureHandleInvalidate(phContext);
894 ntlm_ContextFree(context);
900 BYTE* blob =
nullptr;
904 WINPR_ASSERT(ntproof);
906 target = &ntlm->ChallengeTargetInfo;
908 if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
909 return SEC_E_INSUFFICIENT_MEMORY;
911 blob = (BYTE*)ntproof->pvBuffer;
912 CopyMemory(blob, ntlm->ServerChallenge, 8);
916 CopyMemory(&blob[16], ntlm->Timestamp, 8);
917 CopyMemory(&blob[24], ntlm->ClientChallenge, 8);
920 CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
926 BYTE* blob =
nullptr;
930 WINPR_ASSERT(micvalue);
932 msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
933 ntlm->AuthenticateMessage.cbBuffer;
935 if (!sspi_SecBufferAlloc(micvalue, msgSize))
936 return SEC_E_INSUFFICIENT_MEMORY;
938 blob = (BYTE*)micvalue->pvBuffer;
939 CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
940 blob += ntlm->NegotiateMessage.cbBuffer;
941 CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
942 blob += ntlm->ChallengeMessage.cbBuffer;
943 CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
944 blob += ntlm->MessageIntegrityCheckOffset;
945 ZeroMemory(blob, 16);
950static bool identityToAuthIdentity(
const SEC_WINNT_AUTH_IDENTITY* identity,
953 WINPR_ASSERT(identity);
959 *pAuthIdentity = empty;
961 if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
963 if (identity->UserLength > 0)
965 if (ConvertWCharNToUtf8(identity->User, identity->UserLength, pAuthIdentity->User,
966 ARRAYSIZE(pAuthIdentity->User)) <= 0)
970 if (identity->DomainLength > 0)
972 if (ConvertWCharNToUtf8(identity->Domain, identity->DomainLength, pAuthIdentity->Domain,
973 ARRAYSIZE(pAuthIdentity->Domain)) <= 0)
977 else if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
979 if (identity->UserLength > 0)
981 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->User) - 1, identity->UserLength);
982 strncpy(pAuthIdentity->User, (
char*)identity->User, len);
983 pAuthIdentity->User[len] =
'\0';
986 if (identity->DomainLength > 0)
988 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->Domain) - 1, identity->DomainLength);
989 strncpy(pAuthIdentity->Domain, (
char*)identity->Domain, len);
990 pAuthIdentity->Domain[len] =
'\0';
999static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesCommon(
PCtxtHandle phContext,
1000 ULONG ulAttribute,
void* pBuffer)
1003 return SEC_E_INVALID_HANDLE;
1006 return SEC_E_INSUFFICIENT_MEMORY;
1009 if (!check_context(context))
1010 return SEC_E_INVALID_HANDLE;
1012 switch (ulAttribute)
1014 case SECPKG_ATTR_AUTH_IDENTITY:
1019 return SEC_E_INTERNAL_ERROR;
1020 if (!identityToAuthIdentity(&credentials->identity, AuthIdentity))
1021 return SEC_E_INTERNAL_ERROR;
1022 context->UseSamFileDatabase = FALSE;
1025 case SECPKG_ATTR_SIZES:
1028 ContextSizes->cbMaxToken = 2010;
1029 ContextSizes->cbMaxSignature = 16;
1030 ContextSizes->cbBlockSize = 0;
1031 ContextSizes->cbSecurityTrailer = 16;
1035 case SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE:
1036 return ntlm_computeProofValue(context, (
SecBuffer*)pBuffer);
1038 case SECPKG_ATTR_AUTH_NTLM_RANDKEY:
1042 if (!sspi_SecBufferAlloc(randkey, 16))
1043 return (SEC_E_INSUFFICIENT_MEMORY);
1045 CopyMemory(randkey->pvBuffer, context->EncryptedRandomSessionKey, 16);
1049 case SECPKG_ATTR_AUTH_NTLM_MIC:
1054 if (!sspi_SecBufferAlloc(mic, 16))
1055 return (SEC_E_INSUFFICIENT_MEMORY);
1057 CopyMemory(mic->pvBuffer, message->MessageIntegrityCheck, 16);
1061 case SECPKG_ATTR_AUTH_NTLM_MIC_VALUE:
1062 return ntlm_computeMicValue(context, (
SecBuffer*)pBuffer);
1065 WLog_ERR(TAG,
"TODO: Implement ulAttribute=0x%08" PRIx32, ulAttribute);
1066 return SEC_E_UNSUPPORTED_FUNCTION;
1072static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(
PCtxtHandle phContext,
1073 ULONG ulAttribute,
void* pBuffer)
1076 return SEC_E_INVALID_HANDLE;
1079 return SEC_E_INSUFFICIENT_MEMORY;
1082 if (!check_context(context))
1083 return SEC_E_INVALID_HANDLE;
1085 switch (ulAttribute)
1087 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1089 memcpy(pBuffer, context->Workstation.Buffer, context->Workstation.Length);
1092 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME:
1094 memcpy(pBuffer, context->NbDomainName.Buffer, context->NbDomainName.Length);
1097 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME:
1099 memcpy(pBuffer, context->NbComputerName.Buffer, context->NbComputerName.Length);
1102 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME:
1104 memcpy(pBuffer, context->DnsDomainName.Buffer, context->DnsDomainName.Length);
1107 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME:
1109 memcpy(pBuffer, context->DnsComputerName.Buffer, context->DnsComputerName.Length);
1113 case SECPKG_ATTR_PACKAGE_INFO:
1118 (
SecPkgInfoW*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1121 return SEC_E_INSUFFICIENT_MEMORY;
1123 pPackageInfo->fCapabilities = NTLM_SecPkgInfoW.fCapabilities;
1124 pPackageInfo->wVersion = NTLM_SecPkgInfoW.wVersion;
1125 pPackageInfo->wRPCID = NTLM_SecPkgInfoW.wRPCID;
1126 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoW.cbMaxToken;
1127 pPackageInfo->Name = _wcsdup(NTLM_SecPkgInfoW.Name);
1128 pPackageInfo->Comment = _wcsdup(NTLM_SecPkgInfoW.Comment);
1130 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1132 sspi_ContextBufferFree(pPackageInfo);
1133 return SEC_E_INSUFFICIENT_MEMORY;
1135 PackageInfo->PackageInfo = pPackageInfo;
1139 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1144static SECURITY_STATUS utf8len(
const UNICODE_STRING* str,
void* pBuffer)
1147 WINPR_ASSERT(pBuffer);
1148 ULONG* val = (ULONG*)pBuffer;
1149 const SSIZE_T rc = ConvertWCharNToUtf8(str->Buffer, str->Length,
nullptr, 0);
1151 return SEC_E_INVALID_PARAMETER;
1152 *val = WINPR_ASSERTING_INT_CAST(ULONG, rc);
1157static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(
PCtxtHandle phContext,
1158 ULONG ulAttribute,
void* pBuffer)
1161 return SEC_E_INVALID_HANDLE;
1164 return SEC_E_INSUFFICIENT_MEMORY;
1168 switch (ulAttribute)
1170 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME_LEN:
1171 return utf8len(&context->Workstation, pBuffer);
1172 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME_LEN:
1173 return utf8len(&context->NbDomainName, pBuffer);
1174 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME_LEN:
1175 return utf8len(&context->NbComputerName, pBuffer);
1176 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME_LEN:
1177 return utf8len(&context->DnsDomainName, pBuffer);
1178 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME_LEN:
1179 return utf8len(&context->DnsComputerName, pBuffer);
1180 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1182 ConvertWCharNToUtf8(context->Workstation.Buffer, context->Workstation.Length, pBuffer,
1183 context->Workstation.Length);
1186 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME:
1188 ConvertWCharNToUtf8(context->NbDomainName.Buffer, context->NbDomainName.Length, pBuffer,
1189 context->NbDomainName.Length);
1192 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME:
1194 ConvertWCharNToUtf8(context->NbComputerName.Buffer, context->NbComputerName.Length,
1195 pBuffer, context->NbComputerName.Length);
1198 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME:
1200 ConvertWCharNToUtf8(context->DnsDomainName.Buffer, context->DnsDomainName.Length,
1201 pBuffer, context->DnsDomainName.Length);
1204 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME:
1206 ConvertWCharNToUtf8(context->DnsComputerName.Buffer, context->DnsComputerName.Length,
1207 pBuffer, context->DnsComputerName.Length);
1210 case SECPKG_ATTR_PACKAGE_INFO:
1215 (
SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1218 return SEC_E_INSUFFICIENT_MEMORY;
1220 pPackageInfo->fCapabilities = NTLM_SecPkgInfoA.fCapabilities;
1221 pPackageInfo->wVersion = NTLM_SecPkgInfoA.wVersion;
1222 pPackageInfo->wRPCID = NTLM_SecPkgInfoA.wRPCID;
1223 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoA.cbMaxToken;
1224 pPackageInfo->Name = _strdup(NTLM_SecPkgInfoA.Name);
1225 pPackageInfo->Comment = _strdup(NTLM_SecPkgInfoA.Comment);
1227 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1229 sspi_ContextBufferFree(pPackageInfo);
1230 return SEC_E_INSUFFICIENT_MEMORY;
1232 PackageInfo->PackageInfo = pPackageInfo;
1237 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1242static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesCommon(
PCtxtHandle phContext,
1243 ULONG ulAttribute,
void* pBuffer,
1247 return SEC_E_INVALID_HANDLE;
1250 return SEC_E_INVALID_PARAMETER;
1254 return SEC_E_INVALID_HANDLE;
1256 switch (ulAttribute)
1258 case SECPKG_ATTR_AUTH_NTLM_HASH:
1263 return SEC_E_INVALID_PARAMETER;
1265 if (AuthNtlmHash->Version == 1)
1266 CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
1267 else if (AuthNtlmHash->Version == 2)
1268 CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
1273 case SECPKG_ATTR_AUTH_NTLM_MESSAGE:
1279 return SEC_E_INVALID_PARAMETER;
1281 if (AuthNtlmMessage->type == 1)
1283 if (!ntlm_SecBufferRealloc(&context->NegotiateMessage, AuthNtlmMessage->length))
1284 return SEC_E_INSUFFICIENT_MEMORY;
1286 CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer,
1287 AuthNtlmMessage->length);
1289 else if (AuthNtlmMessage->type == 2)
1291 if (!ntlm_SecBufferRealloc(&context->ChallengeMessage, AuthNtlmMessage->length))
1292 return SEC_E_INSUFFICIENT_MEMORY;
1294 CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer,
1295 AuthNtlmMessage->length);
1297 else if (AuthNtlmMessage->type == 3)
1299 if (!ntlm_SecBufferRealloc(&context->AuthenticateMessage, AuthNtlmMessage->length))
1300 return SEC_E_INSUFFICIENT_MEMORY;
1302 CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer,
1303 AuthNtlmMessage->length);
1309 case SECPKG_ATTR_AUTH_NTLM_TIMESTAMP:
1315 return SEC_E_INVALID_PARAMETER;
1317 if (AuthNtlmTimestamp->ChallengeOrResponse)
1318 CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
1320 CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
1325 case SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE:
1331 return SEC_E_INVALID_PARAMETER;
1333 CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
1337 case SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE:
1343 return SEC_E_INVALID_PARAMETER;
1345 CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
1350 WLog_ERR(TAG,
"TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
1351 return SEC_E_UNSUPPORTED_FUNCTION;
1356static SECURITY_STATUS ntml_setUnicodeStringW(
UNICODE_STRING* str,
const WCHAR* val,
size_t bytelen)
1359 ntlm_free_unicode_string(str);
1360 *str = ntlm_from_unicode_string_w(val, bytelen /
sizeof(WCHAR));
1361 if (ntlm_is_unicode_string_empty(str))
1362 return SEC_E_INVALID_PARAMETER;
1367static SECURITY_STATUS utf16len(
const UNICODE_STRING* str,
void* pBuffer)
1370 WINPR_ASSERT(pBuffer);
1371 ULONG* val = (ULONG*)pBuffer;
1377static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(
PCtxtHandle phContext,
1378 ULONG ulAttribute,
void* pBuffer,
1382 return SEC_E_INVALID_HANDLE;
1385 return SEC_E_INVALID_PARAMETER;
1389 return SEC_E_INVALID_HANDLE;
1391 switch (ulAttribute)
1393 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME_LEN:
1394 return utf16len(&context->Workstation, pBuffer);
1395 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME_LEN:
1396 return utf16len(&context->NbDomainName, pBuffer);
1397 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME_LEN:
1398 return utf16len(&context->NbComputerName, pBuffer);
1399 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME_LEN:
1400 return utf16len(&context->DnsDomainName, pBuffer);
1401 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME_LEN:
1402 return utf16len(&context->DnsComputerName, pBuffer);
1403 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1404 return ntml_setUnicodeStringW(&context->Workstation, pBuffer, cbBuffer);
1405 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME:
1406 return ntml_setUnicodeStringW(&context->NbDomainName, pBuffer, cbBuffer);
1407 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME:
1408 return ntml_setUnicodeStringW(&context->NbComputerName, pBuffer, cbBuffer);
1409 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME:
1410 return ntml_setUnicodeStringW(&context->DnsDomainName, pBuffer, cbBuffer);
1411 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME:
1412 return ntml_setUnicodeStringW(&context->DnsComputerName, pBuffer, cbBuffer);
1415 return ntlm_SetContextAttributesCommon(phContext, ulAttribute, pBuffer, cbBuffer);
1420static SECURITY_STATUS ntml_setUnicodeStringA(
UNICODE_STRING* str,
const char* val,
size_t charlen)
1423 ntlm_free_unicode_string(str);
1424 *str = ntlm_from_unicode_string_utf8(val, charlen);
1425 if (ntlm_is_unicode_string_empty(str))
1426 return SEC_E_INVALID_PARAMETER;
1431static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(
PCtxtHandle phContext,
1432 ULONG ulAttribute,
void* pBuffer,
1436 return SEC_E_INVALID_HANDLE;
1439 return SEC_E_INVALID_PARAMETER;
1443 return SEC_E_INVALID_HANDLE;
1445 switch (ulAttribute)
1447 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1448 return ntml_setUnicodeStringA(&context->Workstation, pBuffer, cbBuffer);
1449 case SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME:
1450 return ntml_setUnicodeStringA(&context->NbDomainName, pBuffer, cbBuffer);
1451 case SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME:
1452 return ntml_setUnicodeStringA(&context->NbComputerName, pBuffer, cbBuffer);
1453 case SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME:
1454 return ntml_setUnicodeStringA(&context->DnsDomainName, pBuffer, cbBuffer);
1455 case SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME:
1456 return ntml_setUnicodeStringA(&context->DnsComputerName, pBuffer, cbBuffer);
1458 return ntlm_SetContextAttributesCommon(phContext, ulAttribute, pBuffer, cbBuffer);
1463static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesW(
1464 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1465 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1467 return SEC_E_UNSUPPORTED_FUNCTION;
1471static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesA(
1472 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1473 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1475 return SEC_E_UNSUPPORTED_FUNCTION;
1479static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
1485static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(
PCtxtHandle phContext,
1486 WINPR_ATTR_UNUSED ULONG fQOP,
1489 const UINT32 SeqNo = MessageSeqNo;
1491 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1492 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1497 if (!check_context(context))
1498 return SEC_E_INVALID_HANDLE;
1500 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1502 SecBuffer* cur = &pMessage->pBuffers[index];
1504 if (cur->BufferType & SECBUFFER_DATA)
1506 else if (cur->BufferType & SECBUFFER_TOKEN)
1507 signature_buffer = cur;
1511 return SEC_E_INVALID_TOKEN;
1513 if (!signature_buffer)
1514 return SEC_E_INVALID_TOKEN;
1517 ULONG length = data_buffer->cbBuffer;
1518 void* data = malloc(length);
1521 return SEC_E_INSUFFICIENT_MEMORY;
1523 CopyMemory(data, data_buffer->pvBuffer, length);
1525 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1527 BOOL success = FALSE;
1531 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1534 winpr_Data_Write_UINT32(&value, SeqNo);
1536 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1538 if (!winpr_HMAC_Update(hmac, data, length))
1540 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1547 winpr_HMAC_Free(hmac);
1551 return SEC_E_INSUFFICIENT_MEMORY;
1555 if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
1557 if (context->confidentiality)
1559 if (!winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
1560 (BYTE*)data_buffer->pvBuffer))
1563 return SEC_E_INSUFFICIENT_MEMORY;
1567 CopyMemory(data_buffer->pvBuffer, data, length);
1570#ifdef WITH_DEBUG_NTLM
1571 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", length);
1572 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1573 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1574 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1578 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1579 return SEC_E_INSUFFICIENT_MEMORY;
1580 if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
1582 BYTE* signature = signature_buffer->pvBuffer;
1584 winpr_Data_Write_UINT32(signature, version);
1585 CopyMemory(&signature[4], (
void*)checksum, 8);
1586 winpr_Data_Write_UINT32(&signature[12], SeqNo);
1588 context->SendSeqNum++;
1589#ifdef WITH_DEBUG_NTLM
1590 WLog_DBG(TAG,
"Signature (length = %" PRIu32
")", signature_buffer->cbBuffer);
1591 winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer);
1598 WINPR_ATTR_UNUSED PULONG pfQOP)
1600 const UINT32 SeqNo = (UINT32)MessageSeqNo;
1602 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1603 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1605 BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1609 if (!check_context(context))
1610 return SEC_E_INVALID_HANDLE;
1612 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1614 if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
1615 data_buffer = &pMessage->pBuffers[index];
1616 else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
1617 signature_buffer = &pMessage->pBuffers[index];
1621 return SEC_E_INVALID_TOKEN;
1623 if (!signature_buffer)
1624 return SEC_E_INVALID_TOKEN;
1627 const ULONG length = data_buffer->cbBuffer;
1628 void* data = malloc(length);
1631 return SEC_E_INSUFFICIENT_MEMORY;
1633 CopyMemory(data, data_buffer->pvBuffer, length);
1637 if (context->confidentiality)
1639 if (!winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*)data,
1640 (BYTE*)data_buffer->pvBuffer))
1643 return SEC_E_INSUFFICIENT_MEMORY;
1647 CopyMemory(data_buffer->pvBuffer, data, length);
1650 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1652 BOOL success = FALSE;
1657 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1660 winpr_Data_Write_UINT32(&value, SeqNo);
1662 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1664 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1666 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1672 winpr_HMAC_Free(hmac);
1676 return SEC_E_INSUFFICIENT_MEMORY;
1679#ifdef WITH_DEBUG_NTLM
1680 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", length);
1681 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1682 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1683 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1687 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1688 return SEC_E_MESSAGE_ALTERED;
1691 winpr_Data_Write_UINT32(expected_signature, version);
1692 CopyMemory(&expected_signature[4], (
void*)checksum, 8);
1693 winpr_Data_Write_UINT32(&expected_signature[12], SeqNo);
1694 context->RecvSeqNum++;
1696 if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
1699 WLog_ERR(TAG,
"signature verification failed, something nasty is going on!");
1700#ifdef WITH_DEBUG_NTLM
1701 WLog_ERR(TAG,
"Expected Signature:");
1702 winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16);
1703 WLog_ERR(TAG,
"Actual Signature:");
1704 winpr_HexDump(TAG, WLOG_ERROR, (BYTE*)signature_buffer->pvBuffer, 16);
1706 return SEC_E_MESSAGE_ALTERED;
1712static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(
PCtxtHandle phContext,
1713 WINPR_ATTR_UNUSED ULONG fQOP,
1716 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1720 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1721 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1723 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1724 if (!check_context(context))
1725 return SEC_E_INVALID_HANDLE;
1727 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1729 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1730 data_buffer = &pMessage->pBuffers[i];
1731 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1732 sig_buffer = &pMessage->pBuffers[i];
1735 if (!data_buffer || !sig_buffer)
1736 return SEC_E_INVALID_TOKEN;
1738 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1740 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1743 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1744 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1746 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1748 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1751 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1754 BYTE* signature = sig_buffer->pvBuffer;
1755 winpr_Data_Write_UINT32(signature, 1L);
1756 CopyMemory(&signature[4], checksum, 8);
1757 winpr_Data_Write_UINT32(&signature[12], seq_no);
1758 sig_buffer->cbBuffer = 16;
1763 winpr_HMAC_Free(hmac);
1768static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(
PCtxtHandle phContext,
1770 WINPR_ATTR_UNUSED PULONG pfQOP)
1772 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1776 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1777 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1778 BYTE signature[16] = WINPR_C_ARRAY_INIT;
1780 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1781 if (!check_context(context))
1782 return SEC_E_INVALID_HANDLE;
1784 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1786 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1787 data_buffer = &pMessage->pBuffers[i];
1788 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1789 sig_buffer = &pMessage->pBuffers[i];
1792 if (!data_buffer || !sig_buffer)
1793 return SEC_E_INVALID_TOKEN;
1795 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1797 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1800 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1801 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1803 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1805 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1808 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1811 winpr_Data_Write_UINT32(signature, 1L);
1812 CopyMemory(&signature[4], checksum, 8);
1813 winpr_Data_Write_UINT32(&signature[12], seq_no);
1816 if (memcmp(sig_buffer->pvBuffer, signature, 16) != 0)
1817 status = SEC_E_MESSAGE_ALTERED;
1820 winpr_HMAC_Free(hmac);
1827 ntlm_QueryCredentialsAttributesA,
1828 ntlm_AcquireCredentialsHandleA,
1829 ntlm_FreeCredentialsHandle,
1831 ntlm_InitializeSecurityContextA,
1832 ntlm_AcceptSecurityContext,
1834 ntlm_DeleteSecurityContext,
1836 ntlm_QueryContextAttributesA,
1837 ntlm_ImpersonateSecurityContext,
1838 ntlm_RevertSecurityContext,
1840 ntlm_VerifySignature,
1850 ntlm_EncryptMessage,
1851 ntlm_DecryptMessage,
1852 ntlm_SetContextAttributesA,
1853 ntlm_SetCredentialsAttributesA,
1859 ntlm_QueryCredentialsAttributesW,
1860 ntlm_AcquireCredentialsHandleW,
1861 ntlm_FreeCredentialsHandle,
1863 ntlm_InitializeSecurityContextW,
1864 ntlm_AcceptSecurityContext,
1866 ntlm_DeleteSecurityContext,
1868 ntlm_QueryContextAttributesW,
1869 ntlm_ImpersonateSecurityContext,
1870 ntlm_RevertSecurityContext,
1872 ntlm_VerifySignature,
1882 ntlm_EncryptMessage,
1883 ntlm_DecryptMessage,
1884 ntlm_SetContextAttributesW,
1885 ntlm_SetCredentialsAttributesW,
1894 "NTLM Security Package"
1897static WCHAR NTLM_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
1898static WCHAR NTLM_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
1905 NTLM_SecPkgInfoW_NameBuffer,
1906 NTLM_SecPkgInfoW_CommentBuffer
1909char* ntlm_negotiate_flags_string(
char* buffer,
size_t size, UINT32 flags)
1911 if (!buffer || (size == 0))
1914 (void)_snprintf(buffer, size,
"[0x%08" PRIx32
"] ", flags);
1916 for (
int x = 0; x < 31; x++)
1918 const UINT32 mask = 1u << x;
1919 size_t len = strnlen(buffer, size);
1922 const char* str = ntlm_get_negotiate_string(mask);
1923 const size_t flen = strlen(str);
1925 if ((len > 0) && (buffer[len - 1] !=
' '))
1929 winpr_str_append(
"|", buffer, size,
nullptr);
1933 if (size - len < flen)
1935 winpr_str_append(str, buffer, size,
nullptr);
1942const char* ntlm_message_type_string(UINT32 messageType)
1944 switch (messageType)
1946 case MESSAGE_TYPE_NEGOTIATE:
1947 return "MESSAGE_TYPE_NEGOTIATE";
1948 case MESSAGE_TYPE_CHALLENGE:
1949 return "MESSAGE_TYPE_CHALLENGE";
1950 case MESSAGE_TYPE_AUTHENTICATE:
1951 return "MESSAGE_TYPE_AUTHENTICATE";
1953 return "MESSAGE_TYPE_UNKNOWN";
1957const char* ntlm_state_string(NTLM_STATE state)
1961 case NTLM_STATE_INITIAL:
1962 return "NTLM_STATE_INITIAL";
1963 case NTLM_STATE_NEGOTIATE:
1964 return "NTLM_STATE_NEGOTIATE";
1965 case NTLM_STATE_CHALLENGE:
1966 return "NTLM_STATE_CHALLENGE";
1967 case NTLM_STATE_AUTHENTICATE:
1968 return "NTLM_STATE_AUTHENTICATE";
1969 case NTLM_STATE_FINAL:
1970 return "NTLM_STATE_FINAL";
1972 return "NTLM_STATE_UNKNOWN";
1975void ntlm_change_state(
NTLM_CONTEXT* ntlm, NTLM_STATE state)
1978 WLog_DBG(TAG,
"change state from %s to %s", ntlm_state_string(ntlm->state),
1979 ntlm_state_string(state));
1980 ntlm->state = state;
1989BOOL ntlm_reset_cipher_state(
PSecHandle phContext)
1991 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1995 if (!check_context(context))
1998 winpr_RC4_Free(context->SendRc4Seal);
1999 winpr_RC4_Free(context->RecvRc4Seal);
2000 context->SendRc4Seal = winpr_RC4_New(context->RecvSealingKey, 16);
2001 context->RecvRc4Seal = winpr_RC4_New(context->SendSealingKey, 16);
2003 if (!context->SendRc4Seal)
2005 WLog_ERR(TAG,
"Failed to allocate context->SendRc4Seal");
2008 if (!context->RecvRc4Seal)
2010 WLog_ERR(TAG,
"Failed to allocate context->RecvRc4Seal");
2020 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Name, NTLM_SecPkgInfoW_NameBuffer,
2021 ARRAYSIZE(NTLM_SecPkgInfoW_NameBuffer));
2022 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Comment, NTLM_SecPkgInfoW_CommentBuffer,
2023 ARRAYSIZE(NTLM_SecPkgInfoW_CommentBuffer));
2028BOOL ntlm_SecBufferRealloc(
SecBuffer* buffer, ULONG len)
2030 sspi_SecBufferFree(buffer);
2031 return sspi_SecBufferAlloc(buffer, len) !=
nullptr;
WINPR_ATTR_NODISCARD psSspiNtlmHashCallback hashCallback