source: trunk/src/crypt32/regstore.c@ 22021

Last change on this file since 22021 was 22020, checked in by dmik, 13 years ago

Disable debug fields of RTL_CRITICAL_SECTION_DEBUG.

Odin uses the DebugInfo ptr in CRITICAL_SECTION for its own purposes
which are incompatible with NT. For this reason any NT-style usage must
be disabled.

This in particular fixes debug assertions and crashes in CRYPT32.DLL (due to
misinterpretation of the structure fields) which happened e.g. during playback of
some Flash content.

File size: 17.8 KB
Line 
1/*
2 * Copyright 2004-2007 Juan Lang
3 *
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.
8 *
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.
13 *
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
17 */
18#include <assert.h>
19#include <stdarg.h>
20#include "windef.h"
21#include "winbase.h"
22#include "wincrypt.h"
23#include "winreg.h"
24#include "winuser.h"
25#include "wine/debug.h"
26#include "wine/list.h"
27#include "crypt32_private.h"
28
29WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30
31typedef struct _WINE_HASH_TO_DELETE
32{
33 BYTE hash[20];
34 struct list entry;
35} WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
36
37typedef struct _WINE_REGSTOREINFO
38{
39 DWORD dwOpenFlags;
40 HCERTSTORE memStore;
41 HKEY key;
42 BOOL dirty;
43 RTL_CRITICAL_SECTION cs;
44 struct list certsToDelete;
45 struct list crlsToDelete;
46 struct list ctlsToDelete;
47} WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
48
49static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash)
50{
51 static const WCHAR fmt[] = { '%','0','2','X',0 };
52 DWORD i;
53
54 assert(hash);
55 assert(asciiHash);
56
57 for (i = 0; i < 20; i++)
58 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
59}
60
61static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
62 0 };
63static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
64static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
65static const WCHAR BlobW[] = { 'B','l','o','b',0 };
66
67static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType,
68 HCERTSTORE store)
69{
70 LONG rc;
71 DWORD index = 0;
72 WCHAR subKeyName[MAX_PATH];
73
74 do {
75 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
76
77 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
78 NULL);
79 if (!rc)
80 {
81 HKEY subKey;
82
83 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
84 if (!rc)
85 {
86 LPBYTE buf = NULL;
87
88 size = 0;
89 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
90 if (!rc)
91 buf = CryptMemAlloc(size);
92 if (buf)
93 {
94 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
95 &size);
96 if (!rc)
97 {
98 const void *context;
99 DWORD addedType;
100
101 TRACE("Adding cert with hash %s\n",
102 debugstr_w(subKeyName));
103 context = CRYPT_ReadSerializedElement(buf, size,
104 contextType, &addedType);
105 if (context)
106 {
107 const WINE_CONTEXT_INTERFACE *contextInterface;
108 BYTE hash[20];
109
110 switch (addedType)
111 {
112 case CERT_STORE_CERTIFICATE_CONTEXT:
113 contextInterface = pCertInterface;
114 break;
115 case CERT_STORE_CRL_CONTEXT:
116 contextInterface = pCRLInterface;
117 break;
118 case CERT_STORE_CTL_CONTEXT:
119 contextInterface = pCTLInterface;
120 break;
121 default:
122 contextInterface = NULL;
123 }
124 if (contextInterface)
125 {
126 size = sizeof(hash);
127 if (contextInterface->getProp(context,
128 CERT_HASH_PROP_ID, hash, &size))
129 {
130 WCHAR asciiHash[20 * 2 + 1];
131
132 CRYPT_HashToStr(hash, asciiHash);
133 TRACE("comparing %s\n",
134 debugstr_w(asciiHash));
135 TRACE("with %s\n", debugstr_w(subKeyName));
136 if (!lstrcmpW(asciiHash, subKeyName))
137 {
138 TRACE("hash matches, adding\n");
139 contextInterface->addContextToStore(
140 store, context,
141 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
142 }
143 else
144 TRACE("hash doesn't match, ignoring\n");
145 }
146 contextInterface->confree(context);
147 }
148 }
149 }
150 CryptMemFree(buf);
151 }
152 RegCloseKey(subKey);
153 }
154 /* Ignore intermediate errors, continue enumerating */
155 rc = ERROR_SUCCESS;
156 }
157 } while (!rc);
158}
159
160static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store)
161{
162 static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW };
163 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
164 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
165 DWORD i;
166
167 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
168 {
169 HKEY hKey;
170 LONG rc;
171
172 rc = RegCreateKeyExW(key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
173 &hKey, NULL);
174 if (!rc)
175 {
176 CRYPT_RegReadSerializedFromReg(hKey, contextFlags[i], store);
177 RegCloseKey(hKey);
178 }
179 }
180}
181
182/* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
183static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *buf,
184 DWORD len)
185{
186 WCHAR asciiHash[20 * 2 + 1];
187 LONG rc;
188 HKEY subKey;
189 BOOL ret;
190
191 CRYPT_HashToStr(hash, asciiHash);
192 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
193 &subKey, NULL);
194 if (!rc)
195 {
196 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, (BYTE*)buf, len);
197 RegCloseKey(subKey);
198 }
199 if (!rc)
200 ret = TRUE;
201 else
202 {
203 SetLastError(rc);
204 ret = FALSE;
205 }
206 return ret;
207}
208
209static BOOL CRYPT_SerializeContextsToReg(HKEY key,
210 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
211{
212 const void *context = NULL;
213 BOOL ret;
214
215 do {
216 context = contextInterface->enumContextsInStore(memStore, context);
217 if (context)
218 {
219 BYTE hash[20];
220 DWORD hashSize = sizeof(hash);
221
222 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
223 &hashSize);
224 if (ret)
225 {
226 DWORD size = 0;
227 LPBYTE buf = NULL;
228
229 ret = contextInterface->serialize(context, 0, NULL, &size);
230 if (size)
231 buf = CryptMemAlloc(size);
232 if (buf)
233 {
234 ret = contextInterface->serialize(context, 0, buf, &size);
235 if (ret)
236 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
237 }
238 CryptMemFree(buf);
239 }
240 }
241 else
242 ret = TRUE;
243 } while (ret && context != NULL);
244 if (context)
245 contextInterface->confree(context);
246 return ret;
247}
248
249static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
250{
251 static const WCHAR * const subKeys[] = { CertsW, CRLsW, CTLsW };
252 const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface,
253 pCRLInterface, pCTLInterface };
254 struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete,
255 &store->ctlsToDelete };
256 BOOL ret = TRUE;
257 DWORD i;
258
259 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
260 {
261 HKEY key;
262 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
263 KEY_ALL_ACCESS, NULL, &key, NULL);
264
265 if (!rc)
266 {
267 if (listToDelete[i])
268 {
269 PWINE_HASH_TO_DELETE toDelete, next;
270 WCHAR asciiHash[20 * 2 + 1];
271
272 EnterCriticalSection((CRITICAL_SECTION*)&store->cs);
273 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
274 WINE_HASH_TO_DELETE, entry)
275 {
276 LONG rc;
277
278 CRYPT_HashToStr(toDelete->hash, asciiHash);
279 TRACE("Removing %s\n", debugstr_w(asciiHash));
280 rc = RegDeleteKeyW(key, asciiHash);
281 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
282 {
283 SetLastError(rc);
284 ret = FALSE;
285 }
286 list_remove(&toDelete->entry);
287 CryptMemFree(toDelete);
288 }
289 LeaveCriticalSection((CRITICAL_SECTION*)&store->cs);
290 }
291 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
292 store->memStore);
293 RegCloseKey(key);
294 }
295 else
296 {
297 SetLastError(rc);
298 ret = FALSE;
299 }
300 }
301 return ret;
302}
303
304/* If force is true or the registry store is dirty, writes the contents of the
305 * store to the registry.
306 */
307static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
308{
309 BOOL ret;
310
311 TRACE("(%p, %d)\n", store, force);
312
313 if (store->dirty || force)
314 ret = CRYPT_RegWriteToReg(store);
315 else
316 ret = TRUE;
317 return ret;
318}
319
320static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
321{
322 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
323
324 TRACE("(%p, %08x)\n", store, dwFlags);
325 if (dwFlags)
326 FIXME("Unimplemented flags: %08x\n", dwFlags);
327
328 CRYPT_RegFlushStore(store, FALSE);
329 RegCloseKey(store->key);
330#ifndef __WIN32OS2__
331 store->cs.DebugInfo->Spare[0] = 0;
332#endif
333 DeleteCriticalSection((CRITICAL_SECTION*)&store->cs);
334 CryptMemFree(store);
335}
336
337static BOOL CRYPT_RegWriteContext(PWINE_REGSTOREINFO store,
338 const void *context, DWORD dwFlags)
339{
340 BOOL ret;
341
342 if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
343 {
344 store->dirty = TRUE;
345 ret = TRUE;
346 }
347 else
348 ret = FALSE;
349 return ret;
350}
351
352static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store,
353 struct list *deleteList, const void *context,
354 PCWINE_CONTEXT_INTERFACE contextInterface)
355{
356 BOOL ret;
357
358 if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
359 {
360 SetLastError(ERROR_ACCESS_DENIED);
361 ret = FALSE;
362 }
363 else
364 {
365 PWINE_HASH_TO_DELETE toDelete =
366 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
367
368 if (toDelete)
369 {
370 DWORD size = sizeof(toDelete->hash);
371
372 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID,
373 toDelete->hash, &size);
374 if (ret)
375 {
376 EnterCriticalSection((CRITICAL_SECTION*)&store->cs);
377 list_add_tail(deleteList, &toDelete->entry);
378 LeaveCriticalSection((CRITICAL_SECTION*)&store->cs);
379 }
380 else
381 {
382 CryptMemFree(toDelete);
383 ret = FALSE;
384 }
385 }
386 else
387 ret = FALSE;
388 if (ret)
389 store->dirty = TRUE;
390 }
391 return ret;
392}
393
394static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
395 PCCERT_CONTEXT cert, DWORD dwFlags)
396{
397 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
398
399 TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags);
400
401 return CRYPT_RegWriteContext(store, cert, dwFlags);
402}
403
404static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
405 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
406{
407 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
408
409 TRACE("(%p, %p, %08x)\n", store, pCertContext, dwFlags);
410
411 return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext,
412 pCertInterface);
413}
414
415static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore,
416 PCCRL_CONTEXT crl, DWORD dwFlags)
417{
418 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
419
420 TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags);
421
422 return CRYPT_RegWriteContext(store, crl, dwFlags);
423}
424
425static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore,
426 PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
427{
428 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
429
430 TRACE("(%p, %p, %08x)\n", store, pCrlContext, dwFlags);
431
432 return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext,
433 pCRLInterface);
434}
435
436static BOOL WINAPI CRYPT_RegWriteCTL(HCERTSTORE hCertStore,
437 PCCTL_CONTEXT ctl, DWORD dwFlags)
438{
439 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
440
441 TRACE("(%p, %p, %d)\n", hCertStore, ctl, dwFlags);
442
443 return CRYPT_RegWriteContext(store, ctl, dwFlags);
444}
445
446static BOOL WINAPI CRYPT_RegDeleteCTL(HCERTSTORE hCertStore,
447 PCCTL_CONTEXT pCtlContext, DWORD dwFlags)
448{
449 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
450
451 TRACE("(%p, %p, %08x)\n", store, pCtlContext, dwFlags);
452
453 return CRYPT_RegDeleteContext(store, &store->ctlsToDelete, pCtlContext,
454 pCTLInterface);
455}
456
457static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
458 DWORD dwCtrlType, void const *pvCtrlPara)
459{
460 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
461 BOOL ret;
462
463 TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
464 pvCtrlPara);
465
466 switch (dwCtrlType)
467 {
468 case CERT_STORE_CTRL_RESYNC:
469 {
470 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
471 CERT_STORE_CREATE_NEW_FLAG, NULL);
472
473 CRYPT_RegFlushStore(store, FALSE);
474 CRYPT_RegReadFromReg(store->key, memStore);
475 I_CertUpdateStore(store->memStore, memStore, 0, 0);
476 CertCloseStore(memStore, 0);
477 ret = TRUE;
478 break;
479 }
480 case CERT_STORE_CTRL_COMMIT:
481 ret = CRYPT_RegFlushStore(store,
482 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
483 break;
484 default:
485 FIXME("%d: stub\n", dwCtrlType);
486 ret = FALSE;
487 }
488 return ret;
489}
490
491static void *regProvFuncs[] = {
492 (void*)CRYPT_RegCloseStore,
493 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
494 (void*)CRYPT_RegWriteCert,
495 (void*)CRYPT_RegDeleteCert,
496 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
497 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
498 (void*)CRYPT_RegWriteCRL,
499 (void*)CRYPT_RegDeleteCRL,
500 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
501 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
502 (void*)CRYPT_RegWriteCTL,
503 (void*)CRYPT_RegDeleteCTL,
504 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
505 (void*)CRYPT_RegControl,
506};
507
508PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
509 const void *pvPara)
510{
511 PWINECRYPT_CERTSTORE store = NULL;
512
513 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
514
515 if (dwFlags & CERT_STORE_DELETE_FLAG)
516 {
517 DWORD rc = RegDeleteTreeW((HKEY)pvPara, CertsW);
518
519 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
520 rc = RegDeleteTreeW((HKEY)pvPara, CRLsW);
521 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
522 rc = RegDeleteTreeW((HKEY)pvPara, CTLsW);
523 if (rc == ERROR_NO_MORE_ITEMS)
524 rc = ERROR_SUCCESS;
525 SetLastError(rc);
526 }
527 else
528 {
529 HKEY key;
530
531 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
532 GetCurrentProcess(), (LPHANDLE)&key,
533 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
534 TRUE, 0))
535 {
536 PWINECRYPT_CERTSTORE memStore;
537
538 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, hCryptProv,
539 CERT_STORE_CREATE_NEW_FLAG, NULL);
540 if (memStore)
541 {
542 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
543 sizeof(WINE_REGSTOREINFO));
544
545 if (regInfo)
546 {
547 CERT_STORE_PROV_INFO provInfo = { 0 };
548
549 regInfo->dwOpenFlags = dwFlags;
550 regInfo->memStore = memStore;
551 regInfo->key = key;
552 InitializeCriticalSection((CRITICAL_SECTION*)&regInfo->cs);
553#ifndef __WIN32OS2__
554 regInfo->cs.DebugInfo->Spare[0] = (DWORD)(DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs");
555#endif
556 list_init(&regInfo->certsToDelete);
557 list_init(&regInfo->crlsToDelete);
558 list_init(&regInfo->ctlsToDelete);
559 CRYPT_RegReadFromReg(regInfo->key, regInfo->memStore);
560 regInfo->dirty = FALSE;
561 provInfo.cbSize = sizeof(provInfo);
562 provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
563 sizeof(regProvFuncs[0]);
564 provInfo.rgpvStoreProvFunc = regProvFuncs;
565 provInfo.hStoreProv = regInfo;
566 store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
567 /* Reg store doesn't need crypto provider, so close it */
568 if (hCryptProv &&
569 !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
570 CryptReleaseContext(hCryptProv, 0);
571 }
572 }
573 }
574 }
575 TRACE("returning %p\n", store);
576 return store;
577}
Note: See TracBrowser for help on using the repository browser.