/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 | } |