2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004-2006 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * - As you can see in the stubs below, support for CRLs and CTLs is missing.
21 * Mostly this should be copy-paste work, and some code (e.g. extended
22 * properties) could be shared between them.
23 * - The concept of physical stores and locations isn't implemented. (This
24 * doesn't mean registry stores et al aren't implemented. See the PSDK for
25 * registering and enumerating physical stores and locations.)
26 * - Many flags, options and whatnot are unimplemented.
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "wine/exception.h"
41 #include "crypt32_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
45 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 static const WINE_CONTEXT_INTERFACE gCertInterface
= {
48 (CreateContextFunc
)CertCreateCertificateContext
,
49 (AddContextToStoreFunc
)CertAddCertificateContextToStore
,
50 (AddEncodedContextToStoreFunc
)CertAddEncodedCertificateToStore
,
51 (DuplicateContextFunc
)CertDuplicateCertificateContext
,
52 (EnumContextsInStoreFunc
)CertEnumCertificatesInStore
,
53 (GetContextPropertyFunc
)CertGetCertificateContextProperty
,
54 (SetContextPropertyFunc
)CertSetCertificateContextProperty
,
55 (SerializeElementFunc
)CertSerializeCertificateStoreElement
,
56 (FreeContextFunc
)CertFreeCertificateContext
,
57 (DeleteContextFunc
)CertDeleteCertificateFromStore
,
59 PCWINE_CONTEXT_INTERFACE pCertInterface
= &gCertInterface
;
61 static const WINE_CONTEXT_INTERFACE gCRLInterface
= {
62 (CreateContextFunc
)CertCreateCRLContext
,
63 (AddContextToStoreFunc
)CertAddCRLContextToStore
,
64 (AddEncodedContextToStoreFunc
)CertAddEncodedCRLToStore
,
65 (DuplicateContextFunc
)CertDuplicateCRLContext
,
66 (EnumContextsInStoreFunc
)CertEnumCRLsInStore
,
67 (GetContextPropertyFunc
)CertGetCRLContextProperty
,
68 (SetContextPropertyFunc
)CertSetCRLContextProperty
,
69 (SerializeElementFunc
)CertSerializeCRLStoreElement
,
70 (FreeContextFunc
)CertFreeCRLContext
,
71 (DeleteContextFunc
)CertDeleteCRLFromStore
,
73 PCWINE_CONTEXT_INTERFACE pCRLInterface
= &gCRLInterface
;
75 static const WINE_CONTEXT_INTERFACE gCTLInterface
= {
76 (CreateContextFunc
)CertCreateCTLContext
,
77 (AddContextToStoreFunc
)CertAddCTLContextToStore
,
78 (AddEncodedContextToStoreFunc
)CertAddEncodedCTLToStore
,
79 (DuplicateContextFunc
)CertDuplicateCTLContext
,
80 (EnumContextsInStoreFunc
)CertEnumCTLsInStore
,
81 (GetContextPropertyFunc
)CertGetCTLContextProperty
,
82 (SetContextPropertyFunc
)CertSetCTLContextProperty
,
83 (SerializeElementFunc
)CertSerializeCTLStoreElement
,
84 (FreeContextFunc
)CertFreeCTLContext
,
85 (DeleteContextFunc
)CertDeleteCTLFromStore
,
87 PCWINE_CONTEXT_INTERFACE pCTLInterface
= &gCTLInterface
;
89 struct WINE_CRYPTCERTSTORE
;
91 typedef struct WINE_CRYPTCERTSTORE
* (*StoreOpenFunc
)(HCRYPTPROV hCryptProv
,
92 DWORD dwFlags
, const void *pvPara
);
94 struct _WINE_CERT_CONTEXT
;
96 /* Called to enumerate the next certificate in a store. */
97 typedef struct _WINE_CERT_CONTEXT
* (*EnumCertFunc
)
98 (struct WINE_CRYPTCERTSTORE
*store
, struct _WINE_CERT_CONTEXT
*pPrev
);
100 /* Called to add a certificate context to a store. If toReplace is not NULL,
101 * context replaces toReplace in the store, and access checks should not be
102 * performed. Otherwise context is a new context, and it should only be
103 * added if the store allows it. If ppStoreContext is not NULL, the added
104 * context should be returned in *ppStoreContext.
106 typedef BOOL (*AddCertFunc
)(struct WINE_CRYPTCERTSTORE
*store
,
107 struct _WINE_CERT_CONTEXT
*context
, struct _WINE_CERT_CONTEXT
*toReplace
,
108 PCCERT_CONTEXT
*ppStoreContext
);
110 typedef enum _CertStoreType
{
116 /* A cert store is polymorphic through the use of function pointers. A type
117 * is still needed to distinguish collection stores from other types.
118 * On the function pointers:
119 * - closeStore is called when the store's ref count becomes 0
120 * - control is optional, but should be implemented by any store that supports
123 typedef struct WINE_CRYPTCERTSTORE
128 HCRYPTPROV cryptProv
;
130 PFN_CERT_STORE_PROV_CLOSE closeStore
;
132 EnumCertFunc enumCert
;
133 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert
;
134 PFN_CERT_STORE_PROV_CONTROL control
; /* optional */
135 } WINECRYPT_CERTSTORE
, *PWINECRYPT_CERTSTORE
;
137 typedef enum _ContextType
{
142 /* A certificate context. This is the base type, and the two real types
143 * (data and link) derive from it. Each one can be cast to a PCCERT_CONTEXT.
145 typedef struct _WINE_CERT_CONTEXT
150 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
151 typedef const struct _WINE_CERT_CONTEXT
*PCWINE_CERT_CONTEXT
;
153 typedef struct _WINE_CERT_CONTEXT_DATA
157 ContextType type
; /* always ContextTypeData */
158 PCONTEXT_PROPERTY_LIST properties
;
159 } WINE_CERT_CONTEXT_DATA
, *PWINE_CERT_CONTEXT_DATA
;
160 typedef const struct _WINE_CERT_CONTEXT_DATA PCWINE_CERT_CONTEXT_DATA
;
162 typedef struct _WINE_CERT_CONTEXT_LINK
166 ContextType type
; /* always ContextTypeLink */
167 PWINE_CERT_CONTEXT linked
;
168 } WINE_CERT_CONTEXT_LINK
, *PWINE_CERT_CONTEXT_LINK
;
169 typedef const struct _WINE_CERT_CONTEXT_LINK PCWINE_CERT_CONTEXT_LINK
;
171 /* A mem store has a list of these. They're also returned by the mem store
172 * during enumeration.
174 typedef struct _WINE_CERT_LIST_ENTRY
176 WINE_CERT_CONTEXT_LINK cert
;
178 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
180 typedef struct _WINE_MEMSTORE
182 WINECRYPT_CERTSTORE hdr
;
185 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
187 typedef struct _WINE_HASH_TO_DELETE
191 } WINE_HASH_TO_DELETE
, *PWINE_HASH_TO_DELETE
;
193 typedef struct _WINE_REGSTOREINFO
196 HCRYPTPROV cryptProv
;
197 PWINECRYPT_CERTSTORE memStore
;
201 struct list certsToDelete
;
202 } WINE_REGSTOREINFO
, *PWINE_REGSTOREINFO
;
204 typedef struct _WINE_STORE_LIST_ENTRY
206 PWINECRYPT_CERTSTORE store
;
210 } WINE_STORE_LIST_ENTRY
, *PWINE_STORE_LIST_ENTRY
;
212 /* Returned by a collection store during enumeration.
213 * Note: relies on the list entry being valid after use, which a number of
214 * conditions might make untrue (reentrancy, closing a collection store before
215 * continuing an enumeration on it, ...). The tests seem to indicate this
216 * sort of unsafety is okay, since Windows isn't well-behaved in these
219 typedef struct _WINE_COLLECTION_CERT_CONTEXT
221 WINE_CERT_CONTEXT_LINK cert
;
222 PWINE_STORE_LIST_ENTRY storeEntry
;
223 } WINE_COLLECTION_CERT_CONTEXT
, *PWINE_COLLECTION_CERT_CONTEXT
;
225 typedef struct _WINE_COLLECTIONSTORE
227 WINECRYPT_CERTSTORE hdr
;
230 } WINE_COLLECTIONSTORE
, *PWINE_COLLECTIONSTORE
;
232 typedef struct _WINE_PROVIDERSTORE
234 WINECRYPT_CERTSTORE hdr
;
235 DWORD dwStoreProvFlags
;
236 PWINECRYPT_CERTSTORE memStore
;
237 HCERTSTOREPROV hStoreProv
;
238 PFN_CERT_STORE_PROV_CLOSE provCloseStore
;
239 PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert
;
240 PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert
;
241 PFN_CERT_STORE_PROV_CONTROL provControl
;
242 } WINE_PROVIDERSTORE
, *PWINE_PROVIDERSTORE
;
244 /* Internal version of CertGetCertificateContextProperty that gets properties
245 * directly from the context (or the context it's linked to, depending on its
246 * type.) Doesn't handle special-case properties, since they are handled by
247 * CertGetCertificateContextProperty, and are particular to the store in which
248 * the property exists (which is separate from the context.)
250 static BOOL WINAPI
CertContext_GetProperty(PWINE_CERT_CONTEXT context
,
251 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
);
253 /* Internal version of CertSetCertificateContextProperty that sets properties
254 * directly on the context (or the context it's linked to, depending on its
255 * type.) Doesn't handle special cases, since they're handled by
256 * CertSetCertificateContextProperty anyway.
258 static BOOL WINAPI
CertContext_SetProperty(PWINE_CERT_CONTEXT context
,
259 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
);
261 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
262 DWORD dwFlags
, CertStoreType type
)
265 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
269 hCryptProv
= CRYPT_GetDefaultProvider();
270 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
272 store
->cryptProv
= hCryptProv
;
273 store
->dwOpenFlags
= dwFlags
;
276 /* Initializes the reference ref to point to context, and increments context's
277 * reference count. Also sets the hCertStore member of the reference to store.
279 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_LINK ref
,
280 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
282 TRACE("(%p, %p)\n", ref
, context
);
283 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
285 ref
->type
= ContextTypeLink
;
286 ref
->linked
= context
;
287 InterlockedIncrement(&context
->ref
);
288 TRACE("%p's ref count is %ld\n", context
, context
->ref
);
289 ref
->cert
.hCertStore
= store
;
292 static BOOL
CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store
,
293 PWINE_CERT_CONTEXT cert
, PWINE_CERT_CONTEXT toReplace
,
294 PCCERT_CONTEXT
*ppStoreContext
)
296 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
297 PWINE_CERT_LIST_ENTRY entry
= CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY
));
300 TRACE("(%p, %p, %p, %p)\n", store
, cert
, toReplace
, ppStoreContext
);
304 PWINE_CERT_LIST_ENTRY existing
= (PWINE_CERT_LIST_ENTRY
)toReplace
;
306 TRACE("adding %p\n", entry
);
307 CRYPT_InitCertRef(&entry
->cert
, (PWINE_CERT_CONTEXT
)cert
, store
);
308 EnterCriticalSection(&ms
->cs
);
311 entry
->entry
.prev
= existing
->entry
.prev
;
312 entry
->entry
.next
= existing
->entry
.next
;
313 entry
->entry
.prev
->next
= &entry
->entry
;
314 entry
->entry
.next
->prev
= &entry
->entry
;
315 existing
->entry
.prev
= existing
->entry
.next
= &existing
->entry
;
316 CertFreeCertificateContext((PCCERT_CONTEXT
)existing
);
319 list_add_tail(&ms
->certs
, &entry
->entry
);
320 LeaveCriticalSection(&ms
->cs
);
323 CertDuplicateCertificateContext((PCCERT_CONTEXT
)entry
);
328 TRACE("returning %d\n", ret
);
332 static PWINE_CERT_CONTEXT
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
333 PWINE_CERT_CONTEXT pPrev
)
335 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
336 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
;
337 PWINE_CERT_CONTEXT ret
;
338 struct list
*listNext
;
340 TRACE("(%p, %p)\n", store
, pPrev
);
341 EnterCriticalSection(&ms
->cs
);
344 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
345 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
348 listNext
= list_next(&ms
->certs
, &ms
->certs
);
350 ret
= (PWINE_CERT_CONTEXT
)CertDuplicateCertificateContext(
351 (PCCERT_CONTEXT
)LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
));
354 SetLastError(CRYPT_E_NOT_FOUND
);
357 LeaveCriticalSection(&ms
->cs
);
359 TRACE("returning %p\n", ret
);
363 static BOOL WINAPI
CRYPT_MemDeleteCert(HCERTSTORE hCertStore
,
364 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
366 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
367 PWINE_CERT_LIST_ENTRY cert
= (PWINE_CERT_LIST_ENTRY
)pCertContext
;
370 /* The passed-in context is itself a list entry, so just remove it. */
371 EnterCriticalSection(&store
->cs
);
372 list_remove(&cert
->entry
);
373 ret
= CertFreeCertificateContext(pCertContext
);
374 LeaveCriticalSection(&store
->cs
);
378 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store
)
380 PWINE_CERT_LIST_ENTRY cert
, next
;
382 EnterCriticalSection(&store
->cs
);
383 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
386 TRACE("removing %p\n", cert
);
387 list_remove(&cert
->entry
);
388 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
390 LeaveCriticalSection(&store
->cs
);
393 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
395 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
397 TRACE("(%p, %08lx)\n", store
, dwFlags
);
399 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
401 CRYPT_MemEmptyStore(store
);
402 DeleteCriticalSection(&store
->cs
);
406 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
407 DWORD dwFlags
, const void *pvPara
)
409 PWINE_MEMSTORE store
;
411 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
413 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
415 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
420 store
= CryptMemAlloc(sizeof(WINE_MEMSTORE
));
423 memset(store
, 0, sizeof(WINE_MEMSTORE
));
424 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
425 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
426 store
->hdr
.addCert
= CRYPT_MemAddCert
;
427 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
428 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
429 store
->hdr
.control
= NULL
;
430 InitializeCriticalSection(&store
->cs
);
431 list_init(&store
->certs
);
434 return (PWINECRYPT_CERTSTORE
)store
;
437 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionCreateContextFromChild(
438 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
439 PWINE_CERT_CONTEXT child
)
441 PWINE_COLLECTION_CERT_CONTEXT ret
=
442 CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT
));
446 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK
)ret
, child
, store
);
447 /* The child has already been addref'd, and CRYPT_InitCertRef does
448 * again, so free child once to get the ref count right. (Not doing so
449 * will leak memory if the caller calls CertFreeCertificateContext
450 * rather than CertEnumCertificatesInStore.)
452 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
453 ret
->storeEntry
= storeEntry
;
456 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
460 static BOOL
CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store
,
461 PWINE_CERT_CONTEXT cert
, PWINE_CERT_CONTEXT toReplace
,
462 PCCERT_CONTEXT
*ppStoreContext
)
465 PCCERT_CONTEXT childContext
= NULL
;
466 PWINE_STORE_LIST_ENTRY storeEntry
= NULL
;
468 TRACE("(%p, %p, %p, %p)\n", store
, cert
, toReplace
, ppStoreContext
);
473 PWINE_COLLECTION_CERT_CONTEXT existing
=
474 (PWINE_COLLECTION_CERT_CONTEXT
)toReplace
;
476 storeEntry
= existing
->storeEntry
;
477 ret
= storeEntry
->store
->addCert(storeEntry
->store
, cert
,
478 existing
->cert
.linked
, &childContext
);
482 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
483 PWINE_STORE_LIST_ENTRY entry
, next
;
485 EnterCriticalSection(&cs
->cs
);
486 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
,
487 WINE_STORE_LIST_ENTRY
, entry
)
489 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
492 ret
= entry
->store
->addCert(entry
->store
, cert
, NULL
,
497 LeaveCriticalSection(&cs
->cs
);
499 SetLastError(E_ACCESSDENIED
);
501 if (ppStoreContext
&& childContext
)
504 (PCCERT_CONTEXT
)CRYPT_CollectionCreateContextFromChild(
505 (PWINE_COLLECTIONSTORE
)store
, storeEntry
,
506 (PWINE_CERT_CONTEXT
)childContext
);
508 CertFreeCertificateContext(childContext
);
512 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
514 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
515 PWINE_STORE_LIST_ENTRY entry
, next
;
517 TRACE("(%p, %08lx)\n", store
, dwFlags
);
519 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
522 TRACE("closing %p\n", entry
);
523 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
526 DeleteCriticalSection(&cs
->cs
);
530 /* Advances a collection enumeration by one cert, if possible, where advancing
532 * - calling the current store's enumeration function once, and returning
533 * the enumerated cert if one is returned
534 * - moving to the next store if the current store has no more items, and
535 * recursively calling itself to get the next item.
536 * Returns NULL if the collection contains no more items or on error.
537 * Assumes the collection store's lock is held.
539 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
540 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
541 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
543 PWINE_COLLECTION_CERT_CONTEXT ret
;
544 PWINE_CERT_CONTEXT child
;
545 struct list
*storeNext
= list_next(&store
->stores
, &storeEntry
->entry
);
547 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
551 /* Ref-counting funny business: "duplicate" (addref) the child, because
552 * the CertFreeCertificateContext(pPrev) below can cause the ref count
553 * to become negative. See comment in
554 * CRYPT_CollectionCreateContextFromChild as well.
556 child
= ((PWINE_COLLECTION_CERT_CONTEXT
)pPrev
)->cert
.linked
;
557 CertDuplicateCertificateContext((PCCERT_CONTEXT
)child
);
558 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
560 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
564 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
567 ret
= CRYPT_CollectionCreateContextFromChild(store
, storeEntry
, child
);
572 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
573 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
577 SetLastError(CRYPT_E_NOT_FOUND
);
581 TRACE("returning %p\n", ret
);
585 static PWINE_CERT_CONTEXT
CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store
,
586 PWINE_CERT_CONTEXT pPrev
)
588 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
589 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
590 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
592 TRACE("(%p, %p)\n", store
, pPrev
);
596 EnterCriticalSection(&cs
->cs
);
597 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->storeEntry
, prevEntry
);
598 LeaveCriticalSection(&cs
->cs
);
602 EnterCriticalSection(&cs
->cs
);
603 if (!list_empty(&cs
->stores
))
605 PWINE_STORE_LIST_ENTRY storeEntry
;
607 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
609 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, NULL
);
613 SetLastError(CRYPT_E_NOT_FOUND
);
616 LeaveCriticalSection(&cs
->cs
);
618 TRACE("returning %p\n", ret
);
619 return (PWINE_CERT_CONTEXT
)ret
;
622 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
623 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
625 PWINE_COLLECTION_CERT_CONTEXT context
=
626 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
629 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
631 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->cert
.linked
);
635 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
636 DWORD dwFlags
, const void *pvPara
)
638 PWINE_COLLECTIONSTORE store
;
640 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
642 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
647 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
650 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
651 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
652 StoreTypeCollection
);
653 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
654 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
655 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
656 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
657 InitializeCriticalSection(&store
->cs
);
658 list_init(&store
->stores
);
661 return (PWINECRYPT_CERTSTORE
)store
;
664 static void WINAPI
CRYPT_ProvCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
666 PWINE_PROVIDERSTORE store
= (PWINE_PROVIDERSTORE
)hCertStore
;
668 TRACE("(%p, %08lx)\n", store
, dwFlags
);
670 if (store
->provCloseStore
)
671 store
->provCloseStore(store
->hStoreProv
, dwFlags
);
672 if (!(store
->dwStoreProvFlags
& CERT_STORE_PROV_EXTERNAL_FLAG
))
673 CertCloseStore(store
->memStore
, dwFlags
);
677 static BOOL
CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store
,
678 PWINE_CERT_CONTEXT cert
, PWINE_CERT_CONTEXT toReplace
,
679 PCCERT_CONTEXT
*ppStoreContext
)
681 PWINE_PROVIDERSTORE ps
= (PWINE_PROVIDERSTORE
)store
;
684 TRACE("(%p, %p, %p, %p)\n", store
, cert
, toReplace
, ppStoreContext
);
687 ret
= ps
->memStore
->addCert(ps
->memStore
, cert
, toReplace
,
691 if (ps
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
693 SetLastError(ERROR_ACCESS_DENIED
);
699 if (ps
->provWriteCert
)
700 ret
= ps
->provWriteCert(ps
->hStoreProv
, (PCCERT_CONTEXT
)cert
,
701 CERT_STORE_PROV_WRITE_ADD_FLAG
);
703 ret
= ps
->memStore
->addCert(ps
->memStore
, cert
, NULL
,
707 /* dirty trick: replace the returned context's hCertStore with
711 (*(PCERT_CONTEXT
*)ppStoreContext
)->hCertStore
= store
;
715 static PWINE_CERT_CONTEXT
CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store
,
716 PWINE_CERT_CONTEXT pPrev
)
718 PWINE_PROVIDERSTORE ps
= (PWINE_PROVIDERSTORE
)store
;
719 PWINE_CERT_CONTEXT ret
;
721 ret
= ps
->memStore
->enumCert(ps
->memStore
, pPrev
);
724 /* same dirty trick: replace the returned context's hCertStore with
727 ret
->cert
.hCertStore
= store
;
732 static BOOL WINAPI
CRYPT_ProvDeleteCert(HCERTSTORE hCertStore
,
733 PCCERT_CONTEXT cert
, DWORD dwFlags
)
735 PWINE_PROVIDERSTORE store
= (PWINE_PROVIDERSTORE
)hCertStore
;
738 TRACE("(%p, %p, %08lx)\n", hCertStore
, cert
, dwFlags
);
740 if (store
->provDeleteCert
)
741 ret
= store
->provDeleteCert(store
->hStoreProv
, cert
, dwFlags
);
743 ret
= store
->memStore
->deleteCert(store
->memStore
, cert
, dwFlags
);
747 static BOOL WINAPI
CRYPT_ProvControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
748 DWORD dwCtrlType
, void const *pvCtrlPara
)
750 PWINE_PROVIDERSTORE store
= (PWINE_PROVIDERSTORE
)hCertStore
;
753 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
756 if (store
->provControl
)
757 ret
= store
->provControl(store
->hStoreProv
, dwFlags
, dwCtrlType
,
762 static PWINECRYPT_CERTSTORE
CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv
,
763 DWORD dwFlags
, PWINECRYPT_CERTSTORE memStore
, PCERT_STORE_PROV_INFO pProvInfo
)
765 PWINE_PROVIDERSTORE ret
= (PWINE_PROVIDERSTORE
)CryptMemAlloc(
766 sizeof(WINE_PROVIDERSTORE
));
770 CRYPT_InitStore(&ret
->hdr
, hCryptProv
, dwFlags
,
772 ret
->dwStoreProvFlags
= pProvInfo
->dwStoreProvFlags
;
773 if (ret
->dwStoreProvFlags
& CERT_STORE_PROV_EXTERNAL_FLAG
)
775 CertCloseStore(memStore
, 0);
776 ret
->memStore
= NULL
;
779 ret
->memStore
= memStore
;
780 ret
->hStoreProv
= pProvInfo
->hStoreProv
;
781 ret
->hdr
.closeStore
= CRYPT_ProvCloseStore
;
782 ret
->hdr
.addCert
= CRYPT_ProvAddCert
;
783 ret
->hdr
.enumCert
= CRYPT_ProvEnumCert
;
784 ret
->hdr
.deleteCert
= CRYPT_ProvDeleteCert
;
785 ret
->hdr
.control
= CRYPT_ProvControl
;
786 if (pProvInfo
->cStoreProvFunc
> CERT_STORE_PROV_CLOSE_FUNC
)
787 ret
->provCloseStore
=
788 pProvInfo
->rgpvStoreProvFunc
[CERT_STORE_PROV_CLOSE_FUNC
];
790 ret
->provCloseStore
= NULL
;
791 if (pProvInfo
->cStoreProvFunc
>
792 CERT_STORE_PROV_WRITE_CERT_FUNC
)
793 ret
->provWriteCert
= pProvInfo
->rgpvStoreProvFunc
[
794 CERT_STORE_PROV_WRITE_CERT_FUNC
];
796 ret
->provWriteCert
= NULL
;
797 if (pProvInfo
->cStoreProvFunc
>
798 CERT_STORE_PROV_DELETE_CERT_FUNC
)
799 ret
->provDeleteCert
= pProvInfo
->rgpvStoreProvFunc
[
800 CERT_STORE_PROV_DELETE_CERT_FUNC
];
802 ret
->provDeleteCert
= NULL
;
803 if (pProvInfo
->cStoreProvFunc
>
804 CERT_STORE_PROV_CONTROL_FUNC
)
805 ret
->provControl
= pProvInfo
->rgpvStoreProvFunc
[
806 CERT_STORE_PROV_CONTROL_FUNC
];
808 ret
->provControl
= NULL
;
810 return (PWINECRYPT_CERTSTORE
)ret
;
813 static PWINECRYPT_CERTSTORE
CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider
,
814 DWORD dwEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
, const void *pvPara
)
816 static HCRYPTOIDFUNCSET set
= NULL
;
817 PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc
;
818 HCRYPTOIDFUNCADDR hFunc
;
819 PWINECRYPT_CERTSTORE ret
= NULL
;
822 set
= CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC
, 0);
823 CryptGetOIDFunctionAddress(set
, dwEncodingType
, lpszStoreProvider
, 0,
824 (void **)&provOpenFunc
, &hFunc
);
827 CERT_STORE_PROV_INFO provInfo
= { 0 };
829 provInfo
.cbSize
= sizeof(provInfo
);
830 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
831 provOpenFunc(lpszStoreProvider
, dwEncodingType
, hCryptProv
,
832 dwFlags
, pvPara
, NULL
, &provInfo
);
837 memStore
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
838 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
841 if (provOpenFunc(lpszStoreProvider
, dwEncodingType
, hCryptProv
,
842 dwFlags
, pvPara
, memStore
, &provInfo
))
843 ret
= CRYPT_ProvCreateStore(hCryptProv
, dwFlags
, memStore
,
846 CertCloseStore(memStore
, 0);
849 CryptFreeOIDFunctionAddress(hFunc
, 0);
852 SetLastError(ERROR_FILE_NOT_FOUND
);
856 static void CRYPT_HashToStr(LPBYTE hash
, LPWSTR asciiHash
)
858 static const WCHAR fmt
[] = { '%','0','2','X',0 };
864 for (i
= 0; i
< 20; i
++)
865 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
868 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
870 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
871 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
872 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
874 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store
, HKEY key
,
879 WCHAR subKeyName
[MAX_PATH
];
882 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
884 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
890 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
896 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
898 buf
= CryptMemAlloc(size
);
901 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
908 TRACE("Adding cert with hash %s\n",
909 debugstr_w(subKeyName
));
910 context
= CRYPT_ReadSerializedElement(buf
, size
,
911 contextType
, &addedType
);
914 const WINE_CONTEXT_INTERFACE
*contextInterface
;
919 case CERT_STORE_CERTIFICATE_CONTEXT
:
920 contextInterface
= &gCertInterface
;
922 case CERT_STORE_CRL_CONTEXT
:
923 contextInterface
= &gCRLInterface
;
925 case CERT_STORE_CTL_CONTEXT
:
926 contextInterface
= &gCTLInterface
;
929 contextInterface
= NULL
;
931 if (contextInterface
)
934 if (contextInterface
->getProp(context
,
935 CERT_HASH_PROP_ID
, hash
, &size
))
937 WCHAR asciiHash
[20 * 2 + 1];
939 CRYPT_HashToStr(hash
, asciiHash
);
940 TRACE("comparing %s\n",
941 debugstr_w(asciiHash
));
942 TRACE("with %s\n", debugstr_w(subKeyName
));
943 if (!lstrcmpW(asciiHash
, subKeyName
))
945 TRACE("hash matches, adding\n");
946 contextInterface
->addContextToStore(
947 store
->memStore
, context
,
948 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
951 TRACE("hash doesn't match, ignoring\n");
953 contextInterface
->free(context
);
961 /* Ignore intermediate errors, continue enumerating */
967 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store
)
969 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
970 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
971 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
974 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
979 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
983 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
989 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
990 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, LPBYTE hash
, LPBYTE buf
,
993 WCHAR asciiHash
[20 * 2 + 1];
998 CRYPT_HashToStr(hash
, asciiHash
);
999 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
1003 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
1004 RegCloseKey(subKey
);
1016 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
1017 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
1019 const void *context
= NULL
;
1023 context
= contextInterface
->enumContextsInStore(memStore
, context
);
1027 DWORD hashSize
= sizeof(hash
);
1029 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
1036 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
1038 buf
= CryptMemAlloc(size
);
1041 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
1043 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
1050 } while (ret
&& context
!= NULL
);
1052 contextInterface
->free(context
);
1056 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store
)
1058 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
1059 static const WINE_CONTEXT_INTERFACE
*interfaces
[] = { &gCertInterface
,
1060 &gCRLInterface
, &gCTLInterface
};
1061 struct list
*listToDelete
[] = { &store
->certsToDelete
, NULL
, NULL
};
1065 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1068 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1069 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1073 if (listToDelete
[i
])
1075 PWINE_HASH_TO_DELETE toDelete
, next
;
1076 WCHAR asciiHash
[20 * 2 + 1];
1078 EnterCriticalSection(&store
->cs
);
1079 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
1080 WINE_HASH_TO_DELETE
, entry
)
1084 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
1085 TRACE("Removing %s\n", debugstr_w(asciiHash
));
1086 rc
= RegDeleteKeyW(key
, asciiHash
);
1087 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
1092 list_remove(&toDelete
->entry
);
1093 CryptMemFree(toDelete
);
1095 LeaveCriticalSection(&store
->cs
);
1097 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
1110 /* If force is true or the registry store is dirty, writes the contents of the
1111 * store to the registry.
1113 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTOREINFO store
, BOOL force
)
1117 TRACE("(%p, %d)\n", store
, force
);
1119 if (store
->dirty
|| force
)
1120 ret
= CRYPT_RegWriteToReg(store
);
1126 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1128 PWINE_REGSTOREINFO store
= (PWINE_REGSTOREINFO
)hCertStore
;
1130 TRACE("(%p, %08lx)\n", store
, dwFlags
);
1132 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
1134 CRYPT_RegFlushStore(store
, FALSE
);
1135 RegCloseKey(store
->key
);
1136 DeleteCriticalSection(&store
->cs
);
1137 CryptMemFree(store
);
1140 static BOOL WINAPI
CRYPT_RegWriteCert(HCERTSTORE hCertStore
,
1141 PCCERT_CONTEXT cert
, DWORD dwFlags
)
1143 PWINE_REGSTOREINFO store
= (PWINE_REGSTOREINFO
)hCertStore
;
1146 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwFlags
);
1148 if (dwFlags
& CERT_STORE_PROV_WRITE_ADD_FLAG
)
1150 store
->dirty
= TRUE
;
1158 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
1159 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
1161 PWINE_REGSTOREINFO store
= (PWINE_REGSTOREINFO
)hCertStore
;
1164 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1166 if (store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1168 SetLastError(ERROR_ACCESS_DENIED
);
1173 PWINE_HASH_TO_DELETE toDelete
=
1174 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
1178 DWORD size
= sizeof(toDelete
->hash
);
1180 ret
= CertGetCertificateContextProperty(pCertContext
,
1181 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
1184 EnterCriticalSection(&store
->cs
);
1185 list_add_tail(&store
->certsToDelete
, &toDelete
->entry
);
1186 LeaveCriticalSection(&store
->cs
);
1190 CryptMemFree(toDelete
);
1197 store
->dirty
= TRUE
;
1202 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
1203 DWORD dwCtrlType
, void const *pvCtrlPara
)
1205 PWINE_REGSTOREINFO store
= (PWINE_REGSTOREINFO
)hCertStore
;
1208 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
1213 case CERT_STORE_CTRL_RESYNC
:
1214 CRYPT_RegFlushStore(store
, FALSE
);
1215 CRYPT_MemEmptyStore((PWINE_MEMSTORE
)store
->memStore
);
1216 CRYPT_RegReadFromReg(store
);
1219 case CERT_STORE_CTRL_COMMIT
:
1220 ret
= CRYPT_RegFlushStore(store
,
1221 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1224 FIXME("%ld: stub\n", dwCtrlType
);
1230 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1231 static DWORD
CRYPT_RecurseDeleteKey(HKEY hKey
, LPCWSTR lpszSubKey
)
1233 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1234 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1237 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1239 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1242 /* Find how many subkeys there are */
1243 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1244 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1248 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1250 /* Name too big: alloc a buffer for it */
1251 lpszName
= CryptMemAlloc(dwMaxSubkeyLen
*sizeof(WCHAR
));
1255 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1258 /* Recursively delete all the subkeys */
1259 for (i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1261 dwSize
= dwMaxSubkeyLen
;
1262 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
,
1265 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1268 if (lpszName
!= szNameBuf
)
1270 /* Free buffer if allocated */
1271 CryptMemFree(lpszName
);
1276 RegCloseKey(hSubKey
);
1278 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1283 static void *regProvFuncs
[] = {
1284 CRYPT_RegCloseStore
,
1285 NULL
, /* CERT_STORE_PROV_READ_CERT_FUNC */
1287 CRYPT_RegDeleteCert
,
1288 NULL
, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1289 NULL
, /* CERT_STORE_PROV_READ_CRL_FUNC */
1290 NULL
, /* CERT_STORE_PROV_WRITE_CRL_FUNC */
1291 NULL
, /* CERT_STORE_PROV_DELETE_CRL_FUNC */
1292 NULL
, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1293 NULL
, /* CERT_STORE_PROV_READ_CTL_FUNC */
1294 NULL
, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1295 NULL
, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1296 NULL
, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1300 static WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
,
1301 DWORD dwFlags
, const void *pvPara
)
1303 PWINECRYPT_CERTSTORE store
= NULL
;
1305 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
1307 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
1309 DWORD rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CertsW
);
1311 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1312 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CRLsW
);
1313 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1314 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CTLsW
);
1315 if (rc
== ERROR_NO_MORE_ITEMS
)
1323 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1324 GetCurrentProcess(), (LPHANDLE
)&key
,
1325 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1328 PWINECRYPT_CERTSTORE memStore
;
1330 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1333 PWINE_REGSTOREINFO regInfo
= CryptMemAlloc(
1334 sizeof(WINE_REGSTOREINFO
));
1338 CERT_STORE_PROV_INFO provInfo
= { 0 };
1340 regInfo
->dwOpenFlags
= dwFlags
;
1341 regInfo
->cryptProv
= hCryptProv
;
1342 regInfo
->memStore
= memStore
;
1344 InitializeCriticalSection(®Info
->cs
);
1345 list_init(®Info
->certsToDelete
);
1346 CRYPT_RegReadFromReg(regInfo
);
1347 regInfo
->dirty
= FALSE
;
1348 provInfo
.cbSize
= sizeof(provInfo
);
1349 provInfo
.cStoreProvFunc
= sizeof(regProvFuncs
) /
1350 sizeof(regProvFuncs
[0]);
1351 provInfo
.rgpvStoreProvFunc
= regProvFuncs
;
1352 provInfo
.hStoreProv
= regInfo
;
1353 store
= CRYPT_ProvCreateStore(hCryptProv
, dwFlags
, memStore
,
1359 TRACE("returning %p\n", store
);
1363 /* FIXME: this isn't complete for the Root store, in which the top-level
1364 * self-signed CA certs reside. Adding a cert to the Root store should present
1365 * the user with a dialog indicating the consequences of doing so, and asking
1366 * the user to confirm whether the cert should be added.
1368 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv
,
1369 DWORD dwFlags
, const void *pvPara
)
1371 static const WCHAR fmt
[] = { '%','s','\\','%','s',0 };
1372 LPCWSTR storeName
= (LPCWSTR
)pvPara
;
1374 PWINECRYPT_CERTSTORE store
= NULL
;
1379 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1380 debugstr_w((LPCWSTR
)pvPara
));
1384 SetLastError(E_INVALIDARG
);
1389 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1391 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1392 root
= HKEY_LOCAL_MACHINE
;
1393 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1395 case CERT_SYSTEM_STORE_CURRENT_USER
:
1396 root
= HKEY_CURRENT_USER
;
1397 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1399 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1400 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1401 * SystemCertificates
1403 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1404 debugstr_w(storeName
));
1406 case CERT_SYSTEM_STORE_SERVICES
:
1407 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1408 * SystemCertificates
1410 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1411 debugstr_w(storeName
));
1413 case CERT_SYSTEM_STORE_USERS
:
1414 /* hku\user sid\Software\Microsoft\SystemCertificates */
1415 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1416 debugstr_w(storeName
));
1418 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1419 root
= HKEY_CURRENT_USER
;
1420 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1423 root
= HKEY_LOCAL_MACHINE
;
1424 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1426 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1427 /* hklm\Software\Microsoft\EnterpriseCertificates */
1428 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1429 debugstr_w(storeName
));
1432 SetLastError(E_INVALIDARG
);
1436 storePath
= CryptMemAlloc((lstrlenW(base
) + lstrlenW(storeName
) + 2) *
1442 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1445 wsprintfW(storePath
, fmt
, base
, storeName
);
1446 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1447 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1452 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1454 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1455 disp
== REG_OPENED_EXISTING_KEY
)
1458 rc
= ERROR_FILE_EXISTS
;
1463 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1468 CryptMemFree(storePath
);
1473 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1474 DWORD dwFlags
, const void *pvPara
)
1477 PWINECRYPT_CERTSTORE ret
= NULL
;
1479 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1480 debugstr_a((LPCSTR
)pvPara
));
1484 SetLastError(ERROR_FILE_NOT_FOUND
);
1487 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1490 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1494 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1495 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1496 CryptMemFree(storeName
);
1502 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1503 DWORD dwFlags
, const void *pvPara
)
1505 HCERTSTORE store
= 0;
1508 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1509 debugstr_w((LPCWSTR
)pvPara
));
1513 SetLastError(ERROR_FILE_NOT_FOUND
);
1516 /* This returns a different error than system registry stores if the
1517 * location is invalid.
1519 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1521 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1522 case CERT_SYSTEM_STORE_CURRENT_USER
:
1523 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1524 case CERT_SYSTEM_STORE_SERVICES
:
1525 case CERT_SYSTEM_STORE_USERS
:
1526 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1527 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1528 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1532 SetLastError(ERROR_FILE_NOT_FOUND
);
1537 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1538 0, hCryptProv
, dwFlags
, pvPara
);
1542 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1543 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1544 CertAddStoreToCollection(store
, regStore
,
1545 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1546 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1547 CertCloseStore(regStore
, 0);
1548 /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1551 if ((dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
) ==
1552 CERT_SYSTEM_STORE_CURRENT_USER
)
1554 dwFlags
&= ~CERT_SYSTEM_STORE_CURRENT_USER
;
1555 dwFlags
|= CERT_SYSTEM_STORE_LOCAL_MACHINE
;
1556 regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
, 0,
1557 hCryptProv
, dwFlags
, pvPara
);
1560 CertAddStoreToCollection(store
, regStore
,
1561 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1562 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1563 CertCloseStore(regStore
, 0);
1568 return (PWINECRYPT_CERTSTORE
)store
;
1571 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv
,
1572 DWORD dwFlags
, const void *pvPara
)
1575 PWINECRYPT_CERTSTORE ret
= NULL
;
1577 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1578 debugstr_a((LPCSTR
)pvPara
));
1582 SetLastError(ERROR_FILE_NOT_FOUND
);
1585 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1588 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1592 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1593 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1594 CryptMemFree(storeName
);
1600 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1601 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
1604 WINECRYPT_CERTSTORE
*hcs
;
1605 StoreOpenFunc openFunc
= NULL
;
1607 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
1608 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
1610 if (!HIWORD(lpszStoreProvider
))
1612 switch (LOWORD(lpszStoreProvider
))
1614 case (int)CERT_STORE_PROV_MEMORY
:
1615 openFunc
= CRYPT_MemOpenStore
;
1617 case (int)CERT_STORE_PROV_REG
:
1618 openFunc
= CRYPT_RegOpenStore
;
1620 case (int)CERT_STORE_PROV_COLLECTION
:
1621 openFunc
= CRYPT_CollectionOpenStore
;
1623 case (int)CERT_STORE_PROV_SYSTEM_A
:
1624 openFunc
= CRYPT_SysOpenStoreA
;
1626 case (int)CERT_STORE_PROV_SYSTEM_W
:
1627 openFunc
= CRYPT_SysOpenStoreW
;
1629 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1630 openFunc
= CRYPT_SysRegOpenStoreA
;
1632 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1633 openFunc
= CRYPT_SysRegOpenStoreW
;
1636 if (LOWORD(lpszStoreProvider
))
1637 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
1640 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
1641 openFunc
= CRYPT_MemOpenStore
;
1642 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
1643 openFunc
= CRYPT_SysOpenStoreW
;
1644 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
1645 openFunc
= CRYPT_CollectionOpenStore
;
1646 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM_REGISTRY
))
1647 openFunc
= CRYPT_SysRegOpenStoreW
;
1650 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1655 hcs
= CRYPT_ProvOpenStore(lpszStoreProvider
, dwMsgAndCertEncodingType
,
1656 hCryptProv
, dwFlags
, pvPara
);
1658 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1659 return (HCERTSTORE
)hcs
;
1662 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1663 LPCSTR szSubSystemProtocol
)
1665 if (!szSubSystemProtocol
)
1667 SetLastError(E_INVALIDARG
);
1670 return CertOpenStore(CERT_STORE_PROV_SYSTEM_A
, 0, hProv
,
1671 CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1674 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1675 LPCWSTR szSubSystemProtocol
)
1677 if (!szSubSystemProtocol
)
1679 SetLastError(E_INVALIDARG
);
1682 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W
, 0, hProv
,
1683 CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1686 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
1687 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
1689 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
1690 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
1694 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1695 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
1700 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
1702 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1703 pcrl
= CryptMemAlloc( sizeof (CRL_CONTEXT
) );
1707 data
= CryptMemAlloc( cbCrlEncoded
);
1710 CryptMemFree( pcrl
);
1714 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1715 pcrl
->pbCrlEncoded
= data
;
1716 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1717 pcrl
->pCrlInfo
= NULL
;
1718 pcrl
->hCertStore
= 0;
1723 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
1724 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1726 PWINE_CERT_CONTEXT_DATA cert
= NULL
;
1728 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1729 PCERT_INFO certInfo
= NULL
;
1732 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1735 /* First try to decode it as a signed cert. */
1736 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
, pbCertEncoded
,
1737 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, (BYTE
*)&signedCert
, &size
);
1741 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
1742 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
1743 CRYPT_DECODE_ALLOC_FLAG
, NULL
, (BYTE
*)&certInfo
, &size
);
1744 LocalFree(signedCert
);
1746 /* Failing that, try it as an unsigned cert */
1750 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
1751 pbCertEncoded
, cbCertEncoded
,
1752 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1753 (BYTE
*)&certInfo
, &size
);
1759 cert
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_DATA
));
1762 data
= CryptMemAlloc(cbCertEncoded
);
1769 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
1770 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
1771 cert
->cert
.pbCertEncoded
= data
;
1772 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
1773 cert
->cert
.pCertInfo
= certInfo
;
1774 cert
->cert
.hCertStore
= 0;
1776 cert
->type
= ContextTypeData
;
1777 cert
->properties
= ContextPropertyList_Create();
1781 return (PCCERT_CONTEXT
)cert
;
1784 /* If context is a link, follows it to its linked context (recursively, if
1785 * necessary) and returns the data context associated with the link.
1786 * Otherwise just returns context.
1788 static inline PWINE_CERT_CONTEXT_DATA
CertContext_GetDataContext(
1789 PWINE_CERT_CONTEXT context
)
1791 PWINE_CERT_CONTEXT ptr
= context
;
1793 while (ptr
&& ptr
->type
== ContextTypeLink
)
1794 ptr
= ((PWINE_CERT_CONTEXT_LINK
)ptr
)->linked
;
1795 return (ptr
&& ptr
->type
== ContextTypeData
) ?
1796 (PWINE_CERT_CONTEXT_DATA
)ptr
: NULL
;
1799 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
1802 PWINE_CERT_CONTEXT_DATA linked
= CertContext_GetDataContext(
1803 (PWINE_CERT_CONTEXT
)pCertContext
);
1806 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1809 ret
= ContextPropertyList_EnumPropIDs(linked
->properties
, dwPropId
);
1815 static BOOL
CertContext_GetHashProp(PWINE_CERT_CONTEXT context
, DWORD dwPropId
,
1816 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
1819 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
1823 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1825 ret
= CertContext_SetProperty(context
, dwPropId
, 0, &blob
);
1830 static BOOL WINAPI
CertContext_GetProperty(PWINE_CERT_CONTEXT context
,
1831 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1833 PWINE_CERT_CONTEXT_DATA linked
= CertContext_GetDataContext(context
);
1835 CRYPT_DATA_BLOB blob
;
1837 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1840 ret
= ContextPropertyList_FindProperty(linked
->properties
, dwPropId
,
1848 *pcbData
= blob
.cbData
;
1851 else if (*pcbData
< blob
.cbData
)
1853 SetLastError(ERROR_MORE_DATA
);
1854 *pcbData
= blob
.cbData
;
1858 memcpy(pvData
, blob
.pbData
, blob
.cbData
);
1859 *pcbData
= blob
.cbData
;
1865 /* Implicit properties */
1868 case CERT_SHA1_HASH_PROP_ID
:
1869 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_SHA1
,
1870 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1873 case CERT_MD5_HASH_PROP_ID
:
1874 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
1875 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1878 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1879 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
1880 context
->cert
.pCertInfo
->Subject
.pbData
,
1881 context
->cert
.pCertInfo
->Subject
.cbData
,
1884 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1885 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
1886 context
->cert
.pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
1887 context
->cert
.pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
,
1890 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1891 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
1892 context
->cert
.pCertInfo
->SerialNumber
.pbData
,
1893 context
->cert
.pCertInfo
->SerialNumber
.cbData
,
1896 case CERT_SIGNATURE_HASH_PROP_ID
:
1897 FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
1898 SetLastError(CRYPT_E_NOT_FOUND
);
1901 SetLastError(CRYPT_E_NOT_FOUND
);
1904 TRACE("returning %d\n", ret
);
1908 /* info is assumed to be a CRYPT_KEY_PROV_INFO, followed by its container name,
1909 * provider name, and any provider parameters, in a contiguous buffer, but
1910 * where info's pointers are assumed to be invalid. Upon return, info's
1911 * pointers point to the appropriate memory locations.
1913 static void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info
)
1915 DWORD i
, containerLen
, provNameLen
;
1916 LPBYTE data
= (LPBYTE
)info
+ sizeof(CRYPT_KEY_PROV_INFO
);
1918 info
->pwszContainerName
= (LPWSTR
)data
;
1919 containerLen
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
1920 data
+= containerLen
;
1922 info
->pwszProvName
= (LPWSTR
)data
;
1923 provNameLen
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
1924 data
+= provNameLen
;
1926 info
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)data
;
1927 data
+= info
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
1929 for (i
= 0; i
< info
->cProvParam
; i
++)
1931 info
->rgProvParam
[i
].pbData
= data
;
1932 data
+= info
->rgProvParam
[i
].cbData
;
1936 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1937 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1941 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1946 case CERT_CERT_PROP_ID
:
1947 case CERT_CRL_PROP_ID
:
1948 case CERT_CTL_PROP_ID
:
1949 SetLastError(E_INVALIDARG
);
1952 case CERT_ACCESS_STATE_PROP_ID
:
1955 *pcbData
= sizeof(DWORD
);
1958 else if (*pcbData
< sizeof(DWORD
))
1960 SetLastError(ERROR_MORE_DATA
);
1961 *pcbData
= sizeof(DWORD
);
1968 if (pCertContext
->hCertStore
)
1970 PWINECRYPT_CERTSTORE store
=
1971 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
1973 if (!(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
1974 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
1976 *(DWORD
*)pvData
= state
;
1980 case CERT_KEY_PROV_INFO_PROP_ID
:
1981 ret
= CertContext_GetProperty((PWINE_CERT_CONTEXT
)pCertContext
,
1982 dwPropId
, pvData
, pcbData
);
1984 CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO
)pvData
);
1987 ret
= CertContext_GetProperty((PWINE_CERT_CONTEXT
)pCertContext
,
1988 dwPropId
, pvData
, pcbData
);
1991 TRACE("returning %d\n", ret
);
1995 /* Copies key provider info from from into to, where to is assumed to be a
1996 * contiguous buffer of memory large enough for from and all its associated
1997 * data, but whose pointers are uninitialized.
1998 * Upon return, to contains a contiguous copy of from, packed in the following
2000 * - CRYPT_KEY_PROV_INFO
2001 * - pwszContainerName
2003 * - rgProvParam[0]...
2005 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to
,
2006 PCRYPT_KEY_PROV_INFO from
)
2009 LPBYTE nextData
= (LPBYTE
)to
+ sizeof(CRYPT_KEY_PROV_INFO
);
2011 to
->pwszContainerName
= (LPWSTR
)nextData
;
2012 lstrcpyW(to
->pwszContainerName
, from
->pwszContainerName
);
2013 nextData
+= (lstrlenW(from
->pwszContainerName
) + 1) * sizeof(WCHAR
);
2014 to
->pwszProvName
= (LPWSTR
)nextData
;
2015 lstrcpyW(to
->pwszProvName
, from
->pwszProvName
);
2016 nextData
+= (lstrlenW(from
->pwszProvName
) + 1) * sizeof(WCHAR
);
2017 to
->dwProvType
= from
->dwProvType
;
2018 to
->dwFlags
= from
->dwFlags
;
2019 to
->cProvParam
= from
->cProvParam
;
2020 to
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)nextData
;
2021 nextData
+= to
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
2022 to
->dwKeySpec
= from
->dwKeySpec
;
2023 for (i
= 0; i
< to
->cProvParam
; i
++)
2025 memcpy(&to
->rgProvParam
[i
], &from
->rgProvParam
[i
],
2026 sizeof(CRYPT_KEY_PROV_PARAM
));
2027 to
->rgProvParam
[i
].pbData
= nextData
;
2028 memcpy(to
->rgProvParam
[i
].pbData
, from
->rgProvParam
[i
].pbData
,
2029 from
->rgProvParam
[i
].cbData
);
2030 nextData
+= from
->rgProvParam
[i
].cbData
;
2034 static BOOL
CertContext_SetKeyProvInfoProperty(PWINE_CERT_CONTEXT_DATA linked
,
2035 PCRYPT_KEY_PROV_INFO info
)
2039 DWORD size
= sizeof(CRYPT_KEY_PROV_INFO
), i
, containerSize
, provNameSize
;
2041 containerSize
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
2042 provNameSize
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
2043 size
+= containerSize
+ provNameSize
;
2044 for (i
= 0; i
< info
->cProvParam
; i
++)
2045 size
+= sizeof(CRYPT_KEY_PROV_PARAM
) + info
->rgProvParam
[i
].cbData
;
2046 buf
= CryptMemAlloc(size
);
2049 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO
)buf
, info
);
2050 ret
= ContextPropertyList_SetProperty(linked
->properties
,
2051 CERT_KEY_PROV_INFO_PROP_ID
, buf
, size
);
2059 static BOOL WINAPI
CertContext_SetProperty(PWINE_CERT_CONTEXT context
,
2060 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2062 PWINE_CERT_CONTEXT_DATA linked
= CertContext_GetDataContext(context
);
2065 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
2071 ContextPropertyList_RemoveProperty(linked
->properties
, dwPropId
);
2078 case CERT_AUTO_ENROLL_PROP_ID
:
2079 case CERT_CTL_USAGE_PROP_ID
: /* same as CERT_ENHKEY_USAGE_PROP_ID */
2080 case CERT_DESCRIPTION_PROP_ID
:
2081 case CERT_FRIENDLY_NAME_PROP_ID
:
2082 case CERT_HASH_PROP_ID
:
2083 case CERT_KEY_IDENTIFIER_PROP_ID
:
2084 case CERT_MD5_HASH_PROP_ID
:
2085 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2086 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2087 case CERT_PVK_FILE_PROP_ID
:
2088 case CERT_SIGNATURE_HASH_PROP_ID
:
2089 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2090 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
2091 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2092 case CERT_ENROLLMENT_PROP_ID
:
2093 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2094 case CERT_RENEWAL_PROP_ID
:
2096 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
2098 ret
= ContextPropertyList_SetProperty(linked
->properties
, dwPropId
,
2099 blob
->pbData
, blob
->cbData
);
2102 case CERT_DATE_STAMP_PROP_ID
:
2103 ret
= ContextPropertyList_SetProperty(linked
->properties
, dwPropId
,
2104 (LPBYTE
)pvData
, sizeof(FILETIME
));
2106 case CERT_KEY_PROV_INFO_PROP_ID
:
2107 ret
= CertContext_SetKeyProvInfoProperty(linked
,
2108 (PCRYPT_KEY_PROV_INFO
)pvData
);
2111 FIXME("%ld: stub\n", dwPropId
);
2115 TRACE("returning %d\n", ret
);
2119 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
2120 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2124 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
2126 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2127 * crashes on most of these, I'll be safer.
2132 case CERT_ACCESS_STATE_PROP_ID
:
2133 case CERT_CERT_PROP_ID
:
2134 case CERT_CRL_PROP_ID
:
2135 case CERT_CTL_PROP_ID
:
2136 SetLastError(E_INVALIDARG
);
2139 ret
= CertContext_SetProperty((PWINE_CERT_CONTEXT
)pCertContext
, dwPropId
,
2141 TRACE("returning %d\n", ret
);
2145 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
2146 PCCERT_CONTEXT pCertContext
)
2148 PWINE_CERT_CONTEXT context
= (PWINE_CERT_CONTEXT
)pCertContext
;
2150 TRACE("(%p)\n", pCertContext
);
2151 InterlockedIncrement(&context
->ref
);
2152 return pCertContext
;
2155 static void CertContext_CopyProperties(PCCERT_CONTEXT to
, PCCERT_CONTEXT from
)
2157 PWINE_CERT_CONTEXT_DATA toData
, fromData
;
2159 toData
= CertContext_GetDataContext((PWINE_CERT_CONTEXT
)to
);
2160 fromData
= CertContext_GetDataContext((PWINE_CERT_CONTEXT
)from
);
2161 ContextPropertyList_Copy(toData
->properties
, fromData
->properties
);
2164 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
2165 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
2166 PCCERT_CONTEXT
*ppStoreContext
)
2168 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
2170 PCCERT_CONTEXT toAdd
= NULL
, existing
= NULL
;
2172 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2173 dwAddDisposition
, ppStoreContext
);
2175 if (dwAddDisposition
!= CERT_STORE_ADD_ALWAYS
)
2178 DWORD size
= sizeof(hashToAdd
);
2180 ret
= CertContext_GetProperty((PWINE_CERT_CONTEXT
)pCertContext
,
2181 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
2184 CRYPT_HASH_BLOB blob
= { sizeof(hashToAdd
), hashToAdd
};
2186 existing
= CertFindCertificateInStore(hCertStore
,
2187 pCertContext
->dwCertEncodingType
, 0, CERT_FIND_SHA1_HASH
, &blob
,
2192 switch (dwAddDisposition
)
2194 case CERT_STORE_ADD_ALWAYS
:
2195 toAdd
= CertDuplicateCertificateContext(pCertContext
);
2197 case CERT_STORE_ADD_NEW
:
2200 TRACE("found matching certificate, not adding\n");
2201 SetLastError(CRYPT_E_EXISTS
);
2205 toAdd
= CertDuplicateCertificateContext(pCertContext
);
2207 case CERT_STORE_ADD_REPLACE_EXISTING
:
2208 toAdd
= CertDuplicateCertificateContext(pCertContext
);
2210 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
2211 toAdd
= CertDuplicateCertificateContext(pCertContext
);
2213 CertContext_CopyProperties(toAdd
, existing
);
2215 case CERT_STORE_ADD_USE_EXISTING
:
2217 CertContext_CopyProperties(existing
, pCertContext
);
2220 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
2226 ret
= store
->addCert(store
, (PWINE_CERT_CONTEXT
)toAdd
,
2227 (PWINE_CERT_CONTEXT
)existing
, ppStoreContext
);
2228 CertFreeCertificateContext(toAdd
);
2230 CertFreeCertificateContext(existing
);
2232 TRACE("returning %d\n", ret
);
2236 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
2237 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
2238 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
2240 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2243 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2244 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2248 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2252 PCCERT_CONTEXT cert
= CertCreateCertificateContext(
2253 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2257 ret
= CertAddCertificateContextToStore(hCertStore
,
2258 cert
, dwAddDisposition
, ppCertContext
);
2259 CertFreeCertificateContext(cert
);
2267 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
2268 PCCERT_CONTEXT pPrev
)
2270 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2273 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2276 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2279 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, (PWINE_CERT_CONTEXT
)pPrev
);
2283 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2287 TRACE("(%p)\n", pCertContext
);
2291 else if (!pCertContext
->hCertStore
)
2294 CertFreeCertificateContext(pCertContext
);
2298 PWINECRYPT_CERTSTORE hcs
=
2299 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2301 if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2304 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2305 CertFreeCertificateContext(pCertContext
);
2310 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
2311 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
2312 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
2314 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2315 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
2320 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
2321 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
2322 PCCRL_CONTEXT
* ppStoreContext
)
2324 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
2325 dwAddDisposition
, ppStoreContext
);
2329 PCCRL_CONTEXT WINAPI
CertDuplicateCRLContext(PCCRL_CONTEXT pCrlContext
)
2331 FIXME("(%p): stub\n", pCrlContext
);
2335 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2337 FIXME("%p\n", pCrlContext
);
2342 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2344 FIXME("(%p): stub\n", pCrlContext
);
2348 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2349 PCCRL_CONTEXT pPrev
)
2351 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2355 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2356 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2358 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
2363 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
2364 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
2365 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
2367 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2368 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
2373 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
2374 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
2375 PCCTL_CONTEXT
* ppStoreContext
)
2377 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
2378 dwAddDisposition
, ppStoreContext
);
2382 PCCTL_CONTEXT WINAPI
CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext
)
2384 FIXME("(%p): stub\n", pCtlContext
);
2388 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2390 FIXME("(%p): stub\n", pCtlContext
);
2394 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2396 FIXME("(%p): stub\n", pCtlContext
);
2400 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2401 PCCTL_CONTEXT pPrev
)
2403 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2407 HCERTSTORE WINAPI
CertDuplicateStore(HCERTSTORE hCertStore
)
2409 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2411 TRACE("(%p)\n", hCertStore
);
2413 if (hcs
&& hcs
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
)
2414 InterlockedIncrement(&hcs
->ref
);
2418 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2420 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2422 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2427 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2430 if (InterlockedDecrement(&hcs
->ref
) == 0)
2432 TRACE("%p's ref count is 0, freeing\n", hcs
);
2434 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2435 CryptReleaseContext(hcs
->cryptProv
, 0);
2436 hcs
->closeStore(hcs
, dwFlags
);
2439 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2443 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2444 DWORD dwCtrlType
, void const *pvCtrlPara
)
2446 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2449 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2454 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2459 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
2466 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2467 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2469 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
2473 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2474 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2476 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
2481 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2482 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2484 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
2488 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2489 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2491 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
2496 static void CertDataContext_Free(PWINE_CERT_CONTEXT_DATA context
)
2498 CryptMemFree(context
->cert
.pbCertEncoded
);
2499 LocalFree(context
->cert
.pCertInfo
);
2500 ContextPropertyList_Free(context
->properties
);
2501 CryptMemFree(context
);
2504 static void CertLinkContext_Free(PWINE_CERT_CONTEXT_LINK context
)
2506 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->linked
);
2507 CryptMemFree(context
);
2510 static void CertContext_Release(PWINE_CERT_CONTEXT context
)
2512 if (InterlockedDecrement(&context
->ref
) == 0)
2514 TRACE("freeing %p\n", context
);
2515 switch (context
->type
)
2517 case ContextTypeData
:
2518 CertDataContext_Free((PWINE_CERT_CONTEXT_DATA
)context
);
2520 case ContextTypeLink
:
2521 CertLinkContext_Free((PWINE_CERT_CONTEXT_LINK
)context
);
2528 TRACE("%p's ref count is %ld\n", context
, context
->ref
);
2531 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2533 TRACE("(%p)\n", pCertContext
);
2536 CertContext_Release((PWINE_CERT_CONTEXT
)pCertContext
);
2540 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
2541 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
2543 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2544 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2545 PWINE_STORE_LIST_ENTRY entry
;
2548 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2549 dwUpdateFlags
, dwPriority
);
2551 if (!collection
|| !sibling
)
2553 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2555 SetLastError(E_INVALIDARG
);
2558 if (collection
->hdr
.type
!= StoreTypeCollection
)
2560 SetLastError(E_INVALIDARG
);
2563 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2565 SetLastError(E_INVALIDARG
);
2569 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
2572 InterlockedIncrement(&sibling
->ref
);
2573 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
2574 entry
->store
= sibling
;
2575 entry
->dwUpdateFlags
= dwUpdateFlags
;
2576 entry
->dwPriority
= dwPriority
;
2577 list_init(&entry
->entry
);
2578 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
2579 EnterCriticalSection(&collection
->cs
);
2582 PWINE_STORE_LIST_ENTRY cursor
;
2585 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
2586 WINE_STORE_LIST_ENTRY
, entry
)
2588 if (cursor
->dwPriority
< dwPriority
)
2590 list_add_before(&cursor
->entry
, &entry
->entry
);
2596 list_add_tail(&collection
->stores
, &entry
->entry
);
2599 list_add_tail(&collection
->stores
, &entry
->entry
);
2600 LeaveCriticalSection(&collection
->cs
);
2608 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
2609 HCERTSTORE hSiblingStore
)
2611 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2612 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2613 PWINE_STORE_LIST_ENTRY store
, next
;
2615 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
2617 if (!collection
|| !sibling
)
2619 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2621 SetLastError(E_INVALIDARG
);
2624 if (collection
->hdr
.type
!= StoreTypeCollection
)
2626 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2628 SetLastError(E_INVALIDARG
);
2631 EnterCriticalSection(&collection
->cs
);
2632 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
2633 WINE_STORE_LIST_ENTRY
, entry
)
2635 if (store
->store
== sibling
)
2637 list_remove(&store
->entry
);
2638 CertCloseStore(store
->store
, 0);
2639 CryptMemFree(store
);
2643 LeaveCriticalSection(&collection
->cs
);