Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/sspi/Schannel/schannel.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Schannel Security Package
4
 *
5
 * Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
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
0
{
36
0
  SCHANNEL_CONTEXT* context = NULL;
37
0
  context = (SCHANNEL_CONTEXT*)calloc(1, sizeof(SCHANNEL_CONTEXT));
38
39
0
  if (!context)
40
0
    return NULL;
41
42
0
  context->openssl = schannel_openssl_new();
43
44
0
  if (!context->openssl)
45
0
  {
46
0
    free(context);
47
0
    return NULL;
48
0
  }
49
50
0
  return context;
51
0
}
52
53
void schannel_ContextFree(SCHANNEL_CONTEXT* context)
54
0
{
55
0
  if (!context)
56
0
    return;
57
58
0
  schannel_openssl_free(context->openssl);
59
0
  free(context);
60
0
}
61
62
static SCHANNEL_CREDENTIALS* schannel_CredentialsNew(void)
63
0
{
64
0
  SCHANNEL_CREDENTIALS* credentials = NULL;
65
0
  credentials = (SCHANNEL_CREDENTIALS*)calloc(1, sizeof(SCHANNEL_CREDENTIALS));
66
0
  return credentials;
67
0
}
68
69
static void schannel_CredentialsFree(SCHANNEL_CREDENTIALS* credentials)
70
0
{
71
0
  free(credentials);
72
0
}
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
0
{
95
0
  if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
96
0
  {
97
0
    PSecPkgCred_SupportedAlgs SupportedAlgs = (PSecPkgCred_SupportedAlgs)pBuffer;
98
0
    SupportedAlgs->cSupportedAlgs = sizeof(schannel_SupportedAlgs) / sizeof(ALG_ID);
99
0
    SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
100
0
    return SEC_E_OK;
101
0
  }
102
0
  else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
103
0
  {
104
0
    PSecPkgCred_CipherStrengths CipherStrengths = (PSecPkgCred_CipherStrengths)pBuffer;
105
0
    CipherStrengths->dwMinimumCipherStrength = 40;
106
0
    CipherStrengths->dwMaximumCipherStrength = 256;
107
0
    return SEC_E_OK;
108
0
  }
109
0
  else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
110
0
  {
111
0
    PSecPkgCred_SupportedProtocols SupportedProtocols = (PSecPkgCred_SupportedProtocols)pBuffer;
112
    /* Observed SupportedProtocols: 0x208A0 */
113
0
    SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
114
0
    return SEC_E_OK;
115
0
  }
116
117
0
  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
118
0
  return SEC_E_UNSUPPORTED_FUNCTION;
119
0
}
120
121
static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential,
122
                                                                      ULONG ulAttribute,
123
                                                                      void* pBuffer)
124
0
{
125
0
  return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
126
0
}
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
0
{
133
0
  SCHANNEL_CREDENTIALS* credentials = NULL;
134
135
0
  if (fCredentialUse == SECPKG_CRED_OUTBOUND)
136
0
  {
137
0
    SCHANNEL_CRED* cred = NULL;
138
0
    credentials = schannel_CredentialsNew();
139
0
    credentials->fCredentialUse = fCredentialUse;
140
0
    cred = (SCHANNEL_CRED*)pAuthData;
141
142
0
    if (cred)
143
0
    {
144
0
      CopyMemory(&credentials->cred, cred, sizeof(SCHANNEL_CRED));
145
0
    }
146
147
0
    sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
148
0
    sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
149
0
    return SEC_E_OK;
150
0
  }
151
0
  else if (fCredentialUse == SECPKG_CRED_INBOUND)
152
0
  {
153
0
    credentials = schannel_CredentialsNew();
154
0
    credentials->fCredentialUse = fCredentialUse;
155
0
    sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
156
0
    sspi_SecureHandleSetUpperPointer(phCredential, (void*)SCHANNEL_PACKAGE_NAME);
157
0
    return SEC_E_OK;
158
0
  }
159
160
0
  return SEC_E_OK;
161
0
}
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
0
{
168
0
  SECURITY_STATUS status = 0;
169
0
  SEC_WCHAR* pszPrincipalW = NULL;
170
0
  SEC_WCHAR* pszPackageW = NULL;
171
0
  if (pszPrincipal)
172
0
    pszPrincipalW = ConvertUtf8ToWCharAlloc(pszPrincipal, NULL);
173
0
  if (pszPackage)
174
0
    pszPackageW = ConvertUtf8ToWCharAlloc(pszPackage, NULL);
175
176
0
  status = schannel_AcquireCredentialsHandleW(pszPrincipalW, pszPackageW, fCredentialUse,
177
0
                                              pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument,
178
0
                                              phCredential, ptsExpiry);
179
0
  free(pszPrincipalW);
180
0
  free(pszPackageW);
181
0
  return status;
182
0
}
183
184
static SECURITY_STATUS SEC_ENTRY schannel_FreeCredentialsHandle(PCredHandle phCredential)
185
0
{
186
0
  SCHANNEL_CREDENTIALS* credentials = NULL;
187
188
0
  if (!phCredential)
189
0
    return SEC_E_INVALID_HANDLE;
190
191
0
  credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
192
193
0
  if (!credentials)
194
0
    return SEC_E_INVALID_HANDLE;
195
196
0
  schannel_CredentialsFree(credentials);
197
0
  return SEC_E_OK;
198
0
}
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
0
{
205
0
  SECURITY_STATUS status = 0;
206
0
  SCHANNEL_CONTEXT* context = NULL;
207
0
  SCHANNEL_CREDENTIALS* credentials = NULL;
208
209
  /* behave like windows SSPIs that don't want empty context */
210
0
  if (phContext && !phContext->dwLower && !phContext->dwUpper)
211
0
    return SEC_E_INVALID_HANDLE;
212
213
0
  context = sspi_SecureHandleGetLowerPointer(phContext);
214
215
0
  if (!context)
216
0
  {
217
0
    context = schannel_ContextNew();
218
219
0
    if (!context)
220
0
      return SEC_E_INSUFFICIENT_MEMORY;
221
222
0
    credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
223
0
    context->server = FALSE;
224
0
    CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
225
0
    sspi_SecureHandleSetLowerPointer(phNewContext, context);
226
0
    sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
227
0
    schannel_openssl_client_init(context->openssl);
228
0
  }
229
230
0
  status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
231
0
  return status;
232
0
}
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
0
{
239
0
  SECURITY_STATUS status = 0;
240
0
  SEC_WCHAR* pszTargetNameW = NULL;
241
242
0
  if (pszTargetName != NULL)
243
0
  {
244
0
    pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, NULL);
245
0
    if (!pszTargetNameW)
246
0
      return SEC_E_INSUFFICIENT_MEMORY;
247
0
  }
248
249
0
  status = schannel_InitializeSecurityContextW(
250
0
      phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
251
0
      Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
252
0
  free(pszTargetNameW);
253
0
  return status;
254
0
}
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
0
{
261
0
  SECURITY_STATUS status = 0;
262
0
  SCHANNEL_CONTEXT* context = NULL;
263
264
  /* behave like windows SSPIs that don't want empty context */
265
0
  if (phContext && !phContext->dwLower && !phContext->dwUpper)
266
0
    return SEC_E_INVALID_HANDLE;
267
268
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
269
270
0
  if (!context)
271
0
  {
272
0
    context = schannel_ContextNew();
273
274
0
    if (!context)
275
0
      return SEC_E_INSUFFICIENT_MEMORY;
276
277
0
    context->server = TRUE;
278
0
    sspi_SecureHandleSetLowerPointer(phNewContext, context);
279
0
    sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
280
0
    schannel_openssl_server_init(context->openssl);
281
0
  }
282
283
0
  status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
284
0
  return status;
285
0
}
286
287
static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
288
0
{
289
0
  SCHANNEL_CONTEXT* context = NULL;
290
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
291
292
0
  if (!context)
293
0
    return SEC_E_INVALID_HANDLE;
294
295
0
  schannel_ContextFree(context);
296
0
  return SEC_E_OK;
297
0
}
298
299
static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
300
                                                                 ULONG ulAttribute, void* pBuffer)
301
0
{
302
0
  if (!phContext)
303
0
    return SEC_E_INVALID_HANDLE;
304
305
0
  if (!pBuffer)
306
0
    return SEC_E_INSUFFICIENT_MEMORY;
307
308
0
  if (ulAttribute == SECPKG_ATTR_SIZES)
309
0
  {
310
0
    SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
311
0
    Sizes->cbMaxToken = 0x6000;
312
0
    Sizes->cbMaxSignature = 16;
313
0
    Sizes->cbBlockSize = 0;
314
0
    Sizes->cbSecurityTrailer = 16;
315
0
    return SEC_E_OK;
316
0
  }
317
0
  else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
318
0
  {
319
0
    SecPkgContext_StreamSizes* StreamSizes = (SecPkgContext_StreamSizes*)pBuffer;
320
0
    StreamSizes->cbHeader = 5;
321
0
    StreamSizes->cbTrailer = 36;
322
0
    StreamSizes->cbMaximumMessage = 0x4000;
323
0
    StreamSizes->cBuffers = 4;
324
0
    StreamSizes->cbBlockSize = 16;
325
0
    return SEC_E_OK;
326
0
  }
327
328
0
  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
329
0
  return SEC_E_UNSUPPORTED_FUNCTION;
330
0
}
331
332
static SECURITY_STATUS SEC_ENTRY schannel_MakeSignature(PCtxtHandle phContext, ULONG fQOP,
333
                                                        PSecBufferDesc pMessage, ULONG MessageSeqNo)
334
0
{
335
0
  return SEC_E_OK;
336
0
}
337
338
static SECURITY_STATUS SEC_ENTRY schannel_VerifySignature(PCtxtHandle phContext,
339
                                                          PSecBufferDesc pMessage,
340
                                                          ULONG MessageSeqNo, ULONG* pfQOP)
341
0
{
342
0
  return SEC_E_OK;
343
0
}
344
345
static SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
346
                                                         PSecBufferDesc pMessage,
347
                                                         ULONG MessageSeqNo)
348
0
{
349
0
  SECURITY_STATUS status = 0;
350
0
  SCHANNEL_CONTEXT* context = NULL;
351
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
352
353
0
  if (!context)
354
0
    return SEC_E_INVALID_HANDLE;
355
356
0
  status = schannel_openssl_encrypt_message(context->openssl, pMessage);
357
0
  return status;
358
0
}
359
360
static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
361
                                                         PSecBufferDesc pMessage,
362
                                                         ULONG MessageSeqNo, ULONG* pfQOP)
363
0
{
364
0
  SECURITY_STATUS status = 0;
365
0
  SCHANNEL_CONTEXT* context = NULL;
366
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
367
368
0
  if (!context)
369
0
    return SEC_E_INVALID_HANDLE;
370
371
0
  status = schannel_openssl_decrypt_message(context->openssl, pMessage);
372
0
  return status;
373
0
}
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
0
{
462
0
  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
463
0
                               ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
464
0
  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
465
0
                               ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
466
0
  return TRUE;
467
0
}