20#include <winpr/config.h>
23#include <winpr/sspi.h>
30static char SCHANNEL_PACKAGE_NAME_A[] =
"Schannel";
31static WCHAR SCHANNEL_PACKAGE_NAME_W[] = { W(
'S'), W(
'c'), W(
'h'), W(
'a'), W(
'n'),
32 W(
'n'), W(
'e'), W(
'l'), W(
'\0') };
34#define TAG WINPR_TAG("sspi.Schannel")
44 context->openssl = schannel_openssl_new();
46 if (!context->openssl)
60 schannel_openssl_free(context->openssl);
76static ALG_ID schannel_SupportedAlgs[] = { CALG_AES_128,
88 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RESERVED7 |
93static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesW(
94 WINPR_ATTR_UNUSED
PCredHandle phCredential, ULONG ulAttribute,
void* pBuffer)
96 if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
99 SupportedAlgs->cSupportedAlgs =
sizeof(schannel_SupportedAlgs) /
sizeof(ALG_ID);
100 SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
103 else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
106 CipherStrengths->dwMinimumCipherStrength = 40;
107 CipherStrengths->dwMaximumCipherStrength = 256;
110 else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
114 SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
118 WLog_ERR(TAG,
"TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
119 return SEC_E_UNSUPPORTED_FUNCTION;
122static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(
PCredHandle phCredential,
126 return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
129static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleX(
130 void* name, ULONG fCredentialUse, WINPR_ATTR_UNUSED
void* pvLogonID,
void* pAuthData,
131 WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn, WINPR_ATTR_UNUSED
void* pvGetKeyArgument,
136 if (fCredentialUse == SECPKG_CRED_OUTBOUND)
140 return SEC_E_INSUFFICIENT_MEMORY;
142 credentials->fCredentialUse = fCredentialUse;
148 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)credentials);
149 sspi_SecureHandleSetUpperPointer(phCredential, name);
152 else if (fCredentialUse == SECPKG_CRED_INBOUND)
156 return SEC_E_INSUFFICIENT_MEMORY;
158 credentials->fCredentialUse = fCredentialUse;
159 sspi_SecureHandleSetLowerPointer(phCredential, (
void*)credentials);
160 sspi_SecureHandleSetUpperPointer(phCredential, name);
164 WLog_WARN(TAG,
"Unsupported fCredentialUse=0x%08" PRIx32, fCredentialUse);
170static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleA(
171 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse,
void* pvLogonID,
172 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
void* pvGetKeyArgument,
PCredHandle phCredential,
175 WINPR_UNUSED(pszPrincipal);
176 WINPR_UNUSED(pszPackage);
177 return schannel_AcquireCredentialsHandleX(SCHANNEL_PACKAGE_NAME_A, fCredentialUse, pvLogonID,
178 pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential,
182static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleW(
183 WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
184 ULONG fCredentialUse, WINPR_ATTR_UNUSED
void* pvLogonID,
void* pAuthData,
185 WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn, WINPR_ATTR_UNUSED
void* pvGetKeyArgument,
189 WINPR_UNUSED(pszPrincipal);
190 WINPR_UNUSED(pszPackage);
191 return schannel_AcquireCredentialsHandleX(SCHANNEL_PACKAGE_NAME_W, fCredentialUse, pvLogonID,
192 pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential,
196static SECURITY_STATUS SEC_ENTRY schannel_FreeCredentialsHandle(
PCredHandle phCredential)
199 return SEC_E_INVALID_HANDLE;
203 sspi_SecureHandleInvalidate(phCredential);
205 return SEC_E_INVALID_HANDLE;
207 schannel_CredentialsFree(credentials);
211static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextX(
213 WINPR_ATTR_UNUSED SEC_WCHAR* pszTargetName, WINPR_ATTR_UNUSED ULONG fContextReq,
214 WINPR_ATTR_UNUSED ULONG Reserved1, WINPR_ATTR_UNUSED ULONG TargetDataRep,
PSecBufferDesc pInput,
216 WINPR_ATTR_UNUSED PULONG pfContextAttr, WINPR_ATTR_UNUSED
PTimeStamp ptsExpiry)
218 SECURITY_STATUS status = 0;
223 if (phContext && !phContext->dwLower && !phContext->dwUpper)
224 return SEC_E_INVALID_HANDLE;
226 context = sspi_SecureHandleGetLowerPointer(phContext);
230 context = schannel_ContextNew();
233 return SEC_E_INSUFFICIENT_MEMORY;
236 context->server = FALSE;
237 CopyMemory(&context->cred, &credentials->cred,
sizeof(
SCHANNEL_CRED));
238 sspi_SecureHandleSetLowerPointer(phNewContext, context);
239 sspi_SecureHandleSetUpperPointer(phNewContext, name);
240 schannel_openssl_client_init(context->openssl);
243 status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
247static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(
249 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
252 return schannel_InitializeSecurityContextX(
253 SCHANNEL_PACKAGE_NAME_W, phCredential, phContext, pszTargetName, fContextReq, Reserved1,
254 TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
257static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(
259 ULONG Reserved1, ULONG TargetDataRep,
PSecBufferDesc pInput, ULONG Reserved2,
262 SECURITY_STATUS status = 0;
263 SEC_WCHAR* pszTargetNameW =
nullptr;
265 if (pszTargetName !=
nullptr)
267 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName,
nullptr);
269 return SEC_E_INSUFFICIENT_MEMORY;
272 status = schannel_InitializeSecurityContextX(
273 SCHANNEL_PACKAGE_NAME_A, phCredential, phContext, pszTargetNameW, fContextReq, Reserved1,
274 TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
275 free(pszTargetNameW);
279static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContextA(
281 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG TargetDataRep,
285 SECURITY_STATUS status = 0;
289 if (phContext && !phContext->dwLower && !phContext->dwUpper)
290 return SEC_E_INVALID_HANDLE;
296 context = schannel_ContextNew();
299 return SEC_E_INSUFFICIENT_MEMORY;
301 context->server = TRUE;
302 sspi_SecureHandleSetLowerPointer(phNewContext, context);
303 sspi_SecureHandleSetUpperPointer(phNewContext, (
void*)SCHANNEL_PACKAGE_NAME_A);
304 schannel_openssl_server_init(context->openssl);
307 status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
311static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContextW(
313 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG TargetDataRep,
317 SECURITY_STATUS status = 0;
321 if (phContext && !phContext->dwLower && !phContext->dwUpper)
322 return SEC_E_INVALID_HANDLE;
328 context = schannel_ContextNew();
331 return SEC_E_INSUFFICIENT_MEMORY;
333 context->server = TRUE;
334 sspi_SecureHandleSetLowerPointer(phNewContext, context);
335 sspi_SecureHandleSetUpperPointer(phNewContext, (
void*)SCHANNEL_PACKAGE_NAME_W);
336 schannel_openssl_server_init(context->openssl);
339 status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
343static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(
PCtxtHandle phContext)
346 sspi_SecureHandleInvalidate(phContext);
349 return SEC_E_INVALID_HANDLE;
351 schannel_ContextFree(context);
355static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(
PCtxtHandle phContext,
356 ULONG ulAttribute,
void* pBuffer)
359 return SEC_E_INVALID_HANDLE;
362 return SEC_E_INSUFFICIENT_MEMORY;
364 if (ulAttribute == SECPKG_ATTR_SIZES)
367 Sizes->cbMaxToken = 0x6000;
368 Sizes->cbMaxSignature = 16;
369 Sizes->cbBlockSize = 0;
370 Sizes->cbSecurityTrailer = 16;
373 else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
376 StreamSizes->cbHeader = 5;
377 StreamSizes->cbTrailer = 36;
378 StreamSizes->cbMaximumMessage = 0x4000;
379 StreamSizes->cBuffers = 4;
380 StreamSizes->cbBlockSize = 16;
384 WLog_ERR(TAG,
"TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
385 return SEC_E_UNSUPPORTED_FUNCTION;
388static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(WINPR_ATTR_UNUSED
PCtxtHandle phContext,
389 WINPR_ATTR_UNUSED ULONG fQOP,
391 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
396static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(WINPR_ATTR_UNUSED
PCtxtHandle phContext,
398 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
399 WINPR_ATTR_UNUSED ULONG* pfQOP)
404static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(WINPR_ATTR_UNUSED
PCtxtHandle phContext,
405 WINPR_ATTR_UNUSED ULONG fQOP,
407 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
409 SECURITY_STATUS status = 0;
414 return SEC_E_INVALID_HANDLE;
416 status = schannel_openssl_encrypt_message(context->openssl, pMessage);
420static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(
PCtxtHandle phContext,
422 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
423 WINPR_ATTR_UNUSED ULONG* pfQOP)
425 SECURITY_STATUS status = 0;
430 return SEC_E_INVALID_HANDLE;
432 status = schannel_openssl_decrypt_message(context->openssl, pMessage);
439 schannel_QueryCredentialsAttributesA,
440 schannel_AcquireCredentialsHandleA,
441 schannel_FreeCredentialsHandle,
443 schannel_InitializeSecurityContextA,
444 schannel_AcceptSecurityContextA,
446 schannel_DeleteSecurityContext,
448 schannel_QueryContextAttributes,
451 schannel_MakeSignature,
452 schannel_VerifySignature,
462 schannel_EncryptMessage,
463 schannel_DecryptMessage,
471 schannel_QueryCredentialsAttributesW,
472 schannel_AcquireCredentialsHandleW,
473 schannel_FreeCredentialsHandle,
475 schannel_InitializeSecurityContextW,
476 schannel_AcceptSecurityContextW,
478 schannel_DeleteSecurityContext,
480 schannel_QueryContextAttributes,
483 schannel_MakeSignature,
484 schannel_VerifySignature,
494 schannel_EncryptMessage,
495 schannel_DecryptMessage,
504 SCHANNEL_CB_MAX_TOKEN,
506 "Schannel Security Package"
509static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
510static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
516 SCHANNEL_CB_MAX_TOKEN,
517 SCHANNEL_SecPkgInfoW_NameBuffer,
518 SCHANNEL_SecPkgInfoW_CommentBuffer
521BOOL SCHANNEL_init(
void)
523 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
524 ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
525 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
526 ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));