FreeRDP
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 
30 static char* SCHANNEL_PACKAGE_NAME = "Schannel";
31 
32 #define TAG WINPR_TAG("sspi.Schannel")
33 
34 SCHANNEL_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 
53 void schannel_ContextFree(SCHANNEL_CONTEXT* context)
54 {
55  if (!context)
56  return;
57 
58  schannel_openssl_free(context->openssl);
59  free(context);
60 }
61 
62 static 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 
69 static void schannel_CredentialsFree(SCHANNEL_CREDENTIALS* credentials)
70 {
71  free(credentials);
72 }
73 
74 static 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 
91 static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesW(PCredHandle phCredential,
92  ULONG ulAttribute,
93  void* pBuffer)
94 {
95  if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
96  {
98  SupportedAlgs->cSupportedAlgs = sizeof(schannel_SupportedAlgs) / sizeof(ALG_ID);
99  SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
100  return SEC_E_OK;
101  }
102  else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
103  {
104  PSecPkgCred_CipherStrengths CipherStrengths = (PSecPkgCred_CipherStrengths)pBuffer;
105  CipherStrengths->dwMinimumCipherStrength = 40;
106  CipherStrengths->dwMaximumCipherStrength = 256;
107  return SEC_E_OK;
108  }
109  else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
110  {
112  /* Observed SupportedProtocols: 0x208A0 */
113  SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
114  return SEC_E_OK;
115  }
116 
117  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
118  return SEC_E_UNSUPPORTED_FUNCTION;
119 }
120 
121 static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential,
122  ULONG ulAttribute,
123  void* pBuffer)
124 {
125  return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
126 }
127 
128 static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleW(
129  SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
130  void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
131  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 
163 static 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 
184 static 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 
200 static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(
201  PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq,
202  ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
203  PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
204 {
205  SECURITY_STATUS status = 0;
206  SCHANNEL_CONTEXT* context = NULL;
207  SCHANNEL_CREDENTIALS* credentials = NULL;
208 
209  /* behave like windows SSPIs that don't want empty context */
210  if (phContext && !phContext->dwLower && !phContext->dwUpper)
211  return SEC_E_INVALID_HANDLE;
212 
213  context = sspi_SecureHandleGetLowerPointer(phContext);
214 
215  if (!context)
216  {
217  context = schannel_ContextNew();
218 
219  if (!context)
220  return SEC_E_INSUFFICIENT_MEMORY;
221 
222  credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
223  context->server = FALSE;
224  CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
225  sspi_SecureHandleSetLowerPointer(phNewContext, context);
226  sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
227  schannel_openssl_client_init(context->openssl);
228  }
229 
230  status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
231  return status;
232 }
233 
234 static SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextA(
235  PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq,
236  ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
237  PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
238 {
239  SECURITY_STATUS status = 0;
240  SEC_WCHAR* pszTargetNameW = NULL;
241 
242  if (pszTargetName != NULL)
243  {
244  pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, NULL);
245  if (!pszTargetNameW)
246  return SEC_E_INSUFFICIENT_MEMORY;
247  }
248 
249  status = schannel_InitializeSecurityContextW(
250  phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
251  Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
252  free(pszTargetNameW);
253  return status;
254 }
255 
256 static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(
257  PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq,
258  ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr,
259  PTimeStamp ptsTimeStamp)
260 {
261  SECURITY_STATUS status = 0;
262  SCHANNEL_CONTEXT* context = NULL;
263 
264  /* behave like windows SSPIs that don't want empty context */
265  if (phContext && !phContext->dwLower && !phContext->dwUpper)
266  return SEC_E_INVALID_HANDLE;
267 
268  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
269 
270  if (!context)
271  {
272  context = schannel_ContextNew();
273 
274  if (!context)
275  return SEC_E_INSUFFICIENT_MEMORY;
276 
277  context->server = TRUE;
278  sspi_SecureHandleSetLowerPointer(phNewContext, context);
279  sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
280  schannel_openssl_server_init(context->openssl);
281  }
282 
283  status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
284  return status;
285 }
286 
287 static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
288 {
289  SCHANNEL_CONTEXT* context = NULL;
290  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
291 
292  if (!context)
293  return SEC_E_INVALID_HANDLE;
294 
295  schannel_ContextFree(context);
296  return SEC_E_OK;
297 }
298 
299 static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
300  ULONG ulAttribute, void* pBuffer)
301 {
302  if (!phContext)
303  return SEC_E_INVALID_HANDLE;
304 
305  if (!pBuffer)
306  return SEC_E_INSUFFICIENT_MEMORY;
307 
308  if (ulAttribute == SECPKG_ATTR_SIZES)
309  {
310  SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
311  Sizes->cbMaxToken = 0x6000;
312  Sizes->cbMaxSignature = 16;
313  Sizes->cbBlockSize = 0;
314  Sizes->cbSecurityTrailer = 16;
315  return SEC_E_OK;
316  }
317  else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
318  {
319  SecPkgContext_StreamSizes* StreamSizes = (SecPkgContext_StreamSizes*)pBuffer;
320  StreamSizes->cbHeader = 5;
321  StreamSizes->cbTrailer = 36;
322  StreamSizes->cbMaximumMessage = 0x4000;
323  StreamSizes->cBuffers = 4;
324  StreamSizes->cbBlockSize = 16;
325  return SEC_E_OK;
326  }
327 
328  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
329  return SEC_E_UNSUPPORTED_FUNCTION;
330 }
331 
332 static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
333  PSecBufferDesc pMessage, ULONG MessageSeqNo)
334 {
335  return SEC_E_OK;
336 }
337 
338 static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(PCtxtHandle phContext,
339  PSecBufferDesc pMessage,
340  ULONG MessageSeqNo, ULONG* pfQOP)
341 {
342  return SEC_E_OK;
343 }
344 
345 static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
346  PSecBufferDesc pMessage,
347  ULONG MessageSeqNo)
348 {
349  SECURITY_STATUS status = 0;
350  SCHANNEL_CONTEXT* context = NULL;
351  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
352 
353  if (!context)
354  return SEC_E_INVALID_HANDLE;
355 
356  status = schannel_openssl_encrypt_message(context->openssl, pMessage);
357  return status;
358 }
359 
360 static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
361  PSecBufferDesc pMessage,
362  ULONG MessageSeqNo, ULONG* pfQOP)
363 {
364  SECURITY_STATUS status = 0;
365  SCHANNEL_CONTEXT* context = NULL;
366  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
367 
368  if (!context)
369  return SEC_E_INVALID_HANDLE;
370 
371  status = schannel_openssl_decrypt_message(context->openssl, pMessage);
372  return status;
373 }
374 
375 const SecurityFunctionTableA SCHANNEL_SecurityFunctionTableA = {
376  3, /* dwVersion */
377  NULL, /* EnumerateSecurityPackages */
378  schannel_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
379  schannel_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
380  schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
381  NULL, /* Reserved2 */
382  schannel_InitializeSecurityContextA, /* InitializeSecurityContext */
383  schannel_AcceptSecurityContext, /* AcceptSecurityContext */
384  NULL, /* CompleteAuthToken */
385  schannel_DeleteSecurityContext, /* DeleteSecurityContext */
386  NULL, /* ApplyControlToken */
387  schannel_QueryContextAttributes, /* QueryContextAttributes */
388  NULL, /* ImpersonateSecurityContext */
389  NULL, /* RevertSecurityContext */
390  schannel_MakeSignature, /* MakeSignature */
391  schannel_VerifySignature, /* VerifySignature */
392  NULL, /* FreeContextBuffer */
393  NULL, /* QuerySecurityPackageInfo */
394  NULL, /* Reserved3 */
395  NULL, /* Reserved4 */
396  NULL, /* ExportSecurityContext */
397  NULL, /* ImportSecurityContext */
398  NULL, /* AddCredentials */
399  NULL, /* Reserved8 */
400  NULL, /* QuerySecurityContextToken */
401  schannel_EncryptMessage, /* EncryptMessage */
402  schannel_DecryptMessage, /* DecryptMessage */
403  NULL, /* SetContextAttributes */
404  NULL, /* SetCredentialsAttributes */
405 };
406 
407 const SecurityFunctionTableW SCHANNEL_SecurityFunctionTableW = {
408  3, /* dwVersion */
409  NULL, /* EnumerateSecurityPackages */
410  schannel_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
411  schannel_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
412  schannel_FreeCredentialsHandle, /* FreeCredentialsHandle */
413  NULL, /* Reserved2 */
414  schannel_InitializeSecurityContextW, /* InitializeSecurityContext */
415  schannel_AcceptSecurityContext, /* AcceptSecurityContext */
416  NULL, /* CompleteAuthToken */
417  schannel_DeleteSecurityContext, /* DeleteSecurityContext */
418  NULL, /* ApplyControlToken */
419  schannel_QueryContextAttributes, /* QueryContextAttributes */
420  NULL, /* ImpersonateSecurityContext */
421  NULL, /* RevertSecurityContext */
422  schannel_MakeSignature, /* MakeSignature */
423  schannel_VerifySignature, /* VerifySignature */
424  NULL, /* FreeContextBuffer */
425  NULL, /* QuerySecurityPackageInfo */
426  NULL, /* Reserved3 */
427  NULL, /* Reserved4 */
428  NULL, /* ExportSecurityContext */
429  NULL, /* ImportSecurityContext */
430  NULL, /* AddCredentials */
431  NULL, /* Reserved8 */
432  NULL, /* QuerySecurityContextToken */
433  schannel_EncryptMessage, /* EncryptMessage */
434  schannel_DecryptMessage, /* DecryptMessage */
435  NULL, /* SetContextAttributes */
436  NULL, /* SetCredentialsAttributes */
437 };
438 
439 const SecPkgInfoA SCHANNEL_SecPkgInfoA = {
440  0x000107B3, /* fCapabilities */
441  1, /* wVersion */
442  0x000E, /* wRPCID */
443  SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
444  "Schannel", /* Name */
445  "Schannel Security Package" /* Comment */
446 };
447 
448 static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = { 0 };
449 static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = { 0 };
450 
451 const SecPkgInfoW SCHANNEL_SecPkgInfoW = {
452  0x000107B3, /* fCapabilities */
453  1, /* wVersion */
454  0x000E, /* wRPCID */
455  SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
456  SCHANNEL_SecPkgInfoW_NameBuffer, /* Name */
457  SCHANNEL_SecPkgInfoW_CommentBuffer /* Comment */
458 };
459 
460 BOOL SCHANNEL_init(void)
461 {
462  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
463  ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
464  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
465  ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
466  return TRUE;
467 }