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__)
53static BOOL check_context_(
NTLM_CONTEXT* context,
const char* file,
const char* fkt,
size_t line)
56 wLog* log = WLog_Get(TAG);
57 const DWORD log_level = WLOG_ERROR;
61 if (WLog_IsLevelActive(log, log_level))
62 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context");
67 if (!context->RecvRc4Seal)
69 if (WLog_IsLevelActive(log, log_level))
70 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->RecvRc4Seal");
73 if (!context->SendRc4Seal)
75 if (WLog_IsLevelActive(log, log_level))
76 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"invalid context->SendRc4Seal");
80 if (!context->SendSigningKey)
82 if (WLog_IsLevelActive(log, log_level))
83 WLog_PrintTextMessage(log, log_level, line, file, fkt,
84 "invalid context->SendSigningKey");
87 if (!context->RecvSigningKey)
89 if (WLog_IsLevelActive(log, log_level))
90 WLog_PrintTextMessage(log, log_level, line, file, fkt,
91 "invalid context->RecvSigningKey");
94 if (!context->SendSealingKey)
96 if (WLog_IsLevelActive(log, log_level))
97 WLog_PrintTextMessage(log, log_level, line, file, fkt,
98 "invalid context->SendSealingKey");
101 if (!context->RecvSealingKey)
103 if (WLog_IsLevelActive(log, log_level))
104 WLog_PrintTextMessage(log, log_level, line, file, fkt,
105 "invalid context->RecvSealingKey");
111char* get_computer_name(COMPUTER_NAME_FORMAT type,
size_t* pSize)
118 if (GetComputerNameExA(type,
nullptr, &nSize))
121 if (GetLastError() != ERROR_MORE_DATA)
124 char* computerName = calloc(1, nSize);
129 if (!GetComputerNameExA(type, computerName, &nSize))
140static void ntlm_FreeContextWorkstation(
NTLM_CONTEXT* context)
142 WINPR_ASSERT(context);
144 free(context->Workstation.Buffer);
145 context->Workstation.Buffer =
nullptr;
146 context->Workstation.Length = 0;
149SECURITY_STATUS ntlm_SetContextWorkstationX(
NTLM_CONTEXT* context, BOOL unicode,
const void* data,
152 ntlm_FreeContextWorkstation(context);
160 if (length > UINT16_MAX)
161 return SEC_E_INVALID_PARAMETER;
163 context->Workstation.Buffer = calloc(length +
sizeof(WCHAR), 1);
164 if (!context->Workstation.Buffer)
165 return SEC_E_INSUFFICIENT_MEMORY;
166 memcpy(context->Workstation.Buffer, data, length);
167 context->Workstation.Length = WINPR_ASSERTING_INT_CAST(USHORT, length);
172 void* ptr = ConvertUtf8NToWCharAlloc(data, length, &s);
174 return SEC_E_INSUFFICIENT_MEMORY;
180 return SEC_E_INVALID_PARAMETER;
182 context->Workstation.Buffer = ptr;
183 context->Workstation.Length = WINPR_ASSERTING_INT_CAST(USHORT, s);
188static int ntlm_SetContextWorkstation(
NTLM_CONTEXT* context,
const char* Workstation)
190 const char* ws = Workstation;
191 CHAR* computerName =
nullptr;
195 computerName = get_computer_name(ComputerNameNetBIOS,
nullptr);
201 const size_t len = strlen(ws);
202 const SECURITY_STATUS status = ntlm_SetContextWorkstationX(context, FALSE, ws, len);
205 return (status == SEC_E_OK) ? 1 : -1;
208static int ntlm_SetContextServicePrincipalNameW(
NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
210 WINPR_ASSERT(context);
212 if (!ServicePrincipalName)
214 context->ServicePrincipalName.Buffer =
nullptr;
215 context->ServicePrincipalName.Length = 0;
219 context->ServicePrincipalName.Length = (USHORT)(_wcslen(ServicePrincipalName) * 2);
220 context->ServicePrincipalName.Buffer = (PWSTR)malloc(context->ServicePrincipalName.Length + 2);
222 if (!context->ServicePrincipalName.Buffer)
225 memcpy(context->ServicePrincipalName.Buffer, ServicePrincipalName,
226 context->ServicePrincipalName.Length + 2);
230static int ntlm_SetContextTargetName(
NTLM_CONTEXT* context,
char* TargetName)
232 char* name = TargetName;
233 WINPR_ASSERT(context);
238 char* computerName = get_computer_name(ComputerNameNetBIOS, &nSize);
243 if (nSize > MAX_COMPUTERNAME_LENGTH)
244 computerName[MAX_COMPUTERNAME_LENGTH] =
'\0';
255 context->TargetName.pvBuffer = ConvertUtf8ToWCharAlloc(name, &len);
257 if (!context->TargetName.pvBuffer || (len > UINT16_MAX /
sizeof(WCHAR)))
259 free(context->TargetName.pvBuffer);
260 context->TargetName.pvBuffer =
nullptr;
268 context->TargetName.cbBuffer = (USHORT)(len *
sizeof(WCHAR));
287 context->NTLMv2 = TRUE;
288 context->UseMIC = FALSE;
289 context->SendVersionInfo = TRUE;
290 context->SendSingleHostData = FALSE;
291 context->SendWorkstationName = TRUE;
292 context->NegotiateKeyExchange = TRUE;
293 context->UseSamFileDatabase = TRUE;
296 char* key = winpr_getApplicatonDetailsRegKey(WINPR_KEY);
300 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
303 if (status == ERROR_SUCCESS)
305 if (RegQueryValueEx(hKey, _T(
"NTLMv2"),
nullptr, &dwType, (BYTE*)&dwValue,
306 &dwSize) == ERROR_SUCCESS)
307 context->NTLMv2 = dwValue ? 1 : 0;
309 if (RegQueryValueEx(hKey, _T(
"UseMIC"),
nullptr, &dwType, (BYTE*)&dwValue,
310 &dwSize) == ERROR_SUCCESS)
311 context->UseMIC = dwValue ? 1 : 0;
313 if (RegQueryValueEx(hKey, _T(
"SendVersionInfo"),
nullptr, &dwType, (BYTE*)&dwValue,
314 &dwSize) == ERROR_SUCCESS)
315 context->SendVersionInfo = dwValue ? 1 : 0;
317 if (RegQueryValueEx(hKey, _T(
"SendSingleHostData"),
nullptr, &dwType,
318 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
319 context->SendSingleHostData = dwValue ? 1 : 0;
321 if (RegQueryValueEx(hKey, _T(
"SendWorkstationName"),
nullptr, &dwType,
322 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
323 context->SendWorkstationName = dwValue ? 1 : 0;
325 if (RegQueryValueEx(hKey, _T(
"WorkstationName"),
nullptr, &dwType,
nullptr,
326 &dwSize) == ERROR_SUCCESS)
328 char* workstation = (
char*)malloc(dwSize + 1);
336 const LONG rc = RegQueryValueExA(hKey,
"WorkstationName",
nullptr, &dwType,
337 (BYTE*)workstation, &dwSize);
338 if (rc != ERROR_SUCCESS)
339 WLog_WARN(TAG,
"Key ''WorkstationName' not found");
340 workstation[dwSize] =
'\0';
342 if (ntlm_SetContextWorkstation(context, workstation) < 0)
361 context->SuppressExtendedProtection = FALSE;
363 RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(
"System\\CurrentControlSet\\Control\\LSA"), 0,
364 KEY_READ | KEY_WOW64_64KEY, &hKey);
366 if (status == ERROR_SUCCESS)
368 if (RegQueryValueEx(hKey, _T(
"SuppressExtendedProtection"),
nullptr, &dwType,
369 (BYTE*)&dwValue, &dwSize) == ERROR_SUCCESS)
370 context->SuppressExtendedProtection = dwValue ? 1 : 0;
375 context->NegotiateFlags = 0;
376 context->LmCompatibilityLevel = 3;
377 ntlm_change_state(context, NTLM_STATE_INITIAL);
378 FillMemory(context->MachineID,
sizeof(context->MachineID), 0xAA);
381 context->UseMIC = TRUE;
391 winpr_RC4_Free(context->SendRc4Seal);
392 winpr_RC4_Free(context->RecvRc4Seal);
393 sspi_SecBufferFree(&context->NegotiateMessage);
394 sspi_SecBufferFree(&context->ChallengeMessage);
395 sspi_SecBufferFree(&context->AuthenticateMessage);
396 sspi_SecBufferFree(&context->ChallengeTargetInfo);
397 sspi_SecBufferFree(&context->TargetName);
398 sspi_SecBufferFree(&context->NtChallengeResponse);
399 sspi_SecBufferFree(&context->LmChallengeResponse);
400 free(context->ServicePrincipalName.Buffer);
401 ntlm_FreeContextWorkstation(context);
404 memset(context->NtlmHash, 0,
sizeof(context->NtlmHash));
405 memset(context->NtlmV2Hash, 0,
sizeof(context->NtlmV2Hash));
406 memset(context->SessionBaseKey, 0,
sizeof(context->SessionBaseKey));
407 memset(context->KeyExchangeKey, 0,
sizeof(context->KeyExchangeKey));
408 memset(context->RandomSessionKey, 0,
sizeof(context->RandomSessionKey));
409 memset(context->ExportedSessionKey, 0,
sizeof(context->ExportedSessionKey));
410 memset(context->EncryptedRandomSessionKey, 0,
sizeof(context->EncryptedRandomSessionKey));
411 memset(context->NtProofString, 0,
sizeof(context->NtProofString));
415static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
416 WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
417 ULONG fCredentialUse, WINPR_ATTR_UNUSED
void* pvLogonID,
void* pAuthData,
418 SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
423 if ((fCredentialUse != SECPKG_CRED_OUTBOUND) && (fCredentialUse != SECPKG_CRED_INBOUND) &&
424 (fCredentialUse != SECPKG_CRED_BOTH))
426 return SEC_E_INVALID_PARAMETER;
432 return SEC_E_INTERNAL_ERROR;
434 credentials->fCredentialUse = fCredentialUse;
435 credentials->pGetKeyFn = pGetKeyFn;
436 credentials->pvGetKeyArgument = pvGetKeyArgument;
440 UINT32 identityFlags = sspi_GetAuthIdentityFlags(pAuthData);
442 if (sspi_CopyAuthIdentity(&(credentials->identity),
445 sspi_CredentialsFree(credentials);
446 return SEC_E_INVALID_PARAMETER;
449 if (identityFlags & SEC_WINNT_AUTH_IDENTITY_EXTENDED)
458 if (!credentials->ntlmSettings.
samFile)
460 sspi_CredentialsFree(credentials);
461 return SEC_E_INSUFFICIENT_MEMORY;
468 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)credentials);
469 sspi_SecureHandleSetUpperPointer(phCredential, (
void*)NTLM_PACKAGE_NAME);
473static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(
474 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
475 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
478 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
479 SEC_WCHAR* principal =
nullptr;
480 SEC_WCHAR*
package = nullptr;
484 principal = ConvertUtf8ToWCharAlloc(pszPrincipal,
nullptr);
490 package = ConvertUtf8ToWCharAlloc(pszPackage, nullptr);
496 ntlm_AcquireCredentialsHandleW(principal, package, fCredentialUse, pvLogonID, pAuthData,
497 pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
506static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(
PCredHandle phCredential)
509 return SEC_E_INVALID_HANDLE;
513 sspi_SecureHandleInvalidate(phCredential);
515 return SEC_E_INVALID_HANDLE;
517 sspi_CredentialsFree(credentials);
521static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
522 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
523 WINPR_ATTR_UNUSED
void* pBuffer)
525 if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
530 WLog_ERR(TAG,
"TODO: Implement");
531 return SEC_E_UNSUPPORTED_FUNCTION;
534static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA(
PCredHandle phCredential,
535 ULONG ulAttribute,
void* pBuffer)
537 return ntlm_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
543static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(
546 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsTimeStamp)
548 SECURITY_STATUS status = 0;
554 if (phContext && !phContext->dwLower && !phContext->dwUpper)
555 return SEC_E_INVALID_HANDLE;
561 context = ntlm_ContextNew();
564 return SEC_E_INSUFFICIENT_MEMORY;
566 context->server = TRUE;
568 if (fContextReq & ASC_REQ_CONFIDENTIALITY)
569 context->confidentiality = TRUE;
571 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
572 context->credentials = credentials;
573 context->SamFile = credentials->ntlmSettings.
samFile;
574 context->HashCallback = credentials->ntlmSettings.
hashCallback;
577 ntlm_SetContextTargetName(context,
nullptr);
578 sspi_SecureHandleSetLowerPointer(phNewContext, context);
579 sspi_SecureHandleSetUpperPointer(phNewContext, (
void*)NTLM_PACKAGE_NAME);
582 switch (ntlm_get_state(context))
584 case NTLM_STATE_INITIAL:
586 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
589 return SEC_E_INVALID_TOKEN;
591 if (pInput->cBuffers < 1)
592 return SEC_E_INVALID_TOKEN;
594 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
597 return SEC_E_INVALID_TOKEN;
599 if (input_buffer->cbBuffer < 1)
600 return SEC_E_INVALID_TOKEN;
602 status = ntlm_read_NegotiateMessage(context, input_buffer);
603 if (status != SEC_I_CONTINUE_NEEDED)
606 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
609 return SEC_E_INVALID_TOKEN;
611 if (pOutput->cBuffers < 1)
612 return SEC_E_INVALID_TOKEN;
614 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
616 if (!output_buffer->BufferType)
617 return SEC_E_INVALID_TOKEN;
619 if (output_buffer->cbBuffer < 1)
620 return SEC_E_INSUFFICIENT_MEMORY;
622 return ntlm_write_ChallengeMessage(context, output_buffer);
625 return SEC_E_OUT_OF_SEQUENCE;
628 case NTLM_STATE_AUTHENTICATE:
631 return SEC_E_INVALID_TOKEN;
633 if (pInput->cBuffers < 1)
634 return SEC_E_INVALID_TOKEN;
636 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
639 return SEC_E_INVALID_TOKEN;
641 if (input_buffer->cbBuffer < 1)
642 return SEC_E_INVALID_TOKEN;
644 status = ntlm_read_AuthenticateMessage(context, input_buffer);
648 for (ULONG i = 0; i < pOutput->cBuffers; i++)
650 pOutput->pBuffers[i].cbBuffer = 0;
651 pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
659 return SEC_E_OUT_OF_SEQUENCE;
663static SECURITY_STATUS SEC_ENTRY
664ntlm_ImpersonateSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
669static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
671 WINPR_ATTR_UNUSED ULONG Reserved1, WINPR_ATTR_UNUSED ULONG TargetDataRep,
PSecBufferDesc pInput,
673 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsExpiry)
675 SECURITY_STATUS status = 0;
681 if (phContext && !phContext->dwLower && !phContext->dwUpper)
682 return SEC_E_INVALID_HANDLE;
688 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
693 context = ntlm_ContextNew();
696 return SEC_E_INSUFFICIENT_MEMORY;
698 if (fContextReq & ISC_REQ_CONFIDENTIALITY)
699 context->confidentiality = TRUE;
701 credentials = (
SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
702 context->credentials = credentials;
704 if (context->Workstation.Length < 1)
706 if (ntlm_SetContextWorkstation(context,
nullptr) < 0)
708 ntlm_ContextFree(context);
709 return SEC_E_INTERNAL_ERROR;
713 if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
715 ntlm_ContextFree(context);
716 return SEC_E_INTERNAL_ERROR;
719 sspi_SecureHandleSetLowerPointer(phNewContext, context);
720 sspi_SecureHandleSetUpperPointer(phNewContext, NTLM_SSP_NAME);
723 if ((!input_buffer) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE))
726 return SEC_E_INVALID_TOKEN;
728 if (pOutput->cBuffers < 1)
729 return SEC_E_INVALID_TOKEN;
731 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
734 return SEC_E_INVALID_TOKEN;
736 if (output_buffer->cbBuffer < 1)
737 return SEC_E_INVALID_TOKEN;
739 if (ntlm_get_state(context) == NTLM_STATE_INITIAL)
740 ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
742 if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE)
743 return ntlm_write_NegotiateMessage(context, output_buffer);
745 return SEC_E_OUT_OF_SEQUENCE;
750 return SEC_E_INVALID_TOKEN;
752 if (input_buffer->cbBuffer < 1)
753 return SEC_E_INVALID_TOKEN;
755 PSecBuffer channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
757 if (channel_bindings)
759 context->Bindings.BindingsLength = channel_bindings->cbBuffer;
763 if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
765 status = ntlm_read_ChallengeMessage(context, input_buffer);
767 if (status != SEC_I_CONTINUE_NEEDED)
771 return SEC_E_INVALID_TOKEN;
773 if (pOutput->cBuffers < 1)
774 return SEC_E_INVALID_TOKEN;
776 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
779 return SEC_E_INVALID_TOKEN;
781 if (output_buffer->cbBuffer < 1)
782 return SEC_E_INSUFFICIENT_MEMORY;
784 if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)
785 return ntlm_write_AuthenticateMessage(context, output_buffer);
788 return SEC_E_OUT_OF_SEQUENCE;
791 return SEC_E_OUT_OF_SEQUENCE;
797static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(
799 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
802 SECURITY_STATUS status = 0;
803 SEC_WCHAR* pszTargetNameW =
nullptr;
807 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName,
nullptr);
809 return SEC_E_INTERNAL_ERROR;
812 status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
813 Reserved1, TargetDataRep, pInput, Reserved2,
814 phNewContext, pOutput, pfContextAttr, ptsExpiry);
815 free(pszTargetNameW);
821static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(
PCtxtHandle phContext)
824 sspi_SecureHandleInvalidate(phContext);
825 ntlm_ContextFree(context);
831 BYTE* blob =
nullptr;
835 WINPR_ASSERT(ntproof);
837 target = &ntlm->ChallengeTargetInfo;
839 if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
840 return SEC_E_INSUFFICIENT_MEMORY;
842 blob = (BYTE*)ntproof->pvBuffer;
843 CopyMemory(blob, ntlm->ServerChallenge, 8);
847 CopyMemory(&blob[16], ntlm->Timestamp, 8);
848 CopyMemory(&blob[24], ntlm->ClientChallenge, 8);
851 CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
857 BYTE* blob =
nullptr;
861 WINPR_ASSERT(micvalue);
863 msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
864 ntlm->AuthenticateMessage.cbBuffer;
866 if (!sspi_SecBufferAlloc(micvalue, msgSize))
867 return SEC_E_INSUFFICIENT_MEMORY;
869 blob = (BYTE*)micvalue->pvBuffer;
870 CopyMemory(blob, ntlm->NegotiateMessage.pvBuffer, ntlm->NegotiateMessage.cbBuffer);
871 blob += ntlm->NegotiateMessage.cbBuffer;
872 CopyMemory(blob, ntlm->ChallengeMessage.pvBuffer, ntlm->ChallengeMessage.cbBuffer);
873 blob += ntlm->ChallengeMessage.cbBuffer;
874 CopyMemory(blob, ntlm->AuthenticateMessage.pvBuffer, ntlm->AuthenticateMessage.cbBuffer);
875 blob += ntlm->MessageIntegrityCheckOffset;
876 ZeroMemory(blob, 16);
881static bool identityToAuthIdentity(
const SEC_WINNT_AUTH_IDENTITY* identity,
884 WINPR_ASSERT(identity);
890 *pAuthIdentity = empty;
892 if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
894 if (identity->UserLength > 0)
896 if (ConvertWCharNToUtf8(identity->User, identity->UserLength, pAuthIdentity->User,
897 ARRAYSIZE(pAuthIdentity->User)) <= 0)
901 if (identity->DomainLength > 0)
903 if (ConvertWCharNToUtf8(identity->Domain, identity->DomainLength, pAuthIdentity->Domain,
904 ARRAYSIZE(pAuthIdentity->Domain)) <= 0)
908 else if ((identity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
910 if (identity->UserLength > 0)
912 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->User) - 1, identity->UserLength);
913 strncpy(pAuthIdentity->User, (
char*)identity->User, len);
914 pAuthIdentity->User[len] =
'\0';
917 if (identity->DomainLength > 0)
919 const size_t len = MIN(ARRAYSIZE(pAuthIdentity->Domain) - 1, identity->DomainLength);
920 strncpy(pAuthIdentity->Domain, (
char*)identity->Domain, len);
921 pAuthIdentity->Domain[len] =
'\0';
930static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesCommon(
PCtxtHandle phContext,
931 ULONG ulAttribute,
void* pBuffer)
934 return SEC_E_INVALID_HANDLE;
937 return SEC_E_INSUFFICIENT_MEMORY;
940 if (!check_context(context))
941 return SEC_E_INVALID_HANDLE;
945 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME_LEN:
947 ULONG* val = (ULONG*)pBuffer;
948 *val = context->Workstation.Length;
952 case SECPKG_ATTR_AUTH_IDENTITY:
957 return SEC_E_INTERNAL_ERROR;
958 if (!identityToAuthIdentity(&credentials->identity, AuthIdentity))
959 return SEC_E_INTERNAL_ERROR;
960 context->UseSamFileDatabase = FALSE;
963 case SECPKG_ATTR_SIZES:
966 ContextSizes->cbMaxToken = 2010;
967 ContextSizes->cbMaxSignature = 16;
968 ContextSizes->cbBlockSize = 0;
969 ContextSizes->cbSecurityTrailer = 16;
973 case SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE:
974 return ntlm_computeProofValue(context, (
SecBuffer*)pBuffer);
976 case SECPKG_ATTR_AUTH_NTLM_RANDKEY:
980 if (!sspi_SecBufferAlloc(randkey, 16))
981 return (SEC_E_INSUFFICIENT_MEMORY);
983 CopyMemory(randkey->pvBuffer, context->EncryptedRandomSessionKey, 16);
987 case SECPKG_ATTR_AUTH_NTLM_MIC:
992 if (!sspi_SecBufferAlloc(mic, 16))
993 return (SEC_E_INSUFFICIENT_MEMORY);
995 CopyMemory(mic->pvBuffer, message->MessageIntegrityCheck, 16);
999 case SECPKG_ATTR_AUTH_NTLM_MIC_VALUE:
1000 return ntlm_computeMicValue(context, (
SecBuffer*)pBuffer);
1003 WLog_ERR(TAG,
"TODO: Implement ulAttribute=0x%08" PRIx32, ulAttribute);
1004 return SEC_E_UNSUPPORTED_FUNCTION;
1010static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(
PCtxtHandle phContext,
1011 ULONG ulAttribute,
void* pBuffer)
1014 return SEC_E_INVALID_HANDLE;
1017 return SEC_E_INSUFFICIENT_MEMORY;
1020 if (!check_context(context))
1021 return SEC_E_INVALID_HANDLE;
1023 switch (ulAttribute)
1025 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1027 memcpy(pBuffer, context->Workstation.Buffer, context->Workstation.Length);
1031 case SECPKG_ATTR_PACKAGE_INFO:
1036 (
SecPkgInfoW*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1039 return SEC_E_INSUFFICIENT_MEMORY;
1041 pPackageInfo->fCapabilities = NTLM_SecPkgInfoW.fCapabilities;
1042 pPackageInfo->wVersion = NTLM_SecPkgInfoW.wVersion;
1043 pPackageInfo->wRPCID = NTLM_SecPkgInfoW.wRPCID;
1044 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoW.cbMaxToken;
1045 pPackageInfo->Name = _wcsdup(NTLM_SecPkgInfoW.Name);
1046 pPackageInfo->Comment = _wcsdup(NTLM_SecPkgInfoW.Comment);
1048 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1050 sspi_ContextBufferFree(pPackageInfo);
1051 return SEC_E_INSUFFICIENT_MEMORY;
1053 PackageInfo->PackageInfo = pPackageInfo;
1057 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1061static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(
PCtxtHandle phContext,
1062 ULONG ulAttribute,
void* pBuffer)
1065 return SEC_E_INVALID_HANDLE;
1068 return SEC_E_INSUFFICIENT_MEMORY;
1071 if (!check_context(context))
1072 return SEC_E_INVALID_HANDLE;
1074 switch (ulAttribute)
1076 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1078 ConvertWCharNToUtf8(context->Workstation.Buffer, context->Workstation.Length, pBuffer,
1079 context->Workstation.Length);
1083 case SECPKG_ATTR_PACKAGE_INFO:
1088 (
SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size);
1091 return SEC_E_INSUFFICIENT_MEMORY;
1093 pPackageInfo->fCapabilities = NTLM_SecPkgInfoA.fCapabilities;
1094 pPackageInfo->wVersion = NTLM_SecPkgInfoA.wVersion;
1095 pPackageInfo->wRPCID = NTLM_SecPkgInfoA.wRPCID;
1096 pPackageInfo->cbMaxToken = NTLM_SecPkgInfoA.cbMaxToken;
1097 pPackageInfo->Name = _strdup(NTLM_SecPkgInfoA.Name);
1098 pPackageInfo->Comment = _strdup(NTLM_SecPkgInfoA.Comment);
1100 if (!pPackageInfo->Name || !pPackageInfo->Comment)
1102 sspi_ContextBufferFree(pPackageInfo);
1103 return SEC_E_INSUFFICIENT_MEMORY;
1105 PackageInfo->PackageInfo = pPackageInfo;
1110 return ntlm_QueryContextAttributesCommon(phContext, ulAttribute, pBuffer);
1114static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesCommon(
PCtxtHandle phContext,
1115 ULONG ulAttribute,
void* pBuffer,
1119 return SEC_E_INVALID_HANDLE;
1122 return SEC_E_INVALID_PARAMETER;
1126 return SEC_E_INVALID_HANDLE;
1128 switch (ulAttribute)
1130 case SECPKG_ATTR_AUTH_NTLM_HASH:
1135 return SEC_E_INVALID_PARAMETER;
1137 if (AuthNtlmHash->Version == 1)
1138 CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
1139 else if (AuthNtlmHash->Version == 2)
1140 CopyMemory(context->NtlmV2Hash, AuthNtlmHash->NtlmHash, 16);
1145 case SECPKG_ATTR_AUTH_NTLM_MESSAGE:
1151 return SEC_E_INVALID_PARAMETER;
1153 if (AuthNtlmMessage->type == 1)
1155 sspi_SecBufferFree(&context->NegotiateMessage);
1157 if (!sspi_SecBufferAlloc(&context->NegotiateMessage, AuthNtlmMessage->length))
1158 return SEC_E_INSUFFICIENT_MEMORY;
1160 CopyMemory(context->NegotiateMessage.pvBuffer, AuthNtlmMessage->buffer,
1161 AuthNtlmMessage->length);
1163 else if (AuthNtlmMessage->type == 2)
1165 sspi_SecBufferFree(&context->ChallengeMessage);
1167 if (!sspi_SecBufferAlloc(&context->ChallengeMessage, AuthNtlmMessage->length))
1168 return SEC_E_INSUFFICIENT_MEMORY;
1170 CopyMemory(context->ChallengeMessage.pvBuffer, AuthNtlmMessage->buffer,
1171 AuthNtlmMessage->length);
1173 else if (AuthNtlmMessage->type == 3)
1175 sspi_SecBufferFree(&context->AuthenticateMessage);
1177 if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, AuthNtlmMessage->length))
1178 return SEC_E_INSUFFICIENT_MEMORY;
1180 CopyMemory(context->AuthenticateMessage.pvBuffer, AuthNtlmMessage->buffer,
1181 AuthNtlmMessage->length);
1187 case SECPKG_ATTR_AUTH_NTLM_TIMESTAMP:
1193 return SEC_E_INVALID_PARAMETER;
1195 if (AuthNtlmTimestamp->ChallengeOrResponse)
1196 CopyMemory(context->ChallengeTimestamp, AuthNtlmTimestamp->Timestamp, 8);
1198 CopyMemory(context->Timestamp, AuthNtlmTimestamp->Timestamp, 8);
1203 case SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE:
1209 return SEC_E_INVALID_PARAMETER;
1211 CopyMemory(context->ClientChallenge, AuthNtlmClientChallenge->ClientChallenge, 8);
1215 case SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE:
1221 return SEC_E_INVALID_PARAMETER;
1223 CopyMemory(context->ServerChallenge, AuthNtlmServerChallenge->ServerChallenge, 8);
1228 WLog_ERR(TAG,
"TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
1229 return SEC_E_UNSUPPORTED_FUNCTION;
1233static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(
PCtxtHandle phContext,
1234 ULONG ulAttribute,
void* pBuffer,
1238 return SEC_E_INVALID_HANDLE;
1241 return SEC_E_INVALID_PARAMETER;
1245 return SEC_E_INVALID_HANDLE;
1247 switch (ulAttribute)
1249 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1250 return ntlm_SetContextWorkstationX(context, TRUE, pBuffer, cbBuffer);
1253 return ntlm_SetContextAttributesCommon(phContext, ulAttribute, pBuffer, cbBuffer);
1257static SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(
PCtxtHandle phContext,
1258 ULONG ulAttribute,
void* pBuffer,
1262 return SEC_E_INVALID_HANDLE;
1265 return SEC_E_INVALID_PARAMETER;
1269 return SEC_E_INVALID_HANDLE;
1271 switch (ulAttribute)
1273 case SECPKG_ATTR_AUTH_NTLM_HOSTNAME:
1274 return ntlm_SetContextWorkstationX(context, FALSE, pBuffer, cbBuffer);
1277 return ntlm_SetContextAttributesCommon(phContext, ulAttribute, pBuffer, cbBuffer);
1281static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesW(
1282 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1283 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1285 return SEC_E_UNSUPPORTED_FUNCTION;
1288static SECURITY_STATUS SEC_ENTRY ntlm_SetCredentialsAttributesA(
1289 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1290 WINPR_ATTR_UNUSED
void* pBuffer, WINPR_ATTR_UNUSED ULONG cbBuffer)
1292 return SEC_E_UNSUPPORTED_FUNCTION;
1295static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
1300static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(
PCtxtHandle phContext,
1301 WINPR_ATTR_UNUSED ULONG fQOP,
1304 const UINT32 SeqNo = MessageSeqNo;
1306 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1307 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1312 if (!check_context(context))
1313 return SEC_E_INVALID_HANDLE;
1315 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1317 SecBuffer* cur = &pMessage->pBuffers[index];
1319 if (cur->BufferType & SECBUFFER_DATA)
1321 else if (cur->BufferType & SECBUFFER_TOKEN)
1322 signature_buffer = cur;
1326 return SEC_E_INVALID_TOKEN;
1328 if (!signature_buffer)
1329 return SEC_E_INVALID_TOKEN;
1332 ULONG length = data_buffer->cbBuffer;
1333 void* data = malloc(length);
1336 return SEC_E_INSUFFICIENT_MEMORY;
1338 CopyMemory(data, data_buffer->pvBuffer, length);
1340 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1342 BOOL success = FALSE;
1346 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1349 winpr_Data_Write_UINT32(&value, SeqNo);
1351 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1353 if (!winpr_HMAC_Update(hmac, data, length))
1355 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1362 winpr_HMAC_Free(hmac);
1366 return SEC_E_INSUFFICIENT_MEMORY;
1370 if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
1372 if (context->confidentiality)
1374 if (!winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
1375 (BYTE*)data_buffer->pvBuffer))
1378 return SEC_E_INSUFFICIENT_MEMORY;
1382 CopyMemory(data_buffer->pvBuffer, data, length);
1385#ifdef WITH_DEBUG_NTLM
1386 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", length);
1387 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1388 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1389 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1393 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1394 return SEC_E_INSUFFICIENT_MEMORY;
1395 if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
1397 BYTE* signature = signature_buffer->pvBuffer;
1399 winpr_Data_Write_UINT32(signature, version);
1400 CopyMemory(&signature[4], (
void*)checksum, 8);
1401 winpr_Data_Write_UINT32(&signature[12], SeqNo);
1403 context->SendSeqNum++;
1404#ifdef WITH_DEBUG_NTLM
1405 WLog_DBG(TAG,
"Signature (length = %" PRIu32
")", signature_buffer->cbBuffer);
1406 winpr_HexDump(TAG, WLOG_DEBUG, signature_buffer->pvBuffer, signature_buffer->cbBuffer);
1413 WINPR_ATTR_UNUSED PULONG pfQOP)
1415 const UINT32 SeqNo = (UINT32)MessageSeqNo;
1417 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1418 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1420 BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1424 if (!check_context(context))
1425 return SEC_E_INVALID_HANDLE;
1427 for (ULONG index = 0; index < pMessage->cBuffers; index++)
1429 if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
1430 data_buffer = &pMessage->pBuffers[index];
1431 else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
1432 signature_buffer = &pMessage->pBuffers[index];
1436 return SEC_E_INVALID_TOKEN;
1438 if (!signature_buffer)
1439 return SEC_E_INVALID_TOKEN;
1442 const ULONG length = data_buffer->cbBuffer;
1443 void* data = malloc(length);
1446 return SEC_E_INSUFFICIENT_MEMORY;
1448 CopyMemory(data, data_buffer->pvBuffer, length);
1452 if (context->confidentiality)
1454 if (!winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*)data,
1455 (BYTE*)data_buffer->pvBuffer))
1458 return SEC_E_INSUFFICIENT_MEMORY;
1462 CopyMemory(data_buffer->pvBuffer, data, length);
1465 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1467 BOOL success = FALSE;
1472 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1475 winpr_Data_Write_UINT32(&value, SeqNo);
1477 if (!winpr_HMAC_Update(hmac, (
void*)&value, 4))
1479 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1481 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1487 winpr_HMAC_Free(hmac);
1491 return SEC_E_INSUFFICIENT_MEMORY;
1494#ifdef WITH_DEBUG_NTLM
1495 WLog_DBG(TAG,
"Encrypted Data Buffer (length = %" PRIu32
")", length);
1496 winpr_HexDump(TAG, WLOG_DEBUG, data, length);
1497 WLog_DBG(TAG,
"Data Buffer (length = %" PRIu32
")", data_buffer->cbBuffer);
1498 winpr_HexDump(TAG, WLOG_DEBUG, data_buffer->pvBuffer, data_buffer->cbBuffer);
1502 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1503 return SEC_E_MESSAGE_ALTERED;
1506 winpr_Data_Write_UINT32(expected_signature, version);
1507 CopyMemory(&expected_signature[4], (
void*)checksum, 8);
1508 winpr_Data_Write_UINT32(&expected_signature[12], SeqNo);
1509 context->RecvSeqNum++;
1511 if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0)
1514 WLog_ERR(TAG,
"signature verification failed, something nasty is going on!");
1515#ifdef WITH_DEBUG_NTLM
1516 WLog_ERR(TAG,
"Expected Signature:");
1517 winpr_HexDump(TAG, WLOG_ERROR, expected_signature, 16);
1518 WLog_ERR(TAG,
"Actual Signature:");
1519 winpr_HexDump(TAG, WLOG_ERROR, (BYTE*)signature_buffer->pvBuffer, 16);
1521 return SEC_E_MESSAGE_ALTERED;
1527static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(
PCtxtHandle phContext,
1528 WINPR_ATTR_UNUSED ULONG fQOP,
1531 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1535 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1536 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1538 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1539 if (!check_context(context))
1540 return SEC_E_INVALID_HANDLE;
1542 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1544 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1545 data_buffer = &pMessage->pBuffers[i];
1546 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1547 sig_buffer = &pMessage->pBuffers[i];
1550 if (!data_buffer || !sig_buffer)
1551 return SEC_E_INVALID_TOKEN;
1553 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1555 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH))
1558 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1559 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1561 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1563 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1566 if (!winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum))
1569 BYTE* signature = sig_buffer->pvBuffer;
1570 winpr_Data_Write_UINT32(signature, 1L);
1571 CopyMemory(&signature[4], checksum, 8);
1572 winpr_Data_Write_UINT32(&signature[12], seq_no);
1573 sig_buffer->cbBuffer = 16;
1578 winpr_HMAC_Free(hmac);
1582static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(
PCtxtHandle phContext,
1584 WINPR_ATTR_UNUSED PULONG pfQOP)
1586 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1590 BYTE digest[WINPR_MD5_DIGEST_LENGTH] = WINPR_C_ARRAY_INIT;
1591 BYTE checksum[8] = WINPR_C_ARRAY_INIT;
1592 BYTE signature[16] = WINPR_C_ARRAY_INIT;
1594 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1595 if (!check_context(context))
1596 return SEC_E_INVALID_HANDLE;
1598 for (ULONG i = 0; i < pMessage->cBuffers; i++)
1600 if (pMessage->pBuffers[i].BufferType == SECBUFFER_DATA)
1601 data_buffer = &pMessage->pBuffers[i];
1602 else if (pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1603 sig_buffer = &pMessage->pBuffers[i];
1606 if (!data_buffer || !sig_buffer)
1607 return SEC_E_INVALID_TOKEN;
1609 WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
1611 if (!winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH))
1614 winpr_Data_Write_UINT32(&seq_no, MessageSeqNo);
1615 if (!winpr_HMAC_Update(hmac, (BYTE*)&seq_no, 4))
1617 if (!winpr_HMAC_Update(hmac, data_buffer->pvBuffer, data_buffer->cbBuffer))
1619 if (!winpr_HMAC_Final(hmac, digest, WINPR_MD5_DIGEST_LENGTH))
1622 if (!winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum))
1625 winpr_Data_Write_UINT32(signature, 1L);
1626 CopyMemory(&signature[4], checksum, 8);
1627 winpr_Data_Write_UINT32(&signature[12], seq_no);
1630 if (memcmp(sig_buffer->pvBuffer, signature, 16) != 0)
1631 status = SEC_E_MESSAGE_ALTERED;
1634 winpr_HMAC_Free(hmac);
1641 ntlm_QueryCredentialsAttributesA,
1642 ntlm_AcquireCredentialsHandleA,
1643 ntlm_FreeCredentialsHandle,
1645 ntlm_InitializeSecurityContextA,
1646 ntlm_AcceptSecurityContext,
1648 ntlm_DeleteSecurityContext,
1650 ntlm_QueryContextAttributesA,
1651 ntlm_ImpersonateSecurityContext,
1652 ntlm_RevertSecurityContext,
1654 ntlm_VerifySignature,
1664 ntlm_EncryptMessage,
1665 ntlm_DecryptMessage,
1666 ntlm_SetContextAttributesA,
1667 ntlm_SetCredentialsAttributesA,
1673 ntlm_QueryCredentialsAttributesW,
1674 ntlm_AcquireCredentialsHandleW,
1675 ntlm_FreeCredentialsHandle,
1677 ntlm_InitializeSecurityContextW,
1678 ntlm_AcceptSecurityContext,
1680 ntlm_DeleteSecurityContext,
1682 ntlm_QueryContextAttributesW,
1683 ntlm_ImpersonateSecurityContext,
1684 ntlm_RevertSecurityContext,
1686 ntlm_VerifySignature,
1696 ntlm_EncryptMessage,
1697 ntlm_DecryptMessage,
1698 ntlm_SetContextAttributesW,
1699 ntlm_SetCredentialsAttributesW,
1708 "NTLM Security Package"
1711static WCHAR NTLM_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
1712static WCHAR NTLM_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
1719 NTLM_SecPkgInfoW_NameBuffer,
1720 NTLM_SecPkgInfoW_CommentBuffer
1723char* ntlm_negotiate_flags_string(
char* buffer,
size_t size, UINT32 flags)
1725 if (!buffer || (size == 0))
1728 (void)_snprintf(buffer, size,
"[0x%08" PRIx32
"] ", flags);
1730 for (
int x = 0; x < 31; x++)
1732 const UINT32 mask = 1u << x;
1733 size_t len = strnlen(buffer, size);
1736 const char* str = ntlm_get_negotiate_string(mask);
1737 const size_t flen = strlen(str);
1739 if ((len > 0) && (buffer[len - 1] !=
' '))
1743 winpr_str_append(
"|", buffer, size,
nullptr);
1747 if (size - len < flen)
1749 winpr_str_append(str, buffer, size,
nullptr);
1756const char* ntlm_message_type_string(UINT32 messageType)
1758 switch (messageType)
1760 case MESSAGE_TYPE_NEGOTIATE:
1761 return "MESSAGE_TYPE_NEGOTIATE";
1762 case MESSAGE_TYPE_CHALLENGE:
1763 return "MESSAGE_TYPE_CHALLENGE";
1764 case MESSAGE_TYPE_AUTHENTICATE:
1765 return "MESSAGE_TYPE_AUTHENTICATE";
1767 return "MESSAGE_TYPE_UNKNOWN";
1771const char* ntlm_state_string(NTLM_STATE state)
1775 case NTLM_STATE_INITIAL:
1776 return "NTLM_STATE_INITIAL";
1777 case NTLM_STATE_NEGOTIATE:
1778 return "NTLM_STATE_NEGOTIATE";
1779 case NTLM_STATE_CHALLENGE:
1780 return "NTLM_STATE_CHALLENGE";
1781 case NTLM_STATE_AUTHENTICATE:
1782 return "NTLM_STATE_AUTHENTICATE";
1783 case NTLM_STATE_FINAL:
1784 return "NTLM_STATE_FINAL";
1786 return "NTLM_STATE_UNKNOWN";
1789void ntlm_change_state(
NTLM_CONTEXT* ntlm, NTLM_STATE state)
1792 WLog_DBG(TAG,
"change state from %s to %s", ntlm_state_string(ntlm->state),
1793 ntlm_state_string(state));
1794 ntlm->state = state;
1803BOOL ntlm_reset_cipher_state(
PSecHandle phContext)
1805 NTLM_CONTEXT* context = sspi_SecureHandleGetLowerPointer(phContext);
1809 check_context(context);
1810 winpr_RC4_Free(context->SendRc4Seal);
1811 winpr_RC4_Free(context->RecvRc4Seal);
1812 context->SendRc4Seal = winpr_RC4_New(context->RecvSealingKey, 16);
1813 context->RecvRc4Seal = winpr_RC4_New(context->SendSealingKey, 16);
1815 if (!context->SendRc4Seal)
1817 WLog_ERR(TAG,
"Failed to allocate context->SendRc4Seal");
1820 if (!context->RecvRc4Seal)
1822 WLog_ERR(TAG,
"Failed to allocate context->RecvRc4Seal");
1832 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Name, NTLM_SecPkgInfoW_NameBuffer,
1833 ARRAYSIZE(NTLM_SecPkgInfoW_NameBuffer));
1834 InitializeConstWCharFromUtf8(NTLM_SecPkgInfoA.Comment, NTLM_SecPkgInfoW_CommentBuffer,
1835 ARRAYSIZE(NTLM_SecPkgInfoW_CommentBuffer));
WINPR_ATTR_NODISCARD psSspiNtlmHashCallback hashCallback