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
22 #include "wine/debug.h"
23 #include "wine/list.h"
24 #include "crypt32_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 typedef struct _WINE_STORE_LIST_ENTRY
30 PWINECRYPT_CERTSTORE store;
34 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
36 typedef struct _WINE_COLLECTIONSTORE
38 WINECRYPT_CERTSTORE hdr;
41 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
43 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
45 PWINE_COLLECTIONSTORE cs = store;
46 PWINE_STORE_LIST_ENTRY entry, next;
48 TRACE("(%p, %08x)\n", store, dwFlags);
50 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
53 TRACE("closing %p\n", entry);
54 CertCloseStore(entry->store, dwFlags);
57 cs->cs.DebugInfo->Spare[0] = 0;
58 DeleteCriticalSection(&cs->cs);
59 CRYPT_FreeStore(store);
62 static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
63 PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
66 void *ret = Context_CreateLinkContext(contextSize, child,
67 sizeof(PWINE_STORE_LIST_ENTRY), addRef);
70 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
76 static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
77 unsigned int contextFuncsOffset, void *context, void *toReplace, unsigned int contextSize,
81 void *childContext = NULL;
82 PWINE_STORE_LIST_ENTRY storeEntry = NULL;
84 TRACE("(%p, %d, %p, %p, %d)\n", store, contextFuncsOffset, context,
85 toReplace, contextSize);
90 void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
91 PCONTEXT_FUNCS contextFuncs;
93 storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
95 contextFuncs = (PCONTEXT_FUNCS)((LPBYTE)storeEntry->store +
97 ret = contextFuncs->addContext(storeEntry->store, context,
98 existingLinked, (const void **)&childContext);
102 PWINE_STORE_LIST_ENTRY entry, next;
104 EnterCriticalSection(&store->cs);
105 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
106 WINE_STORE_LIST_ENTRY, entry)
108 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
110 PCONTEXT_FUNCS contextFuncs = (PCONTEXT_FUNCS)(
111 (LPBYTE)entry->store + contextFuncsOffset);
114 ret = contextFuncs->addContext(entry->store, context, NULL,
115 (const void **)&childContext);
119 LeaveCriticalSection(&store->cs);
121 SetLastError(E_ACCESSDENIED);
123 *pChildContext = childContext;
127 /* Advances a collection enumeration by one context, if possible, where
129 * - calling the current store's enumeration function once, and returning
130 * the enumerated context if one is returned
131 * - moving to the next store if the current store has no more items, and
132 * recursively calling itself to get the next item.
133 * Returns NULL if the collection contains no more items or on error.
134 * Assumes the collection store's lock is held.
136 static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
137 PWINE_STORE_LIST_ENTRY storeEntry, PCONTEXT_FUNCS contextFuncs,
138 PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
141 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
143 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
147 /* Ref-counting funny business: "duplicate" (addref) the child, because
148 * the free(pPrev) below can cause the ref count to become negative.
150 child = Context_GetLinkedContext(pPrev, contextSize);
151 contextInterface->duplicate(child);
152 child = contextFuncs->enumContext(storeEntry->store, child);
153 contextInterface->free(pPrev);
157 child = contextFuncs->enumContext(storeEntry->store, NULL);
159 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
165 /* We always want the same function pointers (from certs, crls)
166 * in the next store, so use the same offset into the next store.
168 size_t offset = (LPBYTE)contextFuncs - (LPBYTE)storeEntry->store;
169 PWINE_STORE_LIST_ENTRY storeNextEntry =
170 LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
171 PCONTEXT_FUNCS storeNextContexts =
172 (PCONTEXT_FUNCS)((LPBYTE)storeNextEntry->store + offset);
174 ret = CRYPT_CollectionAdvanceEnum(store, storeNextEntry,
175 storeNextContexts, contextInterface, NULL, contextSize);
179 SetLastError(CRYPT_E_NOT_FOUND);
183 TRACE("returning %p\n", ret);
187 static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
188 void *toReplace, const void **ppStoreContext)
191 void *childContext = NULL;
192 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
194 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
195 cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
196 if (ppStoreContext && childContext)
198 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
199 Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
200 PCERT_CONTEXT context =
201 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
202 sizeof(CERT_CONTEXT), TRUE);
205 context->hCertStore = store;
206 *ppStoreContext = context;
208 CertFreeCertificateContext(childContext);
212 static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
214 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
217 TRACE("(%p, %p)\n", store, pPrev);
219 EnterCriticalSection(&cs->cs);
222 PWINE_STORE_LIST_ENTRY storeEntry =
223 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
224 sizeof(CERT_CONTEXT));
226 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
227 &storeEntry->store->certs, pCertInterface, pPrev,
228 sizeof(CERT_CONTEXT));
232 if (!list_empty(&cs->stores))
234 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
235 WINE_STORE_LIST_ENTRY, entry);
237 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
238 &storeEntry->store->certs, pCertInterface, NULL,
239 sizeof(CERT_CONTEXT));
243 SetLastError(CRYPT_E_NOT_FOUND);
247 LeaveCriticalSection(&cs->cs);
249 ((PCERT_CONTEXT)ret)->hCertStore = store;
250 TRACE("returning %p\n", ret);
254 static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
259 TRACE("(%p, %p)\n", store, pCertContext);
261 ret = CertDeleteCertificateFromStore(
262 Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
266 static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
267 void *toReplace, const void **ppStoreContext)
270 void *childContext = NULL;
271 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
273 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
274 crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
275 if (ppStoreContext && childContext)
277 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
278 Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
279 PCRL_CONTEXT context =
280 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
281 sizeof(CRL_CONTEXT), TRUE);
284 context->hCertStore = store;
285 *ppStoreContext = context;
287 CertFreeCRLContext(childContext);
291 static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
293 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
296 TRACE("(%p, %p)\n", store, pPrev);
298 EnterCriticalSection(&cs->cs);
301 PWINE_STORE_LIST_ENTRY storeEntry =
302 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
303 sizeof(CRL_CONTEXT));
305 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
306 &storeEntry->store->crls, pCRLInterface, pPrev, sizeof(CRL_CONTEXT));
310 if (!list_empty(&cs->stores))
312 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
313 WINE_STORE_LIST_ENTRY, entry);
315 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
316 &storeEntry->store->crls, pCRLInterface, NULL,
317 sizeof(CRL_CONTEXT));
321 SetLastError(CRYPT_E_NOT_FOUND);
325 LeaveCriticalSection(&cs->cs);
327 ((PCRL_CONTEXT)ret)->hCertStore = store;
328 TRACE("returning %p\n", ret);
332 static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
337 TRACE("(%p, %p)\n", store, pCrlContext);
339 ret = CertDeleteCRLFromStore(
340 Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
344 static BOOL CRYPT_CollectionAddCTL(PWINECRYPT_CERTSTORE store, void *ctl,
345 void *toReplace, const void **ppStoreContext)
348 void *childContext = NULL;
349 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
351 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, ctls),
352 ctl, toReplace, sizeof(CTL_CONTEXT), &childContext);
353 if (ppStoreContext && childContext)
355 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
356 Context_GetExtra(childContext, sizeof(CTL_CONTEXT));
357 PCTL_CONTEXT context =
358 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
359 sizeof(CTL_CONTEXT), TRUE);
362 context->hCertStore = store;
363 *ppStoreContext = context;
365 CertFreeCTLContext(childContext);
369 static void *CRYPT_CollectionEnumCTL(PWINECRYPT_CERTSTORE store, void *pPrev)
371 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
374 TRACE("(%p, %p)\n", store, pPrev);
376 EnterCriticalSection(&cs->cs);
379 PWINE_STORE_LIST_ENTRY storeEntry =
380 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
381 sizeof(CTL_CONTEXT));
383 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
384 &storeEntry->store->ctls, pCTLInterface, pPrev, sizeof(CTL_CONTEXT));
388 if (!list_empty(&cs->stores))
390 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
391 WINE_STORE_LIST_ENTRY, entry);
393 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
394 &storeEntry->store->ctls, pCTLInterface, NULL,
395 sizeof(CTL_CONTEXT));
399 SetLastError(CRYPT_E_NOT_FOUND);
403 LeaveCriticalSection(&cs->cs);
405 ((PCTL_CONTEXT)ret)->hCertStore = store;
406 TRACE("returning %p\n", ret);
410 static BOOL CRYPT_CollectionDeleteCTL(PWINECRYPT_CERTSTORE store,
415 TRACE("(%p, %p)\n", store, pCtlContext);
417 ret = CertDeleteCTLFromStore(
418 Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT)));
422 PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
423 DWORD dwFlags, const void *pvPara)
425 PWINE_COLLECTIONSTORE store;
427 if (dwFlags & CERT_STORE_DELETE_FLAG)
429 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
434 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
437 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
438 CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeCollection);
439 store->hdr.closeStore = CRYPT_CollectionCloseStore;
440 store->hdr.certs.addContext = CRYPT_CollectionAddCert;
441 store->hdr.certs.enumContext = CRYPT_CollectionEnumCert;
442 store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
443 store->hdr.crls.addContext = CRYPT_CollectionAddCRL;
444 store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL;
445 store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL;
446 store->hdr.ctls.addContext = CRYPT_CollectionAddCTL;
447 store->hdr.ctls.enumContext = CRYPT_CollectionEnumCTL;
448 store->hdr.ctls.deleteContext = CRYPT_CollectionDeleteCTL;
449 InitializeCriticalSection(&store->cs);
450 store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs");
451 list_init(&store->stores);
454 return (PWINECRYPT_CERTSTORE)store;
457 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
458 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
460 PWINE_COLLECTIONSTORE collection = hCollectionStore;
461 WINECRYPT_CERTSTORE *sibling = hSiblingStore;
462 PWINE_STORE_LIST_ENTRY entry;
465 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
466 dwUpdateFlags, dwPriority);
468 if (!collection || !sibling)
470 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
472 SetLastError(E_INVALIDARG);
475 if (collection->hdr.type != StoreTypeCollection)
477 SetLastError(E_INVALIDARG);
480 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
482 SetLastError(E_INVALIDARG);
486 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
489 InterlockedIncrement(&sibling->ref);
490 TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref);
491 entry->store = sibling;
492 entry->dwUpdateFlags = dwUpdateFlags;
493 entry->dwPriority = dwPriority;
494 list_init(&entry->entry);
495 TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority);
496 EnterCriticalSection(&collection->cs);
499 PWINE_STORE_LIST_ENTRY cursor;
502 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
503 WINE_STORE_LIST_ENTRY, entry)
505 if (cursor->dwPriority < dwPriority)
507 list_add_before(&cursor->entry, &entry->entry);
513 list_add_tail(&collection->stores, &entry->entry);
516 list_add_tail(&collection->stores, &entry->entry);
517 LeaveCriticalSection(&collection->cs);
525 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
526 HCERTSTORE hSiblingStore)
528 PWINE_COLLECTIONSTORE collection = hCollectionStore;
529 WINECRYPT_CERTSTORE *sibling = hSiblingStore;
530 PWINE_STORE_LIST_ENTRY store, next;
532 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
534 if (!collection || !sibling)
536 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
538 SetLastError(E_INVALIDARG);
541 if (collection->hdr.type != StoreTypeCollection)
543 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
545 SetLastError(E_INVALIDARG);
548 EnterCriticalSection(&collection->cs);
549 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
550 WINE_STORE_LIST_ENTRY, entry)
552 if (store->store == sibling)
554 list_remove(&store->entry);
555 CertCloseStore(store->store, 0);
560 LeaveCriticalSection(&collection->cs);