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 = NULL;
37 context = (SCHANNEL_CONTEXT*)calloc(1, sizeof(SCHANNEL_CONTEXT));
38
39 if (!context)
40 return NULL;
41
42 context->openssl = schannel_openssl_new();
43
44 if (!context->openssl)
45 {
46 free(context);
47 return NULL;
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 = NULL;
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 = NULL;
134
135 if (fCredentialUse == SECPKG_CRED_OUTBOUND)
136 {
137 SCHANNEL_CRED* cred = NULL;
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 = NULL;
170 SEC_WCHAR* pszPackageW = NULL;
171 if (pszPrincipal)
172 pszPrincipalW = ConvertUtf8ToWCharAlloc(pszPrincipal, NULL);
173 if (pszPackage)
174 pszPackageW = ConvertUtf8ToWCharAlloc(pszPackage, NULL);
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 SCHANNEL_CREDENTIALS* credentials = NULL;
187
188 if (!phCredential)
189 return SEC_E_INVALID_HANDLE;
190
191 credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
192
193 if (!credentials)
194 return SEC_E_INVALID_HANDLE;
195
196 schannel_CredentialsFree(credentials);
197 return SEC_E_OK;
198}
199
200static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(
201 PCredHandle phCredential, PCtxtHandle phContext, WINPR_ATTR_UNUSED SEC_WCHAR* pszTargetName,
202 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG Reserved1,
203 WINPR_ATTR_UNUSED ULONG TargetDataRep, PSecBufferDesc pInput, WINPR_ATTR_UNUSED ULONG Reserved2,
204 PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
205 WINPR_ATTR_UNUSED PTimeStamp ptsExpiry)
206{
207 SECURITY_STATUS status = 0;
208 SCHANNEL_CONTEXT* context = NULL;
209 SCHANNEL_CREDENTIALS* credentials = NULL;
210
211 /* behave like windows SSPIs that don't want empty context */
212 if (phContext && !phContext->dwLower && !phContext->dwUpper)
213 return SEC_E_INVALID_HANDLE;
214
215 context = sspi_SecureHandleGetLowerPointer(phContext);
216
217 if (!context)
218 {
219 context = schannel_ContextNew();
220
221 if (!context)
222 return SEC_E_INSUFFICIENT_MEMORY;
223
224 credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
225 context->server = FALSE;
226 CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
227 sspi_SecureHandleSetLowerPointer(phNewContext, context);
228 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
229 schannel_openssl_client_init(context->openssl);
230 }
231
232 status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
233 return status;
234}
235
236static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(
237 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
238 ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
239 PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
240{
241 SECURITY_STATUS status = 0;
242 SEC_WCHAR* pszTargetNameW = NULL;
243
244 if (pszTargetName != NULL)
245 {
246 pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, NULL);
247 if (!pszTargetNameW)
248 return SEC_E_INSUFFICIENT_MEMORY;
249 }
250
251 status = schannel_InitializeSecurityContextW(
252 phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
253 Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
254 free(pszTargetNameW);
255 return status;
256}
257
258static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(
259 WINPR_ATTR_UNUSED PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
260 WINPR_ATTR_UNUSED ULONG fContextReq, WINPR_ATTR_UNUSED ULONG TargetDataRep,
261 PCtxtHandle phNewContext, PSecBufferDesc pOutput, WINPR_ATTR_UNUSED PULONG pfContextAttr,
262 WINPR_ATTR_UNUSED PTimeStamp ptsTimeStamp)
263{
264 SECURITY_STATUS status = 0;
265 SCHANNEL_CONTEXT* context = NULL;
266
267 /* behave like windows SSPIs that don't want empty context */
268 if (phContext && !phContext->dwLower && !phContext->dwUpper)
269 return SEC_E_INVALID_HANDLE;
270
271 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
272
273 if (!context)
274 {
275 context = schannel_ContextNew();
276
277 if (!context)
278 return SEC_E_INSUFFICIENT_MEMORY;
279
280 context->server = TRUE;
281 sspi_SecureHandleSetLowerPointer(phNewContext, context);
282 sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
283 schannel_openssl_server_init(context->openssl);
284 }
285
286 status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
287 return status;
288}
289
290static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
291{
292 SCHANNEL_CONTEXT* context = NULL;
293 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
294
295 if (!context)
296 return SEC_E_INVALID_HANDLE;
297
298 schannel_ContextFree(context);
299 return SEC_E_OK;
300}
301
302static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
303 ULONG ulAttribute, void* pBuffer)
304{
305 if (!phContext)
306 return SEC_E_INVALID_HANDLE;
307
308 if (!pBuffer)
309 return SEC_E_INSUFFICIENT_MEMORY;
310
311 if (ulAttribute == SECPKG_ATTR_SIZES)
312 {
313 SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
314 Sizes->cbMaxToken = 0x6000;
315 Sizes->cbMaxSignature = 16;
316 Sizes->cbBlockSize = 0;
317 Sizes->cbSecurityTrailer = 16;
318 return SEC_E_OK;
319 }
320 else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
321 {
323 StreamSizes->cbHeader = 5;
324 StreamSizes->cbTrailer = 36;
325 StreamSizes->cbMaximumMessage = 0x4000;
326 StreamSizes->cBuffers = 4;
327 StreamSizes->cbBlockSize = 16;
328 return SEC_E_OK;
329 }
330
331 WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
332 return SEC_E_UNSUPPORTED_FUNCTION;
333}
334
335static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
336 WINPR_ATTR_UNUSED ULONG fQOP,
337 WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
338 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
339{
340 return SEC_E_OK;
341}
342
343static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(WINPR_ATTR_UNUSED PCtxtHandle phContext,
344 WINPR_ATTR_UNUSED PSecBufferDesc pMessage,
345 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
346 WINPR_ATTR_UNUSED ULONG* pfQOP)
347{
348 return SEC_E_OK;
349}
350
351static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(WINPR_ATTR_UNUSED PCtxtHandle phContext,
352 WINPR_ATTR_UNUSED ULONG fQOP,
353 PSecBufferDesc pMessage,
354 WINPR_ATTR_UNUSED ULONG MessageSeqNo)
355{
356 SECURITY_STATUS status = 0;
357 SCHANNEL_CONTEXT* context = NULL;
358 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
359
360 if (!context)
361 return SEC_E_INVALID_HANDLE;
362
363 status = schannel_openssl_encrypt_message(context->openssl, pMessage);
364 return status;
365}
366
367static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
368 PSecBufferDesc pMessage,
369 WINPR_ATTR_UNUSED ULONG MessageSeqNo,
370 WINPR_ATTR_UNUSED ULONG* pfQOP)
371{
372 SECURITY_STATUS status = 0;
373 SCHANNEL_CONTEXT* context = NULL;
374 context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
375
376 if (!context)
377 return SEC_E_INVALID_HANDLE;
378
379 status = schannel_openssl_decrypt_message(context->openssl, pMessage);
380 return status;
381}
382
383const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA = {
384 3, /* dwVersion */
385 NULL, /* EnumerateSecurityPackages */
386 schannel_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
387 schannel_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
388 schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
389 NULL, /* Reserved2 */
390 schannel_InitializeSecurityContextA, /* InitializeSecurityContext */
391 schannel_AcceptSecurityContext, /* AcceptSecurityContext */
392 NULL, /* CompleteAuthToken */
393 schannel_DeleteSecurityContext, /* DeleteSecurityContext */
394 NULL, /* ApplyControlToken */
395 schannel_QueryContextAttributes, /* QueryContextAttributes */
396 NULL, /* ImpersonateSecurityContext */
397 NULL, /* RevertSecurityContext */
398 schannel_MakeSignature, /* MakeSignature */
399 schannel_VerifySignature, /* VerifySignature */
400 NULL, /* FreeContextBuffer */
401 NULL, /* QuerySecurityPackageInfo */
402 NULL, /* Reserved3 */
403 NULL, /* Reserved4 */
404 NULL, /* ExportSecurityContext */
405 NULL, /* ImportSecurityContext */
406 NULL, /* AddCredentials */
407 NULL, /* Reserved8 */
408 NULL, /* QuerySecurityContextToken */
409 schannel_EncryptMessage, /* EncryptMessage */
410 schannel_DecryptMessage, /* DecryptMessage */
411 NULL, /* SetContextAttributes */
412 NULL, /* SetCredentialsAttributes */
413};
414
415const SecurityFunctionTableW SCHANNEL_SecurityFunctionTableW = {
416 3, /* dwVersion */
417 NULL, /* EnumerateSecurityPackages */
418 schannel_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
419 schannel_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
420 schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
421 NULL, /* Reserved2 */
422 schannel_InitializeSecurityContextW, /* InitializeSecurityContext */
423 schannel_AcceptSecurityContext, /* AcceptSecurityContext */
424 NULL, /* CompleteAuthToken */
425 schannel_DeleteSecurityContext, /* DeleteSecurityContext */
426 NULL, /* ApplyControlToken */
427 schannel_QueryContextAttributes, /* QueryContextAttributes */
428 NULL, /* ImpersonateSecurityContext */
429 NULL, /* RevertSecurityContext */
430 schannel_MakeSignature, /* MakeSignature */
431 schannel_VerifySignature, /* VerifySignature */
432 NULL, /* FreeContextBuffer */
433 NULL, /* QuerySecurityPackageInfo */
434 NULL, /* Reserved3 */
435 NULL, /* Reserved4 */
436 NULL, /* ExportSecurityContext */
437 NULL, /* ImportSecurityContext */
438 NULL, /* AddCredentials */
439 NULL, /* Reserved8 */
440 NULL, /* QuerySecurityContextToken */
441 schannel_EncryptMessage, /* EncryptMessage */
442 schannel_DecryptMessage, /* DecryptMessage */
443 NULL, /* SetContextAttributes */
444 NULL, /* SetCredentialsAttributes */
445};
446
447const SecPkgInfoA SCHANNEL_SecPkgInfoA = {
448 0x000107B3, /* fCapabilities */
449 1, /* wVersion */
450 0x000E, /* wRPCID */
451 SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
452 "Schannel", /* Name */
453 "Schannel Security Package" /* Comment */
454};
455
456static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = { 0 };
457static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = { 0 };
458
459const SecPkgInfoW SCHANNEL_SecPkgInfoW = {
460 0x000107B3, /* fCapabilities */
461 1, /* wVersion */
462 0x000E, /* wRPCID */
463 SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
464 SCHANNEL_SecPkgInfoW_NameBuffer, /* Name */
465 SCHANNEL_SecPkgInfoW_CommentBuffer /* Comment */
466};
467
468BOOL SCHANNEL_init(void)
469{
470 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
471 ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
472 InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
473 ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
474 return TRUE;
475}