winevulkan: Avoid zero-sized allocations.
[wine.git] / dlls / crypt32 / filestore.c
blob3753283fbca4d006bf1b8dbf9ffa5e5d6dd55cb5
1 /*
2 * Copyright 2004-2007 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "winnls.h"
23 #include "wine/debug.h"
24 #include "crypt32_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 typedef struct _WINE_FILESTOREINFO
30 DWORD dwOpenFlags;
31 HCERTSTORE memStore;
32 HANDLE file;
33 DWORD type;
34 BOOL dirty;
35 } WINE_FILESTOREINFO;
37 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
39 WINE_FILESTOREINFO *store = hCertStore;
41 TRACE("(%p, %08lx)\n", store, dwFlags);
42 if (store->dirty)
43 CertSaveStore(store->memStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
44 store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0);
45 CloseHandle(store->file);
46 CryptMemFree(store);
49 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
50 PCCERT_CONTEXT cert, DWORD dwFlags)
52 WINE_FILESTOREINFO *store = hCertStore;
54 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
55 store->dirty = TRUE;
56 return TRUE;
59 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
60 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
62 WINE_FILESTOREINFO *store = hCertStore;
64 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
65 store->dirty = TRUE;
66 return TRUE;
69 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
70 PCCRL_CONTEXT crl, DWORD dwFlags)
72 WINE_FILESTOREINFO *store = hCertStore;
74 TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
75 store->dirty = TRUE;
76 return TRUE;
79 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
80 PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
82 WINE_FILESTOREINFO *store = hCertStore;
84 TRACE("(%p, %p, %08lx)\n", hCertStore, pCrlContext, dwFlags);
85 store->dirty = TRUE;
86 return TRUE;
89 static BOOL WINAPI CRYPT_FileWriteCTL(HCERTSTORE hCertStore,
90 PCCTL_CONTEXT ctl, DWORD dwFlags)
92 WINE_FILESTOREINFO *store = hCertStore;
94 TRACE("(%p, %p, %ld)\n", hCertStore, ctl, dwFlags);
95 store->dirty = TRUE;
96 return TRUE;
99 static BOOL WINAPI CRYPT_FileDeleteCTL(HCERTSTORE hCertStore,
100 PCCTL_CONTEXT pCtlContext, DWORD dwFlags)
102 WINE_FILESTOREINFO *store = hCertStore;
104 TRACE("(%p, %p, %08lx)\n", hCertStore, pCtlContext, dwFlags);
105 store->dirty = TRUE;
106 return TRUE;
109 static BOOL CRYPT_ReadBlobFromFile(HANDLE file, PCERT_BLOB blob)
111 BOOL ret = TRUE;
113 blob->cbData = GetFileSize(file, NULL);
114 if (blob->cbData)
116 blob->pbData = CryptMemAlloc(blob->cbData);
117 if (blob->pbData)
119 DWORD read;
121 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL) && read == blob->cbData;
122 if (!ret) CryptMemFree(blob->pbData);
124 else
125 ret = FALSE;
127 return ret;
130 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
131 DWORD dwCtrlType, void const *pvCtrlPara)
133 WINE_FILESTOREINFO *store = hCertStore;
134 BOOL ret;
136 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
137 pvCtrlPara);
139 switch (dwCtrlType)
141 case CERT_STORE_CTRL_RESYNC:
142 store->dirty = FALSE;
143 if (store->type == CERT_STORE_SAVE_AS_STORE)
145 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
146 CERT_STORE_CREATE_NEW_FLAG, NULL);
148 /* FIXME: if I could translate a handle to a path, I could use
149 * CryptQueryObject instead, but there's no API to do so yet.
151 ret = CRYPT_ReadSerializedStoreFromFile(store->file, memStore);
152 if (ret)
153 I_CertUpdateStore(store->memStore, memStore, 0, 0);
154 CertCloseStore(memStore, 0);
156 else if (store->type == CERT_STORE_SAVE_AS_PKCS7)
158 CERT_BLOB blob = { 0, NULL };
160 ret = CRYPT_ReadBlobFromFile(store->file, &blob);
161 if (ret)
163 HCERTSTORE messageStore;
165 ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
166 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
167 CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL,
168 &messageStore, NULL, NULL);
169 I_CertUpdateStore(store->memStore, messageStore, 0, 0);
170 CertCloseStore(messageStore, 0);
171 CryptMemFree(blob.pbData);
174 else
176 WARN("unknown type %ld\n", store->type);
177 ret = FALSE;
179 break;
180 case CERT_STORE_CTRL_COMMIT:
181 if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
183 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
184 ret = FALSE;
186 else if (store->dirty)
187 ret = CertSaveStore(store->memStore,
188 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
189 store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0);
190 else
191 ret = TRUE;
192 break;
193 default:
194 FIXME("%ld: stub\n", dwCtrlType);
195 ret = FALSE;
197 return ret;
200 static void *fileProvFuncs[] = {
201 CRYPT_FileCloseStore,
202 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
203 CRYPT_FileWriteCert,
204 CRYPT_FileDeleteCert,
205 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
206 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
207 CRYPT_FileWriteCRL,
208 CRYPT_FileDeleteCRL,
209 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
210 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
211 CRYPT_FileWriteCTL,
212 CRYPT_FileDeleteCTL,
213 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
214 CRYPT_FileControl,
217 static WINECRYPT_CERTSTORE *CRYPT_CreateFileStore(DWORD dwFlags,
218 HCERTSTORE memStore, HANDLE file, DWORD type)
220 WINECRYPT_CERTSTORE *store = NULL;
221 WINE_FILESTOREINFO *info = CryptMemAlloc(sizeof(WINE_FILESTOREINFO));
223 if (info)
225 CERT_STORE_PROV_INFO provInfo = { 0 };
227 info->dwOpenFlags = dwFlags;
228 info->memStore = memStore;
229 info->file = file;
230 info->type = type;
231 info->dirty = FALSE;
232 provInfo.cbSize = sizeof(provInfo);
233 provInfo.cStoreProvFunc = ARRAY_SIZE(fileProvFuncs);
234 provInfo.rgpvStoreProvFunc = fileProvFuncs;
235 provInfo.hStoreProv = info;
236 store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
238 return store;
241 WINECRYPT_CERTSTORE *CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
242 const void *pvPara)
244 WINECRYPT_CERTSTORE *store = NULL;
245 HANDLE file = (HANDLE)pvPara;
247 TRACE("(%Id, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
249 if (!pvPara)
251 SetLastError(ERROR_INVALID_HANDLE);
252 return NULL;
254 if (dwFlags & CERT_STORE_DELETE_FLAG)
256 SetLastError(E_INVALIDARG);
257 return NULL;
259 if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
260 (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
262 SetLastError(E_INVALIDARG);
263 return NULL;
266 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
267 GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
268 GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
270 HCERTSTORE memStore;
272 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
273 CERT_STORE_CREATE_NEW_FLAG, NULL);
274 if (memStore)
276 if (CRYPT_ReadSerializedStoreFromFile(file, memStore))
278 store = CRYPT_CreateFileStore(dwFlags, memStore, file,
279 CERT_STORE_SAVE_AS_STORE);
280 /* File store doesn't need crypto provider, so close it */
281 if (hCryptProv &&
282 !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
283 CryptReleaseContext(hCryptProv, 0);
287 TRACE("returning %p\n", store);
288 return store;
291 WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
292 DWORD dwFlags, const void *pvPara)
294 HCERTSTORE store = 0;
295 LPCWSTR fileName = pvPara;
296 DWORD access, create;
297 HANDLE file;
299 TRACE("(%Id, %08lx, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
301 if (!fileName)
303 SetLastError(ERROR_PATH_NOT_FOUND);
304 return NULL;
306 if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
307 (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
309 SetLastError(E_INVALIDARG);
310 return NULL;
313 access = GENERIC_READ;
314 if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
315 access |= GENERIC_WRITE;
316 if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
317 create = CREATE_NEW;
318 else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
319 create = OPEN_EXISTING;
320 else
321 create = OPEN_ALWAYS;
322 file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
323 FILE_ATTRIBUTE_NORMAL, NULL);
324 if (file != INVALID_HANDLE_VALUE)
326 HCERTSTORE memStore = NULL;
327 DWORD size = GetFileSize(file, NULL), type = 0;
329 /* If the file isn't empty, try to get the type from the file itself */
330 if (size)
332 DWORD contentType;
333 BOOL ret;
335 /* Close the file so CryptQueryObject can succeed.. */
336 CloseHandle(file);
337 ret = CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName,
338 CERT_QUERY_CONTENT_FLAG_CERT |
339 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
340 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
341 CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &contentType, NULL,
342 &memStore, NULL, NULL);
343 if (ret)
345 if (contentType == CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
346 type = CERT_STORE_SAVE_AS_PKCS7;
347 else
348 type = CERT_STORE_SAVE_AS_STORE;
349 /* and reopen the file. */
350 file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL,
351 create, FILE_ATTRIBUTE_NORMAL, NULL);
354 else
356 LPCWSTR ext = wcsrchr(fileName, '.');
358 if (ext)
360 ext++;
361 if (!lstrcmpiW(ext, L"spc") || !lstrcmpiW(ext, L"p7c"))
362 type = CERT_STORE_SAVE_AS_PKCS7;
364 if (!type)
365 type = CERT_STORE_SAVE_AS_STORE;
366 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
367 CERT_STORE_CREATE_NEW_FLAG, NULL);
369 if (memStore)
371 store = CRYPT_CreateFileStore(dwFlags, memStore, file, type);
372 /* File store doesn't need crypto provider, so close it */
373 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
374 CryptReleaseContext(hCryptProv, 0);
377 return store;
380 WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
381 DWORD dwFlags, const void *pvPara)
383 int len;
384 WINECRYPT_CERTSTORE *ret = NULL;
386 TRACE("(%Id, %08lx, %s)\n", hCryptProv, dwFlags,
387 debugstr_a(pvPara));
389 if (!pvPara)
391 SetLastError(ERROR_FILE_NOT_FOUND);
392 return NULL;
394 len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
395 if (len)
397 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
399 if (storeName)
401 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len);
402 ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
403 CryptMemFree(storeName);
406 return ret;