Coverage Report

Created: 2025-07-01 06:46

/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(
92
    WINPR_ATTR_UNUSED PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
93
0
{
94
0
  if (ulAttribute == SECPKG_ATTR_SUPPORTED_ALGS)
95
0
  {
96
0
    PSecPkgCred_SupportedAlgs SupportedAlgs = (PSecPkgCred_SupportedAlgs)pBuffer;
97
0
    SupportedAlgs->cSupportedAlgs = sizeof(schannel_SupportedAlgs) / sizeof(ALG_ID);
98
0
    SupportedAlgs->palgSupportedAlgs = (ALG_ID*)schannel_SupportedAlgs;
99
0
    return SEC_E_OK;
100
0
  }
101
0
  else if (ulAttribute == SECPKG_ATTR_CIPHER_STRENGTHS)
102
0
  {
103
0
    PSecPkgCred_CipherStrengths CipherStrengths = (PSecPkgCred_CipherStrengths)pBuffer;
104
0
    CipherStrengths->dwMinimumCipherStrength = 40;
105
0
    CipherStrengths->dwMaximumCipherStrength = 256;
106
0
    return SEC_E_OK;
107
0
  }
108
0
  else if (ulAttribute == SECPKG_ATTR_SUPPORTED_PROTOCOLS)
109
0
  {
110
0
    PSecPkgCred_SupportedProtocols SupportedProtocols = (PSecPkgCred_SupportedProtocols)pBuffer;
111
    /* Observed SupportedProtocols: 0x208A0 */
112
0
    SupportedProtocols->grbitProtocol = (SP_PROT_CLIENTS | SP_PROT_SERVERS);
113
0
    return SEC_E_OK;
114
0
  }
115
116
0
  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
117
0
  return SEC_E_UNSUPPORTED_FUNCTION;
118
0
}
119
120
static SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential,
121
                                                                      ULONG ulAttribute,
122
                                                                      void* pBuffer)
123
0
{
124
0
  return schannel_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
125
0
}
126
127
static 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
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, 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
0
{
207
0
  SECURITY_STATUS status = 0;
208
0
  SCHANNEL_CONTEXT* context = NULL;
209
0
  SCHANNEL_CREDENTIALS* credentials = NULL;
210
211
  /* behave like windows SSPIs that don't want empty context */
212
0
  if (phContext && !phContext->dwLower && !phContext->dwUpper)
213
0
    return SEC_E_INVALID_HANDLE;
214
215
0
  context = sspi_SecureHandleGetLowerPointer(phContext);
216
217
0
  if (!context)
218
0
  {
219
0
    context = schannel_ContextNew();
220
221
0
    if (!context)
222
0
      return SEC_E_INSUFFICIENT_MEMORY;
223
224
0
    credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential);
225
0
    context->server = FALSE;
226
0
    CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED));
227
0
    sspi_SecureHandleSetLowerPointer(phNewContext, context);
228
0
    sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
229
0
    schannel_openssl_client_init(context->openssl);
230
0
  }
231
232
0
  status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput);
233
0
  return status;
234
0
}
235
236
static 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
0
{
241
0
  SECURITY_STATUS status = 0;
242
0
  SEC_WCHAR* pszTargetNameW = NULL;
243
244
0
  if (pszTargetName != NULL)
245
0
  {
246
0
    pszTargetNameW = ConvertUtf8ToWCharAlloc(pszTargetName, NULL);
247
0
    if (!pszTargetNameW)
248
0
      return SEC_E_INSUFFICIENT_MEMORY;
249
0
  }
250
251
0
  status = schannel_InitializeSecurityContextW(
252
0
      phCredential, phContext, pszTargetNameW, fContextReq, Reserved1, TargetDataRep, pInput,
253
0
      Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
254
0
  free(pszTargetNameW);
255
0
  return status;
256
0
}
257
258
static 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
0
{
264
0
  SECURITY_STATUS status = 0;
265
0
  SCHANNEL_CONTEXT* context = NULL;
266
267
  /* behave like windows SSPIs that don't want empty context */
268
0
  if (phContext && !phContext->dwLower && !phContext->dwUpper)
269
0
    return SEC_E_INVALID_HANDLE;
270
271
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
272
273
0
  if (!context)
274
0
  {
275
0
    context = schannel_ContextNew();
276
277
0
    if (!context)
278
0
      return SEC_E_INSUFFICIENT_MEMORY;
279
280
0
    context->server = TRUE;
281
0
    sspi_SecureHandleSetLowerPointer(phNewContext, context);
282
0
    sspi_SecureHandleSetUpperPointer(phNewContext, (void*)SCHANNEL_PACKAGE_NAME);
283
0
    schannel_openssl_server_init(context->openssl);
284
0
  }
285
286
0
  status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput);
287
0
  return status;
288
0
}
289
290
static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext)
291
0
{
292
0
  SCHANNEL_CONTEXT* context = NULL;
293
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
294
295
0
  if (!context)
296
0
    return SEC_E_INVALID_HANDLE;
297
298
0
  schannel_ContextFree(context);
299
0
  return SEC_E_OK;
300
0
}
301
302
static SECURITY_STATUS SEC_ENTRY schannel_QueryContextAttributes(PCtxtHandle phContext,
303
                                                                 ULONG ulAttribute, void* pBuffer)
304
0
{
305
0
  if (!phContext)
306
0
    return SEC_E_INVALID_HANDLE;
307
308
0
  if (!pBuffer)
309
0
    return SEC_E_INSUFFICIENT_MEMORY;
310
311
0
  if (ulAttribute == SECPKG_ATTR_SIZES)
312
0
  {
313
0
    SecPkgContext_Sizes* Sizes = (SecPkgContext_Sizes*)pBuffer;
314
0
    Sizes->cbMaxToken = 0x6000;
315
0
    Sizes->cbMaxSignature = 16;
316
0
    Sizes->cbBlockSize = 0;
317
0
    Sizes->cbSecurityTrailer = 16;
318
0
    return SEC_E_OK;
319
0
  }
320
0
  else if (ulAttribute == SECPKG_ATTR_STREAM_SIZES)
321
0
  {
322
0
    SecPkgContext_StreamSizes* StreamSizes = (SecPkgContext_StreamSizes*)pBuffer;
323
0
    StreamSizes->cbHeader = 5;
324
0
    StreamSizes->cbTrailer = 36;
325
0
    StreamSizes->cbMaximumMessage = 0x4000;
326
0
    StreamSizes->cBuffers = 4;
327
0
    StreamSizes->cbBlockSize = 16;
328
0
    return SEC_E_OK;
329
0
  }
330
331
0
  WLog_ERR(TAG, "TODO: Implement ulAttribute=%08" PRIx32, ulAttribute);
332
0
  return SEC_E_UNSUPPORTED_FUNCTION;
333
0
}
334
335
static 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
0
{
340
0
  return SEC_E_OK;
341
0
}
342
343
static 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
0
{
348
0
  return SEC_E_OK;
349
0
}
350
351
static 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
0
{
356
0
  SECURITY_STATUS status = 0;
357
0
  SCHANNEL_CONTEXT* context = NULL;
358
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
359
360
0
  if (!context)
361
0
    return SEC_E_INVALID_HANDLE;
362
363
0
  status = schannel_openssl_encrypt_message(context->openssl, pMessage);
364
0
  return status;
365
0
}
366
367
static SECURITY_STATUS SEC_ENTRY schannel_DecryptMessage(PCtxtHandle phContext,
368
                                                         PSecBufferDesc pMessage,
369
                                                         WINPR_ATTR_UNUSED ULONG MessageSeqNo,
370
                                                         WINPR_ATTR_UNUSED ULONG* pfQOP)
371
0
{
372
0
  SECURITY_STATUS status = 0;
373
0
  SCHANNEL_CONTEXT* context = NULL;
374
0
  context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
375
376
0
  if (!context)
377
0
    return SEC_E_INVALID_HANDLE;
378
379
0
  status = schannel_openssl_decrypt_message(context->openssl, pMessage);
380
0
  return status;
381
0
}
382
383
const 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
415
const 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
447
const 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
456
static WCHAR SCHANNEL_SecPkgInfoW_NameBuffer[32] = { 0 };
457
static WCHAR SCHANNEL_SecPkgInfoW_CommentBuffer[32] = { 0 };
458
459
const 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
468
BOOL SCHANNEL_init(void)
469
0
{
470
0
  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Name, SCHANNEL_SecPkgInfoW_NameBuffer,
471
0
                               ARRAYSIZE(SCHANNEL_SecPkgInfoW_NameBuffer));
472
0
  InitializeConstWCharFromUtf8(SCHANNEL_SecPkgInfoA.Comment, SCHANNEL_SecPkgInfoW_CommentBuffer,
473
0
                               ARRAYSIZE(SCHANNEL_SecPkgInfoW_CommentBuffer));
474
0
  return TRUE;
475
0
}