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.
35 #include "wine/debug.h"
36 #include "wine/list.h"
38 #include "wine/exception.h"
39 #include "crypt32_private.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
43 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
44 /* The following aren't defined in wincrypt.h, as they're "reserved" */
45 #define CERT_CERT_PROP_ID 32
46 #define CERT_CRL_PROP_ID 33
47 #define CERT_CTL_PROP_ID 34
49 /* Some typedefs that make it easier to abstract which type of context we're
52 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
53 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
54 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
55 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
56 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
57 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
58 DWORD dwAddDisposition, const void **ppContext);
59 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
60 const void *pPrevContext);
61 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
62 DWORD dwPropID, void *pvData, DWORD *pcbData);
63 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
64 DWORD dwPropID, DWORD dwFlags, const void *pvData);
65 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
66 BYTE *pbElement, DWORD *pcbElement);
67 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
68 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
70 /* An abstract context (certificate, CRL, or CTL) interface */
71 typedef struct _WINE_CONTEXT_INTERFACE
73 CreateContextFunc create;
74 AddContextToStoreFunc addContextToStore;
75 AddEncodedContextToStoreFunc addEncodedToStore;
76 EnumContextsInStoreFunc enumContextsInStore;
77 GetContextPropertyFunc getProp;
78 SetContextPropertyFunc setProp;
79 SerializeElementFunc serialize;
81 DeleteContextFunc deleteFromStore;
82 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
84 static const WINE_CONTEXT_INTERFACE gCertInterface = {
85 (CreateContextFunc)CertCreateCertificateContext,
86 (AddContextToStoreFunc)CertAddCertificateContextToStore,
87 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
88 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
89 (GetContextPropertyFunc)CertGetCertificateContextProperty,
90 (SetContextPropertyFunc)CertSetCertificateContextProperty,
91 (SerializeElementFunc)CertSerializeCertificateStoreElement,
92 (FreeContextFunc)CertFreeCertificateContext,
93 (DeleteContextFunc)CertDeleteCertificateFromStore,
96 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
97 (CreateContextFunc)CertCreateCRLContext,
98 (AddContextToStoreFunc)CertAddCRLContextToStore,
99 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
100 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
101 (GetContextPropertyFunc)CertGetCRLContextProperty,
102 (SetContextPropertyFunc)CertSetCRLContextProperty,
103 (SerializeElementFunc)CertSerializeCRLStoreElement,
104 (FreeContextFunc)CertFreeCRLContext,
105 (DeleteContextFunc)CertDeleteCRLFromStore,
108 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
109 (CreateContextFunc)CertCreateCTLContext,
110 (AddContextToStoreFunc)CertAddCTLContextToStore,
111 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
112 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
113 (GetContextPropertyFunc)CertGetCTLContextProperty,
114 (SetContextPropertyFunc)CertSetCTLContextProperty,
115 (SerializeElementFunc)CertSerializeCTLStoreElement,
116 (FreeContextFunc)CertFreeCTLContext,
117 (DeleteContextFunc)CertDeleteCTLFromStore,
120 struct WINE_CRYPTCERTSTORE;
122 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
123 DWORD dwFlags, const void *pvPara);
125 struct _WINE_CERT_CONTEXT_REF;
127 /* Called to enumerate the next certificate in a store. The returned pointer
128 * must be newly allocated (via HeapAlloc): CertFreeCertificateContext frees
131 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
132 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
134 struct _WINE_CERT_CONTEXT;
136 /* Called to create a new reference to an existing cert context. Should call
137 * CRYPT_InitCertRef to make sure the reference count is properly updated.
138 * If the store does not provide any additional allocated data (that is, does
139 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
142 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
143 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
145 /* Optional, called when a cert context reference is being freed. Don't free
146 * the ref pointer itself, CertFreeCertificateContext does that.
148 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
150 typedef enum _CertStoreType {
157 /* A cert store is polymorphic through the use of function pointers. A type
158 * is still needed to distinguish collection stores from other types.
159 * On the function pointers:
160 * - closeStore is called when the store's ref count becomes 0
161 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
162 * - control is optional, but should be implemented by any store that supports
165 typedef struct WINE_CRYPTCERTSTORE
170 HCRYPTPROV cryptProv;
172 PFN_CERT_STORE_PROV_CLOSE closeStore;
173 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
174 CreateRefFunc createCertRef;
175 EnumCertFunc enumCert;
176 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
177 FreeCertFunc freeCert; /* optional */
178 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
179 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
181 /* A certificate context has pointers to data that are owned by this module,
182 * so rather than duplicate the data every time a certificate context is
183 * copied, I keep a reference count to the data. Thus I have two data
184 * structures, the "true" certificate context (that has the reference count)
185 * and a reference certificate context, that has a pointer to the true context.
186 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
187 * with the reference version.
189 typedef struct _WINE_CERT_CONTEXT
194 struct list extendedProperties;
195 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
197 typedef struct _WINE_CERT_CONTEXT_REF
200 WINE_CERT_CONTEXT *context;
201 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
203 /* An extended certificate property in serialized form is prefixed by this
206 typedef struct _WINE_CERT_PROP_HEADER
209 DWORD unknown; /* always 1 */
211 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
213 /* Stores an extended property in a cert. */
214 typedef struct _WINE_CERT_PROPERTY
216 WINE_CERT_PROP_HEADER hdr;
219 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
221 /* A mem store has a list of these. They're also returned by the mem store
222 * during enumeration.
224 typedef struct _WINE_CERT_LIST_ENTRY
226 WINE_CERT_CONTEXT_REF cert;
228 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
230 typedef struct _WINE_MEMSTORE
232 WINECRYPT_CERTSTORE hdr;
235 } WINE_MEMSTORE, *PWINE_MEMSTORE;
237 typedef struct _WINE_STORE_LIST_ENTRY
239 PWINECRYPT_CERTSTORE store;
243 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
245 /* Returned by a collection store during enumeration.
246 * Note: relies on the list entry being valid after use, which a number of
247 * conditions might make untrue (reentrancy, closing a collection store before
248 * continuing an enumeration on it, ...). The tests seem to indicate this
249 * sort of unsafety is okay, since Windows isn't well-behaved in these
252 typedef struct _WINE_COLLECTION_CERT_CONTEXT
254 WINE_CERT_CONTEXT_REF cert;
255 PWINE_STORE_LIST_ENTRY entry;
256 PWINE_CERT_CONTEXT_REF childContext;
257 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
259 typedef struct _WINE_COLLECTIONSTORE
261 WINECRYPT_CERTSTORE hdr;
264 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
266 /* Like CertGetCertificateContextProperty, but operates directly on the
267 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
268 * are handled by CertGetCertificateContextProperty, and are particular to the
269 * store in which the property exists (which is separate from the context.)
271 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
272 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
274 /* Like CertSetCertificateContextProperty, but operates directly on the
275 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
276 * CertSetCertificateContextProperty anyway.
278 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
279 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
281 /* Helper function for store reading functions and
282 * CertAddSerializedElementToStore. Returns a context of the appropriate type
283 * if it can, or NULL otherwise. Doesn't validate any of the properties in
284 * the serialized context (for example, bad hashes are retained.)
285 * *pdwContentType is set to the type of the returned context.
287 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
288 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
290 /* filter for page-fault exceptions */
291 static WINE_EXCEPTION_FILTER(page_fault)
293 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
294 return EXCEPTION_EXECUTE_HANDLER;
295 return EXCEPTION_CONTINUE_SEARCH;
298 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
299 DWORD dwFlags, CertStoreType type)
302 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
306 hCryptProv = CRYPT_GetDefaultProvider();
307 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
309 store->cryptProv = hCryptProv;
310 store->dwOpenFlags = dwFlags;
313 /* Initializes the reference ref to point to pCertContext, which is assumed to
314 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
315 * Also sets the hCertStore member of the reference to store.
317 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
318 PWINE_CERT_CONTEXT context, HCERTSTORE store)
320 TRACE("(%p, %p)\n", ref, context);
321 memcpy(&ref->cert, context, sizeof(ref->cert));
322 ref->context = context;
323 InterlockedIncrement(&context->ref);
324 ref->cert.hCertStore = store;
327 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
330 PWINE_CERT_CONTEXT_REF pCertRef = HeapAlloc(GetProcessHeap(), 0,
331 sizeof(WINE_CERT_CONTEXT_REF));
334 CRYPT_InitCertRef(pCertRef, context, store);
338 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
339 DWORD dwAddDisposition)
341 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
342 BOOL add = FALSE, ret;
344 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
346 switch (dwAddDisposition)
348 case CERT_STORE_ADD_ALWAYS:
351 case CERT_STORE_ADD_NEW:
353 BYTE hashToAdd[20], hash[20];
354 DWORD size = sizeof(hashToAdd);
356 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
357 CERT_HASH_PROP_ID, hashToAdd, &size);
360 PWINE_CERT_LIST_ENTRY cursor;
362 /* Add if no cert with the same hash is found. */
364 EnterCriticalSection(&ms->cs);
365 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
368 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
369 CERT_HASH_PROP_ID, hash, &size);
370 if (ret && !memcmp(hashToAdd, hash, size))
372 TRACE("found matching certificate, not adding\n");
373 SetLastError(CRYPT_E_EXISTS);
378 LeaveCriticalSection(&ms->cs);
382 case CERT_STORE_ADD_REPLACE_EXISTING:
384 BYTE hashToAdd[20], hash[20];
385 DWORD size = sizeof(hashToAdd);
388 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
389 CERT_HASH_PROP_ID, hashToAdd, &size);
392 PWINE_CERT_LIST_ENTRY cursor, next;
394 /* Look for existing cert to delete */
395 EnterCriticalSection(&ms->cs);
396 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
397 WINE_CERT_LIST_ENTRY, entry)
400 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
401 CERT_HASH_PROP_ID, hash, &size);
402 if (ret && !memcmp(hashToAdd, hash, size))
404 TRACE("found matching certificate, replacing\n");
405 list_remove(&cursor->entry);
406 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
410 LeaveCriticalSection(&ms->cs);
415 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
420 PWINE_CERT_LIST_ENTRY entry = HeapAlloc(GetProcessHeap(), 0,
421 sizeof(WINE_CERT_LIST_ENTRY));
425 TRACE("adding %p\n", entry);
426 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
427 list_init(&entry->entry);
428 EnterCriticalSection(&ms->cs);
429 list_add_tail(&ms->certs, &entry->entry);
430 LeaveCriticalSection(&ms->cs);
441 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
442 PWINE_CERT_CONTEXT_REF pPrev)
444 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
445 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
446 struct list *listNext;
448 TRACE("(%p, %p)\n", store, pPrev);
449 EnterCriticalSection(&ms->cs);
452 listNext = list_next(&ms->certs, &prevEntry->entry);
453 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
456 listNext = list_next(&ms->certs, &ms->certs);
459 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY));
460 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
461 sizeof(WINE_CERT_LIST_ENTRY));
462 InterlockedIncrement(&ret->cert.context->ref);
466 SetLastError(CRYPT_E_NOT_FOUND);
469 LeaveCriticalSection(&ms->cs);
471 TRACE("returning %p\n", ret);
472 return (PWINE_CERT_CONTEXT_REF)ret;
475 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
476 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
478 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
479 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
480 PWINE_CERT_LIST_ENTRY cert, next;
483 /* Find the entry associated with the passed-in context, since the
484 * passed-in context may not be a list entry itself (e.g. if it came from
485 * CertDuplicateCertificateContext.) Pointing to the same context is
486 * a sufficient test of equality.
488 EnterCriticalSection(&store->cs);
489 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
492 if (cert->cert.context == ref->context)
494 TRACE("removing %p\n", cert);
495 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
498 list_remove(&cert->entry);
499 cert->entry.prev = cert->entry.next = &store->certs;
500 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
505 LeaveCriticalSection(&store->cs);
509 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
511 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
512 PWINE_CERT_LIST_ENTRY cert, next;
514 TRACE("(%p, %08lx)\n", store, dwFlags);
516 FIXME("Unimplemented flags: %08lx\n", dwFlags);
518 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
519 * pointer if its ref-count reaches zero. That's okay here because there
520 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
521 * of the CertListEntry.
523 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
526 TRACE("removing %p\n", cert);
527 list_remove(&cert->entry);
528 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
530 DeleteCriticalSection(&store->cs);
531 HeapFree(GetProcessHeap(), 0, store);
534 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
535 DWORD dwFlags, const void *pvPara)
537 PWINE_MEMSTORE store;
539 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
541 if (dwFlags & CERT_STORE_DELETE_FLAG)
543 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
548 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
549 sizeof(WINE_MEMSTORE));
552 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
553 store->hdr.closeStore = CRYPT_MemCloseStore;
554 store->hdr.addCert = CRYPT_MemAddCert;
555 store->hdr.createCertRef = CRYPT_CreateCertRef;
556 store->hdr.enumCert = CRYPT_MemEnumCert;
557 store->hdr.deleteCert = CRYPT_MemDeleteCert;
558 store->hdr.freeCert = NULL;
559 InitializeCriticalSection(&store->cs);
560 list_init(&store->certs);
563 return (PWINECRYPT_CERTSTORE)store;
566 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
567 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
569 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
570 PWINE_STORE_LIST_ENTRY entry, next;
573 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
576 EnterCriticalSection(&cs->cs);
577 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
580 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
582 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
586 LeaveCriticalSection(&cs->cs);
587 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
591 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
592 PWINE_CERT_CONTEXT context, HCERTSTORE store)
594 PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
595 sizeof(WINE_COLLECTION_CERT_CONTEXT));
599 /* Initialize to empty for now, just make sure the size is right */
600 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
602 ret->childContext = NULL;
604 return (PWINE_CERT_CONTEXT_REF)ret;
607 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
609 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
610 PWINE_STORE_LIST_ENTRY entry, next;
612 TRACE("(%p, %08lx)\n", store, dwFlags);
614 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
617 TRACE("closing %p\n", entry);
618 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
619 HeapFree(GetProcessHeap(), 0, entry);
621 DeleteCriticalSection(&cs->cs);
622 HeapFree(GetProcessHeap(), 0, cs);
625 /* Advances a collection enumeration by one cert, if possible, where advancing
627 * - calling the current store's enumeration function once, and returning
628 * the enumerated cert if one is returned
629 * - moving to the next store if the current store has no more items, and
630 * recursively calling itself to get the next item.
631 * Returns NULL if the collection contains no more items or on error.
632 * Assumes the collection store's lock is held.
634 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
635 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
636 PWINE_COLLECTION_CERT_CONTEXT pPrev)
638 PWINE_COLLECTION_CERT_CONTEXT ret;
639 PWINE_CERT_CONTEXT_REF child;
641 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
645 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
646 pPrev->childContext);
650 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
651 ret->cert.cert.hCertStore = (HCERTSTORE)store;
652 InterlockedIncrement(&ret->cert.context->ref);
653 ret->childContext = child;
657 struct list *storeNext = list_next(&store->stores,
660 pPrev->childContext = NULL;
661 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
664 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
666 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
670 SetLastError(CRYPT_E_NOT_FOUND);
677 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
681 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
682 child->context, store);
685 ret->entry = storeEntry;
686 ret->childContext = child;
689 CertFreeCertificateContext((PCCERT_CONTEXT)child);
693 struct list *storeNext = list_next(&store->stores,
698 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
700 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
704 SetLastError(CRYPT_E_NOT_FOUND);
709 TRACE("returning %p\n", ret);
713 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
714 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
716 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
717 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
718 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
720 TRACE("(%p, %p)\n", store, pPrev);
724 EnterCriticalSection(&cs->cs);
725 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
726 LeaveCriticalSection(&cs->cs);
730 EnterCriticalSection(&cs->cs);
731 if (!list_empty(&cs->stores))
733 PWINE_STORE_LIST_ENTRY storeEntry;
735 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
737 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
741 SetLastError(CRYPT_E_NOT_FOUND);
744 LeaveCriticalSection(&cs->cs);
746 TRACE("returning %p\n", ret);
747 return (PWINE_CERT_CONTEXT_REF)ret;
750 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
751 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
753 PWINE_COLLECTION_CERT_CONTEXT context =
754 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
757 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
759 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
762 context->childContext = NULL;
763 CertFreeCertificateContext((PCCERT_CONTEXT)context);
768 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
770 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
772 TRACE("(%p)\n", ref);
774 if (context->childContext)
775 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
778 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
779 DWORD dwFlags, const void *pvPara)
781 PWINE_COLLECTIONSTORE store;
783 if (dwFlags & CERT_STORE_DELETE_FLAG)
785 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
790 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
791 sizeof(WINE_COLLECTIONSTORE));
794 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
795 StoreTypeCollection);
796 store->hdr.closeStore = CRYPT_CollectionCloseStore;
797 store->hdr.addCert = CRYPT_CollectionAddCert;
798 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
799 store->hdr.enumCert = CRYPT_CollectionEnumCert;
800 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
801 store->hdr.freeCert = CRYPT_CollectionFreeCert;
802 InitializeCriticalSection(&store->cs);
803 list_init(&store->stores);
806 return (PWINECRYPT_CERTSTORE)store;
809 static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
811 HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore);
814 static BOOL WINAPI CRYPT_DummyAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
815 DWORD dwAddDisposition)
820 static PWINE_CERT_CONTEXT_REF CRYPT_DummyEnumCert(PWINECRYPT_CERTSTORE store,
821 PWINE_CERT_CONTEXT_REF pPrev)
826 static BOOL WINAPI CRYPT_DummyDeleteCert(HCERTSTORE hCertStore,
827 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
832 static WINECRYPT_CERTSTORE *CRYPT_DummyOpenStore(HCRYPTPROV hCryptProv,
833 DWORD dwFlags, const void *pvPara)
835 PWINECRYPT_CERTSTORE store;
837 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
839 if (dwFlags & CERT_STORE_DELETE_FLAG)
841 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
846 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
847 sizeof(WINECRYPT_CERTSTORE));
850 CRYPT_InitStore(store, hCryptProv, dwFlags, StoreTypeDummy);
851 store->closeStore = CRYPT_DummyCloseStore;
852 store->addCert = CRYPT_DummyAddCert;
853 store->createCertRef = CRYPT_CreateCertRef;
854 store->enumCert = CRYPT_DummyEnumCert;
855 store->deleteCert = CRYPT_DummyDeleteCert;
856 store->freeCert = NULL;
859 return (PWINECRYPT_CERTSTORE)store;
863 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
864 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
867 WINECRYPT_CERTSTORE *hcs;
868 StoreOpenFunc openFunc = NULL;
870 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
871 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
873 if (!HIWORD(lpszStoreProvider))
875 switch (LOWORD(lpszStoreProvider))
877 case (int)CERT_STORE_PROV_MEMORY:
878 openFunc = CRYPT_MemOpenStore;
880 case (int)CERT_STORE_PROV_COLLECTION:
881 openFunc = CRYPT_CollectionOpenStore;
883 case (int)CERT_STORE_PROV_REG:
884 case (int)CERT_STORE_PROV_SYSTEM_A:
885 case (int)CERT_STORE_PROV_SYSTEM_W:
886 openFunc = CRYPT_DummyOpenStore;
889 if (LOWORD(lpszStoreProvider))
890 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
893 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
894 openFunc = CRYPT_MemOpenStore;
895 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
896 openFunc = CRYPT_DummyOpenStore;
897 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
898 openFunc = CRYPT_CollectionOpenStore;
901 FIXME("unimplemented type %s\n", lpszStoreProvider);
907 /* FIXME: need to look for an installed provider for this type */
908 SetLastError(ERROR_FILE_NOT_FOUND);
912 hcs = openFunc(hCryptProv, dwFlags, pvPara);
913 return (HCERTSTORE)hcs;
916 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
917 LPCSTR szSubSystemProtocol)
919 return CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, 0,
920 CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
921 CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
924 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
925 LPCWSTR szSubSystemProtocol)
927 return CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, 0,
928 CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
929 CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
932 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
933 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
935 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
936 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
940 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
941 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
946 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
948 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
949 pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
953 data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
956 HeapFree( GetProcessHeap(), 0, pcrl );
960 pcrl->dwCertEncodingType = dwCertEncodingType;
961 pcrl->pbCrlEncoded = data;
962 pcrl->cbCrlEncoded = cbCrlEncoded;
963 pcrl->pCrlInfo = NULL;
964 pcrl->hCertStore = 0;
969 /* Decodes the encoded certificate and creates the certificate context for it.
970 * The reference count is initially zero, so you must create a reference to it
971 * to avoid leaking memory.
973 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
974 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
976 PWINE_CERT_CONTEXT cert = NULL;
978 PCERT_INFO certInfo = NULL;
981 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
984 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
985 pbCertEncoded, cbCertEncoded,
986 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
987 (BYTE *)&certInfo, &size);
992 cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
995 data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
998 HeapFree(GetProcessHeap(), 0, cert);
1002 memcpy(data, pbCertEncoded, cbCertEncoded);
1003 cert->cert.dwCertEncodingType = dwCertEncodingType;
1004 cert->cert.pbCertEncoded = data;
1005 cert->cert.cbCertEncoded = cbCertEncoded;
1006 cert->cert.pCertInfo = certInfo;
1007 cert->cert.hCertStore = 0;
1009 InitializeCriticalSection(&cert->cs);
1010 list_init(&cert->extendedProperties);
1017 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1019 PWINE_CERT_PROPERTY prop, next;
1021 HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
1022 LocalFree(context->cert.pCertInfo);
1023 HeapFree(GetProcessHeap(), 0, context);
1024 DeleteCriticalSection(&context->cs);
1025 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1026 WINE_CERT_PROPERTY, entry)
1028 list_remove(&prop->entry);
1029 HeapFree(GetProcessHeap(), 0, prop->pbData);
1030 HeapFree(GetProcessHeap(), 0, prop);
1034 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1035 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1037 PWINE_CERT_CONTEXT cert;
1038 PWINE_CERT_CONTEXT_REF ret = NULL;
1040 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1043 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1046 ret = CRYPT_CreateCertRef(cert, 0);
1047 return (PCCERT_CONTEXT)ret;
1050 /* Since the properties are stored in a list, this is a tad inefficient
1051 * (O(n^2)) since I have to find the previous position every time.
1053 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1056 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1059 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1061 EnterCriticalSection(&ref->context->cs);
1064 PWINE_CERT_PROPERTY cursor = NULL;
1066 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1067 WINE_CERT_PROPERTY, entry)
1069 if (cursor->hdr.propID == dwPropId)
1074 if (cursor->entry.next != &ref->context->extendedProperties)
1075 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1083 else if (!list_empty(&ref->context->extendedProperties))
1084 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1085 WINE_CERT_PROPERTY, entry)->hdr.propID;
1088 LeaveCriticalSection(&ref->context->cs);
1092 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1093 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1095 PWINE_CERT_PROPERTY prop;
1098 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1100 EnterCriticalSection(&context->cs);
1103 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1104 WINE_CERT_PROPERTY, entry)
1106 if (prop->hdr.propID == dwPropId)
1110 *pcbData = prop->hdr.cb;
1113 else if (*pcbData < prop->hdr.cb)
1115 SetLastError(ERROR_MORE_DATA);
1116 *pcbData = prop->hdr.cb;
1120 memcpy(pvData, prop->pbData, prop->hdr.cb);
1121 *pcbData = prop->hdr.cb;
1130 /* Implicit properties */
1133 case CERT_SHA1_HASH_PROP_ID:
1134 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1135 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1139 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1141 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1145 case CERT_KEY_PROV_INFO_PROP_ID:
1146 case CERT_MD5_HASH_PROP_ID:
1147 case CERT_SIGNATURE_HASH_PROP_ID:
1148 case CERT_KEY_IDENTIFIER_PROP_ID:
1149 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1150 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1151 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1152 FIXME("implicit property %ld\n", dwPropId);
1156 LeaveCriticalSection(&context->cs);
1157 TRACE("returning %d\n", ret);
1161 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1162 DWORD dwPropId, void *pvData, DWORD *pcbData)
1164 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1167 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1169 /* Special cases for invalid/special prop IDs.
1174 case CERT_CERT_PROP_ID:
1175 case CERT_CRL_PROP_ID:
1176 case CERT_CTL_PROP_ID:
1177 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1179 case CERT_ACCESS_STATE_PROP_ID:
1182 *pcbData = sizeof(DWORD);
1185 else if (*pcbData < sizeof(DWORD))
1187 SetLastError(ERROR_MORE_DATA);
1188 *pcbData = sizeof(DWORD);
1195 if (pCertContext->hCertStore)
1197 PWINECRYPT_CERTSTORE store =
1198 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1200 /* Take advantage of knowledge of the stores to answer the
1201 * access state question
1203 if (store->type != StoreTypeReg ||
1204 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1205 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1207 *(DWORD *)pvData = state;
1212 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
1214 TRACE("returning %d\n", ret);
1218 /* Copies cbData bytes from pbData to the context's property with ID
1221 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
1222 DWORD dwPropId, const BYTE *pbData, size_t cbData)
1229 data = HeapAlloc(GetProcessHeap(), 0, cbData);
1231 memcpy(data, pbData, cbData);
1235 if (!cbData || data)
1237 PWINE_CERT_PROPERTY prop;
1239 EnterCriticalSection(&context->cs);
1240 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1241 WINE_CERT_PROPERTY, entry)
1243 if (prop->hdr.propID == dwPropId)
1246 if (prop && prop->entry.next != &context->extendedProperties)
1248 HeapFree(GetProcessHeap(), 0, prop->pbData);
1249 prop->hdr.cb = cbData;
1250 prop->pbData = cbData ? data : NULL;
1255 prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
1258 prop->hdr.propID = dwPropId;
1259 prop->hdr.unknown = 1;
1260 prop->hdr.cb = cbData;
1261 list_init(&prop->entry);
1262 prop->pbData = cbData ? data : NULL;
1263 list_add_tail(&context->extendedProperties, &prop->entry);
1267 HeapFree(GetProcessHeap(), 0, data);
1269 LeaveCriticalSection(&context->cs);
1274 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
1275 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
1279 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
1283 PWINE_CERT_PROPERTY prop, next;
1285 EnterCriticalSection(&context->cs);
1286 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1287 WINE_CERT_PROPERTY, entry)
1289 if (prop->hdr.propID == dwPropId)
1291 list_remove(&prop->entry);
1292 HeapFree(GetProcessHeap(), 0, prop->pbData);
1293 HeapFree(GetProcessHeap(), 0, prop);
1296 LeaveCriticalSection(&context->cs);
1303 case CERT_AUTO_ENROLL_PROP_ID:
1304 case CERT_CTL_USAGE_PROP_ID:
1305 case CERT_DESCRIPTION_PROP_ID:
1306 case CERT_FRIENDLY_NAME_PROP_ID:
1307 case CERT_HASH_PROP_ID:
1308 case CERT_KEY_IDENTIFIER_PROP_ID:
1309 case CERT_MD5_HASH_PROP_ID:
1310 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
1311 case CERT_PUBKEY_ALG_PARA_PROP_ID:
1312 case CERT_PVK_FILE_PROP_ID:
1313 case CERT_SIGNATURE_HASH_PROP_ID:
1314 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
1315 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1316 case CERT_ENROLLMENT_PROP_ID:
1317 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
1318 case CERT_RENEWAL_PROP_ID:
1320 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
1322 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
1323 blob->pbData, blob->cbData);
1326 case CERT_DATE_STAMP_PROP_ID:
1327 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
1328 pvData, sizeof(FILETIME));
1331 FIXME("%ld: stub\n", dwPropId);
1334 TRACE("returning %d\n", ret);
1338 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1339 DWORD dwPropId, DWORD dwFlags, const void *pvData)
1341 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1344 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
1346 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
1347 * crashes on most of these, I'll be safer.
1352 case CERT_ACCESS_STATE_PROP_ID:
1353 case CERT_CERT_PROP_ID:
1354 case CERT_CRL_PROP_ID:
1355 case CERT_CTL_PROP_ID:
1356 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1359 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
1361 TRACE("returning %d\n", ret);
1365 /* Only the reference portion of the context is duplicated. The returned
1366 * context has the cert store set to 0, to prevent the store's certificate free
1367 * function from getting called on partial data.
1368 * FIXME: is this okay? Needs a test.
1370 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
1371 PCCERT_CONTEXT pCertContext)
1373 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
1375 TRACE("(%p)\n", pCertContext);
1378 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
1381 memcpy(ret, ref, sizeof(*ret));
1382 ret->cert.hCertStore = 0;
1383 InterlockedIncrement(&ret->context->ref);
1388 return (PCCERT_CONTEXT)ret;
1391 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
1392 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
1393 PCCERT_CONTEXT *ppStoreContext)
1395 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1396 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1397 PWINE_CERT_CONTEXT cert;
1400 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
1401 dwAddDisposition, ppStoreContext);
1403 /* FIXME: some tests needed to verify return codes */
1406 SetLastError(ERROR_INVALID_PARAMETER);
1409 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1411 SetLastError(ERROR_INVALID_PARAMETER);
1415 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
1416 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
1419 PWINE_CERT_PROPERTY prop;
1422 EnterCriticalSection(&ref->context->cs);
1423 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1424 WINE_CERT_PROPERTY, entry)
1426 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
1427 prop->pbData, prop->hdr.cb);
1431 LeaveCriticalSection(&ref->context->cs);
1434 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
1435 if (ret && ppStoreContext)
1436 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
1440 CRYPT_FreeCert(cert);
1447 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
1448 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
1449 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
1451 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1454 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
1455 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
1459 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1463 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
1464 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
1468 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
1469 if (ret && ppCertContext)
1470 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
1473 CRYPT_FreeCert(cert);
1481 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1482 PCCERT_CONTEXT pPrev)
1484 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1485 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
1488 TRACE("(%p, %p)\n", hCertStore, pPrev);
1491 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1494 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
1498 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1502 TRACE("(%p)\n", pCertContext);
1506 else if (!pCertContext->hCertStore)
1510 PWINECRYPT_CERTSTORE hcs =
1511 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1515 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1518 ret = hcs->deleteCert(hcs, pCertContext, 0);
1523 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
1524 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
1525 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
1527 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1528 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
1533 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
1534 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
1535 PCCRL_CONTEXT* ppStoreContext )
1537 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
1538 dwAddDisposition, ppStoreContext);
1542 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
1544 FIXME("%p\n", pCrlContext );
1549 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1551 FIXME("(%p): stub\n", pCrlContext);
1555 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1556 PCCRL_CONTEXT pPrev)
1558 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1562 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1563 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1565 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
1570 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1571 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1572 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1574 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1575 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1580 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1581 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1582 PCCTL_CONTEXT* ppStoreContext)
1584 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
1585 dwAddDisposition, ppStoreContext);
1589 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1591 FIXME("(%p): stub\n", pCtlContext );
1595 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1597 FIXME("(%p): stub\n", pCtlContext);
1601 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1602 PCCTL_CONTEXT pPrev)
1604 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1609 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1611 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1613 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
1618 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1621 if (InterlockedDecrement(&hcs->ref) == 0)
1623 TRACE("freeing %p\n", hcs);
1625 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
1626 CryptReleaseContext(hcs->cryptProv, 0);
1627 hcs->closeStore(hcs, dwFlags);
1630 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
1634 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1635 DWORD dwCtrlType, void const *pvCtrlPara)
1637 FIXME("(%p, %08lx, %ld, %p): stub\n", hCertStore, dwFlags, dwCtrlType,
1642 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1643 DWORD dwPropId, void *pvData, DWORD *pcbData)
1645 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
1649 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1650 DWORD dwPropId, DWORD dwFlags, const void *pvData)
1652 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
1657 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
1658 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1660 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
1665 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1666 DWORD dwPropId, void *pvData, DWORD *pcbData)
1668 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1672 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1673 DWORD dwPropId, DWORD dwFlags, const void *pvData)
1675 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1680 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
1681 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1683 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
1688 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
1689 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1693 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
1698 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1699 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
1700 pCertContext->cbCertEncoded;
1701 PWINE_CERT_PROPERTY prop;
1703 EnterCriticalSection(&ref->context->cs);
1704 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1705 WINE_CERT_PROPERTY, entry)
1706 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
1709 *pcbElement = bytesNeeded;
1712 else if (*pcbElement < bytesNeeded)
1714 *pcbElement = bytesNeeded;
1715 SetLastError(ERROR_MORE_DATA);
1720 PWINE_CERT_PROP_HEADER hdr;
1722 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1723 WINE_CERT_PROPERTY, entry)
1725 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
1726 pbElement += sizeof(WINE_CERT_PROP_HEADER);
1729 memcpy(pbElement, prop->pbData, prop->hdr.cb);
1730 pbElement += prop->hdr.cb;
1733 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
1734 hdr->propID = CERT_CERT_PROP_ID;
1736 hdr->cb = pCertContext->cbCertEncoded;
1737 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
1738 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
1741 LeaveCriticalSection(&ref->context->cs);
1748 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
1749 * to its header if a valid header is found, NULL if not. Valid means the
1750 * length of thte property won't overrun buf, and the unknown field is 1.
1752 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
1753 DWORD size, DWORD propID)
1755 const WINE_CERT_PROP_HEADER *ret = NULL;
1758 while (size && !ret && !done)
1760 if (size < sizeof(WINE_CERT_PROP_HEADER))
1762 SetLastError(CRYPT_E_FILE_ERROR);
1767 const WINE_CERT_PROP_HEADER *hdr =
1768 (const WINE_CERT_PROP_HEADER *)buf;
1770 size -= sizeof(WINE_CERT_PROP_HEADER);
1771 buf += sizeof(WINE_CERT_PROP_HEADER);
1774 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1777 else if (!hdr->propID)
1779 /* assume a zero prop ID means the data are uninitialized, so
1784 else if (hdr->unknown != 1)
1786 SetLastError(ERROR_FILE_NOT_FOUND);
1789 else if (hdr->propID == propID)
1801 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
1802 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
1804 const void *context = NULL;
1806 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
1811 SetLastError(ERROR_END_OF_MEDIA);
1817 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
1818 const WINE_CERT_PROP_HEADER *hdr = NULL;
1823 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
1825 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
1827 type = CERT_STORE_CERTIFICATE_CONTEXT;
1830 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
1832 type = CERT_STORE_CRL_CONTEXT;
1835 hdr = CRYPT_findPropID(pbElement, cbElement,
1838 type = CERT_STORE_CTL_CONTEXT;
1842 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
1844 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
1845 type = CERT_STORE_CERTIFICATE_CONTEXT;
1847 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
1849 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
1850 type = CERT_STORE_CRL_CONTEXT;
1852 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
1854 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
1855 type = CERT_STORE_CTL_CONTEXT;
1860 case CERT_STORE_CERTIFICATE_CONTEXT:
1861 contextInterface = &gCertInterface;
1863 case CERT_STORE_CRL_CONTEXT:
1864 contextInterface = &gCRLInterface;
1866 case CERT_STORE_CTL_CONTEXT:
1867 contextInterface = &gCTLInterface;
1870 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1877 context = contextInterface->create(X509_ASN_ENCODING,
1878 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
1881 BOOL noMoreProps = FALSE;
1883 while (!noMoreProps && ret)
1885 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
1889 const WINE_CERT_PROP_HEADER *hdr =
1890 (const WINE_CERT_PROP_HEADER *)pbElement;
1892 TRACE("prop is %ld\n", hdr->propID);
1893 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
1894 pbElement += sizeof(WINE_CERT_PROP_HEADER);
1895 if (cbElement < hdr->cb)
1897 SetLastError(HRESULT_FROM_WIN32(
1898 ERROR_INVALID_PARAMETER));
1901 else if (!hdr->propID)
1903 /* Like in CRYPT_findPropID, stop if the propID is zero
1907 else if (hdr->unknown != 1)
1909 SetLastError(ERROR_FILE_NOT_FOUND);
1912 else if (hdr->propID != CERT_CERT_PROP_ID &&
1913 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
1916 /* Have to create a blob for most types, but not
1919 switch (hdr->propID)
1921 case CERT_AUTO_ENROLL_PROP_ID:
1922 case CERT_CTL_USAGE_PROP_ID:
1923 case CERT_DESCRIPTION_PROP_ID:
1924 case CERT_FRIENDLY_NAME_PROP_ID:
1925 case CERT_HASH_PROP_ID:
1926 case CERT_KEY_IDENTIFIER_PROP_ID:
1927 case CERT_MD5_HASH_PROP_ID:
1928 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
1929 case CERT_PUBKEY_ALG_PARA_PROP_ID:
1930 case CERT_PVK_FILE_PROP_ID:
1931 case CERT_SIGNATURE_HASH_PROP_ID:
1932 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
1933 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1934 case CERT_ENROLLMENT_PROP_ID:
1935 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
1936 case CERT_RENEWAL_PROP_ID:
1938 CRYPT_DATA_BLOB blob = { hdr->cb,
1939 (LPBYTE)pbElement };
1941 ret = contextInterface->setProp(context,
1942 hdr->propID, 0, &blob);
1945 case CERT_DATE_STAMP_PROP_ID:
1946 ret = contextInterface->setProp(context,
1947 hdr->propID, 0, pbElement);
1950 FIXME("prop ID %ld: stub\n", hdr->propID);
1953 pbElement += hdr->cb;
1954 cbElement -= hdr->cb;
1962 *pdwContentType = type;
1966 contextInterface->free(context);
1971 __EXCEPT(page_fault)
1973 SetLastError(STATUS_ACCESS_VIOLATION);
1980 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
1981 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
1982 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
1984 const void *context;
1988 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
1989 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
1990 pdwContentType, ppvContext);
1992 /* Call the internal function, then delete the hashes. Tests show this
1993 * function uses real hash values, not whatever's stored in the hash
1996 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
1997 dwContextTypeFlags, &type);
2000 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2004 case CERT_STORE_CERTIFICATE_CONTEXT:
2005 contextInterface = &gCertInterface;
2007 case CERT_STORE_CRL_CONTEXT:
2008 contextInterface = &gCRLInterface;
2010 case CERT_STORE_CTL_CONTEXT:
2011 contextInterface = &gCTLInterface;
2014 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2016 if (contextInterface)
2018 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2019 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2020 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2023 *pdwContentType = type;
2024 ret = contextInterface->addContextToStore(hCertStore, context,
2025 dwAddDisposition, ppvContext);
2026 contextInterface->free(context);
2036 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2038 TRACE("(%p)\n", pCertContext);
2042 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2043 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2045 if (InterlockedDecrement(&ref->context->ref) == 0)
2047 TRACE("freeing %p\n", ref->context);
2048 CRYPT_FreeCert(ref->context);
2051 TRACE("%p's ref count is %ld\n", ref->context,
2053 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2055 store->freeCert(ref);
2056 HeapFree(GetProcessHeap(), 0, ref);
2061 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2062 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2063 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2065 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2066 dwFlags, dwType, pvPara, pPrevCertContext);
2067 SetLastError(CRYPT_E_NOT_FOUND);
2071 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2072 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2074 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2075 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2076 PWINE_STORE_LIST_ENTRY entry;
2079 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2080 dwUpdateFlags, dwPriority);
2082 if (!collection || !sibling)
2084 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2086 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2089 if (collection->hdr.type != StoreTypeCollection)
2091 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2094 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2096 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2100 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
2103 InterlockedIncrement(&sibling->ref);
2104 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2105 entry->store = sibling;
2106 entry->dwUpdateFlags = dwUpdateFlags;
2107 entry->dwPriority = dwPriority;
2108 list_init(&entry->entry);
2109 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2110 EnterCriticalSection(&collection->cs);
2113 PWINE_STORE_LIST_ENTRY cursor;
2116 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2117 WINE_STORE_LIST_ENTRY, entry)
2119 if (cursor->dwPriority < dwPriority)
2121 list_add_before(&cursor->entry, &entry->entry);
2127 list_add_tail(&collection->stores, &entry->entry);
2130 list_add_tail(&collection->stores, &entry->entry);
2131 LeaveCriticalSection(&collection->cs);
2139 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2140 HCERTSTORE hSiblingStore)
2142 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2143 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2144 PWINE_STORE_LIST_ENTRY store, next;
2146 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2148 if (!collection || !sibling)
2150 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2152 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2155 if (collection->hdr.type != StoreTypeCollection)
2157 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2159 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2162 EnterCriticalSection(&collection->cs);
2163 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2164 WINE_STORE_LIST_ENTRY, entry)
2166 if (store->store == sibling)
2168 list_remove(&store->entry);
2169 CertCloseStore(store->store, 0);
2170 HeapFree(GetProcessHeap(), 0, store);
2174 LeaveCriticalSection(&collection->cs);
2177 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
2178 CRYPT_ATTRIBUTE rgAttr[])
2180 PCRYPT_ATTRIBUTE ret = NULL;
2183 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
2189 SetLastError(ERROR_INVALID_PARAMETER);
2193 for (i = 0; !ret && i < cAttr; i++)
2194 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
2199 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2200 CERT_EXTENSION rgExtensions[])
2202 PCERT_EXTENSION ret = NULL;
2205 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2211 SetLastError(ERROR_INVALID_PARAMETER);
2215 for (i = 0; !ret && i < cExtensions; i++)
2216 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
2217 rgExtensions[i].pszObjId))
2218 ret = &rgExtensions[i];
2222 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2224 PCERT_RDN_ATTR ret = NULL;
2227 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2231 SetLastError(ERROR_INVALID_PARAMETER);
2235 for (i = 0; !ret && i < pName->cRDN; i++)
2236 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2237 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2238 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2239 ret = &pName->rgRDN[i].rgRDNAttr[j];
2243 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2244 PCERT_INFO pCertInfo)
2253 GetSystemTime(&sysTime);
2254 SystemTimeToFileTime(&sysTime, &fileTime);
2255 pTimeToVerify = &fileTime;
2257 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2259 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2266 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
2267 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2268 DWORD *pcbComputedHash)
2271 HCRYPTHASH hHash = 0;
2273 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
2274 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2277 hCryptProv = CRYPT_GetDefaultProvider();
2282 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2285 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2287 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2288 pcbComputedHash, 0);
2289 CryptDestroyHash(hHash);