3#include <winpr/assert.h>
5#include <winpr/print.h>
8#include <winpr/tchar.h>
35 LPTSTR ServicePrincipalName;
40 SecPkgInfo* pPackageInfo;
41 SecurityFunctionTable* table;
46static BYTE TEST_NTLM_TIMESTAMP[8] = { 0x33, 0x57, 0xbd, 0xb1, 0x07, 0x8b, 0xcf, 0x01 };
48static BYTE TEST_NTLM_CLIENT_CHALLENGE[8] = { 0x20, 0xc0, 0x2b, 0x3d, 0xc0, 0x61, 0xa7, 0x73 };
50static BYTE TEST_NTLM_SERVER_CHALLENGE[8] = { 0xa4, 0xf1, 0xba, 0xa6, 0x7c, 0xdc, 0x1a, 0x12 };
52static BYTE TEST_NTLM_NEGOTIATE[] =
53 "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2"
54 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
55 "\x06\x03\x80\x25\x00\x00\x00\x0f";
57static BYTE TEST_NTLM_CHALLENGE[] =
58 "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x02\x00\x00\x00\x00\x00\x00\x00"
59 "\x38\x00\x00\x00\x07\x82\x88\xa2\xa4\xf1\xba\xa6\x7c\xdc\x1a\x12"
60 "\x00\x00\x00\x00\x00\x00\x00\x00\x66\x00\x66\x00\x38\x00\x00\x00"
61 "\x06\x03\x80\x25\x00\x00\x00\x0f\x02\x00\x0e\x00\x4e\x00\x45\x00"
62 "\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00"
63 "\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00"
64 "\x6c\x00\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00"
65 "\x2e\x00\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00"
66 "\x6e\x00\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00"
67 "\x08\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x00\x00\x00\x00";
69static BYTE TEST_NTLM_AUTHENTICATE[] =
70 "\x4e\x54\x4c\x4d\x53\x53\x50\x00\x03\x00\x00\x00\x18\x00\x18\x00"
71 "\x82\x00\x00\x00\x08\x01\x08\x01\x9a\x00\x00\x00\x0c\x00\x0c\x00"
72 "\x58\x00\x00\x00\x10\x00\x10\x00\x64\x00\x00\x00\x0e\x00\x0e\x00"
73 "\x74\x00\x00\x00\x00\x00\x00\x00\xa2\x01\x00\x00\x05\x82\x88\xa2"
74 "\x06\x03\x80\x25\x00\x00\x00\x0f\x12\xe5\x5a\xf5\x80\xee\x3f\x29"
75 "\xe1\xde\x90\x4d\x73\x77\x06\x25\x44\x00\x6f\x00\x6d\x00\x61\x00"
76 "\x69\x00\x6e\x00\x55\x00\x73\x00\x65\x00\x72\x00\x6e\x00\x61\x00"
77 "\x6d\x00\x65\x00\x4e\x00\x45\x00\x57\x00\x59\x00\x45\x00\x41\x00"
78 "\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
79 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x62\x14\x68\xc8\x98\x12"
80 "\xe7\x39\xd8\x76\x1b\xe9\xf7\x54\xb5\xe3\x01\x01\x00\x00\x00\x00"
81 "\x00\x00\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x20\xc0\x2b\x3d\xc0\x61"
82 "\xa7\x73\x00\x00\x00\x00\x02\x00\x0e\x00\x4e\x00\x45\x00\x57\x00"
83 "\x59\x00\x45\x00\x41\x00\x52\x00\x01\x00\x0e\x00\x4e\x00\x45\x00"
84 "\x57\x00\x59\x00\x45\x00\x41\x00\x52\x00\x04\x00\x1c\x00\x6c\x00"
85 "\x61\x00\x62\x00\x2e\x00\x77\x00\x61\x00\x79\x00\x6b\x00\x2e\x00"
86 "\x6c\x00\x6f\x00\x63\x00\x61\x00\x6c\x00\x03\x00\x0e\x00\x6e\x00"
87 "\x65\x00\x77\x00\x79\x00\x65\x00\x61\x00\x72\x00\x07\x00\x08\x00"
88 "\x33\x57\xbd\xb1\x07\x8b\xcf\x01\x06\x00\x04\x00\x02\x00\x00\x00"
89 "\x08\x00\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
90 "\x00\x20\x00\x00\x1e\x10\xf5\x2c\x54\x2f\x2e\x77\x1c\x13\xbf\xc3"
91 "\x3f\xe1\x7b\x28\x7e\x0b\x93\x5a\x39\xd2\xce\x12\xd7\xbd\x8c\x4e"
92 "\x2b\xb5\x0b\xf5\x0a\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
93 "\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x1a\x00\x48\x00\x54\x00"
94 "\x54\x00\x50\x00\x2f\x00\x72\x00\x77\x00\x2e\x00\x6c\x00\x6f\x00"
95 "\x63\x00\x61\x00\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
98#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
100static const char* TEST_NTLM_USER =
"Username";
101static const char* TEST_NTLM_DOMAIN =
"Domain";
102static const char* TEST_NTLM_PASSWORD =
"P4ss123!";
106static const BYTE TEST_NTLM_HASH[16] = { 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82,
107 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
111static const BYTE TEST_NTLM_V2_HASH[16] = { 0x4c, 0x7f, 0x70, 0x6f, 0x7d, 0xde, 0x05, 0xa9,
112 0xd1, 0xa0, 0xf4, 0xe7, 0xff, 0xe3, 0xbf, 0xb8 };
114static const BYTE TEST_EMPTY_PWD_NTLM_HASH[] = { 0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
115 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 };
117static const BYTE TEST_EMPTY_PWD_NTLM_V2_HASH[] = {
118 0x0b, 0xce, 0x54, 0x87, 0x4e, 0x94, 0x20, 0x9e, 0x34, 0x48, 0x97, 0xc1, 0x60, 0x03, 0x6e, 0x3b
121#define NTLM_PACKAGE_NAME NTLM_SSP_NAME
134 BOOL haveInputBuffer;
135 LPTSTR ServicePrincipalName;
139 BOOL confidentiality;
140 SecPkgInfo* pPackageInfo;
141 SecurityFunctionTable* table;
142 SEC_WINNT_AUTH_IDENTITY identity;
147static BOOL test_attributes_read(SecurityFunctionTable* table,
CtxtHandle* context,
148 const void* expected,
size_t expectedLen)
151 WINPR_ASSERT(context);
152 WINPR_ASSERT(expected);
153 WINPR_ASSERT(expectedLen > 0);
154 WINPR_ASSERT(expectedLen <= UINT32_MAX);
161 const struct attr_pair_t attributes[] = {
162 { SECPKG_ATTR_AUTH_NTLM_HOSTNAME, SECPKG_ATTR_AUTH_NTLM_HOSTNAME_LEN },
163 { SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME, SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME_LEN },
164 { SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME, SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME_LEN },
165 { SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME, SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME_LEN },
166 { SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME, SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME_LEN }
170 TCHAR* buffer = calloc(expectedLen + 1,
sizeof(TCHAR));
173 for (
size_t x = 0; x < ARRAYSIZE(attributes); x++)
175 const struct attr_pair_t attribute = attributes[x];
179 SECURITY_STATUS status = table->QueryContextAttributes(context, attribute.len, &len);
180 if (status != SEC_E_OK)
182 if (len != expectedLen)
187 memset(buffer, 0, expectedLen);
188 SECURITY_STATUS status = table->QueryContextAttributes(context, attribute.val, buffer);
189 if (status != SEC_E_OK)
191 if (memcmp(expected, buffer, expectedLen) != 0)
203static BOOL test_attributes_write(SecurityFunctionTable* table,
CtxtHandle* context,
204 const void* expected,
size_t expectedLen)
207 WINPR_ASSERT(context);
208 WINPR_ASSERT(expected);
209 WINPR_ASSERT(expectedLen > 0);
210 WINPR_ASSERT(expectedLen <= UINT32_MAX);
217 const struct attr_pair_t attributes[] = {
218 { SECPKG_ATTR_AUTH_NTLM_HOSTNAME, SECPKG_ATTR_AUTH_NTLM_HOSTNAME_LEN },
219 { SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME, SECPKG_ATTR_AUTH_NTLM_NB_COMPUTER_NAME_LEN },
220 { SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME, SECPKG_ATTR_AUTH_NTLM_NB_DOMAIN_NAME_LEN },
221 { SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME, SECPKG_ATTR_AUTH_NTLM_DNS_COMPUTER_NAME_LEN },
222 { SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME, SECPKG_ATTR_AUTH_NTLM_DNS_DOMAIN_NAME_LEN }
226 for (
size_t x = 0; x < ARRAYSIZE(attributes); x++)
228 const struct attr_pair_t attribute = attributes[x];
230 SECURITY_STATUS status =
231 table->SetContextAttributes(context, attribute.val, expected, expectedLen);
232 if (status != SEC_E_OK)
243static BOOL test_attributes(WINPR_ATTR_UNUSED SecurityFunctionTable* table,
247 const TCHAR* testvalues[] = { _T(
"foobar"), _T(
"gaga"), _T(
"gag"), _T(
"ga"), _T(
"a") };
249 for (
size_t x = 0; x < ARRAYSIZE(testvalues); x++)
251 const TCHAR* cur = testvalues[x];
252 const size_t len = _tcslen(cur);
253 if (!test_attributes_write(table, context, cur, len))
255 if (!test_attributes_read(table, context, cur, len))
263static BOOL test_short_signature(SecurityFunctionTable* table,
CtxtHandle* context)
265 BYTE data[16] = WINPR_C_ARRAY_INIT;
269 WINPR_ASSERT(context);
275 BYTE* signature = malloc(1);
279 SecBuffer buffers[2] = WINPR_C_ARRAY_INIT;
280 buffers[0].BufferType = SECBUFFER_DATA;
281 buffers[0].pvBuffer = data;
282 buffers[0].cbBuffer =
sizeof(data);
283 buffers[1].BufferType = SECBUFFER_TOKEN;
284 buffers[1].pvBuffer = signature;
285 buffers[1].cbBuffer = 1;
287 SecBufferDesc desc = { SECBUFFER_VERSION, ARRAYSIZE(buffers), buffers };
289 if (table->MakeSignature(context, 0, &desc, 0) == SEC_E_OK)
293 if (table->VerifySignature(context, &desc, 0, &qop) == SEC_E_OK)
303static void* getServerAuthData(TEST_NTLM_SERVER* ntlm,
const struct test_input_t* arg,
304 psSspiNtlmHashCallback fkt)
309 ntlm->authData.identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
310 ntlm->authData.identity.Length =
sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
311 ntlm->authData.identity.Flags |=
312 SEC_WINNT_AUTH_IDENTITY_EXTENDED | SEC_WINNT_AUTH_IDENTITY_UNICODE;
313 ntlm->settings.hashCallback = fkt;
314 ntlm->settings.hashCallbackArg = arg;
315 ntlm->authData.ntlmSettings = &ntlm->settings;
316 ntlm->UseCallback = TRUE;
317 return &ntlm->authData;
319 ntlm->UseCallback = FALSE;
324static int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm,
const char* user,
const char* domain,
325 const char* password)
327 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
331 SecInvalidateHandle(&(ntlm->context));
332 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
335 const int rc = sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
339 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
341 if (status != SEC_E_OK)
343 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
344 GetSecurityStatusString(status), status);
348 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
349 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
350 nullptr, &ntlm->identity,
nullptr,
nullptr,
351 &ntlm->credentials, &ntlm->expiration);
353 if (status != SEC_E_OK)
355 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
356 GetSecurityStatusString(status), status);
360 ntlm->haveContext = FALSE;
361 ntlm->haveInputBuffer = FALSE;
362 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
363 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
364 ntlm->fContextReq = 0;
367 ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
368 ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
369 ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
373static void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
378 if (ntlm->outputBuffer[0].pvBuffer)
380 free(ntlm->outputBuffer[0].pvBuffer);
381 ntlm->outputBuffer[0].pvBuffer =
nullptr;
384 free(ntlm->identity.User);
385 free(ntlm->identity.Domain);
386 free(ntlm->identity.Password);
387 free(ntlm->ServicePrincipalName);
391 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
392 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
393 (status == SEC_E_UNSUPPORTED_FUNCTION));
395 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
396 WINPR_ASSERT((status == SEC_E_OK) || (status = SEC_E_INVALID_HANDLE));
398 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
399 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
400 (status == SEC_E_UNSUPPORTED_FUNCTION));
442static BOOL IsSecurityStatusError(SECURITY_STATUS status)
449 case SEC_I_CONTINUE_NEEDED:
450 case SEC_I_COMPLETE_NEEDED:
451 case SEC_I_COMPLETE_AND_CONTINUE:
452 case SEC_I_LOCAL_LOGON:
453 case SEC_I_CONTEXT_EXPIRED:
454 case SEC_I_INCOMPLETE_CREDENTIALS:
455 case SEC_I_RENEGOTIATE:
456 case SEC_I_NO_LSA_CONTEXT:
457 case SEC_I_SIGNATURE_NEEDED:
458 case SEC_I_NO_RENEGOTIATION:
469static int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
471 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
474 if (ntlm->outputBuffer[0].pvBuffer)
476 free(ntlm->outputBuffer[0].pvBuffer);
477 ntlm->outputBuffer[0].pvBuffer =
nullptr;
480 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
481 ntlm->outputBufferDesc.cBuffers = 1;
482 ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
483 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
484 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
485 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
487 if (!ntlm->outputBuffer[0].pvBuffer)
490 if (ntlm->haveInputBuffer)
492 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
493 ntlm->inputBufferDesc.cBuffers = 1;
494 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
495 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
498 if ((!ntlm) || (!ntlm->table))
500 (void)fprintf(stderr,
"ntlm_authenticate: invalid ntlm context\n");
504 status = ntlm->table->InitializeSecurityContext(
505 &ntlm->credentials, (ntlm->haveContext) ? &ntlm->context :
nullptr,
506 (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : nullptr, ntlm->fContextReq, 0,
507 SECURITY_NATIVE_DREP, (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : nullptr, 0,
508 &ntlm->context, &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
510 if (IsSecurityStatusError(status))
513 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
515 if (ntlm->table->CompleteAuthToken)
518 ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
523 if (status == SEC_I_COMPLETE_NEEDED)
525 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
526 status = SEC_I_CONTINUE_NEEDED;
529 if (ntlm->haveInputBuffer)
531 free(ntlm->inputBuffer[0].pvBuffer);
532 ntlm->inputBuffer[0].pvBuffer =
nullptr;
535 ntlm->haveInputBuffer = TRUE;
536 ntlm->haveContext = TRUE;
537 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
540static void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
545 test_ntlm_client_uninit(ntlm);
549WINPR_ATTR_MALLOC(test_ntlm_client_free, 1)
550static TEST_NTLM_CLIENT* test_ntlm_client_new(
void)
552 TEST_NTLM_CLIENT* ntlm = (TEST_NTLM_CLIENT*)calloc(1,
sizeof(TEST_NTLM_CLIENT));
561static int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm,
const struct test_input_t* arg,
562 psSspiNtlmHashCallback fkt)
564 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
568 ntlm->UseNtlmV2Hash = TRUE;
569 SecInvalidateHandle(&(ntlm->context));
570 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
572 return SEC_E_INTERNAL_ERROR;
574 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
576 if (status != SEC_E_OK)
578 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
579 GetSecurityStatusString(status), status);
583 void* authData = getServerAuthData(ntlm, arg, fkt);
584 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
585 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
586 nullptr, authData,
nullptr,
nullptr,
587 &ntlm->credentials, &ntlm->expiration);
589 if (status != SEC_E_OK)
591 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
592 GetSecurityStatusString(status), status);
596 ntlm->haveContext = FALSE;
597 ntlm->haveInputBuffer = FALSE;
598 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
599 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
600 ntlm->fContextReq = 0;
602 ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
603 ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
604 ntlm->fContextReq |= ASC_REQ_CONNECTION;
605 ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
606 ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
607 ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
608 ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
612static void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
617 if (ntlm->outputBuffer[0].pvBuffer)
619 free(ntlm->outputBuffer[0].pvBuffer);
620 ntlm->outputBuffer[0].pvBuffer =
nullptr;
623 free(ntlm->ServicePrincipalName);
627 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
628 WINPR_ASSERT(status == SEC_E_OK);
629 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
630 WINPR_ASSERT(status == SEC_E_OK);
631 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
632 WINPR_ASSERT(status == SEC_E_OK);
637static int test_ntlm_server_authenticate(
const struct test_input_t* targ, TEST_NTLM_SERVER* ntlm)
639 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
644 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
645 ntlm->inputBufferDesc.cBuffers = 1;
646 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
647 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
648 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
649 ntlm->outputBufferDesc.cBuffers = 1;
650 ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
651 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
652 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
653 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
655 if (!ntlm->outputBuffer[0].pvBuffer)
658 status = ntlm->table->AcceptSecurityContext(
659 &ntlm->credentials, ntlm->haveContext ? &ntlm->context : nullptr, &ntlm->inputBufferDesc,
660 ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, &ntlm->outputBufferDesc,
661 &ntlm->pfContextAttr, &ntlm->expiration);
663 if (status == SEC_I_CONTINUE_NEEDED)
667 if (!ntlm->UseCallback)
669 if (ntlm->UseNtlmV2Hash)
671 AuthNtlmHash.Version = 2;
672 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlmv2, 16);
676 AuthNtlmHash.Version = 1;
677 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlm, 16);
680 status = ntlm->table->SetContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_NTLM_HASH,
686 if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
688 (void)fprintf(stderr,
"AcceptSecurityContext status: %s (0x%08" PRIX32
")\n",
689 GetSecurityStatusString(status), status);
693 ntlm->haveContext = TRUE;
694 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
697static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
702 test_ntlm_server_uninit(ntlm);
706WINPR_ATTR_MALLOC(test_ntlm_server_free, 1)
707static TEST_NTLM_SERVER* test_ntlm_server_new(
void)
709 TEST_NTLM_SERVER* ntlm = (TEST_NTLM_SERVER*)calloc(1,
sizeof(TEST_NTLM_SERVER));
718static BOOL test_default(
const struct test_input_t* arg, psSspiNtlmHashCallback fkt)
724 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s}\n", arg->user, arg->domain,
725 arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE");
730 TEST_NTLM_CLIENT* client = test_ntlm_client_new();
731 TEST_NTLM_SERVER* server = test_ntlm_server_new();
733 if (!client || !server)
735 printf(
"Memory allocation failed\n");
739 int status = test_ntlm_client_init(client, arg->user, arg->domain, arg->pwd);
743 printf(
"test_ntlm_client_init failure\n");
751 status = test_ntlm_server_init(server, arg, fkt);
755 printf(
"test_ntlm_server_init failure\n");
762 status = test_ntlm_client_authenticate(client);
766 printf(
"test_ntlm_client_authenticate failure\n");
770 if (client->haveContext)
772 if (!test_attributes(client->table, &client->context))
781 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
782 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
783 SECURITY_STATUS rc = client->table->SetContextAttributes(
784 &client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
786 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
788 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
789 rc = client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
792 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
794 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
795 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
796 rc = client->table->SetContextAttributes(
797 &client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
799 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
801 rc = client->table->SetContextAttributes(
802 &client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
804 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
807 PSecBuffer pSecBuffer = &(client->outputBuffer[0]);
811 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_NEGOTIATE) - 1;
812 free(pSecBuffer->pvBuffer);
813 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
815 if (!pSecBuffer->pvBuffer)
817 printf(
"Memory allocation failed\n");
821 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
824 (void)fprintf(stderr,
"NTLM_NEGOTIATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
825 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
830 server->haveInputBuffer = TRUE;
831 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
832 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
833 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
834 status = test_ntlm_server_authenticate(arg, server);
838 printf(
"test_ntlm_server_authenticate failure\n");
842 if (server->haveContext)
844 if (!test_attributes(server->table, &server->context))
853 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
854 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
855 SECURITY_STATUS rc = client->table->SetContextAttributes(
856 &server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
858 WINPR_ASSERT(rc == SEC_E_OK);
860 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
861 rc = client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
864 WINPR_ASSERT(rc == SEC_E_OK);
866 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
867 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
868 rc = server->table->SetContextAttributes(
869 &server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
871 WINPR_ASSERT(rc == SEC_E_OK);
873 rc = server->table->SetContextAttributes(
874 &server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
876 WINPR_ASSERT(rc == SEC_E_OK);
879 pSecBuffer = &(server->outputBuffer[0]);
884 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_CHALLENGE) - 1;
885 free(pSecBuffer->pvBuffer);
886 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
888 if (!pSecBuffer->pvBuffer)
890 printf(
"Memory allocation failed\n");
894 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
895 AuthNtlmMessage.type = 2;
896 AuthNtlmMessage.length = pSecBuffer->cbBuffer;
897 AuthNtlmMessage.buffer = (BYTE*)pSecBuffer->pvBuffer;
898 SECURITY_STATUS rc = server->table->SetContextAttributes(
899 &server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, &AuthNtlmMessage,
905 (void)fprintf(stderr,
"NTLM_CHALLENGE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
906 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
911 client->haveInputBuffer = TRUE;
912 client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
913 client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
914 client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
915 status = test_ntlm_client_authenticate(client);
919 printf(
"test_ntlm_client_authenticate failure\n");
923 pSecBuffer = &(client->outputBuffer[0]);
927 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_AUTHENTICATE) - 1;
928 free(pSecBuffer->pvBuffer);
929 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
931 if (!pSecBuffer->pvBuffer)
933 printf(
"Memory allocation failed\n");
937 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
940 (void)fprintf(stderr,
"NTLM_AUTHENTICATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
941 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
945 server->haveInputBuffer = TRUE;
946 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
947 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
948 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
949 status = test_ntlm_server_authenticate(arg, server);
953 printf(
"test_ntlm_server_authenticate failure\n");
957 if (!test_short_signature(server->table, &server->context))
959 printf(
"test_short_signature failure\n");
969 test_ntlm_client_free(client);
970 test_ntlm_server_free(server);
972 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s} returns %d\n", arg->user,
973 arg->domain, arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE", rc);
978static SECURITY_STATUS testCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
979 const SecBuffer* ntproofvalue,
const BYTE* randkey,
980 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
982 const struct test_input_t* arg = client;
984 WINPR_ASSERT(authIdentity);
985 WINPR_ASSERT(ntproofvalue);
986 WINPR_ASSERT(randkey);
988 WINPR_ASSERT(micvalue);
989 WINPR_ASSERT(ntlmhash);
991 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
993 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
994 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
995 return SEC_E_ENCRYPT_FAILURE;
999 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
1000 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
1001 return SEC_E_ENCRYPT_FAILURE;
1004 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
1005 return SEC_E_DECRYPT_FAILURE;
1011static SECURITY_STATUS testFailCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
1012 const SecBuffer* ntproofvalue,
const BYTE* randkey,
1013 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
1015 const struct test_input_t* arg = client;
1017 WINPR_ASSERT(authIdentity);
1018 WINPR_ASSERT(ntproofvalue);
1019 WINPR_ASSERT(randkey);
1021 WINPR_ASSERT(micvalue);
1022 WINPR_ASSERT(ntlmhash);
1024 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
1026 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
1027 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
1028 return SEC_E_ENCRYPT_FAILURE;
1032 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
1033 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
1034 return SEC_E_ENCRYPT_FAILURE;
1037 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
1038 return SEC_E_DECRYPT_FAILURE;
1040 return SEC_E_DECRYPT_FAILURE;
1043int TestSspiNTLM(
int argc,
char* argv[])
1048 const struct test_input_t inputs[] = {
1049 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1051 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1053 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
"", TEST_EMPTY_PWD_NTLM_HASH,
1054 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, TRUE },
1055 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
nullptr, TEST_EMPTY_PWD_NTLM_HASH,
1056 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, FALSE }
1059 for (
size_t x = 0; x < ARRAYSIZE(inputs); x++)
1061 const struct test_input_t* cur = &inputs[x];
1062 const BOOL res = test_default(cur,
nullptr);
1063 if (res != cur->expected)
1065 printf(
"%s [%" PRIuz
"] fail 1!\n", __func__, x);
1068 const BOOL res2 = test_default(cur, testCallback);
1069 if (res2 != cur->expected)
1071 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1074 const BOOL res3 = test_default(cur, testFailCallback);
1077 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1081 printf(
"%s success!\n", __func__);