Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/ncrypt/ncrypt.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * NCrypt library
4
 *
5
 * Copyright 2021 David Fort <contact@hardening-consulting.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/assert.h>
21
#include <winpr/library.h>
22
#include <winpr/ncrypt.h>
23
24
#ifndef _WIN32
25
26
#include <winpr/print.h>
27
#include "../log.h"
28
29
#include "ncrypt.h"
30
31
#define TAG WINPR_TAG("ncrypt")
32
33
const static char NCRYPT_MAGIC[6] = { 'N', 'C', 'R', 'Y', 'P', 'T' };
34
35
SECURITY_STATUS checkNCryptHandle(NCRYPT_HANDLE handle, NCryptHandleType matchType)
36
0
{
37
0
  if (!handle)
38
0
  {
39
0
    WLog_VRB(TAG, "invalid handle 'NULL'");
40
0
    return ERROR_INVALID_PARAMETER;
41
0
  }
42
43
0
  const NCryptBaseHandle* base = (NCryptBaseHandle*)handle;
44
0
  if (memcmp(base->magic, NCRYPT_MAGIC, ARRAYSIZE(NCRYPT_MAGIC)) != 0)
45
0
  {
46
0
    char magic1[ARRAYSIZE(NCRYPT_MAGIC) + 1] = WINPR_C_ARRAY_INIT;
47
0
    char magic2[ARRAYSIZE(NCRYPT_MAGIC) + 1] = WINPR_C_ARRAY_INIT;
48
49
0
    memcpy(magic1, base->magic, ARRAYSIZE(NCRYPT_MAGIC));
50
0
    memcpy(magic2, NCRYPT_MAGIC, ARRAYSIZE(NCRYPT_MAGIC));
51
52
0
    WLog_VRB(TAG, "handle '%p' invalid magic '%s' instead of '%s'",
53
0
             WINPR_CXX_COMPAT_CAST(const void*, base), magic1, magic2);
54
0
    return ERROR_INVALID_PARAMETER;
55
0
  }
56
57
0
  switch (base->type)
58
0
  {
59
0
    case WINPR_NCRYPT_PROVIDER:
60
0
    case WINPR_NCRYPT_KEY:
61
0
      break;
62
0
    default:
63
0
      WLog_VRB(TAG, "handle '%p' invalid type %d", WINPR_CXX_COMPAT_CAST(const void*, base),
64
0
               WINPR_CXX_COMPAT_CAST(int32_t, base->type));
65
0
      return ERROR_INVALID_PARAMETER;
66
0
  }
67
68
0
  if ((matchType != WINPR_NCRYPT_INVALID) && (base->type != matchType))
69
0
  {
70
0
    WLog_VRB(TAG, "handle '%p' invalid type %d, expected %d",
71
0
             WINPR_CXX_COMPAT_CAST(const void*, base),
72
0
             WINPR_CXX_COMPAT_CAST(int32_t, base->type),
73
0
             WINPR_CXX_COMPAT_CAST(int32_t, matchType));
74
0
    return ERROR_INVALID_PARAMETER;
75
0
  }
76
0
  return ERROR_SUCCESS;
77
0
}
78
79
void* ncrypt_new_handle(NCryptHandleType kind, size_t len, NCryptGetPropertyFn getProp,
80
                        NCryptReleaseFn dtor)
81
0
{
82
0
  NCryptBaseHandle* ret = calloc(1, len);
83
0
  if (!ret)
84
0
    return NULL;
85
86
0
  memcpy(ret->magic, NCRYPT_MAGIC, sizeof(ret->magic));
87
0
  ret->type = kind;
88
0
  ret->getPropertyFn = getProp;
89
0
  ret->releaseFn = dtor;
90
0
  return ret;
91
0
}
92
93
SECURITY_STATUS winpr_NCryptDefault_dtor(NCRYPT_HANDLE handle)
94
0
{
95
0
  NCryptBaseHandle* h = (NCryptBaseHandle*)handle;
96
0
  if (h)
97
0
  {
98
0
    memset(h->magic, 0, sizeof(h->magic));
99
0
    h->type = WINPR_NCRYPT_INVALID;
100
0
    h->releaseFn = NULL;
101
0
    free(h);
102
0
  }
103
0
  return ERROR_SUCCESS;
104
0
}
105
106
SECURITY_STATUS NCryptEnumStorageProviders(DWORD* wProviderCount,
107
                                           NCryptProviderName** ppProviderList,
108
                                           WINPR_ATTR_UNUSED DWORD dwFlags)
109
0
{
110
0
  NCryptProviderName* ret = NULL;
111
0
  size_t stringAllocSize = 0;
112
0
#ifdef WITH_PKCS11
113
0
  LPWSTR strPtr = NULL;
114
0
  static const WCHAR emptyComment[] = WINPR_C_ARRAY_INIT;
115
0
  size_t copyAmount = 0;
116
0
#endif
117
118
0
  *wProviderCount = 0;
119
0
  *ppProviderList = NULL;
120
121
0
#ifdef WITH_PKCS11
122
0
  *wProviderCount += 1;
123
0
  stringAllocSize += (_wcslen(MS_SCARD_PROV) + 1) * sizeof(WCHAR);
124
0
  stringAllocSize += sizeof(emptyComment);
125
0
#endif
126
127
0
  if (!*wProviderCount)
128
0
    return ERROR_SUCCESS;
129
130
0
  ret = malloc(*wProviderCount * sizeof(NCryptProviderName) + stringAllocSize);
131
0
  if (!ret)
132
0
    return NTE_NO_MEMORY;
133
134
0
#ifdef WITH_PKCS11
135
0
  strPtr = (LPWSTR)(ret + *wProviderCount);
136
137
0
  ret->pszName = strPtr;
138
0
  copyAmount = (_wcslen(MS_SCARD_PROV) + 1) * sizeof(WCHAR);
139
0
  memcpy(strPtr, MS_SCARD_PROV, copyAmount);
140
0
  strPtr += copyAmount / 2;
141
142
0
  ret->pszComment = strPtr;
143
0
  copyAmount = sizeof(emptyComment);
144
0
  memcpy(strPtr, emptyComment, copyAmount);
145
146
0
  *ppProviderList = ret;
147
0
#endif
148
149
0
  return ERROR_SUCCESS;
150
0
}
151
152
SECURITY_STATUS NCryptOpenStorageProvider(NCRYPT_PROV_HANDLE* phProvider, LPCWSTR pszProviderName,
153
                                          DWORD dwFlags)
154
0
{
155
0
  return winpr_NCryptOpenStorageProviderEx(phProvider, pszProviderName, dwFlags, NULL);
156
0
}
157
158
SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
159
                                                  LPCWSTR pszProviderName, DWORD dwFlags,
160
                                                  LPCSTR* modulePaths)
161
0
{
162
0
#if defined(WITH_PKCS11)
163
0
  if (pszProviderName && ((_wcscmp(pszProviderName, MS_SMART_CARD_KEY_STORAGE_PROVIDER) == 0) ||
164
0
                          (_wcscmp(pszProviderName, MS_SCARD_PROV) == 0)))
165
0
    return NCryptOpenP11StorageProviderEx(phProvider, pszProviderName, dwFlags, modulePaths);
166
167
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
168
0
  (void)ConvertWCharToUtf8(pszProviderName, buffer, sizeof(buffer));
169
0
  WLog_WARN(TAG, "provider '%s' not supported", buffer);
170
0
  return ERROR_NOT_SUPPORTED;
171
#else
172
  WLog_WARN(TAG, "rebuild with -DWITH_PKCS11=ON to enable smartcard logon support");
173
  return ERROR_NOT_SUPPORTED;
174
#endif
175
0
}
176
177
SECURITY_STATUS NCryptEnumKeys(NCRYPT_PROV_HANDLE hProvider, LPCWSTR pszScope,
178
                               NCryptKeyName** ppKeyName, PVOID* ppEnumState, DWORD dwFlags)
179
0
{
180
0
  SECURITY_STATUS ret = 0;
181
0
  NCryptBaseProvider* provider = (NCryptBaseProvider*)hProvider;
182
183
0
  ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
184
0
  if (ret != ERROR_SUCCESS)
185
0
    return ret;
186
187
0
  return provider->enumKeysFn(hProvider, pszScope, ppKeyName, ppEnumState, dwFlags);
188
0
}
189
190
SECURITY_STATUS NCryptOpenKey(NCRYPT_PROV_HANDLE hProvider, NCRYPT_KEY_HANDLE* phKey,
191
                              LPCWSTR pszKeyName, DWORD dwLegacyKeySpec, DWORD dwFlags)
192
0
{
193
0
  SECURITY_STATUS ret = 0;
194
0
  NCryptBaseProvider* provider = (NCryptBaseProvider*)hProvider;
195
196
0
  ret = checkNCryptHandle((NCRYPT_HANDLE)hProvider, WINPR_NCRYPT_PROVIDER);
197
0
  if (ret != ERROR_SUCCESS)
198
0
    return ret;
199
0
  if (!phKey || !pszKeyName)
200
0
    return ERROR_INVALID_PARAMETER;
201
202
0
  return provider->openKeyFn(hProvider, phKey, pszKeyName, dwLegacyKeySpec, dwFlags);
203
0
}
204
205
static NCryptKeyGetPropertyEnum propertyStringToEnum(LPCWSTR pszProperty)
206
0
{
207
0
  if (_wcscmp(pszProperty, NCRYPT_CERTIFICATE_PROPERTY) == 0)
208
0
  {
209
0
    return NCRYPT_PROPERTY_CERTIFICATE;
210
0
  }
211
0
  else if (_wcscmp(pszProperty, NCRYPT_READER_PROPERTY) == 0)
212
0
  {
213
0
    return NCRYPT_PROPERTY_READER;
214
0
  }
215
0
  else if (_wcscmp(pszProperty, NCRYPT_WINPR_SLOTID) == 0)
216
0
  {
217
0
    return NCRYPT_PROPERTY_SLOTID;
218
0
  }
219
0
  else if (_wcscmp(pszProperty, NCRYPT_NAME_PROPERTY) == 0)
220
0
  {
221
0
    return NCRYPT_PROPERTY_NAME;
222
0
  }
223
224
0
  return NCRYPT_PROPERTY_UNKNOWN;
225
0
}
226
227
SECURITY_STATUS NCryptGetProperty(NCRYPT_HANDLE hObject, LPCWSTR pszProperty, PBYTE pbOutput,
228
                                  DWORD cbOutput, DWORD* pcbResult, DWORD dwFlags)
229
0
{
230
0
  NCryptKeyGetPropertyEnum property = NCRYPT_PROPERTY_UNKNOWN;
231
0
  NCryptBaseHandle* base = NULL;
232
233
0
  if (!hObject)
234
0
    return ERROR_INVALID_PARAMETER;
235
236
0
  base = (NCryptBaseHandle*)hObject;
237
0
  if (memcmp(base->magic, NCRYPT_MAGIC, 6) != 0)
238
0
    return ERROR_INVALID_HANDLE;
239
240
0
  property = propertyStringToEnum(pszProperty);
241
0
  if (property == NCRYPT_PROPERTY_UNKNOWN)
242
0
    return ERROR_NOT_SUPPORTED;
243
244
0
  return base->getPropertyFn(hObject, property, pbOutput, cbOutput, pcbResult, dwFlags);
245
0
}
246
247
SECURITY_STATUS NCryptFreeObject(NCRYPT_HANDLE hObject)
248
0
{
249
0
  NCryptBaseHandle* base = NULL;
250
0
  SECURITY_STATUS ret = checkNCryptHandle(hObject, WINPR_NCRYPT_INVALID);
251
0
  if (ret != ERROR_SUCCESS)
252
0
    return ret;
253
254
0
  base = (NCryptBaseHandle*)hObject;
255
0
  if (base->releaseFn)
256
0
    ret = base->releaseFn(hObject);
257
258
0
  return ret;
259
0
}
260
261
SECURITY_STATUS NCryptFreeBuffer(PVOID pvInput)
262
0
{
263
0
  if (!pvInput)
264
0
    return ERROR_INVALID_PARAMETER;
265
266
0
  free(pvInput);
267
0
  return ERROR_SUCCESS;
268
0
}
269
270
#else
271
SECURITY_STATUS winpr_NCryptOpenStorageProviderEx(NCRYPT_PROV_HANDLE* phProvider,
272
                                                  LPCWSTR pszProviderName, DWORD dwFlags,
273
                                                  LPCSTR* modulePaths)
274
{
275
  typedef SECURITY_STATUS (*NCryptOpenStorageProviderFn)(NCRYPT_PROV_HANDLE * phProvider,
276
                                                         LPCWSTR pszProviderName, DWORD dwFlags);
277
  SECURITY_STATUS ret = NTE_PROV_DLL_NOT_FOUND;
278
  HANDLE lib = LoadLibraryA("ncrypt.dll");
279
  if (!lib)
280
    return NTE_PROV_DLL_NOT_FOUND;
281
282
  NCryptOpenStorageProviderFn ncryptOpenStorageProviderFn =
283
      GetProcAddressAs(lib, "NCryptOpenStorageProvider", NCryptOpenStorageProviderFn);
284
  if (!ncryptOpenStorageProviderFn)
285
  {
286
    ret = NTE_PROV_DLL_NOT_FOUND;
287
    goto out_free_lib;
288
  }
289
290
  ret = ncryptOpenStorageProviderFn(phProvider, pszProviderName, dwFlags);
291
292
out_free_lib:
293
  FreeLibrary(lib);
294
  return ret;
295
}
296
#endif /* _WIN32 */
297
298
const char* winpr_NCryptSecurityStatusError(SECURITY_STATUS status)
299
0
{
300
0
#define NTE_CASE(S)            \
301
0
  case (SECURITY_STATUS)(S): \
302
0
    return #S
303
304
0
  switch (status)
305
0
  {
306
0
    NTE_CASE(ERROR_SUCCESS);
307
0
    NTE_CASE(ERROR_INVALID_PARAMETER);
308
0
    NTE_CASE(ERROR_INVALID_HANDLE);
309
0
    NTE_CASE(ERROR_NOT_SUPPORTED);
310
311
0
    NTE_CASE(NTE_BAD_UID);
312
0
    NTE_CASE(NTE_BAD_HASH);
313
0
    NTE_CASE(NTE_BAD_KEY);
314
0
    NTE_CASE(NTE_BAD_LEN);
315
0
    NTE_CASE(NTE_BAD_DATA);
316
0
    NTE_CASE(NTE_BAD_SIGNATURE);
317
0
    NTE_CASE(NTE_BAD_VER);
318
0
    NTE_CASE(NTE_BAD_ALGID);
319
0
    NTE_CASE(NTE_BAD_FLAGS);
320
0
    NTE_CASE(NTE_BAD_TYPE);
321
0
    NTE_CASE(NTE_BAD_KEY_STATE);
322
0
    NTE_CASE(NTE_BAD_HASH_STATE);
323
0
    NTE_CASE(NTE_NO_KEY);
324
0
    NTE_CASE(NTE_NO_MEMORY);
325
0
    NTE_CASE(NTE_EXISTS);
326
0
    NTE_CASE(NTE_PERM);
327
0
    NTE_CASE(NTE_NOT_FOUND);
328
0
    NTE_CASE(NTE_DOUBLE_ENCRYPT);
329
0
    NTE_CASE(NTE_BAD_PROVIDER);
330
0
    NTE_CASE(NTE_BAD_PROV_TYPE);
331
0
    NTE_CASE(NTE_BAD_PUBLIC_KEY);
332
0
    NTE_CASE(NTE_BAD_KEYSET);
333
0
    NTE_CASE(NTE_PROV_TYPE_NOT_DEF);
334
0
    NTE_CASE(NTE_PROV_TYPE_ENTRY_BAD);
335
0
    NTE_CASE(NTE_KEYSET_NOT_DEF);
336
0
    NTE_CASE(NTE_KEYSET_ENTRY_BAD);
337
0
    NTE_CASE(NTE_PROV_TYPE_NO_MATCH);
338
0
    NTE_CASE(NTE_SIGNATURE_FILE_BAD);
339
0
    NTE_CASE(NTE_PROVIDER_DLL_FAIL);
340
0
    NTE_CASE(NTE_PROV_DLL_NOT_FOUND);
341
0
    NTE_CASE(NTE_BAD_KEYSET_PARAM);
342
0
    NTE_CASE(NTE_FAIL);
343
0
    NTE_CASE(NTE_SYS_ERR);
344
0
    NTE_CASE(NTE_SILENT_CONTEXT);
345
0
    NTE_CASE(NTE_TOKEN_KEYSET_STORAGE_FULL);
346
0
    NTE_CASE(NTE_TEMPORARY_PROFILE);
347
0
    NTE_CASE(NTE_FIXEDPARAMETER);
348
349
0
    default:
350
0
      return "<unknown>";
351
0
  }
352
353
0
#undef NTE_CASE
354
0
}
355
356
const char* winpr_NCryptGetModulePath(NCRYPT_PROV_HANDLE phProvider)
357
0
{
358
0
#if defined(WITH_PKCS11)
359
0
  return NCryptGetModulePath(phProvider);
360
#else
361
  return NULL;
362
#endif
363
0
}