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
,
258 PCCERT_CONTEXT linked
;
260 TRACE("(%p, %p)\n", store
, pCertContext
);
262 /* Deleting the linked context results in its ref count getting
263 * decreased, but the caller of this (CertDeleteCertificateFromStore) also
264 * decreases pCertContext's ref count, by calling
265 * CertFreeCertificateContext. Increase ref count of linked context to
268 linked
= Context_GetLinkedContext(pCertContext
, sizeof(CERT_CONTEXT
));
269 CertDuplicateCertificateContext(linked
);
270 ret
= CertDeleteCertificateFromStore(linked
);
274 static BOOL
CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store
, void *crl
,
275 void *toReplace
, const void **ppStoreContext
)
278 void *childContext
= NULL
;
279 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
281 ret
= CRYPT_CollectionAddContext(cs
, offsetof(WINECRYPT_CERTSTORE
, crls
),
282 crl
, toReplace
, sizeof(CRL_CONTEXT
), &childContext
);
283 if (ppStoreContext
&& childContext
)
285 PWINE_STORE_LIST_ENTRY storeEntry
= *(PWINE_STORE_LIST_ENTRY
*)
286 Context_GetExtra(childContext
, sizeof(CRL_CONTEXT
));
287 PCRL_CONTEXT context
=
288 CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
, childContext
,
289 sizeof(CRL_CONTEXT
), TRUE
);
292 context
->hCertStore
= store
;
293 *ppStoreContext
= context
;
295 CertFreeCRLContext(childContext
);
299 static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store
, void *pPrev
)
301 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
304 TRACE("(%p, %p)\n", store
, pPrev
);
306 EnterCriticalSection(&cs
->cs
);
309 PWINE_STORE_LIST_ENTRY storeEntry
=
310 *(PWINE_STORE_LIST_ENTRY
*)Context_GetExtra(pPrev
,
311 sizeof(CRL_CONTEXT
));
313 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
314 &storeEntry
->store
->crls
, pCRLInterface
, pPrev
, sizeof(CRL_CONTEXT
));
318 if (!list_empty(&cs
->stores
))
320 PWINE_STORE_LIST_ENTRY storeEntry
= LIST_ENTRY(cs
->stores
.next
,
321 WINE_STORE_LIST_ENTRY
, entry
);
323 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
324 &storeEntry
->store
->crls
, pCRLInterface
, NULL
,
325 sizeof(CRL_CONTEXT
));
329 SetLastError(CRYPT_E_NOT_FOUND
);
333 LeaveCriticalSection(&cs
->cs
);
335 ((PCRL_CONTEXT
)ret
)->hCertStore
= store
;
336 TRACE("returning %p\n", ret
);
340 static BOOL
CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store
,
344 PCCRL_CONTEXT linked
;
346 TRACE("(%p, %p)\n", store
, pCrlContext
);
348 /* Deleting the linked context results in its ref count getting
349 * decreased, but the caller of this (CertDeleteCRLFromStore) also
350 * decreases pCrlContext's ref count, by calling CertFreeCRLContext.
351 * Increase ref count of linked context to compensate.
353 linked
= Context_GetLinkedContext(pCrlContext
, sizeof(CRL_CONTEXT
));
354 CertDuplicateCRLContext(linked
);
355 ret
= CertDeleteCRLFromStore(linked
);
359 static BOOL
CRYPT_CollectionAddCTL(PWINECRYPT_CERTSTORE store
, void *ctl
,
360 void *toReplace
, const void **ppStoreContext
)
363 void *childContext
= NULL
;
364 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
366 ret
= CRYPT_CollectionAddContext(cs
, offsetof(WINECRYPT_CERTSTORE
, ctls
),
367 ctl
, toReplace
, sizeof(CTL_CONTEXT
), &childContext
);
368 if (ppStoreContext
&& childContext
)
370 PWINE_STORE_LIST_ENTRY storeEntry
= *(PWINE_STORE_LIST_ENTRY
*)
371 Context_GetExtra(childContext
, sizeof(CTL_CONTEXT
));
372 PCTL_CONTEXT context
=
373 CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
, childContext
,
374 sizeof(CTL_CONTEXT
), TRUE
);
377 context
->hCertStore
= store
;
378 *ppStoreContext
= context
;
380 CertFreeCTLContext(childContext
);
384 static void *CRYPT_CollectionEnumCTL(PWINECRYPT_CERTSTORE store
, void *pPrev
)
386 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
389 TRACE("(%p, %p)\n", store
, pPrev
);
391 EnterCriticalSection(&cs
->cs
);
394 PWINE_STORE_LIST_ENTRY storeEntry
=
395 *(PWINE_STORE_LIST_ENTRY
*)Context_GetExtra(pPrev
,
396 sizeof(CTL_CONTEXT
));
398 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
399 &storeEntry
->store
->ctls
, pCTLInterface
, pPrev
, sizeof(CTL_CONTEXT
));
403 if (!list_empty(&cs
->stores
))
405 PWINE_STORE_LIST_ENTRY storeEntry
= LIST_ENTRY(cs
->stores
.next
,
406 WINE_STORE_LIST_ENTRY
, entry
);
408 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
409 &storeEntry
->store
->ctls
, pCTLInterface
, NULL
,
410 sizeof(CTL_CONTEXT
));
414 SetLastError(CRYPT_E_NOT_FOUND
);
418 LeaveCriticalSection(&cs
->cs
);
420 ((PCTL_CONTEXT
)ret
)->hCertStore
= store
;
421 TRACE("returning %p\n", ret
);
425 static BOOL
CRYPT_CollectionDeleteCTL(PWINECRYPT_CERTSTORE store
,
429 PCCTL_CONTEXT linked
;
431 TRACE("(%p, %p)\n", store
, pCtlContext
);
433 /* Deleting the linked context results in its ref count getting
434 * decreased, but the caller of this (CertDeleteCTLFromStore) also
435 * decreases pCtlContext's ref count, by calling CertFreeCTLContext.
436 * Increase ref count of linked context to compensate.
438 linked
= Context_GetLinkedContext(pCtlContext
, sizeof(CTL_CONTEXT
));
439 CertDuplicateCTLContext(linked
);
440 ret
= CertDeleteCTLFromStore(linked
);
444 static BOOL WINAPI
CRYPT_CollectionControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
445 DWORD dwCtrlType
, void const *pvCtrlPara
)
448 PWINE_COLLECTIONSTORE store
= hCertStore
;
449 PWINE_STORE_LIST_ENTRY entry
;
451 TRACE("(%p, %08x, %d, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
456 if (store
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
458 SetLastError(E_INVALIDARG
);
461 if (store
->hdr
.type
!= StoreTypeCollection
)
463 SetLastError(E_INVALIDARG
);
468 EnterCriticalSection(&store
->cs
);
469 LIST_FOR_EACH_ENTRY(entry
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
471 if (entry
->store
->control
)
473 ret
= entry
->store
->control(entry
->store
, dwFlags
, dwCtrlType
,
479 LeaveCriticalSection(&store
->cs
);
483 PWINECRYPT_CERTSTORE
CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
484 DWORD dwFlags
, const void *pvPara
)
486 PWINE_COLLECTIONSTORE store
;
488 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
490 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
495 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
498 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
499 CRYPT_InitStore(&store
->hdr
, dwFlags
, StoreTypeCollection
);
500 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
501 store
->hdr
.certs
.addContext
= CRYPT_CollectionAddCert
;
502 store
->hdr
.certs
.enumContext
= CRYPT_CollectionEnumCert
;
503 store
->hdr
.certs
.deleteContext
= CRYPT_CollectionDeleteCert
;
504 store
->hdr
.crls
.addContext
= CRYPT_CollectionAddCRL
;
505 store
->hdr
.crls
.enumContext
= CRYPT_CollectionEnumCRL
;
506 store
->hdr
.crls
.deleteContext
= CRYPT_CollectionDeleteCRL
;
507 store
->hdr
.ctls
.addContext
= CRYPT_CollectionAddCTL
;
508 store
->hdr
.ctls
.enumContext
= CRYPT_CollectionEnumCTL
;
509 store
->hdr
.ctls
.deleteContext
= CRYPT_CollectionDeleteCTL
;
510 store
->hdr
.control
= CRYPT_CollectionControl
;
511 InitializeCriticalSection(&store
->cs
);
512 store
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_COLLECTIONSTORE->cs");
513 list_init(&store
->stores
);
516 return (PWINECRYPT_CERTSTORE
)store
;
519 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
520 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
522 PWINE_COLLECTIONSTORE collection
= hCollectionStore
;
523 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
524 PWINE_STORE_LIST_ENTRY entry
;
527 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore
, hSiblingStore
,
528 dwUpdateFlags
, dwPriority
);
530 if (!collection
|| !sibling
)
532 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
534 SetLastError(E_INVALIDARG
);
537 if (collection
->hdr
.type
!= StoreTypeCollection
)
539 SetLastError(E_INVALIDARG
);
542 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
544 SetLastError(E_INVALIDARG
);
548 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
551 InterlockedIncrement(&sibling
->ref
);
552 TRACE("sibling %p's ref count is %d\n", sibling
, sibling
->ref
);
553 entry
->store
= sibling
;
554 entry
->dwUpdateFlags
= dwUpdateFlags
;
555 entry
->dwPriority
= dwPriority
;
556 list_init(&entry
->entry
);
557 TRACE("%p: adding %p, priority %d\n", collection
, entry
, dwPriority
);
558 EnterCriticalSection(&collection
->cs
);
561 PWINE_STORE_LIST_ENTRY cursor
;
564 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
565 WINE_STORE_LIST_ENTRY
, entry
)
567 if (cursor
->dwPriority
< dwPriority
)
569 list_add_before(&cursor
->entry
, &entry
->entry
);
575 list_add_tail(&collection
->stores
, &entry
->entry
);
578 list_add_tail(&collection
->stores
, &entry
->entry
);
579 LeaveCriticalSection(&collection
->cs
);
587 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
588 HCERTSTORE hSiblingStore
)
590 PWINE_COLLECTIONSTORE collection
= hCollectionStore
;
591 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
592 PWINE_STORE_LIST_ENTRY store
, next
;
594 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
596 if (!collection
|| !sibling
)
598 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
600 SetLastError(E_INVALIDARG
);
603 if (collection
->hdr
.type
!= StoreTypeCollection
)
605 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
607 SetLastError(E_INVALIDARG
);
610 EnterCriticalSection(&collection
->cs
);
611 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
612 WINE_STORE_LIST_ENTRY
, entry
)
614 if (store
->store
== sibling
)
616 list_remove(&store
->entry
);
617 CertCloseStore(store
->store
, 0);
622 LeaveCriticalSection(&collection
->cs
);