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