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