2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004,2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 * - Opening a cert store provider should be morphed to support loading
25 * - The concept of physical stores and locations isn't implemented. (This
26 * doesn't mean registry stores et al aren't implemented. See the PSDK for
27 * registering and enumerating physical stores and locations.)
28 * - Many flags, options and whatnot are unimplemented.
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 #include "wine/exception.h"
42 #include "crypt32_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
46 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 /* The following aren't defined in wincrypt.h, as they're "reserved" */
48 #define CERT_CERT_PROP_ID 32
49 #define CERT_CRL_PROP_ID 33
50 #define CERT_CTL_PROP_ID 34
52 /* Some typedefs that make it easier to abstract which type of context we're
55 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
56 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
57 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
58 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
59 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
60 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
61 DWORD dwAddDisposition, const void **ppContext);
62 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
63 const void *pPrevContext);
64 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
65 DWORD dwPropID, void *pvData, DWORD *pcbData);
66 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
67 DWORD dwPropID, DWORD dwFlags, const void *pvData);
68 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
69 BYTE *pbElement, DWORD *pcbElement);
70 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
71 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
73 /* An abstract context (certificate, CRL, or CTL) interface */
74 typedef struct _WINE_CONTEXT_INTERFACE
76 CreateContextFunc create;
77 AddContextToStoreFunc addContextToStore;
78 AddEncodedContextToStoreFunc addEncodedToStore;
79 EnumContextsInStoreFunc enumContextsInStore;
80 GetContextPropertyFunc getProp;
81 SetContextPropertyFunc setProp;
82 SerializeElementFunc serialize;
84 DeleteContextFunc deleteFromStore;
85 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
87 static const WINE_CONTEXT_INTERFACE gCertInterface = {
88 (CreateContextFunc)CertCreateCertificateContext,
89 (AddContextToStoreFunc)CertAddCertificateContextToStore,
90 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
91 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
92 (GetContextPropertyFunc)CertGetCertificateContextProperty,
93 (SetContextPropertyFunc)CertSetCertificateContextProperty,
94 (SerializeElementFunc)CertSerializeCertificateStoreElement,
95 (FreeContextFunc)CertFreeCertificateContext,
96 (DeleteContextFunc)CertDeleteCertificateFromStore,
99 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
100 (CreateContextFunc)CertCreateCRLContext,
101 (AddContextToStoreFunc)CertAddCRLContextToStore,
102 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
103 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
104 (GetContextPropertyFunc)CertGetCRLContextProperty,
105 (SetContextPropertyFunc)CertSetCRLContextProperty,
106 (SerializeElementFunc)CertSerializeCRLStoreElement,
107 (FreeContextFunc)CertFreeCRLContext,
108 (DeleteContextFunc)CertDeleteCRLFromStore,
111 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
112 (CreateContextFunc)CertCreateCTLContext,
113 (AddContextToStoreFunc)CertAddCTLContextToStore,
114 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
115 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
116 (GetContextPropertyFunc)CertGetCTLContextProperty,
117 (SetContextPropertyFunc)CertSetCTLContextProperty,
118 (SerializeElementFunc)CertSerializeCTLStoreElement,
119 (FreeContextFunc)CertFreeCTLContext,
120 (DeleteContextFunc)CertDeleteCTLFromStore,
123 struct WINE_CRYPTCERTSTORE;
125 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
126 DWORD dwFlags, const void *pvPara);
128 struct _WINE_CERT_CONTEXT_REF;
130 /* Called to enumerate the next certificate in a store. The returned pointer
131 * must be newly allocated (via HeapAlloc): CertFreeCertificateContext frees
134 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
135 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
137 struct _WINE_CERT_CONTEXT;
139 /* Called to create a new reference to an existing cert context. Should call
140 * CRYPT_InitCertRef to make sure the reference count is properly updated.
141 * If the store does not provide any additional allocated data (that is, does
142 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
145 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
146 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
148 /* Optional, called when a cert context reference is being freed. Don't free
149 * the ref pointer itself, CertFreeCertificateContext does that.
151 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
153 typedef enum _CertStoreType {
160 /* A cert store is polymorphic through the use of function pointers. A type
161 * is still needed to distinguish collection stores from other types.
162 * On the function pointers:
163 * - closeStore is called when the store's ref count becomes 0
164 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
165 * - control is optional, but should be implemented by any store that supports
168 typedef struct WINE_CRYPTCERTSTORE
173 HCRYPTPROV cryptProv;
175 PFN_CERT_STORE_PROV_CLOSE closeStore;
176 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
177 CreateRefFunc createCertRef;
178 EnumCertFunc enumCert;
179 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
180 FreeCertFunc freeCert; /* optional */
181 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
182 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
184 /* A certificate context has pointers to data that are owned by this module,
185 * so rather than duplicate the data every time a certificate context is
186 * copied, I keep a reference count to the data. Thus I have two data
187 * structures, the "true" certificate context (that has the reference count)
188 * and a reference certificate context, that has a pointer to the true context.
189 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
190 * with the reference version.
192 typedef struct _WINE_CERT_CONTEXT
197 struct list extendedProperties;
198 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
200 typedef struct _WINE_CERT_CONTEXT_REF
203 WINE_CERT_CONTEXT *context;
204 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
206 /* An extended certificate property in serialized form is prefixed by this
209 typedef struct _WINE_CERT_PROP_HEADER
212 DWORD unknown; /* always 1 */
214 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
216 /* Stores an extended property in a cert. */
217 typedef struct _WINE_CERT_PROPERTY
219 WINE_CERT_PROP_HEADER hdr;
222 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
224 /* A mem store has a list of these. They're also returned by the mem store
225 * during enumeration.
227 typedef struct _WINE_CERT_LIST_ENTRY
229 WINE_CERT_CONTEXT_REF cert;
231 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
233 typedef struct _WINE_MEMSTORE
235 WINECRYPT_CERTSTORE hdr;
238 } WINE_MEMSTORE, *PWINE_MEMSTORE;
240 typedef struct _WINE_HASH_TO_DELETE
244 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
246 /* Returned by a reg store during enumeration. */
247 typedef struct _WINE_REG_CERT_CONTEXT
249 WINE_CERT_CONTEXT_REF cert;
250 PWINE_CERT_CONTEXT_REF childContext;
251 } WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT;
253 typedef struct _WINE_REGSTORE
255 WINECRYPT_CERTSTORE hdr;
256 PWINECRYPT_CERTSTORE memStore;
260 struct list certsToDelete;
261 } WINE_REGSTORE, *PWINE_REGSTORE;
263 typedef struct _WINE_STORE_LIST_ENTRY
265 PWINECRYPT_CERTSTORE store;
269 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
271 /* Returned by a collection store during enumeration.
272 * Note: relies on the list entry being valid after use, which a number of
273 * conditions might make untrue (reentrancy, closing a collection store before
274 * continuing an enumeration on it, ...). The tests seem to indicate this
275 * sort of unsafety is okay, since Windows isn't well-behaved in these
278 typedef struct _WINE_COLLECTION_CERT_CONTEXT
280 WINE_CERT_CONTEXT_REF cert;
281 PWINE_STORE_LIST_ENTRY entry;
282 PWINE_CERT_CONTEXT_REF childContext;
283 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
285 typedef struct _WINE_COLLECTIONSTORE
287 WINECRYPT_CERTSTORE hdr;
290 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
292 /* Like CertGetCertificateContextProperty, but operates directly on the
293 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
294 * are handled by CertGetCertificateContextProperty, and are particular to the
295 * store in which the property exists (which is separate from the context.)
297 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
298 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
300 /* Like CertSetCertificateContextProperty, but operates directly on the
301 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
302 * CertSetCertificateContextProperty anyway.
304 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
305 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
307 /* Helper function for store reading functions and
308 * CertAddSerializedElementToStore. Returns a context of the appropriate type
309 * if it can, or NULL otherwise. Doesn't validate any of the properties in
310 * the serialized context (for example, bad hashes are retained.)
311 * *pdwContentType is set to the type of the returned context.
313 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
314 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
316 /* filter for page-fault exceptions */
317 static WINE_EXCEPTION_FILTER(page_fault)
319 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
320 return EXCEPTION_EXECUTE_HANDLER;
321 return EXCEPTION_CONTINUE_SEARCH;
324 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
325 DWORD dwFlags, CertStoreType type)
328 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
332 hCryptProv = CRYPT_GetDefaultProvider();
333 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
335 store->cryptProv = hCryptProv;
336 store->dwOpenFlags = dwFlags;
339 /* Initializes the reference ref to point to pCertContext, which is assumed to
340 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
341 * Also sets the hCertStore member of the reference to store.
343 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
344 PWINE_CERT_CONTEXT context, HCERTSTORE store)
346 TRACE("(%p, %p)\n", ref, context);
347 memcpy(&ref->cert, context, sizeof(ref->cert));
348 ref->context = context;
349 InterlockedIncrement(&context->ref);
350 ref->cert.hCertStore = store;
353 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
356 PWINE_CERT_CONTEXT_REF pCertRef = HeapAlloc(GetProcessHeap(), 0,
357 sizeof(WINE_CERT_CONTEXT_REF));
360 CRYPT_InitCertRef(pCertRef, context, store);
364 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
365 DWORD dwAddDisposition)
367 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
368 BOOL add = FALSE, ret;
370 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
372 switch (dwAddDisposition)
374 case CERT_STORE_ADD_ALWAYS:
377 case CERT_STORE_ADD_NEW:
379 BYTE hashToAdd[20], hash[20];
380 DWORD size = sizeof(hashToAdd);
382 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
383 CERT_HASH_PROP_ID, hashToAdd, &size);
386 PWINE_CERT_LIST_ENTRY cursor;
388 /* Add if no cert with the same hash is found. */
390 EnterCriticalSection(&ms->cs);
391 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
394 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
395 CERT_HASH_PROP_ID, hash, &size);
396 if (ret && !memcmp(hashToAdd, hash, size))
398 TRACE("found matching certificate, not adding\n");
399 SetLastError(CRYPT_E_EXISTS);
404 LeaveCriticalSection(&ms->cs);
408 case CERT_STORE_ADD_REPLACE_EXISTING:
410 BYTE hashToAdd[20], hash[20];
411 DWORD size = sizeof(hashToAdd);
414 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
415 CERT_HASH_PROP_ID, hashToAdd, &size);
418 PWINE_CERT_LIST_ENTRY cursor, next;
420 /* Look for existing cert to delete */
421 EnterCriticalSection(&ms->cs);
422 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
423 WINE_CERT_LIST_ENTRY, entry)
426 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
427 CERT_HASH_PROP_ID, hash, &size);
428 if (ret && !memcmp(hashToAdd, hash, size))
430 TRACE("found matching certificate, replacing\n");
431 list_remove(&cursor->entry);
432 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
436 LeaveCriticalSection(&ms->cs);
441 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
446 PWINE_CERT_LIST_ENTRY entry = HeapAlloc(GetProcessHeap(), 0,
447 sizeof(WINE_CERT_LIST_ENTRY));
451 TRACE("adding %p\n", entry);
452 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
453 list_init(&entry->entry);
454 EnterCriticalSection(&ms->cs);
455 list_add_tail(&ms->certs, &entry->entry);
456 LeaveCriticalSection(&ms->cs);
467 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
468 PWINE_CERT_CONTEXT_REF pPrev)
470 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
471 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
472 struct list *listNext;
474 TRACE("(%p, %p)\n", store, pPrev);
475 EnterCriticalSection(&ms->cs);
478 listNext = list_next(&ms->certs, &prevEntry->entry);
479 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
482 listNext = list_next(&ms->certs, &ms->certs);
485 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY));
486 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
487 sizeof(WINE_CERT_LIST_ENTRY));
488 InterlockedIncrement(&ret->cert.context->ref);
492 SetLastError(CRYPT_E_NOT_FOUND);
495 LeaveCriticalSection(&ms->cs);
497 TRACE("returning %p\n", ret);
498 return (PWINE_CERT_CONTEXT_REF)ret;
501 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
502 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
504 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
505 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
506 PWINE_CERT_LIST_ENTRY cert, next;
509 /* Find the entry associated with the passed-in context, since the
510 * passed-in context may not be a list entry itself (e.g. if it came from
511 * CertDuplicateCertificateContext.) Pointing to the same context is
512 * a sufficient test of equality.
514 EnterCriticalSection(&store->cs);
515 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
518 if (cert->cert.context == ref->context)
520 TRACE("removing %p\n", cert);
521 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
524 list_remove(&cert->entry);
525 cert->entry.prev = cert->entry.next = &store->certs;
526 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
531 LeaveCriticalSection(&store->cs);
535 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
537 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
538 PWINE_CERT_LIST_ENTRY cert, next;
540 TRACE("(%p, %08lx)\n", store, dwFlags);
542 FIXME("Unimplemented flags: %08lx\n", dwFlags);
544 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
545 * pointer if its ref-count reaches zero. That's okay here because there
546 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
547 * of the CertListEntry.
549 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
552 TRACE("removing %p\n", cert);
553 list_remove(&cert->entry);
554 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
556 DeleteCriticalSection(&store->cs);
557 HeapFree(GetProcessHeap(), 0, store);
560 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
561 DWORD dwFlags, const void *pvPara)
563 PWINE_MEMSTORE store;
565 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
567 if (dwFlags & CERT_STORE_DELETE_FLAG)
569 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
574 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
575 sizeof(WINE_MEMSTORE));
578 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
579 store->hdr.closeStore = CRYPT_MemCloseStore;
580 store->hdr.addCert = CRYPT_MemAddCert;
581 store->hdr.createCertRef = CRYPT_CreateCertRef;
582 store->hdr.enumCert = CRYPT_MemEnumCert;
583 store->hdr.deleteCert = CRYPT_MemDeleteCert;
584 store->hdr.freeCert = NULL;
585 InitializeCriticalSection(&store->cs);
586 list_init(&store->certs);
589 return (PWINECRYPT_CERTSTORE)store;
592 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
593 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
595 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
596 PWINE_STORE_LIST_ENTRY entry, next;
599 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
602 EnterCriticalSection(&cs->cs);
603 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
606 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
608 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
612 LeaveCriticalSection(&cs->cs);
613 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
617 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
618 PWINE_CERT_CONTEXT context, HCERTSTORE store)
620 PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
621 sizeof(WINE_COLLECTION_CERT_CONTEXT));
625 /* Initialize to empty for now, just make sure the size is right */
626 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
628 ret->childContext = NULL;
630 return (PWINE_CERT_CONTEXT_REF)ret;
633 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
635 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
636 PWINE_STORE_LIST_ENTRY entry, next;
638 TRACE("(%p, %08lx)\n", store, dwFlags);
640 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
643 TRACE("closing %p\n", entry);
644 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
645 HeapFree(GetProcessHeap(), 0, entry);
647 DeleteCriticalSection(&cs->cs);
648 HeapFree(GetProcessHeap(), 0, cs);
651 /* Advances a collection enumeration by one cert, if possible, where advancing
653 * - calling the current store's enumeration function once, and returning
654 * the enumerated cert if one is returned
655 * - moving to the next store if the current store has no more items, and
656 * recursively calling itself to get the next item.
657 * Returns NULL if the collection contains no more items or on error.
658 * Assumes the collection store's lock is held.
660 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
661 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
662 PWINE_COLLECTION_CERT_CONTEXT pPrev)
664 PWINE_COLLECTION_CERT_CONTEXT ret;
665 PWINE_CERT_CONTEXT_REF child;
667 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
671 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
672 pPrev->childContext);
676 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
677 ret->cert.cert.hCertStore = (HCERTSTORE)store;
678 InterlockedIncrement(&ret->cert.context->ref);
679 ret->childContext = child;
683 struct list *storeNext = list_next(&store->stores,
686 pPrev->childContext = NULL;
687 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
690 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
692 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
696 SetLastError(CRYPT_E_NOT_FOUND);
703 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
707 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
708 child->context, store);
711 ret->entry = storeEntry;
712 ret->childContext = child;
715 CertFreeCertificateContext((PCCERT_CONTEXT)child);
719 struct list *storeNext = list_next(&store->stores,
724 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
726 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
730 SetLastError(CRYPT_E_NOT_FOUND);
735 TRACE("returning %p\n", ret);
739 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
740 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
742 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
743 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
744 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
746 TRACE("(%p, %p)\n", store, pPrev);
750 EnterCriticalSection(&cs->cs);
751 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
752 LeaveCriticalSection(&cs->cs);
756 EnterCriticalSection(&cs->cs);
757 if (!list_empty(&cs->stores))
759 PWINE_STORE_LIST_ENTRY storeEntry;
761 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
763 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
767 SetLastError(CRYPT_E_NOT_FOUND);
770 LeaveCriticalSection(&cs->cs);
772 TRACE("returning %p\n", ret);
773 return (PWINE_CERT_CONTEXT_REF)ret;
776 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
777 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
779 PWINE_COLLECTION_CERT_CONTEXT context =
780 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
783 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
785 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
788 context->childContext = NULL;
789 CertFreeCertificateContext((PCCERT_CONTEXT)context);
794 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
796 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
798 TRACE("(%p)\n", ref);
800 if (context->childContext)
801 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
804 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
805 DWORD dwFlags, const void *pvPara)
807 PWINE_COLLECTIONSTORE store;
809 if (dwFlags & CERT_STORE_DELETE_FLAG)
811 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
816 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
817 sizeof(WINE_COLLECTIONSTORE));
820 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
821 StoreTypeCollection);
822 store->hdr.closeStore = CRYPT_CollectionCloseStore;
823 store->hdr.addCert = CRYPT_CollectionAddCert;
824 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
825 store->hdr.enumCert = CRYPT_CollectionEnumCert;
826 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
827 store->hdr.freeCert = CRYPT_CollectionFreeCert;
828 InitializeCriticalSection(&store->cs);
829 list_init(&store->stores);
832 return (PWINECRYPT_CERTSTORE)store;
835 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
837 static const WCHAR fmt[] = { '%','0','2','X',0 };
843 for (i = 0; i < 20; i++)
844 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
847 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
849 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
850 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
851 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
853 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
858 WCHAR subKeyName[MAX_PATH];
861 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
863 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
869 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
875 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
877 buf = HeapAlloc(GetProcessHeap(), 0, size);
880 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
887 TRACE("Adding cert with hash %s\n",
888 debugstr_w(subKeyName));
889 context = CRYPT_ReadSerializedElement(buf, size,
890 contextType, &addedType);
893 const WINE_CONTEXT_INTERFACE *contextInterface;
898 case CERT_STORE_CERTIFICATE_CONTEXT:
899 contextInterface = &gCertInterface;
901 case CERT_STORE_CRL_CONTEXT:
902 contextInterface = &gCRLInterface;
904 case CERT_STORE_CTL_CONTEXT:
905 contextInterface = &gCTLInterface;
908 contextInterface = NULL;
910 if (contextInterface)
913 if (contextInterface->getProp(context,
914 CERT_HASH_PROP_ID, hash, &size))
916 WCHAR asciiHash[20 * 2 + 1];
918 CRYPT_HashToStr(hash, asciiHash);
919 TRACE("comparing %s\n",
920 debugstr_w(asciiHash));
921 TRACE("with %s\n", debugstr_w(subKeyName));
922 if (!lstrcmpW(asciiHash, subKeyName))
924 TRACE("hash matches, adding\n");
925 contextInterface->addContextToStore(
927 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
931 TRACE("hash doesn't match, ignoring\n");
932 contextInterface->free(context);
938 HeapFree(GetProcessHeap(), 0, buf);
942 /* Ignore intermediate errors, continue enumerating */
948 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
950 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
951 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
952 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
955 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
960 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
964 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
970 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
971 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
974 WCHAR asciiHash[20 * 2 + 1];
979 CRYPT_HashToStr(hash, asciiHash);
980 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
984 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
997 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
998 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1000 const void *context = NULL;
1004 context = contextInterface->enumContextsInStore(memStore, context);
1008 DWORD hashSize = sizeof(hash);
1010 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1017 ret = contextInterface->serialize(context, 0, NULL, &size);
1019 buf = HeapAlloc(GetProcessHeap(), 0, size);
1022 ret = contextInterface->serialize(context, 0, buf, &size);
1024 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1026 HeapFree(GetProcessHeap(), 0, buf);
1031 } while (ret && context != NULL);
1033 contextInterface->free(context);
1037 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1039 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1040 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1041 &gCRLInterface, &gCTLInterface };
1042 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1046 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1049 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1050 KEY_ALL_ACCESS, NULL, &key, NULL);
1054 if (listToDelete[i])
1056 PWINE_HASH_TO_DELETE toDelete, next;
1057 WCHAR asciiHash[20 * 2 + 1];
1059 EnterCriticalSection(&store->cs);
1060 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1061 WINE_HASH_TO_DELETE, entry)
1065 CRYPT_HashToStr(toDelete->hash, asciiHash);
1066 TRACE("Removing %s\n", debugstr_w(asciiHash));
1067 rc = RegDeleteKeyW(key, asciiHash);
1068 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1073 list_remove(&toDelete->entry);
1074 HeapFree(GetProcessHeap(), 0, toDelete);
1076 LeaveCriticalSection(&store->cs);
1078 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1091 /* If force is true or the registry store is dirty, writes the contents of the
1092 * store to the registry.
1094 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1098 if (store->dirty || force)
1099 ret = CRYPT_RegWriteToReg(store);
1105 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1107 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1109 TRACE("(%p, %08lx)\n", store, dwFlags);
1111 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1113 CRYPT_RegFlushStore(store, FALSE);
1114 /* certsToDelete should already be cleared by this point */
1115 store->memStore->closeStore(store->memStore, 0);
1116 RegCloseKey(store->key);
1117 DeleteCriticalSection(&store->cs);
1118 HeapFree(GetProcessHeap(), 0, store);
1121 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1122 DWORD dwAddDisposition)
1124 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1127 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1129 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1131 SetLastError(ERROR_ACCESS_DENIED);
1136 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1138 store->dirty = TRUE;
1143 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1144 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1146 PWINE_REG_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
1147 sizeof(WINE_REG_CERT_CONTEXT));
1151 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1152 ret->childContext = NULL;
1154 return (PWINE_CERT_CONTEXT_REF)ret;
1157 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1158 PWINE_CERT_CONTEXT_REF pPrev)
1160 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1161 PWINE_CERT_CONTEXT_REF child;
1162 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1164 TRACE("(%p, %p)\n", store, pPrev);
1168 child = rs->memStore->enumCert(rs->memStore, prev->childContext);
1171 ret = (PWINE_REG_CERT_CONTEXT)pPrev;
1172 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1173 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1174 InterlockedIncrement(&ret->cert.context->ref);
1175 ret->childContext = child;
1180 child = rs->memStore->enumCert(rs->memStore, NULL);
1183 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_REG_CERT_CONTEXT));
1187 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1188 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1189 InterlockedIncrement(&ret->cert.context->ref);
1190 ret->childContext = child;
1193 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1196 return (PWINE_CERT_CONTEXT_REF)ret;
1199 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1200 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1202 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1205 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1207 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1209 SetLastError(ERROR_ACCESS_DENIED);
1214 PWINE_HASH_TO_DELETE toDelete =
1215 HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HASH_TO_DELETE));
1219 DWORD size = sizeof(toDelete->hash);
1221 ret = CertGetCertificateContextProperty(pCertContext,
1222 CERT_HASH_PROP_ID, toDelete->hash, &size);
1225 list_init(&toDelete->entry);
1226 EnterCriticalSection(&store->cs);
1227 list_add_tail(&store->certsToDelete, &toDelete->entry);
1228 LeaveCriticalSection(&store->cs);
1229 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1233 HeapFree(GetProcessHeap(), 0, toDelete);
1238 store->dirty = TRUE;
1243 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1245 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1247 TRACE("(%p)\n", ref);
1249 if (context->childContext)
1250 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1253 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1254 DWORD dwCtrlType, void const *pvCtrlPara)
1256 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1261 case CERT_STORE_CTRL_RESYNC:
1262 CRYPT_RegFlushStore(store, FALSE);
1263 store->memStore->closeStore(store->memStore, 0);
1264 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1265 store->hdr.dwOpenFlags, NULL);
1266 if (store->memStore)
1268 CRYPT_RegReadFromReg(store);
1274 case CERT_STORE_CTRL_COMMIT:
1275 ret = CRYPT_RegFlushStore(store,
1276 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1279 FIXME("%ld: stub\n", dwCtrlType);
1285 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1286 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1288 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1289 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1292 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1294 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1297 /* Find how many subkeys there are */
1298 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1299 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1303 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1305 /* Name too big: alloc a buffer for it */
1306 lpszName = HeapAlloc(GetProcessHeap(), 0,
1307 dwMaxSubkeyLen*sizeof(WCHAR));
1311 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1314 /* Recursively delete all the subkeys */
1315 for (i = 0; i < dwKeyCount && !dwRet; i++)
1317 dwSize = dwMaxSubkeyLen;
1318 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1321 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1324 if (lpszName != szNameBuf)
1326 /* Free buffer if allocated */
1327 HeapFree(GetProcessHeap(), 0, lpszName);
1332 RegCloseKey(hSubKey);
1334 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1339 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1340 DWORD dwFlags, const void *pvPara)
1342 PWINE_REGSTORE store = NULL;
1344 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1346 if (dwFlags & CERT_STORE_DELETE_FLAG)
1348 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1350 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1351 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1352 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1353 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1354 if (rc == ERROR_NO_MORE_ITEMS)
1362 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1363 GetCurrentProcess(), (LPHANDLE)&key,
1364 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1367 PWINECRYPT_CERTSTORE memStore;
1369 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1372 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1373 sizeof(WINE_REGSTORE));
1376 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1378 store->hdr.closeStore = CRYPT_RegCloseStore;
1379 store->hdr.addCert = CRYPT_RegAddCert;
1380 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1381 store->hdr.enumCert = CRYPT_RegEnumCert;
1382 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1383 store->hdr.freeCert = CRYPT_RegFreeCert;
1384 store->hdr.control = CRYPT_RegControl;
1385 store->memStore = memStore;
1387 InitializeCriticalSection(&store->cs);
1388 list_init(&store->certsToDelete);
1389 CRYPT_RegReadFromReg(store);
1390 store->dirty = FALSE;
1395 TRACE("returning %p\n", store);
1396 return (WINECRYPT_CERTSTORE *)store;
1399 /* FIXME: this isn't complete for the Root store, in which the top-level
1400 * self-signed CA certs reside. Adding a cert to the Root store should present
1401 * the user with a dialog indicating the consequences of doing so, and asking
1402 * the user to confirm whether the cert should be added.
1404 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1405 DWORD dwFlags, const void *pvPara)
1407 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1408 LPWSTR storeName = (LPWSTR)pvPara;
1410 PWINECRYPT_CERTSTORE store = NULL;
1415 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1416 debugstr_w((LPCWSTR)pvPara));
1420 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1425 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1427 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1428 root = HKEY_LOCAL_MACHINE;
1429 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1431 case CERT_SYSTEM_STORE_CURRENT_USER:
1432 root = HKEY_CURRENT_USER;
1433 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1435 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1436 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1437 * SystemCertificates
1439 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1440 debugstr_w(storeName));
1442 case CERT_SYSTEM_STORE_SERVICES:
1443 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1444 * SystemCertificates
1446 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1447 debugstr_w(storeName));
1449 case CERT_SYSTEM_STORE_USERS:
1450 /* hku\user sid\Software\Microsoft\SystemCertificates */
1451 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1452 debugstr_w(storeName));
1454 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1455 root = HKEY_CURRENT_USER;
1456 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1458 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1459 root = HKEY_LOCAL_MACHINE;
1460 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1462 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1463 /* hklm\Software\Microsoft\EnterpriseCertificates */
1464 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1465 debugstr_w(storeName));
1468 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1472 storePath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(base) +
1473 lstrlenW(storeName) + 2) * sizeof(WCHAR));
1478 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1481 wsprintfW(storePath, fmt, base, storeName);
1482 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1483 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1488 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1490 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1491 disp == REG_OPENED_EXISTING_KEY)
1494 rc = ERROR_FILE_EXISTS;
1499 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1504 HeapFree(GetProcessHeap(), 0, storePath);
1509 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1510 DWORD dwFlags, const void *pvPara)
1513 PWINECRYPT_CERTSTORE ret = NULL;
1515 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1516 debugstr_a((LPCSTR)pvPara));
1520 SetLastError(ERROR_FILE_NOT_FOUND);
1523 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1526 LPWSTR storeName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1530 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1531 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1532 HeapFree(GetProcessHeap(), 0, storeName);
1538 static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1540 HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore);
1543 static BOOL WINAPI CRYPT_DummyAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
1544 DWORD dwAddDisposition)
1549 static PWINE_CERT_CONTEXT_REF CRYPT_DummyEnumCert(PWINECRYPT_CERTSTORE store,
1550 PWINE_CERT_CONTEXT_REF pPrev)
1555 static BOOL WINAPI CRYPT_DummyDeleteCert(HCERTSTORE hCertStore,
1556 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1561 static WINECRYPT_CERTSTORE *CRYPT_DummyOpenStore(HCRYPTPROV hCryptProv,
1562 DWORD dwFlags, const void *pvPara)
1564 PWINECRYPT_CERTSTORE store;
1566 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1568 if (dwFlags & CERT_STORE_DELETE_FLAG)
1570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1575 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1576 sizeof(WINECRYPT_CERTSTORE));
1579 CRYPT_InitStore(store, hCryptProv, dwFlags, StoreTypeDummy);
1580 store->closeStore = CRYPT_DummyCloseStore;
1581 store->addCert = CRYPT_DummyAddCert;
1582 store->createCertRef = CRYPT_CreateCertRef;
1583 store->enumCert = CRYPT_DummyEnumCert;
1584 store->deleteCert = CRYPT_DummyDeleteCert;
1585 store->freeCert = NULL;
1588 return (PWINECRYPT_CERTSTORE)store;
1592 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1593 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1596 WINECRYPT_CERTSTORE *hcs;
1597 StoreOpenFunc openFunc = NULL;
1599 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1600 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1602 if (!HIWORD(lpszStoreProvider))
1604 switch (LOWORD(lpszStoreProvider))
1606 case (int)CERT_STORE_PROV_MEMORY:
1607 openFunc = CRYPT_MemOpenStore;
1609 case (int)CERT_STORE_PROV_REG:
1610 openFunc = CRYPT_RegOpenStore;
1612 case (int)CERT_STORE_PROV_COLLECTION:
1613 openFunc = CRYPT_CollectionOpenStore;
1615 case (int)CERT_STORE_PROV_SYSTEM_A:
1616 case (int)CERT_STORE_PROV_SYSTEM_W:
1617 openFunc = CRYPT_DummyOpenStore;
1619 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1620 openFunc = CRYPT_SysRegOpenStoreA;
1622 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1623 openFunc = CRYPT_SysRegOpenStoreW;
1626 if (LOWORD(lpszStoreProvider))
1627 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1630 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1631 openFunc = CRYPT_MemOpenStore;
1632 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1633 openFunc = CRYPT_DummyOpenStore;
1634 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1635 openFunc = CRYPT_CollectionOpenStore;
1636 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1637 openFunc = CRYPT_SysRegOpenStoreW;
1640 FIXME("unimplemented type %s\n", lpszStoreProvider);
1646 /* FIXME: need to look for an installed provider for this type */
1647 SetLastError(ERROR_FILE_NOT_FOUND);
1651 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1652 return (HCERTSTORE)hcs;
1655 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1656 LPCSTR szSubSystemProtocol)
1658 return CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, 0,
1659 CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
1660 CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
1663 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1664 LPCWSTR szSubSystemProtocol)
1666 return CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, 0,
1667 CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
1668 CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
1671 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1672 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1674 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1675 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1679 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1680 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1685 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1687 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1688 pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
1692 data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
1695 HeapFree( GetProcessHeap(), 0, pcrl );
1699 pcrl->dwCertEncodingType = dwCertEncodingType;
1700 pcrl->pbCrlEncoded = data;
1701 pcrl->cbCrlEncoded = cbCrlEncoded;
1702 pcrl->pCrlInfo = NULL;
1703 pcrl->hCertStore = 0;
1708 /* Decodes the encoded certificate and creates the certificate context for it.
1709 * The reference count is initially zero, so you must create a reference to it
1710 * to avoid leaking memory.
1712 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1713 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1715 PWINE_CERT_CONTEXT cert = NULL;
1717 PCERT_INFO certInfo = NULL;
1720 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1723 /* First try to decode it as a signed cert. */
1724 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1725 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1726 (BYTE *)&certInfo, &size);
1727 /* Failing that, try it as an unsigned cert */
1729 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1730 pbCertEncoded, cbCertEncoded,
1731 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1732 (BYTE *)&certInfo, &size);
1737 cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
1740 data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
1743 HeapFree(GetProcessHeap(), 0, cert);
1747 memcpy(data, pbCertEncoded, cbCertEncoded);
1748 cert->cert.dwCertEncodingType = dwCertEncodingType;
1749 cert->cert.pbCertEncoded = data;
1750 cert->cert.cbCertEncoded = cbCertEncoded;
1751 cert->cert.pCertInfo = certInfo;
1752 cert->cert.hCertStore = 0;
1754 InitializeCriticalSection(&cert->cs);
1755 list_init(&cert->extendedProperties);
1762 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1764 PWINE_CERT_PROPERTY prop, next;
1766 HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
1767 LocalFree(context->cert.pCertInfo);
1768 DeleteCriticalSection(&context->cs);
1769 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1770 WINE_CERT_PROPERTY, entry)
1772 list_remove(&prop->entry);
1773 HeapFree(GetProcessHeap(), 0, prop->pbData);
1774 HeapFree(GetProcessHeap(), 0, prop);
1776 HeapFree(GetProcessHeap(), 0, context);
1779 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1780 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1782 PWINE_CERT_CONTEXT cert;
1783 PWINE_CERT_CONTEXT_REF ret = NULL;
1785 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1788 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1791 ret = CRYPT_CreateCertRef(cert, 0);
1792 return (PCCERT_CONTEXT)ret;
1795 /* Since the properties are stored in a list, this is a tad inefficient
1796 * (O(n^2)) since I have to find the previous position every time.
1798 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1801 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1804 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1806 EnterCriticalSection(&ref->context->cs);
1809 PWINE_CERT_PROPERTY cursor = NULL;
1811 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1812 WINE_CERT_PROPERTY, entry)
1814 if (cursor->hdr.propID == dwPropId)
1819 if (cursor->entry.next != &ref->context->extendedProperties)
1820 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1828 else if (!list_empty(&ref->context->extendedProperties))
1829 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1830 WINE_CERT_PROPERTY, entry)->hdr.propID;
1833 LeaveCriticalSection(&ref->context->cs);
1837 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1838 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1840 PWINE_CERT_PROPERTY prop;
1843 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1845 EnterCriticalSection(&context->cs);
1848 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1849 WINE_CERT_PROPERTY, entry)
1851 if (prop->hdr.propID == dwPropId)
1855 *pcbData = prop->hdr.cb;
1858 else if (*pcbData < prop->hdr.cb)
1860 SetLastError(ERROR_MORE_DATA);
1861 *pcbData = prop->hdr.cb;
1865 memcpy(pvData, prop->pbData, prop->hdr.cb);
1866 *pcbData = prop->hdr.cb;
1875 /* Implicit properties */
1878 case CERT_SHA1_HASH_PROP_ID:
1879 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1880 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1884 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1886 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1890 case CERT_KEY_PROV_INFO_PROP_ID:
1891 case CERT_MD5_HASH_PROP_ID:
1892 case CERT_SIGNATURE_HASH_PROP_ID:
1893 case CERT_KEY_IDENTIFIER_PROP_ID:
1894 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1895 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1896 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1897 FIXME("implicit property %ld\n", dwPropId);
1901 LeaveCriticalSection(&context->cs);
1902 TRACE("returning %d\n", ret);
1906 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1907 DWORD dwPropId, void *pvData, DWORD *pcbData)
1909 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1912 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1914 /* Special cases for invalid/special prop IDs.
1919 case CERT_CERT_PROP_ID:
1920 case CERT_CRL_PROP_ID:
1921 case CERT_CTL_PROP_ID:
1922 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1924 case CERT_ACCESS_STATE_PROP_ID:
1927 *pcbData = sizeof(DWORD);
1930 else if (*pcbData < sizeof(DWORD))
1932 SetLastError(ERROR_MORE_DATA);
1933 *pcbData = sizeof(DWORD);
1940 if (pCertContext->hCertStore)
1942 PWINECRYPT_CERTSTORE store =
1943 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1945 /* Take advantage of knowledge of the stores to answer the
1946 * access state question
1948 if (store->type != StoreTypeReg ||
1949 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1950 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1952 *(DWORD *)pvData = state;
1957 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
1959 TRACE("returning %d\n", ret);
1963 /* Copies cbData bytes from pbData to the context's property with ID
1966 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
1967 DWORD dwPropId, const BYTE *pbData, size_t cbData)
1974 data = HeapAlloc(GetProcessHeap(), 0, cbData);
1976 memcpy(data, pbData, cbData);
1980 if (!cbData || data)
1982 PWINE_CERT_PROPERTY prop;
1984 EnterCriticalSection(&context->cs);
1985 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1986 WINE_CERT_PROPERTY, entry)
1988 if (prop->hdr.propID == dwPropId)
1991 if (prop && prop->entry.next != &context->extendedProperties)
1993 HeapFree(GetProcessHeap(), 0, prop->pbData);
1994 prop->hdr.cb = cbData;
1995 prop->pbData = cbData ? data : NULL;
2000 prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
2003 prop->hdr.propID = dwPropId;
2004 prop->hdr.unknown = 1;
2005 prop->hdr.cb = cbData;
2006 list_init(&prop->entry);
2007 prop->pbData = cbData ? data : NULL;
2008 list_add_tail(&context->extendedProperties, &prop->entry);
2012 HeapFree(GetProcessHeap(), 0, data);
2014 LeaveCriticalSection(&context->cs);
2019 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2020 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2024 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2028 PWINE_CERT_PROPERTY prop, next;
2030 EnterCriticalSection(&context->cs);
2031 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2032 WINE_CERT_PROPERTY, entry)
2034 if (prop->hdr.propID == dwPropId)
2036 list_remove(&prop->entry);
2037 HeapFree(GetProcessHeap(), 0, prop->pbData);
2038 HeapFree(GetProcessHeap(), 0, prop);
2041 LeaveCriticalSection(&context->cs);
2048 case CERT_AUTO_ENROLL_PROP_ID:
2049 case CERT_CTL_USAGE_PROP_ID:
2050 case CERT_DESCRIPTION_PROP_ID:
2051 case CERT_FRIENDLY_NAME_PROP_ID:
2052 case CERT_HASH_PROP_ID:
2053 case CERT_KEY_IDENTIFIER_PROP_ID:
2054 case CERT_MD5_HASH_PROP_ID:
2055 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2056 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2057 case CERT_PVK_FILE_PROP_ID:
2058 case CERT_SIGNATURE_HASH_PROP_ID:
2059 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2060 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2061 case CERT_ENROLLMENT_PROP_ID:
2062 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2063 case CERT_RENEWAL_PROP_ID:
2065 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2067 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2068 blob->pbData, blob->cbData);
2071 case CERT_DATE_STAMP_PROP_ID:
2072 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2073 pvData, sizeof(FILETIME));
2076 FIXME("%ld: stub\n", dwPropId);
2079 TRACE("returning %d\n", ret);
2083 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2084 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2086 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2089 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2091 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2092 * crashes on most of these, I'll be safer.
2097 case CERT_ACCESS_STATE_PROP_ID:
2098 case CERT_CERT_PROP_ID:
2099 case CERT_CRL_PROP_ID:
2100 case CERT_CTL_PROP_ID:
2101 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2104 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2106 TRACE("returning %d\n", ret);
2110 /* Only the reference portion of the context is duplicated. The returned
2111 * context has the cert store set to 0, to prevent the store's certificate free
2112 * function from getting called on partial data.
2113 * FIXME: is this okay? Needs a test.
2115 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2116 PCCERT_CONTEXT pCertContext)
2118 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2120 TRACE("(%p)\n", pCertContext);
2123 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
2126 memcpy(ret, ref, sizeof(*ret));
2127 ret->cert.hCertStore = 0;
2128 InterlockedIncrement(&ret->context->ref);
2133 return (PCCERT_CONTEXT)ret;
2136 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2137 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2138 PCCERT_CONTEXT *ppStoreContext)
2140 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2141 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2142 PWINE_CERT_CONTEXT cert;
2145 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2146 dwAddDisposition, ppStoreContext);
2148 /* FIXME: some tests needed to verify return codes */
2151 SetLastError(ERROR_INVALID_PARAMETER);
2154 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2156 SetLastError(ERROR_INVALID_PARAMETER);
2160 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2161 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2164 PWINE_CERT_PROPERTY prop;
2167 EnterCriticalSection(&ref->context->cs);
2168 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2169 WINE_CERT_PROPERTY, entry)
2171 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2172 prop->pbData, prop->hdr.cb);
2176 LeaveCriticalSection(&ref->context->cs);
2179 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2180 if (ret && ppStoreContext)
2181 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2185 CRYPT_FreeCert(cert);
2192 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2193 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2194 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2196 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2199 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2200 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2204 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2208 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2209 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2213 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2214 if (ret && ppCertContext)
2215 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2218 CRYPT_FreeCert(cert);
2226 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2227 PCCERT_CONTEXT pPrev)
2229 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2230 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2233 TRACE("(%p, %p)\n", hCertStore, pPrev);
2236 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2239 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2243 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2247 TRACE("(%p)\n", pCertContext);
2251 else if (!pCertContext->hCertStore)
2255 PWINECRYPT_CERTSTORE hcs =
2256 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2260 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2263 ret = hcs->deleteCert(hcs, pCertContext, 0);
2268 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2269 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2270 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2272 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2273 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2278 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2279 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2280 PCCRL_CONTEXT* ppStoreContext )
2282 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2283 dwAddDisposition, ppStoreContext);
2287 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2289 FIXME("%p\n", pCrlContext );
2294 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2296 FIXME("(%p): stub\n", pCrlContext);
2300 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2301 PCCRL_CONTEXT pPrev)
2303 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2307 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2308 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2310 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2315 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2316 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2317 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2319 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2320 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2325 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2326 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2327 PCCTL_CONTEXT* ppStoreContext)
2329 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2330 dwAddDisposition, ppStoreContext);
2334 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2336 FIXME("(%p): stub\n", pCtlContext );
2340 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2342 FIXME("(%p): stub\n", pCtlContext);
2346 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2347 PCCTL_CONTEXT pPrev)
2349 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2354 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2356 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2358 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2363 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2366 if (InterlockedDecrement(&hcs->ref) == 0)
2368 TRACE("freeing %p\n", hcs);
2370 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2371 CryptReleaseContext(hcs->cryptProv, 0);
2372 hcs->closeStore(hcs, dwFlags);
2375 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2379 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2380 DWORD dwCtrlType, void const *pvCtrlPara)
2382 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2385 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2390 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2395 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2402 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2403 DWORD dwPropId, void *pvData, DWORD *pcbData)
2405 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2409 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2410 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2412 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2417 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2418 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2420 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2425 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2426 DWORD dwPropId, void *pvData, DWORD *pcbData)
2428 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2432 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2433 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2435 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2440 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2441 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2443 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2448 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2449 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2453 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2458 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2459 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2460 pCertContext->cbCertEncoded;
2461 PWINE_CERT_PROPERTY prop;
2463 EnterCriticalSection(&ref->context->cs);
2464 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2465 WINE_CERT_PROPERTY, entry)
2466 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2469 *pcbElement = bytesNeeded;
2472 else if (*pcbElement < bytesNeeded)
2474 *pcbElement = bytesNeeded;
2475 SetLastError(ERROR_MORE_DATA);
2480 PWINE_CERT_PROP_HEADER hdr;
2482 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2483 WINE_CERT_PROPERTY, entry)
2485 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2486 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2489 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2490 pbElement += prop->hdr.cb;
2493 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2494 hdr->propID = CERT_CERT_PROP_ID;
2496 hdr->cb = pCertContext->cbCertEncoded;
2497 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2498 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2501 LeaveCriticalSection(&ref->context->cs);
2508 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2509 * to its header if a valid header is found, NULL if not. Valid means the
2510 * length of thte property won't overrun buf, and the unknown field is 1.
2512 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2513 DWORD size, DWORD propID)
2515 const WINE_CERT_PROP_HEADER *ret = NULL;
2518 while (size && !ret && !done)
2520 if (size < sizeof(WINE_CERT_PROP_HEADER))
2522 SetLastError(CRYPT_E_FILE_ERROR);
2527 const WINE_CERT_PROP_HEADER *hdr =
2528 (const WINE_CERT_PROP_HEADER *)buf;
2530 size -= sizeof(WINE_CERT_PROP_HEADER);
2531 buf += sizeof(WINE_CERT_PROP_HEADER);
2534 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2537 else if (!hdr->propID)
2539 /* assume a zero prop ID means the data are uninitialized, so
2544 else if (hdr->unknown != 1)
2546 SetLastError(ERROR_FILE_NOT_FOUND);
2549 else if (hdr->propID == propID)
2561 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2562 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2564 const void *context = NULL;
2566 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2571 SetLastError(ERROR_END_OF_MEDIA);
2577 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2578 const WINE_CERT_PROP_HEADER *hdr = NULL;
2583 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2585 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2587 type = CERT_STORE_CERTIFICATE_CONTEXT;
2590 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2592 type = CERT_STORE_CRL_CONTEXT;
2595 hdr = CRYPT_findPropID(pbElement, cbElement,
2598 type = CERT_STORE_CTL_CONTEXT;
2602 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2604 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2605 type = CERT_STORE_CERTIFICATE_CONTEXT;
2607 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2609 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2610 type = CERT_STORE_CRL_CONTEXT;
2612 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2614 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2615 type = CERT_STORE_CTL_CONTEXT;
2620 case CERT_STORE_CERTIFICATE_CONTEXT:
2621 contextInterface = &gCertInterface;
2623 case CERT_STORE_CRL_CONTEXT:
2624 contextInterface = &gCRLInterface;
2626 case CERT_STORE_CTL_CONTEXT:
2627 contextInterface = &gCTLInterface;
2630 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2637 context = contextInterface->create(X509_ASN_ENCODING,
2638 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2641 BOOL noMoreProps = FALSE;
2643 while (!noMoreProps && ret)
2645 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2649 const WINE_CERT_PROP_HEADER *hdr =
2650 (const WINE_CERT_PROP_HEADER *)pbElement;
2652 TRACE("prop is %ld\n", hdr->propID);
2653 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2654 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2655 if (cbElement < hdr->cb)
2657 SetLastError(HRESULT_FROM_WIN32(
2658 ERROR_INVALID_PARAMETER));
2661 else if (!hdr->propID)
2663 /* Like in CRYPT_findPropID, stop if the propID is zero
2667 else if (hdr->unknown != 1)
2669 SetLastError(ERROR_FILE_NOT_FOUND);
2672 else if (hdr->propID != CERT_CERT_PROP_ID &&
2673 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2676 /* Have to create a blob for most types, but not
2679 switch (hdr->propID)
2681 case CERT_AUTO_ENROLL_PROP_ID:
2682 case CERT_CTL_USAGE_PROP_ID:
2683 case CERT_DESCRIPTION_PROP_ID:
2684 case CERT_FRIENDLY_NAME_PROP_ID:
2685 case CERT_HASH_PROP_ID:
2686 case CERT_KEY_IDENTIFIER_PROP_ID:
2687 case CERT_MD5_HASH_PROP_ID:
2688 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2689 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2690 case CERT_PVK_FILE_PROP_ID:
2691 case CERT_SIGNATURE_HASH_PROP_ID:
2692 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2693 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2694 case CERT_ENROLLMENT_PROP_ID:
2695 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2696 case CERT_RENEWAL_PROP_ID:
2698 CRYPT_DATA_BLOB blob = { hdr->cb,
2699 (LPBYTE)pbElement };
2701 ret = contextInterface->setProp(context,
2702 hdr->propID, 0, &blob);
2705 case CERT_DATE_STAMP_PROP_ID:
2706 ret = contextInterface->setProp(context,
2707 hdr->propID, 0, pbElement);
2710 FIXME("prop ID %ld: stub\n", hdr->propID);
2713 pbElement += hdr->cb;
2714 cbElement -= hdr->cb;
2722 *pdwContentType = type;
2726 contextInterface->free(context);
2731 __EXCEPT(page_fault)
2733 SetLastError(STATUS_ACCESS_VIOLATION);
2740 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2741 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2742 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2744 const void *context;
2748 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2749 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2750 pdwContentType, ppvContext);
2752 /* Call the internal function, then delete the hashes. Tests show this
2753 * function uses real hash values, not whatever's stored in the hash
2756 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2757 dwContextTypeFlags, &type);
2760 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2764 case CERT_STORE_CERTIFICATE_CONTEXT:
2765 contextInterface = &gCertInterface;
2767 case CERT_STORE_CRL_CONTEXT:
2768 contextInterface = &gCRLInterface;
2770 case CERT_STORE_CTL_CONTEXT:
2771 contextInterface = &gCTLInterface;
2774 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2776 if (contextInterface)
2778 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2779 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2780 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2783 *pdwContentType = type;
2784 ret = contextInterface->addContextToStore(hCertStore, context,
2785 dwAddDisposition, ppvContext);
2786 contextInterface->free(context);
2796 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2798 TRACE("(%p)\n", pCertContext);
2802 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2803 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2805 if (InterlockedDecrement(&ref->context->ref) == 0)
2807 TRACE("freeing %p\n", ref->context);
2808 CRYPT_FreeCert(ref->context);
2811 TRACE("%p's ref count is %ld\n", ref->context,
2813 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2815 store->freeCert(ref);
2816 HeapFree(GetProcessHeap(), 0, ref);
2821 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2822 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2823 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2825 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2826 dwFlags, dwType, pvPara, pPrevCertContext);
2827 SetLastError(CRYPT_E_NOT_FOUND);
2831 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2832 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2834 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2835 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2836 PWINE_STORE_LIST_ENTRY entry;
2839 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2840 dwUpdateFlags, dwPriority);
2842 if (!collection || !sibling)
2844 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2846 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2849 if (collection->hdr.type != StoreTypeCollection)
2851 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2854 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2856 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2860 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
2863 InterlockedIncrement(&sibling->ref);
2864 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2865 entry->store = sibling;
2866 entry->dwUpdateFlags = dwUpdateFlags;
2867 entry->dwPriority = dwPriority;
2868 list_init(&entry->entry);
2869 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2870 EnterCriticalSection(&collection->cs);
2873 PWINE_STORE_LIST_ENTRY cursor;
2876 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2877 WINE_STORE_LIST_ENTRY, entry)
2879 if (cursor->dwPriority < dwPriority)
2881 list_add_before(&cursor->entry, &entry->entry);
2887 list_add_tail(&collection->stores, &entry->entry);
2890 list_add_tail(&collection->stores, &entry->entry);
2891 LeaveCriticalSection(&collection->cs);
2899 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2900 HCERTSTORE hSiblingStore)
2902 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2903 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2904 PWINE_STORE_LIST_ENTRY store, next;
2906 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2908 if (!collection || !sibling)
2910 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2912 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2915 if (collection->hdr.type != StoreTypeCollection)
2917 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2919 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2922 EnterCriticalSection(&collection->cs);
2923 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2924 WINE_STORE_LIST_ENTRY, entry)
2926 if (store->store == sibling)
2928 list_remove(&store->entry);
2929 CertCloseStore(store->store, 0);
2930 HeapFree(GetProcessHeap(), 0, store);
2934 LeaveCriticalSection(&collection->cs);
2937 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
2938 CRYPT_ATTRIBUTE rgAttr[])
2940 PCRYPT_ATTRIBUTE ret = NULL;
2943 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
2949 SetLastError(ERROR_INVALID_PARAMETER);
2953 for (i = 0; !ret && i < cAttr; i++)
2954 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
2959 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2960 CERT_EXTENSION rgExtensions[])
2962 PCERT_EXTENSION ret = NULL;
2965 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2971 SetLastError(ERROR_INVALID_PARAMETER);
2975 for (i = 0; !ret && i < cExtensions; i++)
2976 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
2977 rgExtensions[i].pszObjId))
2978 ret = &rgExtensions[i];
2982 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2984 PCERT_RDN_ATTR ret = NULL;
2987 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2991 SetLastError(ERROR_INVALID_PARAMETER);
2995 for (i = 0; !ret && i < pName->cRDN; i++)
2996 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2997 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2998 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2999 ret = &pName->rgRDN[i].rgRDNAttr[j];
3003 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3004 PCERT_INFO pCertInfo)
3013 GetSystemTime(&sysTime);
3014 SystemTimeToFileTime(&sysTime, &fileTime);
3015 pTimeToVerify = &fileTime;
3017 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3019 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3026 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3027 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3028 DWORD *pcbComputedHash)
3031 HCRYPTHASH hHash = 0;
3033 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3034 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3037 hCryptProv = CRYPT_GetDefaultProvider();
3042 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3045 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3047 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3048 pcbComputedHash, 0);
3049 CryptDestroyHash(hHash);