21#include <winpr/config.h>
24#include <winpr/wtypes.h>
25#include <winpr/assert.h>
26#include <winpr/sspi.h>
27#include <winpr/tchar.h>
28#include <winpr/registry.h>
29#include <winpr/build-config.h>
30#include <winpr/asn1.h>
34#include "../NTLM/ntlm.h"
35#include "../NTLM/ntlm_export.h"
36#include "../Kerberos/kerberos.h"
38#include "../../utils.h"
40#define TAG WINPR_TAG("negotiate")
42#define NEGO_REG_KEY "Software\\%s\\SSPI\\Negotiate"
44static const char PACKAGE_NAME_DISABLE_ALL[] =
"none";
45static const char PACKAGE_NAME_NTLM[] =
"ntlm";
46static const char PACKAGE_NAME_KERBEROS[] =
"kerberos";
47static const char PACKAGE_NAME_KERBEROS_U2U[] =
"u2u";
77 "Microsoft Package Negotiator"
80static WCHAR NEGOTIATE_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
81static WCHAR NEGOTIATE_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
88 NEGOTIATE_SecPkgInfoW_NameBuffer,
89 NEGOTIATE_SecPkgInfoW_CommentBuffer
92static const WinPrAsn1_OID spnego_OID = { 6, (BYTE*)
"\x2b\x06\x01\x05\x05\x02" };
94 (BYTE*)
"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03" };
95static const WinPrAsn1_OID kerberos_OID = { 9, (BYTE*)
"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
97 (BYTE*)
"\x2a\x86\x48\x82\xf7\x12\x01\x02\x02" };
98static const WinPrAsn1_OID ntlm_OID = { 10, (BYTE*)
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a" };
100static const WinPrAsn1_OID negoex_OID = { 10, (BYTE*)
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e" };
103static const SecPkg SecPkgTable[] = {
104 { KERBEROS_SSP_NAME, &KERBEROS_SecurityFunctionTableA, &KERBEROS_SecurityFunctionTableW },
105 { KERBEROS_SSP_NAME, &KERBEROS_SecurityFunctionTableA, &KERBEROS_SecurityFunctionTableW },
106 { NTLM_SSP_NAME, &NTLM_SecurityFunctionTableA, &NTLM_SecurityFunctionTableW }
109static const Mech MechTable[] = {
110 { &kerberos_u2u_OID, &SecPkgTable[0], ISC_REQ_INTEGRITY | ISC_REQ_USE_SESSION_KEY, TRUE },
111 { &kerberos_OID, &SecPkgTable[1], ISC_REQ_INTEGRITY, TRUE },
112 { &ntlm_OID, &SecPkgTable[2], 0, FALSE },
115static const SecPkg SecPkgTable[] = { { NTLM_SSP_NAME, &NTLM_SecurityFunctionTableA,
116 &NTLM_SecurityFunctionTableW } };
118static const Mech MechTable[] = {
119 { &ntlm_OID, &SecPkgTable[0], 0, FALSE },
123static const size_t MECH_COUNT = ARRAYSIZE(MechTable);
136 enum NegState negState;
144static const NegToken empty_neg_token = { NOSTATE, FALSE,
145 { 0,
nullptr }, { 0, 0,
nullptr },
146 { 0, 0,
nullptr }, { 0, 0,
nullptr } };
152 WINPR_ASSERT(init_context);
158 if (init_context->spnego)
160 init_context->mechTypes.pvBuffer = malloc(init_context->mechTypes.cbBuffer);
161 if (!init_context->mechTypes.pvBuffer)
168 *context = *init_context;
175 WINPR_ASSERT(context);
177 if (context->mechTypes.pvBuffer)
178 free(context->mechTypes.pvBuffer);
182static const char* negotiate_mech_name(
const WinPrAsn1_OID* oid)
184 if (sspi_gss_oid_compare(oid, &spnego_OID))
185 return "SPNEGO (1.3.6.1.5.5.2)";
186 else if (sspi_gss_oid_compare(oid, &kerberos_u2u_OID))
187 return "Kerberos user to user (1.2.840.113554.1.2.2.3)";
188 else if (sspi_gss_oid_compare(oid, &kerberos_OID))
189 return "Kerberos (1.2.840.113554.1.2.2)";
190 else if (sspi_gss_oid_compare(oid, &kerberos_wrong_OID))
191 return "Kerberos [wrong OID] (1.2.840.48018.1.2.2)";
192 else if (sspi_gss_oid_compare(oid, &ntlm_OID))
193 return "NTLM (1.3.6.1.4.1.311.2.2.10)";
194 else if (sspi_gss_oid_compare(oid, &negoex_OID))
195 return "NegoEx (1.3.6.1.4.1.311.2.2.30)";
197 return "Unknown mechanism";
200static const Mech* negotiate_GetMechByOID(
const WinPrAsn1_OID* oid)
206 if (sspi_gss_oid_compare(&testOid, &kerberos_wrong_OID))
208 testOid.len = kerberos_OID.len;
209 testOid.data = kerberos_OID.data;
212 for (
size_t i = 0; i < MECH_COUNT; i++)
214 if (sspi_gss_oid_compare(&testOid, MechTable[i].oid))
215 return &MechTable[i];
220static PSecHandle negotiate_FindCredential(MechCred* creds,
const Mech* mech)
227 for (
size_t i = 0; i < MECH_COUNT; i++)
229 MechCred* cred = &creds[i];
231 if (cred->mech == mech)
242static BOOL negotiate_get_dword(HKEY hKey,
const char* subkey, DWORD* pdwValue)
246 DWORD dwSize =
sizeof(dwValue);
247 LONG rc = RegQueryValueExA(hKey, subkey,
nullptr, &dwType, (BYTE*)&dwValue, &dwSize);
249 if (rc != ERROR_SUCCESS)
251 if (dwType != REG_DWORD)
258static BOOL negotiate_get_config_from_auth_package_list(
void* pAuthData, BOOL* kerberos, BOOL* ntlm,
262 char* tok_ctx =
nullptr;
263 char* PackageList =
nullptr;
268 char* tok_ptr = strtok_s(PackageList,
",", &tok_ctx);
272 const char* PackageName = tok_ptr;
273 BOOL PackageInclude = TRUE;
275 if (PackageName[0] ==
'!')
277 PackageName = &PackageName[1];
278 PackageInclude = FALSE;
281 if (_stricmp(PackageName, PACKAGE_NAME_NTLM) == 0)
283 *ntlm = PackageInclude;
285 else if (_stricmp(PackageName, PACKAGE_NAME_KERBEROS) == 0)
287 *kerberos = PackageInclude;
289 else if (_stricmp(PackageName, PACKAGE_NAME_KERBEROS_U2U) == 0)
291 *u2u = PackageInclude;
293 else if (_stricmp(PackageName, PACKAGE_NAME_DISABLE_ALL) == 0)
299 if (PackageName != PackageList)
301 WLog_WARN(TAG,
"Special keyword '%s' not first in list, aborting", PackageName);
307 WLog_WARN(TAG,
"Unknown authentication package name: %s, ignoring", PackageName);
310 tok_ptr = strtok_s(
nullptr,
",", &tok_ctx);
319static BOOL negotiate_get_config(
void* pAuthData, BOOL* kerberos, BOOL* ntlm, BOOL* u2u)
323 WINPR_ASSERT(kerberos);
327#if !defined(WITH_KRB5_NO_NTLM_FALLBACK)
332#if defined(WITH_KRB5)
340 if (negotiate_get_config_from_auth_package_list(pAuthData, kerberos, ntlm, u2u))
346 char* key = winpr_getApplicatonDetailsRegKey(NEGO_REG_KEY);
350 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
352 if (rc == ERROR_SUCCESS)
356 if (negotiate_get_dword(hKey, PACKAGE_NAME_KERBEROS, &dwValue))
357 *kerberos = (dwValue != 0);
359 if (negotiate_get_dword(hKey, PACKAGE_NAME_KERBEROS_U2U, &dwValue))
360 *u2u = (dwValue != 0);
362#if !defined(WITH_KRB5_NO_NTLM_FALLBACK)
363 if (negotiate_get_dword(hKey, PACKAGE_NAME_NTLM, &dwValue))
364 *ntlm = (dwValue != 0);
375static BOOL negotiate_write_neg_token(
PSecBuffer output_buffer, NegToken* token)
377 WINPR_ASSERT(output_buffer);
381 WinPrAsn1Encoder* enc =
nullptr;
388 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
396 if (!WinPrAsn1EncAppContainer(enc, 0))
400 if (!WinPrAsn1EncOID(enc, &spnego_OID))
405 if (!WinPrAsn1EncContextualSeqContainer(enc, token->init ? 0 : 1))
408 WLog_DBG(TAG, token->init ?
"Writing negTokenInit..." :
"Writing negTokenResp...");
413 if (!WinPrAsn1EncContextualRawContent(enc, 0, &mechTypes))
415 WLog_DBG(TAG,
"\tmechTypes [0] (%" PRIu32
" bytes)", token->mechTypes.cbBuffer);
418 else if (token->negState != NOSTATE)
420 if (!WinPrAsn1EncContextualEnumerated(enc, 0, token->negState))
422 WLog_DBG(TAG,
"\tnegState [0] (%d)", token->negState);
426 if (token->supportedMech.len)
428 if (!WinPrAsn1EncContextualOID(enc, 1, &token->supportedMech))
430 WLog_DBG(TAG,
"\tsupportedMech [1] (%s)", negotiate_mech_name(&token->supportedMech));
434 if (token->mechToken.cbBuffer)
436 if (WinPrAsn1EncContextualOctetString(enc, 2, &mechToken) == 0)
438 WLog_DBG(TAG,
"\tmechToken [2] (%" PRIu32
" bytes)", token->mechToken.cbBuffer);
442 if (token->mic.cbBuffer)
444 if (WinPrAsn1EncContextualOctetString(enc, 3, &mechListMic) == 0)
446 WLog_DBG(TAG,
"\tmechListMIC [3] (%" PRIu32
" bytes)", token->mic.cbBuffer);
450 if (!WinPrAsn1EncEndContainer(enc))
456 if (!WinPrAsn1EncEndContainer(enc))
460 if (!WinPrAsn1EncStreamSize(enc, &len) || len > output_buffer->cbBuffer)
463 if (len > UINT32_MAX)
466 Stream_StaticInit(&s, output_buffer->pvBuffer, len);
468 if (WinPrAsn1EncToStream(enc, &s))
470 output_buffer->cbBuffer = (UINT32)len;
475 WinPrAsn1Encoder_Free(&enc);
479static BOOL negotiate_read_neg_token(
PSecBuffer input, NegToken* token)
484 WinPrAsn1_tagId contextual = 0;
485 WinPrAsn1_tag tag = 0;
493 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, input->pvBuffer, input->cbBuffer);
495 if (!WinPrAsn1DecPeekTag(&dec, &tag))
501 if (!WinPrAsn1DecReadApp(&dec, &tag, &dec2) || tag != 0)
506 if (!WinPrAsn1DecReadOID(&dec, &oid, FALSE))
509 if (!sspi_gss_oid_compare(&spnego_OID, &oid))
513 if (!WinPrAsn1DecReadContextualSequence(&dec, 0, &err, &dec2))
519 else if (!WinPrAsn1DecReadContextualSequence(&dec, 1, &err, &dec2))
523 WLog_DBG(TAG, token->init ?
"Reading negTokenInit..." :
"Reading negTokenResp...");
528 if (!WinPrAsn1DecReadContextualTag(&dec, &contextual, &dec2))
537 wStream s = WinPrAsn1DecGetStream(&dec2);
538 token->mechTypes.BufferType = SECBUFFER_TOKEN;
539 const size_t mlen = Stream_Length(&s);
540 if (mlen > UINT32_MAX)
542 token->mechTypes.cbBuffer = (UINT32)mlen;
543 token->mechTypes.pvBuffer = Stream_Buffer(&s);
544 WLog_DBG(TAG,
"\tmechTypes [0] (%" PRIu32
" bytes)", token->mechTypes.cbBuffer);
549 WinPrAsn1_ENUMERATED rd = 0;
550 if (!WinPrAsn1DecReadEnumerated(&dec2, &rd))
555 case ACCEPT_COMPLETED:
556 case ACCEPT_INCOMPLETE:
561 WLog_ERR(TAG,
"Invalid negState enumeration value %d", rd);
565 token->negState = WINPR_ASSERTING_INT_CAST(
enum NegState, rd);
566 WLog_DBG(TAG,
"\tnegState [0] (%d)", rd);
573 if (!WinPrAsn1DecPeekTagAndLen(&dec2, &tag, &len) || (tag != ER_TAG_BIT_STRING))
575 WLog_DBG(TAG,
"\treqFlags [1] (%" PRIuz
" bytes)", len);
580 if (!WinPrAsn1DecReadOID(&dec2, &token->supportedMech, FALSE))
582 WLog_DBG(TAG,
"\tsupportedMech [1] (%s)",
583 negotiate_mech_name(&token->supportedMech));
588 if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE))
590 if (octet_string.len > UINT32_MAX)
592 token->mechToken.cbBuffer = (UINT32)octet_string.len;
593 token->mechToken.pvBuffer = octet_string.data;
594 token->mechToken.BufferType = SECBUFFER_TOKEN;
595 WLog_DBG(TAG,
"\tmechToken [2] (%" PRIuz
" bytes)", octet_string.len);
599 if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE))
601 if (octet_string.len > UINT32_MAX)
603 token->mic.cbBuffer = (UINT32)octet_string.len;
604 token->mic.pvBuffer = octet_string.data;
605 token->mic.BufferType = SECBUFFER_TOKEN;
606 WLog_DBG(TAG,
"\tmechListMIC [3] (%" PRIuz
" bytes)", octet_string.len);
609 WLog_ERR(TAG,
"unknown contextual item %d", contextual);
612 }
while (WinPrAsn1DecPeekTag(&dec, &tag));
617static SECURITY_STATUS negotiate_mic_exchange(
NEGOTIATE_CONTEXT* context, NegToken* input_token,
618 NegToken* output_token,
PSecBuffer output_buffer)
620 SecBuffer mic_buffers[2] = WINPR_C_ARRAY_INIT;
621 SecBufferDesc mic_buffer_desc = { SECBUFFER_VERSION, 2, mic_buffers };
622 SECURITY_STATUS status = 0;
624 WINPR_ASSERT(context);
625 WINPR_ASSERT(input_token);
626 WINPR_ASSERT(output_token);
627 WINPR_ASSERT(context->mech);
628 WINPR_ASSERT(context->mech->pkg);
633 mic_buffers[0] = context->mechTypes;
636 if (input_token->mic.cbBuffer > 0)
638 mic_buffers[1] = input_token->mic;
640 status = table->VerifySignature(&context->sub_context, &mic_buffer_desc, 0,
nullptr);
641 if (status != SEC_E_OK)
644 output_token->negState = ACCEPT_COMPLETED;
648 if (input_token->negState != ACCEPT_COMPLETED)
651 output_token->mic.BufferType = SECBUFFER_TOKEN;
654 output_token->mic.cbBuffer = output_buffer->cbBuffer - output_token->mechToken.cbBuffer;
655 output_token->mic.pvBuffer =
656 (BYTE*)output_buffer->pvBuffer + output_token->mechToken.cbBuffer;
658 mic_buffers[1] = output_token->mic;
660 status = table->MakeSignature(&context->sub_context, 0, &mic_buffer_desc, 0);
661 if (status != SEC_E_OK)
664 output_token->mic = mic_buffers[1];
668 const SSPI_PACKAGE_ID sub_id = sspi_SecureHandleGetPackageId(&context->sub_context);
670 return SEC_E_INTERNAL_ERROR;
672 if (sub_id == SSPI_PACKAGE_NTLM)
674 if (!ntlm_reset_cipher_state(&context->sub_context))
675 return SEC_E_INTERNAL_ERROR;
681static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(
683 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
688 MechCred* creds =
nullptr;
691 NegToken input_token = empty_neg_token;
692 NegToken output_token = empty_neg_token;
696 SecBuffer mech_input_buffers[2] = WINPR_C_ARRAY_INIT;
697 SecBufferDesc mech_input = { SECBUFFER_VERSION, 2, mech_input_buffers };
698 SecBufferDesc mech_output = { SECBUFFER_VERSION, 1, &output_token.mechToken };
699 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
700 SECURITY_STATUS sub_status = SEC_E_INTERNAL_ERROR;
701 WinPrAsn1Encoder* enc =
nullptr;
703 const Mech* mech =
nullptr;
705 if (!phCredential || !SecIsValidHandle(phCredential))
706 return SEC_E_NO_CREDENTIALS;
708 creds = sspi_SecureHandleGetLowerPointer(phCredential);
711 if (phContext && !phContext->dwLower && !phContext->dwUpper)
712 return SEC_E_INVALID_HANDLE;
714 context = sspi_SecureHandleGetLowerPointer(phContext);
718 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
719 bindings_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
722 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
726 enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
728 return SEC_E_INSUFFICIENT_MEMORY;
730 if (!WinPrAsn1EncSeqContainer(enc))
733 for (
size_t i = 0; i < MECH_COUNT; i++)
735 MechCred* cred = &creds[i];
736 const SecPkg* pkg = MechTable[i].pkg;
738 WINPR_ASSERT(pkg->table_w);
742 WLog_DBG(TAG,
"Unavailable mechanism: %s", negotiate_mech_name(cred->mech->oid));
747 if (!init_context.mech)
753 CopyMemory(&output_token.mechToken, output_buffer,
sizeof(
SecBuffer));
756 mech_input_buffers[0] = *bindings_buffer;
758 WINPR_ASSERT(pkg->table_w->InitializeSecurityContextW);
759 sub_status = pkg->table_w->InitializeSecurityContextW(
760 &cred->cred,
nullptr, pszTargetName, fContextReq | cred->mech->flags, Reserved1,
761 TargetDataRep, &mech_input, Reserved2, &init_context.sub_context, &mech_output,
762 pfContextAttr, ptsExpiry);
765 if (IsSecurityStatusError(sub_status))
767 if (SecIsValidHandle(&init_context.sub_context))
769 WINPR_ASSERT(pkg->table_w->DeleteSecurityContext);
770 pkg->table_w->DeleteSecurityContext(&init_context.sub_context);
776 init_context.mech = cred->mech;
779 if (!WinPrAsn1EncOID(enc, cred->mech->oid))
781 WLog_DBG(TAG,
"Available mechanism: %s", negotiate_mech_name(cred->mech->oid));
785 if (!init_context.mech)
789 if (init_context.mech->oid == &ntlm_OID)
791 init_context.spnego = FALSE;
792 output_buffer->cbBuffer = output_token.mechToken.cbBuffer;
793 WLog_DBG(TAG,
"Using direct NTLM");
797 init_context.spnego = TRUE;
798 init_context.mechTypes.BufferType = SECBUFFER_DATA;
799 const size_t cb = WinPrAsn1EncEndContainer(enc);
800 WINPR_ASSERT(cb <= UINT32_MAX);
801 init_context.mechTypes.cbBuffer = (UINT32)cb;
805 context = negotiate_ContextNew(&init_context);
808 init_context.mech->pkg->table->DeleteSecurityContext(&init_context.sub_context);
809 WinPrAsn1Encoder_Free(&enc);
810 return SEC_E_INSUFFICIENT_MEMORY;
813 sspi_SecureHandleSetPackageId(phNewContext, SSPI_PACKAGE_NEGOTIATE);
814 sspi_SecureHandleSetLowerPointer(phNewContext, context);
816 if (!context->spnego)
823 Stream_StaticInit(&s, context->mechTypes.pvBuffer, context->mechTypes.cbBuffer);
824 if (!WinPrAsn1EncToStream(enc, &s))
827 output_token.mechTypes.cbBuffer = context->mechTypes.cbBuffer;
828 output_token.mechTypes.pvBuffer = context->mechTypes.pvBuffer;
829 output_token.init = TRUE;
831 if (sub_status == SEC_E_OK)
832 context->state = NEGOTIATE_STATE_FINAL_OPTIMISTIC;
837 return SEC_E_INVALID_TOKEN;
839 sub_context = &context->sub_context;
840 sub_cred = negotiate_FindCredential(creds, context->mech);
842 if (!context->spnego)
844 return context->mech->pkg->table_w->InitializeSecurityContextW(
845 sub_cred, sub_context, pszTargetName, fContextReq | context->mech->flags, Reserved1,
846 TargetDataRep, pInput, Reserved2, sub_context, pOutput, pfContextAttr, ptsExpiry);
849 if (!negotiate_read_neg_token(input_buffer, &input_token))
850 return SEC_E_INVALID_TOKEN;
853 if (context->state < NEGOTIATE_STATE_NEGORESP && input_token.supportedMech.len &&
854 !sspi_gss_oid_compare(&input_token.supportedMech, context->mech->oid))
856 mech = negotiate_GetMechByOID(&input_token.supportedMech);
858 return SEC_E_INVALID_TOKEN;
861 sub_cred = negotiate_FindCredential(creds, mech);
863 return SEC_E_INVALID_TOKEN;
866 context->mech->pkg->table_w->DeleteSecurityContext(&context->sub_context);
867 sub_context =
nullptr;
869 context->mech = mech;
874 if (context->state < NEGOTIATE_STATE_NEGORESP)
876 switch (input_token.negState)
879 return SEC_E_INVALID_TOKEN;
881 return SEC_E_LOGON_DENIED;
886 case ACCEPT_INCOMPLETE:
887 context->state = NEGOTIATE_STATE_NEGORESP;
889 case ACCEPT_COMPLETED:
890 if (context->state == NEGOTIATE_STATE_INITIAL)
891 context->state = NEGOTIATE_STATE_NEGORESP;
893 context->state = NEGOTIATE_STATE_FINAL;
899 WLog_DBG(TAG,
"Negotiated mechanism: %s", negotiate_mech_name(context->mech->oid));
902 if (context->state == NEGOTIATE_STATE_NEGORESP)
907 CopyMemory(&output_token.mechToken, output_buffer,
sizeof(
SecBuffer));
909 mech_input_buffers[0] = input_token.mechToken;
911 mech_input_buffers[1] = *bindings_buffer;
913 status = context->mech->pkg->table_w->InitializeSecurityContextW(
914 sub_cred, sub_context, pszTargetName, fContextReq | context->mech->flags, Reserved1,
915 TargetDataRep, input_token.mechToken.cbBuffer ? &mech_input : nullptr, Reserved2,
916 &context->sub_context, &mech_output, pfContextAttr, ptsExpiry);
918 if (IsSecurityStatusError(status))
922 if (status == SEC_E_OK)
924 if (output_token.mechToken.cbBuffer > 0)
925 context->state = NEGOTIATE_STATE_MIC;
927 context->state = NEGOTIATE_STATE_FINAL;
931 if (context->state == NEGOTIATE_STATE_FINAL && input_token.mic.cbBuffer == 0)
933 if (context->mic || input_token.negState != ACCEPT_COMPLETED)
934 return SEC_E_INVALID_TOKEN;
937 output_buffer->cbBuffer = 0;
941 if ((context->state == NEGOTIATE_STATE_MIC && context->mic) ||
942 context->state == NEGOTIATE_STATE_FINAL)
944 status = negotiate_mic_exchange(context, &input_token, &output_token, output_buffer);
945 if (status != SEC_E_OK)
950 if (input_token.negState == ACCEPT_COMPLETED)
953 output_buffer->cbBuffer = 0;
957 if (output_token.negState == ACCEPT_COMPLETED)
960 status = SEC_I_CONTINUE_NEEDED;
962 if (!negotiate_write_neg_token(output_buffer, &output_token))
963 status = SEC_E_INTERNAL_ERROR;
966 WinPrAsn1Encoder_Free(&enc);
970static SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(
972 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
975 SECURITY_STATUS status = 0;
976 SEC_WCHAR* pszTargetNameW =
nullptr;
980 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName,
nullptr);
982 return SEC_E_INTERNAL_ERROR;
985 status = negotiate_InitializeSecurityContextW(
986 phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
987 Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
988 free(pszTargetNameW);
997 WinPrAsn1_tagId tag = 0;
998 const char ssp[] =
"NTLMSSP";
1000 if (!input_buffer || !input_buffer->pvBuffer || (input_buffer->cbBuffer == 0))
1006 if (input_buffer->cbBuffer >= 8 && strncmp(input_buffer->pvBuffer, ssp,
sizeof(ssp)) == 0)
1009 return negotiate_GetMechByOID(&ntlm_OID);
1013 WinPrAsn1Decoder_InitMem(&decoder, WINPR_ASN1_DER, input_buffer->pvBuffer,
1014 input_buffer->cbBuffer);
1016 if (!WinPrAsn1DecReadApp(&decoder, &tag, &appDecoder) || tag != 0)
1019 if (!WinPrAsn1DecReadOID(&appDecoder, oid, FALSE))
1022 if (sspi_gss_oid_compare(oid, &spnego_OID))
1028 return negotiate_GetMechByOID(oid);
1031static SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(
1038 MechCred* creds =
nullptr;
1040 NegToken input_token = empty_neg_token;
1041 NegToken output_token = empty_neg_token;
1044 SecBufferDesc mech_input = { SECBUFFER_VERSION, 1, &input_token.mechToken };
1045 SecBufferDesc mech_output = { SECBUFFER_VERSION, 1, &output_token.mechToken };
1046 SECURITY_STATUS status = SEC_E_INTERNAL_ERROR;
1049 WinPrAsn1_tagId tag = 0;
1051 const Mech* first_mech =
nullptr;
1053 if (!phCredential || !SecIsValidHandle(phCredential))
1054 return SEC_E_NO_CREDENTIALS;
1056 creds = sspi_SecureHandleGetLowerPointer(phCredential);
1059 return SEC_E_INVALID_TOKEN;
1062 if (phContext && !phContext->dwLower && !phContext->dwUpper)
1063 return SEC_E_INVALID_HANDLE;
1065 context = sspi_SecureHandleGetLowerPointer(phContext);
1067 input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
1069 output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
1073 init_context.mech = guessMech(input_buffer, &init_context.spnego, &oid);
1074 if (!init_context.mech && !init_context.spnego)
1075 return SEC_E_INVALID_TOKEN;
1077 WLog_DBG(TAG,
"Mechanism: %s", negotiate_mech_name(&oid));
1079 if (init_context.spnego)
1082 if (!negotiate_read_neg_token(input_buffer, &input_token))
1083 return SEC_E_INVALID_TOKEN;
1086 if (!input_token.init || input_token.mechTypes.cbBuffer == 0)
1087 return SEC_E_INVALID_TOKEN;
1089 init_context.mechTypes.BufferType = SECBUFFER_DATA;
1090 init_context.mechTypes.cbBuffer = input_token.mechTypes.cbBuffer;
1093 WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, input_token.mechTypes.pvBuffer,
1094 input_token.mechTypes.cbBuffer);
1096 if (!WinPrAsn1DecReadSequence(&dec, &dec2))
1097 return SEC_E_INVALID_TOKEN;
1101 if (input_token.mechToken.cbBuffer)
1103 if (!WinPrAsn1DecReadOID(&dec, &oid, FALSE))
1104 return SEC_E_INVALID_TOKEN;
1106 init_context.mech = negotiate_GetMechByOID(&oid);
1108 if (init_context.mech)
1111 output_token.mechToken = *output_buffer;
1112 WLog_DBG(TAG,
"Requested mechanism: %s",
1113 negotiate_mech_name(init_context.mech->oid));
1118 if (init_context.mech)
1120 sub_cred = negotiate_FindCredential(creds, init_context.mech);
1124 status = init_context.mech->pkg->table->AcceptSecurityContext(
1125 sub_cred,
nullptr, init_context.spnego ? &mech_input : pInput, fContextReq,
1126 TargetDataRep, &init_context.sub_context,
1127 init_context.spnego ? &mech_output : pOutput, pfContextAttr, ptsTimeStamp);
1131 if (IsSecurityStatusError(status))
1133 if (!init_context.spnego)
1139 if (init_context.mech)
1140 init_context.mech->pkg->table->DeleteSecurityContext(&init_context.sub_context);
1142 init_context.mic = TRUE;
1143 first_mech = init_context.mech;
1144 init_context.mech =
nullptr;
1145 output_token.mechToken.cbBuffer = 0;
1148 while (!init_context.mech && WinPrAsn1DecPeekTag(&dec, &tag))
1151 if (!WinPrAsn1DecReadOID(&dec, &oid, FALSE))
1152 return SEC_E_INVALID_TOKEN;
1154 init_context.mech = negotiate_GetMechByOID(&oid);
1155 WLog_DBG(TAG,
"Requested mechanism: %s", negotiate_mech_name(&oid));
1158 if (init_context.mech == first_mech)
1159 init_context.mech =
nullptr;
1161 if (init_context.mech && !negotiate_FindCredential(creds, init_context.mech))
1162 init_context.mech =
nullptr;
1165 if (!init_context.mech)
1166 return SEC_E_INTERNAL_ERROR;
1168 context = negotiate_ContextNew(&init_context);
1171 if (!IsSecurityStatusError(status))
1172 init_context.mech->pkg->table->DeleteSecurityContext(&init_context.sub_context);
1173 return SEC_E_INSUFFICIENT_MEMORY;
1176 sspi_SecureHandleSetPackageId(phNewContext, SSPI_PACKAGE_NEGOTIATE);
1177 sspi_SecureHandleSetLowerPointer(phNewContext, context);
1179 if (!init_context.spnego)
1182 CopyMemory(init_context.mechTypes.pvBuffer, input_token.mechTypes.pvBuffer,
1183 input_token.mechTypes.cbBuffer);
1185 if (!context->mech->preferred)
1187 output_token.negState = REQUEST_MIC;
1188 context->mic = TRUE;
1192 output_token.negState = ACCEPT_INCOMPLETE;
1195 if (status == SEC_E_OK)
1196 context->state = NEGOTIATE_STATE_FINAL;
1198 context->state = NEGOTIATE_STATE_NEGORESP;
1200 output_token.supportedMech = oid;
1201 WLog_DBG(TAG,
"Accepted mechanism: %s", negotiate_mech_name(&output_token.supportedMech));
1205 sub_cred = negotiate_FindCredential(creds, context->mech);
1207 return SEC_E_NO_CREDENTIALS;
1209 if (!context->spnego)
1211 return context->mech->pkg->table->AcceptSecurityContext(
1212 sub_cred, &context->sub_context, pInput, fContextReq, TargetDataRep,
1213 &context->sub_context, pOutput, pfContextAttr, ptsTimeStamp);
1216 if (!negotiate_read_neg_token(input_buffer, &input_token))
1217 return SEC_E_INVALID_TOKEN;
1220 if (input_token.mechToken.cbBuffer > 0)
1222 if (context->state != NEGOTIATE_STATE_NEGORESP)
1223 return SEC_E_INVALID_TOKEN;
1227 CopyMemory(&output_token.mechToken, output_buffer,
sizeof(
SecBuffer));
1233 PCtxtHandle sub_context = sspi_SecureHandleGetLowerPointer(&context->sub_context)
1234 ? &context->sub_context
1236 status = context->mech->pkg->table->AcceptSecurityContext(
1237 sub_cred, sub_context, &mech_input, fContextReq | context->mech->flags,
1238 TargetDataRep, &context->sub_context, &mech_output, pfContextAttr, ptsTimeStamp);
1240 if (IsSecurityStatusError(status))
1243 if (status == SEC_E_OK)
1244 context->state = NEGOTIATE_STATE_FINAL;
1246 else if (context->state == NEGOTIATE_STATE_NEGORESP)
1247 return SEC_E_INVALID_TOKEN;
1250 if (context->state == NEGOTIATE_STATE_FINAL)
1253 if (context->mic && output_token.mechToken.cbBuffer == 0 && input_token.mic.cbBuffer == 0)
1254 return SEC_E_INVALID_TOKEN;
1256 if (context->mic || input_token.mic.cbBuffer > 0)
1258 status = negotiate_mic_exchange(context, &input_token, &output_token, output_buffer);
1259 if (status != SEC_E_OK)
1263 output_token.negState = ACCEPT_COMPLETED;
1266 if (input_token.negState == ACCEPT_COMPLETED)
1269 output_buffer->cbBuffer = 0;
1273 if (output_token.negState == ACCEPT_COMPLETED)
1276 status = SEC_I_CONTINUE_NEEDED;
1278 if (!negotiate_write_neg_token(output_buffer, &output_token))
1279 return SEC_E_INTERNAL_ERROR;
1284static SECURITY_STATUS SEC_ENTRY negotiate_CompleteAuthToken(
PCtxtHandle phContext,
1288 SECURITY_STATUS status = SEC_E_OK;
1292 return SEC_E_INVALID_HANDLE;
1294 WINPR_ASSERT(context->mech);
1295 WINPR_ASSERT(context->mech->pkg);
1296 WINPR_ASSERT(context->mech->pkg->table);
1297 if (context->mech->pkg->table->CompleteAuthToken)
1298 status = context->mech->pkg->table->CompleteAuthToken(&context->sub_context, pToken);
1303static SECURITY_STATUS SEC_ENTRY negotiate_DeleteSecurityContext(
PCtxtHandle phContext)
1305 SECURITY_STATUS status = SEC_E_OK;
1307 sspi_SecureHandleInvalidate(phContext);
1308 const SecPkg* pkg =
nullptr;
1311 return SEC_E_INVALID_HANDLE;
1313 WINPR_ASSERT(context->mech);
1314 WINPR_ASSERT(context->mech->pkg);
1315 WINPR_ASSERT(context->mech->pkg->table);
1316 pkg = context->mech->pkg;
1318 if (pkg->table->DeleteSecurityContext)
1319 status = pkg->table->DeleteSecurityContext(&context->sub_context);
1321 negotiate_ContextFree(context);
1325static SECURITY_STATUS SEC_ENTRY
1326negotiate_ImpersonateSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
1331static SECURITY_STATUS SEC_ENTRY
1332negotiate_RevertSecurityContext(WINPR_ATTR_UNUSED
PCtxtHandle phContext)
1337static SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesW(
PCtxtHandle phContext,
1338 ULONG ulAttribute,
void* pBuffer)
1343 return SEC_E_INVALID_HANDLE;
1345 WINPR_ASSERT(context->mech);
1346 WINPR_ASSERT(context->mech->pkg);
1347 WINPR_ASSERT(context->mech->pkg->table_w);
1348 if (context->mech->pkg->table_w->QueryContextAttributesW)
1349 return context->mech->pkg->table_w->QueryContextAttributesW(&context->sub_context,
1350 ulAttribute, pBuffer);
1352 return SEC_E_UNSUPPORTED_FUNCTION;
1355static SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesA(
PCtxtHandle phContext,
1356 ULONG ulAttribute,
void* pBuffer)
1361 return SEC_E_INVALID_HANDLE;
1363 WINPR_ASSERT(context->mech);
1364 WINPR_ASSERT(context->mech->pkg);
1365 WINPR_ASSERT(context->mech->pkg->table);
1366 if (context->mech->pkg->table->QueryContextAttributesA)
1367 return context->mech->pkg->table->QueryContextAttributesA(&context->sub_context,
1368 ulAttribute, pBuffer);
1370 return SEC_E_UNSUPPORTED_FUNCTION;
1373static SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesW(
PCtxtHandle phContext,
1374 ULONG ulAttribute,
void* pBuffer,
1380 return SEC_E_INVALID_HANDLE;
1382 WINPR_ASSERT(context->mech);
1383 WINPR_ASSERT(context->mech->pkg);
1384 WINPR_ASSERT(context->mech->pkg->table_w);
1385 if (context->mech->pkg->table_w->SetContextAttributesW)
1386 return context->mech->pkg->table_w->SetContextAttributesW(&context->sub_context,
1387 ulAttribute, pBuffer, cbBuffer);
1389 return SEC_E_UNSUPPORTED_FUNCTION;
1392static SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesA(
PCtxtHandle phContext,
1393 ULONG ulAttribute,
void* pBuffer,
1399 return SEC_E_INVALID_HANDLE;
1401 WINPR_ASSERT(context->mech);
1402 WINPR_ASSERT(context->mech->pkg);
1403 WINPR_ASSERT(context->mech->pkg->table);
1404 if (context->mech->pkg->table->SetContextAttributesA)
1405 return context->mech->pkg->table->SetContextAttributesA(&context->sub_context, ulAttribute,
1408 return SEC_E_UNSUPPORTED_FUNCTION;
1411static SECURITY_STATUS SEC_ENTRY negotiate_SetCredentialsAttributesW(
PCredHandle phCredential,
1413 void* pBuffer, ULONG cbBuffer)
1415 BOOL success = FALSE;
1416 MechCred* creds = sspi_SecureHandleGetLowerPointer(phCredential);
1419 return SEC_E_INVALID_HANDLE;
1421 for (
size_t i = 0; i < MECH_COUNT; i++)
1423 MechCred* cred = &creds[i];
1425 WINPR_ASSERT(cred->mech);
1426 WINPR_ASSERT(cred->mech->pkg);
1427 WINPR_ASSERT(cred->mech->pkg->table);
1428 WINPR_ASSERT(cred->mech->pkg->table_w->SetCredentialsAttributesW);
1429 const SECURITY_STATUS secStatus = cred->mech->pkg->table_w->SetCredentialsAttributesW(
1430 &cred->cred, ulAttribute, pBuffer, cbBuffer);
1432 if (secStatus == SEC_E_OK)
1435 WLog_WARN(TAG,
"SetCredentialsAttributesW returned %s",
1436 GetSecurityStatusString(secStatus));
1440 return (success ? SEC_E_OK : SEC_E_UNSUPPORTED_FUNCTION);
1443static SECURITY_STATUS SEC_ENTRY negotiate_SetCredentialsAttributesA(
PCredHandle phCredential,
1445 void* pBuffer, ULONG cbBuffer)
1447 BOOL success = FALSE;
1449 MechCred* creds = sspi_SecureHandleGetLowerPointer(phCredential);
1452 return SEC_E_INVALID_HANDLE;
1454 for (
size_t i = 0; i < MECH_COUNT; i++)
1456 MechCred* cred = &creds[i];
1461 WINPR_ASSERT(cred->mech);
1462 WINPR_ASSERT(cred->mech->pkg);
1463 WINPR_ASSERT(cred->mech->pkg->table);
1464 WINPR_ASSERT(cred->mech->pkg->table->SetCredentialsAttributesA);
1465 const SECURITY_STATUS secStatus = cred->mech->pkg->table->SetCredentialsAttributesA(
1466 &cred->cred, ulAttribute, pBuffer, cbBuffer);
1468 if (secStatus == SEC_E_OK)
1473 WLog_WARN(TAG,
"SetCredentialsAttributesA returned %s",
1474 GetSecurityStatusString(secStatus));
1478 return (success ? SEC_E_OK : SEC_E_UNSUPPORTED_FUNCTION);
1482static BOOL checkMechCredValid(
void* pAuthData, MechCred* cred)
1485 WINPR_ASSERT(cred->mech);
1486 WINPR_ASSERT(cred->mech->pkg);
1488 BOOL kerberos = FALSE;
1491 if (!negotiate_get_config(pAuthData, &kerberos, &ntlm, &u2u))
1493 WLog_DBG(TAG,
"Failed to get negotiate configuration");
1497 if (!kerberos && sspi_gss_oid_compare(cred->mech->oid, &kerberos_OID))
1499 WLog_DBG(TAG,
"Kerberos disabled, skipping");
1503 if (!u2u && sspi_gss_oid_compare(cred->mech->oid, &kerberos_u2u_OID))
1505 WLog_DBG(TAG,
"Kerberos U2U disabled, skipping");
1509 if (!ntlm && _tcsncmp(cred->mech->pkg->name, NTLM_SSP_NAME, ARRAYSIZE(NTLM_SSP_NAME)) == 0)
1511 WLog_DBG(TAG,
"NTLM disabled, skipping");
1517static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(
1518 SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
1519 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
1522 MechCred* creds = calloc(MECH_COUNT,
sizeof(MechCred));
1525 return SEC_E_INTERNAL_ERROR;
1527 for (
size_t i = 0; i < MECH_COUNT; i++)
1529 MechCred* cred = &creds[i];
1530 const SecPkg* pkg = MechTable[i].pkg;
1531 cred->mech = &MechTable[i];
1533 if (!checkMechCredValid(pAuthData, cred))
1536 WINPR_ASSERT(pkg->table_w);
1537 WINPR_ASSERT(pkg->table_w->AcquireCredentialsHandleW);
1538 const SECURITY_STATUS rc = pkg->table_w->AcquireCredentialsHandleW(
1539 pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn,
1540 pvGetKeyArgument, &cred->cred, ptsExpiry);
1543 WLog_DBG(TAG,
"AcquireCredentialsHandleW returned %s", GetSecurityStatusString(rc));
1550 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)creds);
1551 sspi_SecureHandleSetPackageId(phCredential, SSPI_PACKAGE_NEGOTIATE);
1555static SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(
1556 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
1557 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
1560 MechCred* creds = calloc(MECH_COUNT,
sizeof(MechCred));
1563 return SEC_E_INTERNAL_ERROR;
1565 for (
size_t i = 0; i < MECH_COUNT; i++)
1567 const SecPkg* pkg = MechTable[i].pkg;
1568 MechCred* cred = &creds[i];
1570 cred->mech = &MechTable[i];
1572 if (!checkMechCredValid(pAuthData, cred))
1575 WINPR_ASSERT(pkg->table);
1576 WINPR_ASSERT(pkg->table->AcquireCredentialsHandleA);
1577 const SECURITY_STATUS rc = pkg->table->AcquireCredentialsHandleA(
1578 pszPrincipal, pszPackage, fCredentialUse, pvLogonID, pAuthData, pGetKeyFn,
1579 pvGetKeyArgument, &cred->cred, ptsExpiry);
1582 WLog_DBG(TAG,
"AcquireCredentialsHandleA returned %s", GetSecurityStatusString(rc));
1589 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)creds);
1590 sspi_SecureHandleSetPackageId(phCredential, SSPI_PACKAGE_NEGOTIATE);
1594static SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesW(
1595 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1596 WINPR_ATTR_UNUSED
void* pBuffer)
1598 WLog_ERR(TAG,
"TODO: Implement");
1599 return SEC_E_UNSUPPORTED_FUNCTION;
1602static SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesA(
1603 WINPR_ATTR_UNUSED
PCredHandle phCredential, WINPR_ATTR_UNUSED ULONG ulAttribute,
1604 WINPR_ATTR_UNUSED
void* pBuffer)
1606 WLog_ERR(TAG,
"TODO: Implement");
1607 return SEC_E_UNSUPPORTED_FUNCTION;
1610static SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(
PCredHandle phCredential)
1612 MechCred* creds = sspi_SecureHandleGetLowerPointer(phCredential);
1613 sspi_SecureHandleInvalidate(phCredential);
1615 return SEC_E_INVALID_HANDLE;
1617 for (
size_t i = 0; i < MECH_COUNT; i++)
1619 MechCred* cred = &creds[i];
1621 WINPR_ASSERT(cred->mech);
1622 WINPR_ASSERT(cred->mech->pkg);
1623 WINPR_ASSERT(cred->mech->pkg->table);
1624 WINPR_ASSERT(cred->mech->pkg->table->FreeCredentialsHandle);
1625 const SECURITY_STATUS rc = cred->mech->pkg->table->FreeCredentialsHandle(&cred->cred);
1627 WLog_DBG(TAG,
"FreeCredentialsHandle returned %s", GetSecurityStatusString(rc));
1634static SECURITY_STATUS SEC_ENTRY negotiate_EncryptMessage(
PCtxtHandle phContext, ULONG fQOP,
1641 return SEC_E_INVALID_HANDLE;
1646 WINPR_ASSERT(context->mech);
1647 WINPR_ASSERT(context->mech->pkg);
1648 WINPR_ASSERT(context->mech->pkg->table);
1649 if (context->mech->pkg->table->EncryptMessage)
1650 return context->mech->pkg->table->EncryptMessage(&context->sub_context, fQOP, pMessage,
1653 return SEC_E_UNSUPPORTED_FUNCTION;
1656static SECURITY_STATUS SEC_ENTRY negotiate_DecryptMessage(
PCtxtHandle phContext,
1658 ULONG MessageSeqNo, ULONG* pfQOP)
1663 return SEC_E_INVALID_HANDLE;
1668 WINPR_ASSERT(context->mech);
1669 WINPR_ASSERT(context->mech->pkg);
1670 WINPR_ASSERT(context->mech->pkg->table);
1671 if (context->mech->pkg->table->DecryptMessage)
1672 return context->mech->pkg->table->DecryptMessage(&context->sub_context, pMessage,
1673 MessageSeqNo, pfQOP);
1675 return SEC_E_UNSUPPORTED_FUNCTION;
1678static SECURITY_STATUS SEC_ENTRY negotiate_MakeSignature(
PCtxtHandle phContext, ULONG fQOP,
1685 return SEC_E_INVALID_HANDLE;
1690 WINPR_ASSERT(context->mech);
1691 WINPR_ASSERT(context->mech->pkg);
1692 WINPR_ASSERT(context->mech->pkg->table);
1693 if (context->mech->pkg->table->MakeSignature)
1694 return context->mech->pkg->table->MakeSignature(&context->sub_context, fQOP, pMessage,
1697 return SEC_E_UNSUPPORTED_FUNCTION;
1700static SECURITY_STATUS SEC_ENTRY negotiate_VerifySignature(
PCtxtHandle phContext,
1702 ULONG MessageSeqNo, ULONG* pfQOP)
1707 return SEC_E_INVALID_HANDLE;
1712 WINPR_ASSERT(context->mech);
1713 WINPR_ASSERT(context->mech->pkg);
1714 WINPR_ASSERT(context->mech->pkg->table);
1715 if (context->mech->pkg->table->VerifySignature)
1716 return context->mech->pkg->table->VerifySignature(&context->sub_context, pMessage,
1717 MessageSeqNo, pfQOP);
1719 return SEC_E_UNSUPPORTED_FUNCTION;
1725 negotiate_QueryCredentialsAttributesA,
1726 negotiate_AcquireCredentialsHandleA,
1727 negotiate_FreeCredentialsHandle,
1729 negotiate_InitializeSecurityContextA,
1730 negotiate_AcceptSecurityContext,
1731 negotiate_CompleteAuthToken,
1732 negotiate_DeleteSecurityContext,
1734 negotiate_QueryContextAttributesA,
1735 negotiate_ImpersonateSecurityContext,
1736 negotiate_RevertSecurityContext,
1737 negotiate_MakeSignature,
1738 negotiate_VerifySignature,
1748 negotiate_EncryptMessage,
1749 negotiate_DecryptMessage,
1750 negotiate_SetContextAttributesA,
1751 negotiate_SetCredentialsAttributesA,
1757 negotiate_QueryCredentialsAttributesW,
1758 negotiate_AcquireCredentialsHandleW,
1759 negotiate_FreeCredentialsHandle,
1761 negotiate_InitializeSecurityContextW,
1762 negotiate_AcceptSecurityContext,
1763 negotiate_CompleteAuthToken,
1764 negotiate_DeleteSecurityContext,
1766 negotiate_QueryContextAttributesW,
1767 negotiate_ImpersonateSecurityContext,
1768 negotiate_RevertSecurityContext,
1769 negotiate_MakeSignature,
1770 negotiate_VerifySignature,
1780 negotiate_EncryptMessage,
1781 negotiate_DecryptMessage,
1782 negotiate_SetContextAttributesW,
1783 negotiate_SetCredentialsAttributesW,
1786BOOL NEGOTIATE_init(
void)
1788 InitializeConstWCharFromUtf8(NEGOTIATE_SecPkgInfoA.Name, NEGOTIATE_SecPkgInfoW_NameBuffer,
1789 ARRAYSIZE(NEGOTIATE_SecPkgInfoW_NameBuffer));
1790 InitializeConstWCharFromUtf8(NEGOTIATE_SecPkgInfoA.Comment, NEGOTIATE_SecPkgInfoW_CommentBuffer,
1791 ARRAYSIZE(NEGOTIATE_SecPkgInfoW_CommentBuffer));