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