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 void* getServerAuthData(TEST_NTLM_SERVER* ntlm,
const struct test_input_t* arg,
264 psSspiNtlmHashCallback fkt)
269 ntlm->authData.identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
270 ntlm->authData.identity.Length =
sizeof(SEC_WINNT_AUTH_IDENTITY_EX);
271 ntlm->authData.identity.Flags |=
272 SEC_WINNT_AUTH_IDENTITY_EXTENDED | SEC_WINNT_AUTH_IDENTITY_UNICODE;
273 ntlm->settings.hashCallback = fkt;
274 ntlm->settings.hashCallbackArg = arg;
275 ntlm->authData.ntlmSettings = &ntlm->settings;
276 ntlm->UseCallback = TRUE;
277 return &ntlm->authData;
279 ntlm->UseCallback = FALSE;
284static int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm,
const char* user,
const char* domain,
285 const char* password)
287 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
291 SecInvalidateHandle(&(ntlm->context));
292 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
295 const int rc = sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
299 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
301 if (status != SEC_E_OK)
303 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
304 GetSecurityStatusString(status), status);
308 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
309 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND,
310 nullptr, &ntlm->identity,
nullptr,
nullptr,
311 &ntlm->credentials, &ntlm->expiration);
313 if (status != SEC_E_OK)
315 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
316 GetSecurityStatusString(status), status);
320 ntlm->haveContext = FALSE;
321 ntlm->haveInputBuffer = FALSE;
322 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
323 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
324 ntlm->fContextReq = 0;
327 ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
328 ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
329 ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
333static void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
338 if (ntlm->outputBuffer[0].pvBuffer)
340 free(ntlm->outputBuffer[0].pvBuffer);
341 ntlm->outputBuffer[0].pvBuffer =
nullptr;
344 free(ntlm->identity.User);
345 free(ntlm->identity.Domain);
346 free(ntlm->identity.Password);
347 free(ntlm->ServicePrincipalName);
351 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
352 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
353 (status == SEC_E_UNSUPPORTED_FUNCTION));
355 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
356 WINPR_ASSERT((status == SEC_E_OK) || (status = SEC_E_INVALID_HANDLE));
358 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
359 WINPR_ASSERT((status == SEC_E_OK) || (status == SEC_E_SECPKG_NOT_FOUND) ||
360 (status == SEC_E_UNSUPPORTED_FUNCTION));
402static BOOL IsSecurityStatusError(SECURITY_STATUS status)
409 case SEC_I_CONTINUE_NEEDED:
410 case SEC_I_COMPLETE_NEEDED:
411 case SEC_I_COMPLETE_AND_CONTINUE:
412 case SEC_I_LOCAL_LOGON:
413 case SEC_I_CONTEXT_EXPIRED:
414 case SEC_I_INCOMPLETE_CREDENTIALS:
415 case SEC_I_RENEGOTIATE:
416 case SEC_I_NO_LSA_CONTEXT:
417 case SEC_I_SIGNATURE_NEEDED:
418 case SEC_I_NO_RENEGOTIATION:
429static int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
431 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
434 if (ntlm->outputBuffer[0].pvBuffer)
436 free(ntlm->outputBuffer[0].pvBuffer);
437 ntlm->outputBuffer[0].pvBuffer =
nullptr;
440 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
441 ntlm->outputBufferDesc.cBuffers = 1;
442 ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
443 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
444 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
445 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
447 if (!ntlm->outputBuffer[0].pvBuffer)
450 if (ntlm->haveInputBuffer)
452 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
453 ntlm->inputBufferDesc.cBuffers = 1;
454 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
455 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
458 if ((!ntlm) || (!ntlm->table))
460 (void)fprintf(stderr,
"ntlm_authenticate: invalid ntlm context\n");
464 status = ntlm->table->InitializeSecurityContext(
465 &ntlm->credentials, (ntlm->haveContext) ? &ntlm->context :
nullptr,
466 (ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : nullptr, ntlm->fContextReq, 0,
467 SECURITY_NATIVE_DREP, (ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : nullptr, 0,
468 &ntlm->context, &ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
470 if (IsSecurityStatusError(status))
473 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
475 if (ntlm->table->CompleteAuthToken)
478 ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
483 if (status == SEC_I_COMPLETE_NEEDED)
485 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
486 status = SEC_I_CONTINUE_NEEDED;
489 if (ntlm->haveInputBuffer)
491 free(ntlm->inputBuffer[0].pvBuffer);
492 ntlm->inputBuffer[0].pvBuffer =
nullptr;
495 ntlm->haveInputBuffer = TRUE;
496 ntlm->haveContext = TRUE;
497 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
500static void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
505 test_ntlm_client_uninit(ntlm);
509WINPR_ATTR_MALLOC(test_ntlm_client_free, 1)
510static TEST_NTLM_CLIENT* test_ntlm_client_new(
void)
512 TEST_NTLM_CLIENT* ntlm = (TEST_NTLM_CLIENT*)calloc(1,
sizeof(TEST_NTLM_CLIENT));
521static int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm,
const struct test_input_t* arg,
522 psSspiNtlmHashCallback fkt)
524 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
528 ntlm->UseNtlmV2Hash = TRUE;
529 SecInvalidateHandle(&(ntlm->context));
530 ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
532 return SEC_E_INTERNAL_ERROR;
534 status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
536 if (status != SEC_E_OK)
538 (void)fprintf(stderr,
"QuerySecurityPackageInfo status: %s (0x%08" PRIX32
")\n",
539 GetSecurityStatusString(status), status);
543 void* authData = getServerAuthData(ntlm, arg, fkt);
544 ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
545 status = ntlm->table->AcquireCredentialsHandle(
nullptr, NTLM_PACKAGE_NAME, SECPKG_CRED_INBOUND,
546 nullptr, authData,
nullptr,
nullptr,
547 &ntlm->credentials, &ntlm->expiration);
549 if (status != SEC_E_OK)
551 (void)fprintf(stderr,
"AcquireCredentialsHandle status: %s (0x%08" PRIX32
")\n",
552 GetSecurityStatusString(status), status);
556 ntlm->haveContext = FALSE;
557 ntlm->haveInputBuffer = FALSE;
558 ZeroMemory(&ntlm->inputBuffer,
sizeof(
SecBuffer));
559 ZeroMemory(&ntlm->outputBuffer,
sizeof(
SecBuffer));
560 ntlm->fContextReq = 0;
562 ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
563 ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
564 ntlm->fContextReq |= ASC_REQ_CONNECTION;
565 ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
566 ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
567 ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
568 ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
572static void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
577 if (ntlm->outputBuffer[0].pvBuffer)
579 free(ntlm->outputBuffer[0].pvBuffer);
580 ntlm->outputBuffer[0].pvBuffer =
nullptr;
583 free(ntlm->ServicePrincipalName);
587 SECURITY_STATUS status = ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
588 WINPR_ASSERT(status == SEC_E_OK);
589 status = ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
590 WINPR_ASSERT(status == SEC_E_OK);
591 status = ntlm->table->DeleteSecurityContext(&ntlm->context);
592 WINPR_ASSERT(status == SEC_E_OK);
597static int test_ntlm_server_authenticate(
const struct test_input_t* targ, TEST_NTLM_SERVER* ntlm)
599 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
604 ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
605 ntlm->inputBufferDesc.cBuffers = 1;
606 ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
607 ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
608 ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
609 ntlm->outputBufferDesc.cBuffers = 1;
610 ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
611 ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
612 ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
613 ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
615 if (!ntlm->outputBuffer[0].pvBuffer)
618 status = ntlm->table->AcceptSecurityContext(
619 &ntlm->credentials, ntlm->haveContext ? &ntlm->context : nullptr, &ntlm->inputBufferDesc,
620 ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context, &ntlm->outputBufferDesc,
621 &ntlm->pfContextAttr, &ntlm->expiration);
623 if (status == SEC_I_CONTINUE_NEEDED)
627 if (!ntlm->UseCallback)
629 if (ntlm->UseNtlmV2Hash)
631 AuthNtlmHash.Version = 2;
632 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlmv2, 16);
636 AuthNtlmHash.Version = 1;
637 CopyMemory(AuthNtlmHash.NtlmHash, targ->ntlm, 16);
640 status = ntlm->table->SetContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_NTLM_HASH,
646 if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
648 (void)fprintf(stderr,
"AcceptSecurityContext status: %s (0x%08" PRIX32
")\n",
649 GetSecurityStatusString(status), status);
653 ntlm->haveContext = TRUE;
654 return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
657static void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
662 test_ntlm_server_uninit(ntlm);
666WINPR_ATTR_MALLOC(test_ntlm_server_free, 1)
667static TEST_NTLM_SERVER* test_ntlm_server_new(
void)
669 TEST_NTLM_SERVER* ntlm = (TEST_NTLM_SERVER*)calloc(1,
sizeof(TEST_NTLM_SERVER));
678static BOOL test_default(
const struct test_input_t* arg, psSspiNtlmHashCallback fkt)
684 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s}\n", arg->user, arg->domain,
685 arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE");
690 TEST_NTLM_CLIENT* client = test_ntlm_client_new();
691 TEST_NTLM_SERVER* server = test_ntlm_server_new();
693 if (!client || !server)
695 printf(
"Memory allocation failed\n");
699 int status = test_ntlm_client_init(client, arg->user, arg->domain, arg->pwd);
703 printf(
"test_ntlm_client_init failure\n");
711 status = test_ntlm_server_init(server, arg, fkt);
715 printf(
"test_ntlm_server_init failure\n");
722 status = test_ntlm_client_authenticate(client);
726 printf(
"test_ntlm_client_authenticate failure\n");
730 if (client->haveContext)
732 if (!test_attributes(client->table, &client->context))
741 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
742 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
743 SECURITY_STATUS rc = client->table->SetContextAttributes(
744 &client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
746 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
748 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
749 rc = client->table->SetContextAttributes(&client->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
752 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
754 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
755 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
756 rc = client->table->SetContextAttributes(
757 &client->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
759 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
761 rc = client->table->SetContextAttributes(
762 &client->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
764 WINPR_ASSERT((rc == SEC_E_OK) || (rc == SEC_E_SECPKG_NOT_FOUND));
767 PSecBuffer pSecBuffer = &(client->outputBuffer[0]);
771 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_NEGOTIATE) - 1;
772 free(pSecBuffer->pvBuffer);
773 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
775 if (!pSecBuffer->pvBuffer)
777 printf(
"Memory allocation failed\n");
781 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_NEGOTIATE, pSecBuffer->cbBuffer);
784 (void)fprintf(stderr,
"NTLM_NEGOTIATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
785 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
790 server->haveInputBuffer = TRUE;
791 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
792 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
793 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
794 status = test_ntlm_server_authenticate(arg, server);
798 printf(
"test_ntlm_server_authenticate failure\n");
802 if (server->haveContext)
804 if (!test_attributes(server->table, &server->context))
813 CopyMemory(AuthNtlmTimestamp.Timestamp, TEST_NTLM_TIMESTAMP, 8);
814 AuthNtlmTimestamp.ChallengeOrResponse = TRUE;
815 SECURITY_STATUS rc = client->table->SetContextAttributes(
816 &server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP, &AuthNtlmTimestamp,
818 WINPR_ASSERT(rc == SEC_E_OK);
820 AuthNtlmTimestamp.ChallengeOrResponse = FALSE;
821 rc = client->table->SetContextAttributes(&server->context, SECPKG_ATTR_AUTH_NTLM_TIMESTAMP,
824 WINPR_ASSERT(rc == SEC_E_OK);
826 CopyMemory(AuthNtlmClientChallenge.ClientChallenge, TEST_NTLM_CLIENT_CHALLENGE, 8);
827 CopyMemory(AuthNtlmServerChallenge.ServerChallenge, TEST_NTLM_SERVER_CHALLENGE, 8);
828 rc = server->table->SetContextAttributes(
829 &server->context, SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE, &AuthNtlmClientChallenge,
831 WINPR_ASSERT(rc == SEC_E_OK);
833 rc = server->table->SetContextAttributes(
834 &server->context, SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE, &AuthNtlmServerChallenge,
836 WINPR_ASSERT(rc == SEC_E_OK);
839 pSecBuffer = &(server->outputBuffer[0]);
844 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_CHALLENGE) - 1;
845 free(pSecBuffer->pvBuffer);
846 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
848 if (!pSecBuffer->pvBuffer)
850 printf(
"Memory allocation failed\n");
854 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_CHALLENGE, pSecBuffer->cbBuffer);
855 AuthNtlmMessage.type = 2;
856 AuthNtlmMessage.length = pSecBuffer->cbBuffer;
857 AuthNtlmMessage.buffer = (BYTE*)pSecBuffer->pvBuffer;
858 SECURITY_STATUS rc = server->table->SetContextAttributes(
859 &server->context, SECPKG_ATTR_AUTH_NTLM_MESSAGE, &AuthNtlmMessage,
865 (void)fprintf(stderr,
"NTLM_CHALLENGE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
866 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
871 client->haveInputBuffer = TRUE;
872 client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
873 client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
874 client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
875 status = test_ntlm_client_authenticate(client);
879 printf(
"test_ntlm_client_authenticate failure\n");
883 pSecBuffer = &(client->outputBuffer[0]);
887 pSecBuffer->cbBuffer =
sizeof(TEST_NTLM_AUTHENTICATE) - 1;
888 free(pSecBuffer->pvBuffer);
889 pSecBuffer->pvBuffer = malloc(pSecBuffer->cbBuffer);
891 if (!pSecBuffer->pvBuffer)
893 printf(
"Memory allocation failed\n");
897 CopyMemory(pSecBuffer->pvBuffer, TEST_NTLM_AUTHENTICATE, pSecBuffer->cbBuffer);
900 (void)fprintf(stderr,
"NTLM_AUTHENTICATE (length = %" PRIu32
"):\n", pSecBuffer->cbBuffer);
901 winpr_HexDump(
"sspi.test", WLOG_DEBUG, (BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
905 server->haveInputBuffer = TRUE;
906 server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
907 server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
908 server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
909 status = test_ntlm_server_authenticate(arg, server);
913 printf(
"test_ntlm_server_authenticate failure\n");
923 test_ntlm_client_free(client);
924 test_ntlm_server_free(server);
926 printf(
"testcase {user=%s, domain=%s, password=%s, dynamic=%s} returns %d\n", arg->user,
927 arg->domain, arg->pwd, arg->dynamic ?
"TRUE" :
"FALSE", rc);
932static SECURITY_STATUS testCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
933 const SecBuffer* ntproofvalue,
const BYTE* randkey,
934 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
936 const struct test_input_t* arg = client;
938 WINPR_ASSERT(authIdentity);
939 WINPR_ASSERT(ntproofvalue);
940 WINPR_ASSERT(randkey);
942 WINPR_ASSERT(micvalue);
943 WINPR_ASSERT(ntlmhash);
945 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
947 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
948 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
949 return SEC_E_ENCRYPT_FAILURE;
953 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
954 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
955 return SEC_E_ENCRYPT_FAILURE;
958 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
959 return SEC_E_DECRYPT_FAILURE;
965static SECURITY_STATUS testFailCallback(
void* client,
const SEC_WINNT_AUTH_IDENTITY* authIdentity,
966 const SecBuffer* ntproofvalue,
const BYTE* randkey,
967 const BYTE* mic,
const SecBuffer* micvalue, BYTE* ntlmhash)
969 const struct test_input_t* arg = client;
971 WINPR_ASSERT(authIdentity);
972 WINPR_ASSERT(ntproofvalue);
973 WINPR_ASSERT(randkey);
975 WINPR_ASSERT(micvalue);
976 WINPR_ASSERT(ntlmhash);
978 if ((authIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) != 0)
980 if (!NTOWFv2FromHashW(arg->ntlm, authIdentity->User, authIdentity->UserLength * 2,
981 authIdentity->Domain, authIdentity->DomainLength * 2, ntlmhash))
982 return SEC_E_ENCRYPT_FAILURE;
986 if (!NTOWFv2FromHashA(arg->ntlm, (
char*)authIdentity->User, authIdentity->UserLength,
987 (
char*)authIdentity->Domain, authIdentity->DomainLength, ntlmhash))
988 return SEC_E_ENCRYPT_FAILURE;
991 if (memcmp(ntlmhash, arg->ntlmv2, 16) != 0)
992 return SEC_E_DECRYPT_FAILURE;
994 return SEC_E_DECRYPT_FAILURE;
997int TestSspiNTLM(
int argc,
char* argv[])
1002 const struct test_input_t inputs[] = {
1003 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1005 { TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD, TEST_NTLM_HASH, TEST_NTLM_V2_HASH,
1007 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
"", TEST_EMPTY_PWD_NTLM_HASH,
1008 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, TRUE },
1009 { TEST_NTLM_USER, TEST_NTLM_DOMAIN,
nullptr, TEST_EMPTY_PWD_NTLM_HASH,
1010 TEST_EMPTY_PWD_NTLM_V2_HASH, TRUE, FALSE }
1013 for (
size_t x = 0; x < ARRAYSIZE(inputs); x++)
1015 const struct test_input_t* cur = &inputs[x];
1016 const BOOL res = test_default(cur,
nullptr);
1017 if (res != cur->expected)
1019 printf(
"%s [%" PRIuz
"] fail 1!\n", __func__, x);
1022 const BOOL res2 = test_default(cur, testCallback);
1023 if (res2 != cur->expected)
1025 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1028 const BOOL res3 = test_default(cur, testFailCallback);
1031 printf(
"%s [%" PRIuz
"] fail 2!\n", __func__, x);
1035 printf(
"%s success!\n", __func__);