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
);