FreeRDP
Loading...
Searching...
No Matches
schannel.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/sspi.h>
24
25#include "schannel.h"
26
27#include "../sspi.h"
28#include "../../log.h"
29
30static char* SCHANNEL_PACKAGE_NAME = "Schannel";
31
32#define TAG WINPR_TAG("sspi.Schannel")
33
34SCHANNEL_CONTEXT* schannel_ContextNew(void)
35{
36 SCHANNEL_CONTEXT* context = nullptr;
37 context = (SCHANNEL_CONTEXT*)calloc(1, sizeof(SCHANNEL_CONTEXT));
38
39 if (!context)
40 return nullptr;
41
42 context->openssl = schannel_openssl_new();
43
44 if (!context->openssl)
45 {
46 free(context);
47 return nullptr;
48 }
49
50 return context;
51}
52
53void schannel_ContextFree(SCHANNEL_CONTEXT* context)
54{
55 if (!context)
56 return;
57
58 schannel_openssl_free(context->openssl);
59 free(context);
60}
61
62static SCHANNEL_CREDENTIALS* schannel_CredentialsNew(void)
63{
64 SCHANNEL_CREDENTIALS* credentials = nullptr;
65 credentials = (SCHANNEL_CREDENTIALS*)calloc(1, sizeof(SCHANNEL_CREDENTIALS));
66 return credentials;
67}
68
69static void schannel_CredentialsFree(SCHANNEL_CREDENTIALS* credentials)
70{
71 free(credentials);
72}
73
74static ALG_ID schannel_SupportedAlgs[] = { CALG_AES_128,
75 CALG_AES_256,
76 CALG_RC4,
77 CALG_DES,
78 CALG_3DES,
79 CALG_MD5,
80 CALG_SHA1,
81 CALG_SHA_256,
82 CALG_SHA_384,
83 CALG_SHA_512,
84 CALG_RSA_SIGN,
85 CALG_DH_EPHEM,
86 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RESERVED7 |
87 6), /* what is this? */
88 CALG_DSS_SIGN,
89 CALG_ECDSA };
90
91static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesW(
92 WINPR_ATTR_UNUSED PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
93{
94 if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
95 {
97 SupportedAlgs->cSupportedAlgs = sizeof(schannel_SupportedAlgs) / sizeof(ALG_ID);
98 SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
99 return SEC_E_OK;
100 }
101 else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
102 {
104 CipherStrengths->dwMinimumCipherStrength = 40;
105 CipherStrengths->dwMaximumCipherStrength = 256;
106 return SEC_E_OK;
107 }
108 else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
109 {
111 /* Observed SupportedProtocols: 0x208A0 */
112 SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
113 return SEC_E_OK;
114 }
115
116 WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
117 return SEC_E_UNSUPPORTED_FUNCTION;
118}
119
120static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential,
121 ULONG ulAttribute,
122 void* pBuffer)
123{
124 return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
125}
126
127static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleW(
128 WINPR_ATTR_UNUSED SEC_WCHAR* pszPrincipal, WINPR_ATTR_UNUSED SEC_WCHAR* pszPackage,
129 ULONG fCredentialUse, WINPR_ATTR_UNUSED void* pvLogonID, void* pAuthData,
130 WINPR_ATTR_UNUSED SEC_GET_KEY_FN pGetKeyFn, WINPR_ATTR_UNUSED void* pvGetKeyArgument,
131 PCredHandle phCredential, WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
132{
133 SCHANNEL_CREDENTIALS* credentials = nullptr;
134
135 if (fCredentialUse == SECPKG_CRED_OUTBOUND)
136 {
137 SCHANNEL_CRED* cred = nullptr;
138 credentials = schannel_CredentialsNew();
139 credentials->fCredentialUse = fCredentialUse;
140 cred = (SCHANNEL_CRED*)pAuthData;
141
142 if (cred)
143 {
144 CopyMemory(&credentials->cred, cred, sizeof(SCHANNEL_CRED));
145 }
146
147 sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
148 sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
149 return SEC_E_OK;
150 }
151 else if (fCredentialUse == SECPKG_CRED_INBOUND)
152 {
153 credentials = schannel_CredentialsNew();
154 credentials->fCredentialUse = fCredentialUse;
155 sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
156 sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
157 return SEC_E_OK;
158 }
159
160 return SEC_E_OK;
161}
162
163static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleA(
164 SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
165 void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
166 PTimeStamp ptsExpiry)
167{
168 SECURITY_STATUS status = 0;
169 SEC_WCHAR* pszPrincipalW = nullptr;
170 SEC_WCHAR* pszPackageW = nullptr;
171 if (pszPrincipal)
172 pszPrincipalW = ConvertUtf8ToWCharAlloc(pszPrincipal, nullptr);
173 if (pszPackage)
174 pszPackageW = ConvertUtf8ToWCharAlloc(pszPackage, nullptr);
175
176 status = schannel_AcquireCredentialsHandleW(pszPrincipalW, pszPackageW, fCredentialUse,
177 pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
178 phCredential, ptsExpiry);
179 free(pszPrincipalW);
180 free(pszPackageW);
181 return status;
182}
183
184static SECURITY_STATUS SEC_ENTRY schannel_FreeCredentialsHandle(PCredHandle phCredential)
185{
186 if (!phCredential)
187 return SEC_E_INVALID_HANDLE;
188
189 SCHANNEL_CREDENTIALS* credentials =
190 (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
191 sspi_SecureHandleInvalidate(phCredential);
192 if (!credentials)
193 return SEC_E_INVALID_HANDLE;
194
195 schannel_CredentialsFree(credentials);
196 return SEC_E_OK;
197}
198
199static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(
200 PCredHandle phCredential, PCtxtHandle phContext, WINPR_ATTR_UNUSED SEC_WCHAR* pszTargetName,
201 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG Reserved1,
202 WINPR_ATTR_UNUSED ULONG TargetDataRep, PSecBufferDesc pInput, WINPR_ATTR_UNUSED ULONG Reserved2,
203 PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
204 WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
205{
206 SECURITY_STATUS status = 0;
207 SCHANNEL_CONTEXT* context = nullptr;
208 SCHANNEL_CREDENTIALS* credentials = nullptr;
209
210 /* behave like windows SSPIs that don't want empty context */
211 if (phContext && !phContext->dwLower && !phContext->dwUpper)
212 return SEC_E_INVALID_HANDLE;
213
214 context = sspi_SecureHandleGetLowerPointer(phContext);
215
216 if (!context)
217 {
218 context = schannel_ContextNew();
219
220 if (!context)
221 return SEC_E_INSUFFICIENT_MEMORY;
222
223 credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
224 context->server = FALSE;
225 CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
226 sspi_SecureHandleSetLowerPointer(phNewContext, context);
227 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
228 schannel_openssl_client_init(context->openssl);
229 }
230
231 status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
232 return status;
233}
234
235static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(
236 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
237 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
238 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
239{
240 SECURITY_STATUS status = 0;
241 SEC_WCHAR* pszTargetNameW = nullptr;
242
243 if (pszTargetName != nullptr)
244 {
245 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, nullptr);
246 if (!pszTargetNameW)
247 return SEC_E_INSUFFICIENT_MEMORY;
248 }
249
250 status = schannel_InitializeSecurityContextW(
251 phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
252 Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
253 free(pszTargetNameW);
254 return status;
255}
256
257static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(
258 WINPR_ATTR_UNUSED PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
259 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG TargetDataRep,
260 PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
261 WINPR_ATTR_UNUSED PTimeStamp ptsTimeStamp)
262{
263 SECURITY_STATUS status = 0;
264 SCHANNEL_CONTEXT* context = nullptr;
265
266 /* behave like windows SSPIs that don't want empty context */
267 if (phContext && !phContext->dwLower && !phContext->dwUpper)
268 return SEC_E_INVALID_HANDLE;
269
270 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
271
272 if (!context)
273 {
274 context = schannel_ContextNew();
275
276 if (!context)
277 return SEC_E_INSUFFICIENT_MEMORY;
278
279 context->server = TRUE;
280 sspi_SecureHandleSetLowerPointer(phNewContext, context);
281 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
282 schannel_openssl_server_init(context->openssl);
283 }
284
285 status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
286 return status;
287}
288
289static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
290{
291 SCHANNEL_CONTEXT* context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
292 sspi_SecureHandleInvalidate(phContext);
293
294 if (!context)
295 return SEC_E_INVALID_HANDLE;
296
297 schannel_ContextFree(context);
298 return SEC_E_OK;
299}
300
301static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
302 ULONG ulAttribute, void* pBuffer)
303{
304 if (!phContext)
305 return SEC_E_INVALID_HANDLE;
306
307 if (!pBuffer)
308 return SEC_E_INSUFFICIENT_MEMORY;
309
310 if (ulAttribute == SECPKG_ATTR_SIZES)
311 {
312 SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
313 Sizes->cbMaxToken = 0x6000;
314 Sizes->cbMaxSignature = 16;
315 Sizes->cbBlockSize = 0;
316 Sizes->cbSecurityTrailer = 16;
317 return SEC_E_OK;
318 }
319 else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
320 {
322 StreamSizes->cbHeader = 5;
323 StreamSizes->cbTrailer = 36;
324 StreamSizes->cbMaximumMessage = 0x4000;
325 StreamSizes->cBuffers = 4;
326 StreamSizes->cbBlockSize = 16;
327 return SEC_E_OK;
328 }
329
330 WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
331 return SEC_E_UNSUPPORTED_FUNCTION;
332}
333
334static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
335 WINPR_ATTR_UNUSED ULONG fQOP,
336 WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
337 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
338{
339 return SEC_E_OK;
340}
341
342static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
343 WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
344 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
345 WINPR_ATTR_UNUSED ULONG* pfQOP)
346{
347 return SEC_E_OK;
348}
349
350static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(WINPR_ATTR_UNUSED PCtxtHandle phContext,
351 WINPR_ATTR_UNUSED ULONG fQOP,
352 PSecBufferDesc pMessage,
353 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
354{
355 SECURITY_STATUS status = 0;
356 SCHANNEL_CONTEXT* context = nullptr;
357 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
358
359 if (!context)
360 return SEC_E_INVALID_HANDLE;
361
362 status = schannel_openssl_encrypt_message(context->openssl, pMessage);
363 return status;
364}
365
366static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
367 PSecBufferDesc pMessage,
368 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
369 WINPR_ATTR_UNUSED ULONG* pfQOP)
370{
371 SECURITY_STATUS status = 0;
372 SCHANNEL_CONTEXT* context = nullptr;
373 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
374
375 if (!context)
376 return SEC_E_INVALID_HANDLE;
377
378 status = schannel_openssl_decrypt_message(context->openssl, pMessage);
379 return status;
380}
381
382const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA = {
383 3, /* dwVersion */
384 nullptr, /* EnumerateSecurityPackages */
385 schannel_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
386 schannel_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
387 schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
388 nullptr, /* Reserved2 */
389 schannel_InitializeSecurityContextA, /* InitializeSecurityContext */
390 schannel_AcceptSecurityContext, /* AcceptSecurityContext */
391 nullptr, /* CompleteAuthToken */
392 schannel_DeleteSecurityContext, /* DeleteSecurityContext */
393 nullptr, /* ApplyControlToken */
394 schannel_QueryContextAttributes, /* QueryContextAttributes */
395 nullptr, /* ImpersonateSecurityContext */
396 nullptr, /* RevertSecurityContext */
397 schannel_MakeSignature, /* MakeSignature */
398 schannel_VerifySignature, /* VerifySignature */
399 nullptr, /* FreeContextBuffer */
400 nullptr, /* QuerySecurityPackageInfo */
401 nullptr, /* Reserved3 */
402 nullptr, /* Reserved4 */
403 nullptr, /* ExportSecurityContext */
404 nullptr, /* ImportSecurityContext */
405 nullptr, /* AddCredentials */
406 nullptr, /* Reserved8 */
407 nullptr, /* QuerySecurityContextToken */
408 schannel_EncryptMessage, /* EncryptMessage */
409 schannel_DecryptMessage, /* DecryptMessage */
410 nullptr, /* SetContextAttributes */
411 nullptr, /* SetCredentialsAttributes */
412};
413
414const SecurityFunctionTableW SCHANNEL_SecurityFunctionTableW = {
415 3, /* dwVersion */
416 nullptr, /* EnumerateSecurityPackages */
417 schannel_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
418 schannel_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
419 schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
420 nullptr, /* Reserved2 */
421 schannel_InitializeSecurityContextW, /* InitializeSecurityContext */
422 schannel_AcceptSecurityContext, /* AcceptSecurityContext */
423 nullptr, /* CompleteAuthToken */
424 schannel_DeleteSecurityContext, /* DeleteSecurityContext */
425 nullptr, /* ApplyControlToken */
426 schannel_QueryContextAttributes, /* QueryContextAttributes */
427 nullptr, /* ImpersonateSecurityContext */
428 nullptr, /* RevertSecurityContext */
429 schannel_MakeSignature, /* MakeSignature */
430 schannel_VerifySignature, /* VerifySignature */
431 nullptr, /* FreeContextBuffer */
432 nullptr, /* QuerySecurityPackageInfo */
433 nullptr, /* Reserved3 */
434 nullptr, /* Reserved4 */
435 nullptr, /* ExportSecurityContext */
436 nullptr, /* ImportSecurityContext */
437 nullptr, /* AddCredentials */
438 nullptr, /* Reserved8 */
439 nullptr, /* QuerySecurityContextToken */
440 schannel_EncryptMessage, /* EncryptMessage */
441 schannel_DecryptMessage, /* DecryptMessage */
442 nullptr, /* SetContextAttributes */
443 nullptr, /* SetCredentialsAttributes */
444};
445
446const SecPkgInfoA SCHANNEL_SecPkgInfoA = {
447 0x000107B3, /* fCapabilities */
448 1, /* wVersion */
449 0x000E, /* wRPCID */
450 SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
451 "Schannel", /* Name */
452 "Schannel Security Package" /* Comment */
453};
454
455static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = WINPR_C_ARRAY_INIT;
456static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = WINPR_C_ARRAY_INIT;
457
458const SecPkgInfoW SCHANNEL_SecPkgInfoW = {
459 0x000107B3, /* fCapabilities */
460 1, /* wVersion */
461 0x000E, /* wRPCID */
462 SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
463 SCHANNEL_SecPkgInfoW_NameBuffer, /* Name */
464 SCHANNEL_SecPkgInfoW_CommentBuffer /* Comment */
465};
466
467BOOL SCHANNEL_init(void)
468{
469 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
470 ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
471 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
472 ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
473 return TRUE;
474}