3#include <winpr/assert.h>
5#include <winpr/print.h>
8#include <winpr/tchar.h>
35 LPTSTR ServicePrincipalName;
40 SecPkgInfo* pPackageInfo;
41 SecurityFunctionTable* table;
42 SEC_WINNT_AUTH_IDENTITY_WINPR_V2 authDataV2;
43 SEC_WINPR_NTLM_SETTINGS_V2* settingsV2;
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->authDataV2.version = SEC_WINNT_AUTH_IDENTITY_WINPR_V2_REVISION_1;
310 ntlm->authDataV2.identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
311 ntlm->authDataV2.identity.Length =
sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
312 ntlm->authDataV2.identity.Flags |=
313 SEC_WINNT_AUTH_IDENTITY_EXTENDED_v2 | SEC_WINNT_AUTH_IDENTITY_UNICODE;
314 ntlm->settingsV2->hashCallback = fkt;
315 ntlm->settingsV2->hashCallbackArg = arg;
316 ntlm->authDataV2.ntlmSettingsV2 = ntlm->settingsV2;
317 ntlm->UseCallback = TRUE;
318 return &ntlm->authDataV2;
320 ntlm->UseCallback = FALSE;
325static int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm,
const char* user,
const char* domain,
326 const char* password)
328 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
332 SecInvalidateHandle(&(ntlm->context));
333 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
336 const int rc = sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
340 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
342 if (status != SEC_E_OK)
344 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
345 GetSecurityStatusString(status), status);
349 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
350 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
351 nullptr, &ntlm->identity,
nullptr,
nullptr,
352 &ntlm->credentials, &ntlm->expiration);
354 if (status != SEC_E_OK)
356 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
357 GetSecurityStatusString(status), status);
361 ntlm->haveContext = FALSE;
362 ntlm->haveInputBuffer = FALSE;
363 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
364 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
365 ntlm->fContextReq = 0;
368 ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
369 ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
370 ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
374static void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
379 if (ntlm->outputBuffer[0].pvBuffer)
381 free(ntlm->outputBuffer[0].pvBuffer);
382 ntlm->outputBuffer[0].pvBuffer =
nullptr;
385 free(ntlm->identity.User);
386 free(ntlm->identity.Domain);
387 free(ntlm->identity.Password);
388 free(ntlm->ServicePrincipalName);
392 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
393 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
394 (status == SEC_E_UNSUPPORTED_FUNCTION));
396 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
397 WINPR_ASSERT((status == SEC_E_OK) || (status = SEC_E_INVALID_HANDLE));
399 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
400 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
401 (status == SEC_E_UNSUPPORTED_FUNCTION));
443static BOOL IsSecurityStatusError(SECURITY_STATUS status)
450 case SEC_I_CONTINUE_NEEDED:
451 case SEC_I_COMPLETE_NEEDED:
452 case SEC_I_COMPLETE_AND_CONTINUE:
453 case SEC_I_LOCAL_LOGON:
454 case SEC_I_CONTEXT_EXPIRED:
455 case SEC_I_INCOMPLETE_CREDENTIALS:
456 case SEC_I_RENEGOTIATE:
457 case SEC_I_NO_LSA_CONTEXT:
458 case SEC_I_SIGNATURE_NEEDED:
459 case SEC_I_NO_RENEGOTIATION:
470static int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
472 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
475 if (ntlm->outputBuffer[0].pvBuffer)
477 free(ntlm->outputBuffer[0].pvBuffer);
478 ntlm->outputBuffer[0].pvBuffer =
nullptr;
481 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
482 ntlm->outputBufferDesc.cBuffers = 1;
483 ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
484 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
485 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
486 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
488 if (!ntlm->outputBuffer[0].pvBuffer)
491 if (ntlm->haveInputBuffer)
493 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
494 ntlm->inputBufferDesc.cBuffers = 1;
495 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
496 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
499 if ((!ntlm) || (!ntlm->table))
501 (void)fprintf(stderr,
"ntlm_authenticate: invalid ntlm context\n");
505 status = ntlm->table->InitializeSecurityContext(
506 &ntlm->credentials, (ntlm->haveContext) ? &ntlm->context :
nullptr,
507 (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : nullptr, ntlm->fContextReq, 0,
508 SECURITY_NATIVE_DREP, (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : nullptr, 0,
509 &ntlm->context, &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
511 if (IsSecurityStatusError(status))
514 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
516 if (ntlm->table->CompleteAuthToken)
519 ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
524 if (status == SEC_I_COMPLETE_NEEDED)
526 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
527 status = SEC_I_CONTINUE_NEEDED;
530 if (ntlm->haveInputBuffer)
532 free(ntlm->inputBuffer[0].pvBuffer);
533 ntlm->inputBuffer[0].pvBuffer =
nullptr;
536 ntlm->haveInputBuffer = TRUE;
537 ntlm->haveContext = TRUE;
538 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
541static void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
546 test_ntlm_client_uninit(ntlm);
550WINPR_ATTR_MALLOC(test_ntlm_client_free, 1)
551static TEST_NTLM_CLIENT* test_ntlm_client_new(
void)
553 TEST_NTLM_CLIENT* ntlm = (TEST_NTLM_CLIENT*)calloc(1,
sizeof(TEST_NTLM_CLIENT));
562static int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm,
const struct test_input_t* arg,
563 psSspiNtlmHashCallback fkt)
565 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
569 ntlm->UseNtlmV2Hash = TRUE;
570 SecInvalidateHandle(&(ntlm->context));
571 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
573 return SEC_E_INTERNAL_ERROR;
575 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
577 if (status != SEC_E_OK)
579 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
580 GetSecurityStatusString(status), status);
584 void* authData = getServerAuthData(ntlm, arg, fkt);
585 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
586 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
587 nullptr, authData,
nullptr,
nullptr,
588 &ntlm->credentials, &ntlm->expiration);
590 if (status != SEC_E_OK)
592 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
593 GetSecurityStatusString(status), status);
597 ntlm->haveContext = FALSE;
598 ntlm->haveInputBuffer = FALSE;
599 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
600 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
601 ntlm->fContextReq = 0;
603 ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
604 ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
605 ntlm->fContextReq |= ASC_REQ_CONNECTION;
606 ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
607 ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
608 ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
609 ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
614static void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
619 if (ntlm->outputBuffer[0].pvBuffer)
621 free(ntlm->outputBuffer[0].pvBuffer);
622 ntlm->outputBuffer[0].pvBuffer =
nullptr;
625 free(ntlm->ServicePrincipalName);
629 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
630 WINPR_ASSERT(status == SEC_E_OK);
631 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
632 WINPR_ASSERT(status == SEC_E_OK);
633 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
634 WINPR_ASSERT(status == SEC_E_OK);
639static int test_ntlm_server_authenticate(
const struct test_input_t* targ, TEST_NTLM_SERVER* ntlm)
641 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
646 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
647 ntlm->inputBufferDesc.cBuffers = 1;
648 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
649 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
650 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
651 ntlm->outputBufferDesc.cBuffers = 1;
652 ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
653 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
654 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
655 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
657 if (!ntlm->outputBuffer[0].pvBuffer)
660 status = ntlm->table->AcceptSecurityContext(
661 &ntlm->credentials, ntlm->haveContext ? &ntlm->context : nullptr, &ntlm->inputBufferDesc,
662 ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, &ntlm->outputBufferDesc,
663 &ntlm->pfContextAttr, &ntlm->expiration);
665 if (status == SEC_I_CONTINUE_NEEDED)
669 if (!ntlm->UseCallback)
671 if (ntlm->UseNtlmV2Hash)
673 AuthNtlmHash.Version = 2;
674 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlmv2, 16);
678 AuthNtlmHash.Version = 1;
679 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlm, 16);
682 status = ntlm->table->SetContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_NTLM_HASH,
688 if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
690 (void)fprintf(stderr,
"AcceptSecurityContext status: %s (0x%08" PRIX32
")\n",
691 GetSecurityStatusString(status), status);
695 ntlm->haveContext = TRUE;
696 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
699static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
704 test_ntlm_server_uninit(ntlm);
705 sspi_FreeSecNtlmSettings(ntlm->settingsV2);
709WINPR_ATTR_MALLOC(test_ntlm_server_free, 1)
710static TEST_NTLM_SERVER* test_ntlm_server_new(
void)
712 TEST_NTLM_SERVER* ntlm = (TEST_NTLM_SERVER*)calloc(1,
sizeof(TEST_NTLM_SERVER));
716 ntlm->settingsV2 = sspi_AllocSecNtlmSettings();
717 if (!ntlm->settingsV2)
726static BOOL test_default(
const struct test_input_t* arg, psSspiNtlmHashCallback fkt)
732 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s}\n", arg->user, arg->domain,
733 arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE");
738 TEST_NTLM_CLIENT* client = test_ntlm_client_new();
739 TEST_NTLM_SERVER* server = test_ntlm_server_new();
741 if (!client || !server)
743 printf(
"Memory allocation failed\n");
747 int status = test_ntlm_client_init(client, arg->user, arg->domain, arg->pwd);
751 printf(
"test_ntlm_client_init failure\n");
759 status = test_ntlm_server_init(server, arg, fkt);
763 printf(
"test_ntlm_server_init failure\n");
770 status = test_ntlm_client_authenticate(client);
774 printf(
"test_ntlm_client_authenticate failure\n");
778 if (client->haveContext)
780 if (!test_attributes(client->table, &client->context))
789 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
790 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
791 SECURITY_STATUS rc = client->table->SetContextAttributes(
792 &client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
794 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
796 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
797 rc = client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
800 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
802 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
803 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
804 rc = client->table->SetContextAttributes(
805 &client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
807 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
809 rc = client->table->SetContextAttributes(
810 &client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
812 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
815 PSecBuffer pSecBuffer = &(client->outputBuffer[0]);
819 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_NEGOTIATE) - 1;
820 free(pSecBuffer->pvBuffer);
821 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
823 if (!pSecBuffer->pvBuffer)
825 printf(
"Memory allocation failed\n");
829 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
832 (void)fprintf(stderr,
"NTLM_NEGOTIATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
833 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
838 server->haveInputBuffer = TRUE;
839 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
840 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
841 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
842 status = test_ntlm_server_authenticate(arg, server);
846 printf(
"test_ntlm_server_authenticate failure\n");
850 if (server->haveContext)
852 if (!test_attributes(server->table, &server->context))
861 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
862 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
863 SECURITY_STATUS rc = client->table->SetContextAttributes(
864 &server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
866 WINPR_ASSERT(rc == SEC_E_OK);
868 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
869 rc = client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
872 WINPR_ASSERT(rc == SEC_E_OK);
874 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
875 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
876 rc = server->table->SetContextAttributes(
877 &server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
879 WINPR_ASSERT(rc == SEC_E_OK);
881 rc = server->table->SetContextAttributes(
882 &server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
884 WINPR_ASSERT(rc == SEC_E_OK);
887 pSecBuffer = &(server->outputBuffer[0]);
892 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_CHALLENGE) - 1;
893 free(pSecBuffer->pvBuffer);
894 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
896 if (!pSecBuffer->pvBuffer)
898 printf(
"Memory allocation failed\n");
902 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
903 AuthNtlmMessage.type = 2;
904 AuthNtlmMessage.length = pSecBuffer->cbBuffer;
905 AuthNtlmMessage.buffer = (BYTE*)pSecBuffer->pvBuffer;
906 SECURITY_STATUS rc = server->table->SetContextAttributes(
907 &server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, &AuthNtlmMessage,
913 (void)fprintf(stderr,
"NTLM_CHALLENGE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
914 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
919 client->haveInputBuffer = TRUE;
920 client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
921 client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
922 client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
923 status = test_ntlm_client_authenticate(client);
927 printf(
"test_ntlm_client_authenticate failure\n");
931 pSecBuffer = &(client->outputBuffer[0]);
935 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_AUTHENTICATE) - 1;
936 free(pSecBuffer->pvBuffer);
937 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
939 if (!pSecBuffer->pvBuffer)
941 printf(
"Memory allocation failed\n");
945 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
948 (void)fprintf(stderr,
"NTLM_AUTHENTICATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
949 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
953 server->haveInputBuffer = TRUE;
954 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
955 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
956 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
957 status = test_ntlm_server_authenticate(arg, server);
961 printf(
"test_ntlm_server_authenticate failure\n");
965 if (!test_short_signature(server->table, &server->context))
967 printf(
"test_short_signature failure\n");
977 test_ntlm_client_free(client);
978 test_ntlm_server_free(server);
980 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s} returns %d\n", arg->user,
981 arg->domain, arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE", rc);
986static SECURITY_STATUS testCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
987 const SecBuffer* ntproofvalue,
const BYTE* randkey,
988 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
990 const struct test_input_t* arg = client;
992 WINPR_ASSERT(authIdentity);
993 WINPR_ASSERT(ntproofvalue);
994 WINPR_ASSERT(randkey);
996 WINPR_ASSERT(micvalue);
997 WINPR_ASSERT(ntlmhash);
999 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
1001 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
1002 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
1003 return SEC_E_ENCRYPT_FAILURE;
1007 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
1008 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
1009 return SEC_E_ENCRYPT_FAILURE;
1012 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
1013 return SEC_E_DECRYPT_FAILURE;
1019static SECURITY_STATUS testFailCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
1020 const SecBuffer* ntproofvalue,
const BYTE* randkey,
1021 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
1023 const struct test_input_t* arg = client;
1025 WINPR_ASSERT(authIdentity);
1026 WINPR_ASSERT(ntproofvalue);
1027 WINPR_ASSERT(randkey);
1029 WINPR_ASSERT(micvalue);
1030 WINPR_ASSERT(ntlmhash);
1032 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
1034 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
1035 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
1036 return SEC_E_ENCRYPT_FAILURE;
1040 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
1041 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
1042 return SEC_E_ENCRYPT_FAILURE;
1045 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
1046 return SEC_E_DECRYPT_FAILURE;
1048 return SEC_E_DECRYPT_FAILURE;
1051int TestSspiNTLM(
int argc,
char* argv[])
1056 const struct test_input_t inputs[] = {
1057 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1059 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1061 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
"", TEST_EMPTY_PWD_NTLM_HASH,
1062 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, TRUE },
1063 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
nullptr, TEST_EMPTY_PWD_NTLM_HASH,
1064 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, FALSE }
1067 for (
size_t x = 0; x < ARRAYSIZE(inputs); x++)
1069 const struct test_input_t* cur = &inputs[x];
1070 const BOOL res = test_default(cur,
nullptr);
1071 if (res != cur->expected)
1073 printf(
"%s [%" PRIuz
"] fail 1!\n", __func__, x);
1076 const BOOL res2 = test_default(cur, testCallback);
1077 if (res2 != cur->expected)
1079 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1082 const BOOL res3 = test_default(cur, testFailCallback);
1085 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1089 printf(
"%s success!\n", __func__);