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 CryptMemAlloc): CertFreeCertificateContext
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 = CryptMemAlloc(
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 = CryptMemAlloc(
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 = CryptMemAlloc(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;
530 LeaveCriticalSection(&store->cs);
534 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
536 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
537 PWINE_CERT_LIST_ENTRY cert, next;
539 TRACE("(%p, %08lx)\n", store, dwFlags);
541 FIXME("Unimplemented flags: %08lx\n", dwFlags);
543 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
544 * pointer if its ref-count reaches zero. That's okay here because there
545 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
546 * of the CertListEntry.
548 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
551 TRACE("removing %p\n", cert);
552 list_remove(&cert->entry);
553 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
555 DeleteCriticalSection(&store->cs);
559 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
560 DWORD dwFlags, const void *pvPara)
562 PWINE_MEMSTORE store;
564 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
566 if (dwFlags & CERT_STORE_DELETE_FLAG)
568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
573 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
576 memset(store, 0, sizeof(WINE_MEMSTORE));
577 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
578 store->hdr.closeStore = CRYPT_MemCloseStore;
579 store->hdr.addCert = CRYPT_MemAddCert;
580 store->hdr.createCertRef = CRYPT_CreateCertRef;
581 store->hdr.enumCert = CRYPT_MemEnumCert;
582 store->hdr.deleteCert = CRYPT_MemDeleteCert;
583 store->hdr.freeCert = NULL;
584 InitializeCriticalSection(&store->cs);
585 list_init(&store->certs);
588 return (PWINECRYPT_CERTSTORE)store;
591 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
592 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
594 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
595 PWINE_STORE_LIST_ENTRY entry, next;
598 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
601 EnterCriticalSection(&cs->cs);
602 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
605 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
607 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
611 LeaveCriticalSection(&cs->cs);
612 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
616 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
617 PWINE_CERT_CONTEXT context, HCERTSTORE store)
619 PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
620 sizeof(WINE_COLLECTION_CERT_CONTEXT));
624 /* Initialize to empty for now, just make sure the size is right */
625 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
627 ret->childContext = NULL;
629 return (PWINE_CERT_CONTEXT_REF)ret;
632 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
634 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
635 PWINE_STORE_LIST_ENTRY entry, next;
637 TRACE("(%p, %08lx)\n", store, dwFlags);
639 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
642 TRACE("closing %p\n", entry);
643 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
646 DeleteCriticalSection(&cs->cs);
650 /* Advances a collection enumeration by one cert, if possible, where advancing
652 * - calling the current store's enumeration function once, and returning
653 * the enumerated cert if one is returned
654 * - moving to the next store if the current store has no more items, and
655 * recursively calling itself to get the next item.
656 * Returns NULL if the collection contains no more items or on error.
657 * Assumes the collection store's lock is held.
659 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
660 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
661 PWINE_COLLECTION_CERT_CONTEXT pPrev)
663 PWINE_COLLECTION_CERT_CONTEXT ret;
664 PWINE_CERT_CONTEXT_REF child;
666 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
670 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
671 pPrev->childContext);
675 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
676 ret->cert.cert.hCertStore = (HCERTSTORE)store;
677 InterlockedIncrement(&ret->cert.context->ref);
678 ret->childContext = child;
682 struct list *storeNext = list_next(&store->stores,
685 pPrev->childContext = NULL;
686 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
689 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
691 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
695 SetLastError(CRYPT_E_NOT_FOUND);
702 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
706 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
707 child->context, store);
710 ret->entry = storeEntry;
711 ret->childContext = child;
714 CertFreeCertificateContext((PCCERT_CONTEXT)child);
718 struct list *storeNext = list_next(&store->stores,
723 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
725 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
729 SetLastError(CRYPT_E_NOT_FOUND);
734 TRACE("returning %p\n", ret);
738 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
739 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
741 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
742 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
743 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
745 TRACE("(%p, %p)\n", store, pPrev);
749 EnterCriticalSection(&cs->cs);
750 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
751 LeaveCriticalSection(&cs->cs);
755 EnterCriticalSection(&cs->cs);
756 if (!list_empty(&cs->stores))
758 PWINE_STORE_LIST_ENTRY storeEntry;
760 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
762 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
766 SetLastError(CRYPT_E_NOT_FOUND);
769 LeaveCriticalSection(&cs->cs);
771 TRACE("returning %p\n", ret);
772 return (PWINE_CERT_CONTEXT_REF)ret;
775 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
776 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
778 PWINE_COLLECTION_CERT_CONTEXT context =
779 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
782 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
784 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
786 context->childContext = NULL;
790 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
792 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
794 TRACE("(%p)\n", ref);
796 if (context->childContext)
797 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
800 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
801 DWORD dwFlags, const void *pvPara)
803 PWINE_COLLECTIONSTORE store;
805 if (dwFlags & CERT_STORE_DELETE_FLAG)
807 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
812 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
815 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
816 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
817 StoreTypeCollection);
818 store->hdr.closeStore = CRYPT_CollectionCloseStore;
819 store->hdr.addCert = CRYPT_CollectionAddCert;
820 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
821 store->hdr.enumCert = CRYPT_CollectionEnumCert;
822 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
823 store->hdr.freeCert = CRYPT_CollectionFreeCert;
824 InitializeCriticalSection(&store->cs);
825 list_init(&store->stores);
828 return (PWINECRYPT_CERTSTORE)store;
831 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
833 static const WCHAR fmt[] = { '%','0','2','X',0 };
839 for (i = 0; i < 20; i++)
840 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
843 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
845 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
846 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
847 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
849 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
854 WCHAR subKeyName[MAX_PATH];
857 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
859 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
865 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
871 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
873 buf = CryptMemAlloc(size);
876 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
883 TRACE("Adding cert with hash %s\n",
884 debugstr_w(subKeyName));
885 context = CRYPT_ReadSerializedElement(buf, size,
886 contextType, &addedType);
889 const WINE_CONTEXT_INTERFACE *contextInterface;
894 case CERT_STORE_CERTIFICATE_CONTEXT:
895 contextInterface = &gCertInterface;
897 case CERT_STORE_CRL_CONTEXT:
898 contextInterface = &gCRLInterface;
900 case CERT_STORE_CTL_CONTEXT:
901 contextInterface = &gCTLInterface;
904 contextInterface = NULL;
906 if (contextInterface)
909 if (contextInterface->getProp(context,
910 CERT_HASH_PROP_ID, hash, &size))
912 WCHAR asciiHash[20 * 2 + 1];
914 CRYPT_HashToStr(hash, asciiHash);
915 TRACE("comparing %s\n",
916 debugstr_w(asciiHash));
917 TRACE("with %s\n", debugstr_w(subKeyName));
918 if (!lstrcmpW(asciiHash, subKeyName))
920 TRACE("hash matches, adding\n");
921 contextInterface->addContextToStore(
923 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
927 TRACE("hash doesn't match, ignoring\n");
928 contextInterface->free(context);
938 /* Ignore intermediate errors, continue enumerating */
944 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
946 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
947 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
948 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
951 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
956 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
960 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
966 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
967 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
970 WCHAR asciiHash[20 * 2 + 1];
975 CRYPT_HashToStr(hash, asciiHash);
976 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
980 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
993 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
994 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
996 const void *context = NULL;
1000 context = contextInterface->enumContextsInStore(memStore, context);
1004 DWORD hashSize = sizeof(hash);
1006 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1013 ret = contextInterface->serialize(context, 0, NULL, &size);
1015 buf = CryptMemAlloc(size);
1018 ret = contextInterface->serialize(context, 0, buf, &size);
1020 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1027 } while (ret && context != NULL);
1029 contextInterface->free(context);
1033 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1035 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1036 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1037 &gCRLInterface, &gCTLInterface };
1038 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1042 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1045 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1046 KEY_ALL_ACCESS, NULL, &key, NULL);
1050 if (listToDelete[i])
1052 PWINE_HASH_TO_DELETE toDelete, next;
1053 WCHAR asciiHash[20 * 2 + 1];
1055 EnterCriticalSection(&store->cs);
1056 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1057 WINE_HASH_TO_DELETE, entry)
1061 CRYPT_HashToStr(toDelete->hash, asciiHash);
1062 TRACE("Removing %s\n", debugstr_w(asciiHash));
1063 rc = RegDeleteKeyW(key, asciiHash);
1064 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1069 list_remove(&toDelete->entry);
1070 CryptMemFree(toDelete);
1072 LeaveCriticalSection(&store->cs);
1074 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1087 /* If force is true or the registry store is dirty, writes the contents of the
1088 * store to the registry.
1090 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1094 if (store->dirty || force)
1095 ret = CRYPT_RegWriteToReg(store);
1101 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1103 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1105 TRACE("(%p, %08lx)\n", store, dwFlags);
1107 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1109 CRYPT_RegFlushStore(store, FALSE);
1110 /* certsToDelete should already be cleared by this point */
1111 store->memStore->closeStore(store->memStore, 0);
1112 RegCloseKey(store->key);
1113 DeleteCriticalSection(&store->cs);
1114 CryptMemFree(store);
1117 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1118 DWORD dwAddDisposition)
1120 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1123 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1125 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1127 SetLastError(ERROR_ACCESS_DENIED);
1132 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1134 store->dirty = TRUE;
1139 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1140 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1142 PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(
1143 sizeof(WINE_REG_CERT_CONTEXT));
1147 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1148 ret->childContext = NULL;
1150 return (PWINE_CERT_CONTEXT_REF)ret;
1153 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1154 PWINE_CERT_CONTEXT_REF pPrev)
1156 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1157 PWINE_CERT_CONTEXT_REF child;
1158 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1160 TRACE("(%p, %p)\n", store, pPrev);
1164 child = rs->memStore->enumCert(rs->memStore, prev->childContext);
1167 ret = (PWINE_REG_CERT_CONTEXT)pPrev;
1168 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1169 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1170 ret->childContext = child;
1175 child = rs->memStore->enumCert(rs->memStore, NULL);
1178 ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
1182 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1183 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1184 ret->childContext = child;
1187 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1190 return (PWINE_CERT_CONTEXT_REF)ret;
1193 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1194 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1196 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1199 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1201 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1203 SetLastError(ERROR_ACCESS_DENIED);
1208 PWINE_HASH_TO_DELETE toDelete =
1209 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1213 DWORD size = sizeof(toDelete->hash);
1215 ret = CertGetCertificateContextProperty(pCertContext,
1216 CERT_HASH_PROP_ID, toDelete->hash, &size);
1219 list_init(&toDelete->entry);
1220 EnterCriticalSection(&store->cs);
1221 list_add_tail(&store->certsToDelete, &toDelete->entry);
1222 LeaveCriticalSection(&store->cs);
1223 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1227 CryptMemFree(toDelete);
1232 store->dirty = TRUE;
1237 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1239 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1241 TRACE("(%p)\n", ref);
1243 if (context->childContext)
1244 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1247 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1248 DWORD dwCtrlType, void const *pvCtrlPara)
1250 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1255 case CERT_STORE_CTRL_RESYNC:
1256 CRYPT_RegFlushStore(store, FALSE);
1257 store->memStore->closeStore(store->memStore, 0);
1258 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1259 store->hdr.dwOpenFlags, NULL);
1260 if (store->memStore)
1262 CRYPT_RegReadFromReg(store);
1268 case CERT_STORE_CTRL_COMMIT:
1269 ret = CRYPT_RegFlushStore(store,
1270 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1273 FIXME("%ld: stub\n", dwCtrlType);
1279 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1280 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1282 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1283 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1286 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1288 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1291 /* Find how many subkeys there are */
1292 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1293 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1297 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1299 /* Name too big: alloc a buffer for it */
1300 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1304 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1307 /* Recursively delete all the subkeys */
1308 for (i = 0; i < dwKeyCount && !dwRet; i++)
1310 dwSize = dwMaxSubkeyLen;
1311 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1314 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1317 if (lpszName != szNameBuf)
1319 /* Free buffer if allocated */
1320 CryptMemFree(lpszName);
1325 RegCloseKey(hSubKey);
1327 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1332 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1333 DWORD dwFlags, const void *pvPara)
1335 PWINE_REGSTORE store = NULL;
1337 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1339 if (dwFlags & CERT_STORE_DELETE_FLAG)
1341 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1343 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1344 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1345 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1346 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1347 if (rc == ERROR_NO_MORE_ITEMS)
1355 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1356 GetCurrentProcess(), (LPHANDLE)&key,
1357 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1360 PWINECRYPT_CERTSTORE memStore;
1362 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1365 store = CryptMemAlloc(sizeof(WINE_REGSTORE));
1368 memset(store, 0, sizeof(WINE_REGSTORE));
1369 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1371 store->hdr.closeStore = CRYPT_RegCloseStore;
1372 store->hdr.addCert = CRYPT_RegAddCert;
1373 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1374 store->hdr.enumCert = CRYPT_RegEnumCert;
1375 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1376 store->hdr.freeCert = CRYPT_RegFreeCert;
1377 store->hdr.control = CRYPT_RegControl;
1378 store->memStore = memStore;
1380 InitializeCriticalSection(&store->cs);
1381 list_init(&store->certsToDelete);
1382 CRYPT_RegReadFromReg(store);
1383 store->dirty = FALSE;
1388 TRACE("returning %p\n", store);
1389 return (WINECRYPT_CERTSTORE *)store;
1392 /* FIXME: this isn't complete for the Root store, in which the top-level
1393 * self-signed CA certs reside. Adding a cert to the Root store should present
1394 * the user with a dialog indicating the consequences of doing so, and asking
1395 * the user to confirm whether the cert should be added.
1397 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1398 DWORD dwFlags, const void *pvPara)
1400 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1401 LPCWSTR storeName = (LPCWSTR)pvPara;
1403 PWINECRYPT_CERTSTORE store = NULL;
1408 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1409 debugstr_w((LPCWSTR)pvPara));
1413 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1418 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1420 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1421 root = HKEY_LOCAL_MACHINE;
1422 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1424 case CERT_SYSTEM_STORE_CURRENT_USER:
1425 root = HKEY_CURRENT_USER;
1426 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1428 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1429 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1430 * SystemCertificates
1432 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1433 debugstr_w(storeName));
1435 case CERT_SYSTEM_STORE_SERVICES:
1436 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1437 * SystemCertificates
1439 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1440 debugstr_w(storeName));
1442 case CERT_SYSTEM_STORE_USERS:
1443 /* hku\user sid\Software\Microsoft\SystemCertificates */
1444 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1445 debugstr_w(storeName));
1447 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1448 root = HKEY_CURRENT_USER;
1449 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1451 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1452 root = HKEY_LOCAL_MACHINE;
1453 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1455 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1456 /* hklm\Software\Microsoft\EnterpriseCertificates */
1457 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1458 debugstr_w(storeName));
1461 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1465 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1471 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1474 wsprintfW(storePath, fmt, base, storeName);
1475 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1476 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1481 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1483 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1484 disp == REG_OPENED_EXISTING_KEY)
1487 rc = ERROR_FILE_EXISTS;
1492 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1497 CryptMemFree(storePath);
1502 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1503 DWORD dwFlags, const void *pvPara)
1506 PWINECRYPT_CERTSTORE ret = NULL;
1508 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1509 debugstr_a((LPCSTR)pvPara));
1513 SetLastError(ERROR_FILE_NOT_FOUND);
1516 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1519 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1523 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1524 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1525 CryptMemFree(storeName);
1531 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1532 DWORD dwFlags, const void *pvPara)
1534 HCERTSTORE store = 0;
1537 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1538 debugstr_w((LPCWSTR)pvPara));
1542 SetLastError(ERROR_FILE_NOT_FOUND);
1545 /* This returns a different error than system registry stores if the
1546 * location is invalid.
1548 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1550 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1551 case CERT_SYSTEM_STORE_CURRENT_USER:
1552 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1553 case CERT_SYSTEM_STORE_SERVICES:
1554 case CERT_SYSTEM_STORE_USERS:
1555 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1556 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1557 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1561 SetLastError(ERROR_FILE_NOT_FOUND);
1566 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1567 0, hCryptProv, dwFlags, pvPara);
1571 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1572 CERT_STORE_CREATE_NEW_FLAG, NULL);
1575 CertAddStoreToCollection(store, regStore,
1576 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1577 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1578 CertCloseStore(regStore, 0);
1582 return (PWINECRYPT_CERTSTORE)store;
1585 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1586 DWORD dwFlags, const void *pvPara)
1589 PWINECRYPT_CERTSTORE ret = NULL;
1591 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1592 debugstr_a((LPCSTR)pvPara));
1596 SetLastError(ERROR_FILE_NOT_FOUND);
1599 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1602 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1606 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1607 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1608 CryptMemFree(storeName);
1614 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1615 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1618 WINECRYPT_CERTSTORE *hcs;
1619 StoreOpenFunc openFunc = NULL;
1621 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1622 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1624 if (!HIWORD(lpszStoreProvider))
1626 switch (LOWORD(lpszStoreProvider))
1628 case (int)CERT_STORE_PROV_MEMORY:
1629 openFunc = CRYPT_MemOpenStore;
1631 case (int)CERT_STORE_PROV_REG:
1632 openFunc = CRYPT_RegOpenStore;
1634 case (int)CERT_STORE_PROV_COLLECTION:
1635 openFunc = CRYPT_CollectionOpenStore;
1637 case (int)CERT_STORE_PROV_SYSTEM_A:
1638 openFunc = CRYPT_SysOpenStoreA;
1640 case (int)CERT_STORE_PROV_SYSTEM_W:
1641 openFunc = CRYPT_SysOpenStoreW;
1643 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1644 openFunc = CRYPT_SysRegOpenStoreA;
1646 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1647 openFunc = CRYPT_SysRegOpenStoreW;
1650 if (LOWORD(lpszStoreProvider))
1651 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1654 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1655 openFunc = CRYPT_MemOpenStore;
1656 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1657 openFunc = CRYPT_SysOpenStoreW;
1658 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1659 openFunc = CRYPT_CollectionOpenStore;
1660 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1661 openFunc = CRYPT_SysRegOpenStoreW;
1664 FIXME("unimplemented type %s\n", lpszStoreProvider);
1670 /* FIXME: need to look for an installed provider for this type */
1671 SetLastError(ERROR_FILE_NOT_FOUND);
1675 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1676 return (HCERTSTORE)hcs;
1679 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1680 LPCSTR szSubSystemProtocol)
1684 if (szSubSystemProtocol)
1686 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1688 LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR));
1692 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1693 ret = CertOpenSystemStoreW(hProv, param);
1694 CryptMemFree(param);
1698 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1702 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1703 LPCWSTR szSubSystemProtocol)
1707 if (!szSubSystemProtocol)
1709 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1713 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1714 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1717 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1718 CERT_STORE_CREATE_NEW_FLAG, NULL);
1721 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1722 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1726 CertAddStoreToCollection(ret, store,
1727 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1728 CertCloseStore(store, 0);
1730 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1731 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1734 CertAddStoreToCollection(ret, store,
1735 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1736 CertCloseStore(store, 0);
1742 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1743 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1745 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1746 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1750 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1751 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1756 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1758 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1759 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1763 data = CryptMemAlloc( cbCrlEncoded );
1766 CryptMemFree( pcrl );
1770 pcrl->dwCertEncodingType = dwCertEncodingType;
1771 pcrl->pbCrlEncoded = data;
1772 pcrl->cbCrlEncoded = cbCrlEncoded;
1773 pcrl->pCrlInfo = NULL;
1774 pcrl->hCertStore = 0;
1779 /* Decodes the encoded certificate and creates the certificate context for it.
1780 * The reference count is initially zero, so you must create a reference to it
1781 * to avoid leaking memory.
1783 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1784 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1786 PWINE_CERT_CONTEXT cert = NULL;
1788 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1789 PCERT_INFO certInfo = NULL;
1792 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1795 /* First try to decode it as a signed cert. */
1796 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1797 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1798 (BYTE *)&signedCert, &size);
1802 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1803 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1804 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1805 (BYTE *)&certInfo, &size);
1806 LocalFree(signedCert);
1808 /* Failing that, try it as an unsigned cert */
1812 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1813 pbCertEncoded, cbCertEncoded,
1814 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1815 (BYTE *)&certInfo, &size);
1821 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1824 data = CryptMemAlloc(cbCertEncoded);
1831 memcpy(data, pbCertEncoded, cbCertEncoded);
1832 cert->cert.dwCertEncodingType = dwCertEncodingType;
1833 cert->cert.pbCertEncoded = data;
1834 cert->cert.cbCertEncoded = cbCertEncoded;
1835 cert->cert.pCertInfo = certInfo;
1836 cert->cert.hCertStore = 0;
1838 InitializeCriticalSection(&cert->cs);
1839 list_init(&cert->extendedProperties);
1846 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1848 PWINE_CERT_PROPERTY prop, next;
1850 CryptMemFree(context->cert.pbCertEncoded);
1851 LocalFree(context->cert.pCertInfo);
1852 DeleteCriticalSection(&context->cs);
1853 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1854 WINE_CERT_PROPERTY, entry)
1856 list_remove(&prop->entry);
1857 CryptMemFree(prop->pbData);
1860 CryptMemFree(context);
1863 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1864 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1866 PWINE_CERT_CONTEXT cert;
1867 PWINE_CERT_CONTEXT_REF ret = NULL;
1869 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1872 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1875 ret = CRYPT_CreateCertRef(cert, 0);
1876 return (PCCERT_CONTEXT)ret;
1879 /* Since the properties are stored in a list, this is a tad inefficient
1880 * (O(n^2)) since I have to find the previous position every time.
1882 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1885 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1888 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1890 EnterCriticalSection(&ref->context->cs);
1893 PWINE_CERT_PROPERTY cursor = NULL;
1895 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1896 WINE_CERT_PROPERTY, entry)
1898 if (cursor->hdr.propID == dwPropId)
1903 if (cursor->entry.next != &ref->context->extendedProperties)
1904 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1912 else if (!list_empty(&ref->context->extendedProperties))
1913 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1914 WINE_CERT_PROPERTY, entry)->hdr.propID;
1917 LeaveCriticalSection(&ref->context->cs);
1921 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1922 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1924 PWINE_CERT_PROPERTY prop;
1927 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1929 EnterCriticalSection(&context->cs);
1932 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1933 WINE_CERT_PROPERTY, entry)
1935 if (prop->hdr.propID == dwPropId)
1939 *pcbData = prop->hdr.cb;
1942 else if (*pcbData < prop->hdr.cb)
1944 SetLastError(ERROR_MORE_DATA);
1945 *pcbData = prop->hdr.cb;
1949 memcpy(pvData, prop->pbData, prop->hdr.cb);
1950 *pcbData = prop->hdr.cb;
1959 /* Implicit properties */
1962 case CERT_SHA1_HASH_PROP_ID:
1963 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1964 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1968 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1970 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1974 case CERT_KEY_PROV_INFO_PROP_ID:
1975 case CERT_MD5_HASH_PROP_ID:
1976 case CERT_SIGNATURE_HASH_PROP_ID:
1977 case CERT_KEY_IDENTIFIER_PROP_ID:
1978 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1979 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1980 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1981 FIXME("implicit property %ld\n", dwPropId);
1985 LeaveCriticalSection(&context->cs);
1986 TRACE("returning %d\n", ret);
1990 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1991 DWORD dwPropId, void *pvData, DWORD *pcbData)
1993 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1996 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1998 /* Special cases for invalid/special prop IDs.
2003 case CERT_CERT_PROP_ID:
2004 case CERT_CRL_PROP_ID:
2005 case CERT_CTL_PROP_ID:
2006 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2008 case CERT_ACCESS_STATE_PROP_ID:
2011 *pcbData = sizeof(DWORD);
2014 else if (*pcbData < sizeof(DWORD))
2016 SetLastError(ERROR_MORE_DATA);
2017 *pcbData = sizeof(DWORD);
2024 if (pCertContext->hCertStore)
2026 PWINECRYPT_CERTSTORE store =
2027 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2029 /* Take advantage of knowledge of the stores to answer the
2030 * access state question
2032 if (store->type != StoreTypeReg ||
2033 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2034 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2036 *(DWORD *)pvData = state;
2041 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2043 TRACE("returning %d\n", ret);
2047 /* Copies cbData bytes from pbData to the context's property with ID
2050 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2051 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2058 data = CryptMemAlloc(cbData);
2060 memcpy(data, pbData, cbData);
2064 if (!cbData || data)
2066 PWINE_CERT_PROPERTY prop;
2068 EnterCriticalSection(&context->cs);
2069 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2070 WINE_CERT_PROPERTY, entry)
2072 if (prop->hdr.propID == dwPropId)
2075 if (prop && prop->entry.next != &context->extendedProperties)
2077 CryptMemFree(prop->pbData);
2078 prop->hdr.cb = cbData;
2079 prop->pbData = cbData ? data : NULL;
2084 prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2087 prop->hdr.propID = dwPropId;
2088 prop->hdr.unknown = 1;
2089 prop->hdr.cb = cbData;
2090 list_init(&prop->entry);
2091 prop->pbData = cbData ? data : NULL;
2092 list_add_tail(&context->extendedProperties, &prop->entry);
2098 LeaveCriticalSection(&context->cs);
2103 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2104 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2108 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2112 PWINE_CERT_PROPERTY prop, next;
2114 EnterCriticalSection(&context->cs);
2115 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2116 WINE_CERT_PROPERTY, entry)
2118 if (prop->hdr.propID == dwPropId)
2120 list_remove(&prop->entry);
2121 CryptMemFree(prop->pbData);
2125 LeaveCriticalSection(&context->cs);
2132 case CERT_AUTO_ENROLL_PROP_ID:
2133 case CERT_CTL_USAGE_PROP_ID:
2134 case CERT_DESCRIPTION_PROP_ID:
2135 case CERT_FRIENDLY_NAME_PROP_ID:
2136 case CERT_HASH_PROP_ID:
2137 case CERT_KEY_IDENTIFIER_PROP_ID:
2138 case CERT_MD5_HASH_PROP_ID:
2139 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2140 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2141 case CERT_PVK_FILE_PROP_ID:
2142 case CERT_SIGNATURE_HASH_PROP_ID:
2143 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2144 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2145 case CERT_ENROLLMENT_PROP_ID:
2146 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2147 case CERT_RENEWAL_PROP_ID:
2149 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2151 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2152 blob->pbData, blob->cbData);
2155 case CERT_DATE_STAMP_PROP_ID:
2156 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2157 pvData, sizeof(FILETIME));
2160 FIXME("%ld: stub\n", dwPropId);
2163 TRACE("returning %d\n", ret);
2167 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2168 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2170 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2173 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2175 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2176 * crashes on most of these, I'll be safer.
2181 case CERT_ACCESS_STATE_PROP_ID:
2182 case CERT_CERT_PROP_ID:
2183 case CERT_CRL_PROP_ID:
2184 case CERT_CTL_PROP_ID:
2185 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2188 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2190 TRACE("returning %d\n", ret);
2194 /* Only the reference portion of the context is duplicated. The returned
2195 * context has the cert store set to 0, to prevent the store's certificate free
2196 * function from getting called on partial data.
2197 * FIXME: is this okay? Needs a test.
2199 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2200 PCCERT_CONTEXT pCertContext)
2202 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2204 TRACE("(%p)\n", pCertContext);
2207 ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2210 memcpy(ret, ref, sizeof(*ret));
2211 ret->cert.hCertStore = 0;
2212 InterlockedIncrement(&ret->context->ref);
2217 return (PCCERT_CONTEXT)ret;
2220 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2221 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2222 PCCERT_CONTEXT *ppStoreContext)
2224 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2225 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2226 PWINE_CERT_CONTEXT cert;
2229 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2230 dwAddDisposition, ppStoreContext);
2232 /* FIXME: some tests needed to verify return codes */
2235 SetLastError(ERROR_INVALID_PARAMETER);
2238 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2240 SetLastError(ERROR_INVALID_PARAMETER);
2244 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2245 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2248 PWINE_CERT_PROPERTY prop;
2251 EnterCriticalSection(&ref->context->cs);
2252 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2253 WINE_CERT_PROPERTY, entry)
2255 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2256 prop->pbData, prop->hdr.cb);
2260 LeaveCriticalSection(&ref->context->cs);
2263 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2264 if (ret && ppStoreContext)
2265 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2269 CRYPT_FreeCert(cert);
2276 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2277 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2278 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2280 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2283 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2284 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2288 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2292 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2293 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2297 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2298 if (ret && ppCertContext)
2299 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2302 CRYPT_FreeCert(cert);
2310 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2311 PCCERT_CONTEXT pPrev)
2313 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2314 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2317 TRACE("(%p, %p)\n", hCertStore, pPrev);
2320 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2323 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2327 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2331 TRACE("(%p)\n", pCertContext);
2335 else if (!pCertContext->hCertStore)
2338 CertFreeCertificateContext(pCertContext);
2342 PWINECRYPT_CERTSTORE hcs =
2343 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2347 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2351 ret = hcs->deleteCert(hcs, pCertContext, 0);
2352 CertFreeCertificateContext(pCertContext);
2358 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2359 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2360 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2362 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2363 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2368 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2369 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2370 PCCRL_CONTEXT* ppStoreContext )
2372 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2373 dwAddDisposition, ppStoreContext);
2377 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2379 FIXME("%p\n", pCrlContext );
2384 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2386 FIXME("(%p): stub\n", pCrlContext);
2390 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2391 PCCRL_CONTEXT pPrev)
2393 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2397 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2398 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2400 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2405 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2406 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2407 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2409 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2410 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2415 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2416 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2417 PCCTL_CONTEXT* ppStoreContext)
2419 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2420 dwAddDisposition, ppStoreContext);
2424 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2426 FIXME("(%p): stub\n", pCtlContext );
2430 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2432 FIXME("(%p): stub\n", pCtlContext);
2436 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2437 PCCTL_CONTEXT pPrev)
2439 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2444 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2446 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2448 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2453 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2456 if (InterlockedDecrement(&hcs->ref) == 0)
2458 TRACE("%p's ref count is 0, freeing\n", hcs);
2460 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2461 CryptReleaseContext(hcs->cryptProv, 0);
2462 hcs->closeStore(hcs, dwFlags);
2465 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2469 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2470 DWORD dwCtrlType, void const *pvCtrlPara)
2472 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2475 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2480 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2485 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2492 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2493 DWORD dwPropId, void *pvData, DWORD *pcbData)
2495 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2499 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2500 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2502 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2507 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2508 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2510 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2515 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2516 DWORD dwPropId, void *pvData, DWORD *pcbData)
2518 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2522 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2523 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2525 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2530 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2531 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2533 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2538 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2539 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2543 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2548 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2549 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2550 pCertContext->cbCertEncoded;
2551 PWINE_CERT_PROPERTY prop;
2553 EnterCriticalSection(&ref->context->cs);
2554 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2555 WINE_CERT_PROPERTY, entry)
2556 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2559 *pcbElement = bytesNeeded;
2562 else if (*pcbElement < bytesNeeded)
2564 *pcbElement = bytesNeeded;
2565 SetLastError(ERROR_MORE_DATA);
2570 PWINE_CERT_PROP_HEADER hdr;
2572 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2573 WINE_CERT_PROPERTY, entry)
2575 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2576 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2579 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2580 pbElement += prop->hdr.cb;
2583 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2584 hdr->propID = CERT_CERT_PROP_ID;
2586 hdr->cb = pCertContext->cbCertEncoded;
2587 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2588 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2591 LeaveCriticalSection(&ref->context->cs);
2598 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2599 * to its header if a valid header is found, NULL if not. Valid means the
2600 * length of thte property won't overrun buf, and the unknown field is 1.
2602 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2603 DWORD size, DWORD propID)
2605 const WINE_CERT_PROP_HEADER *ret = NULL;
2608 while (size && !ret && !done)
2610 if (size < sizeof(WINE_CERT_PROP_HEADER))
2612 SetLastError(CRYPT_E_FILE_ERROR);
2617 const WINE_CERT_PROP_HEADER *hdr =
2618 (const WINE_CERT_PROP_HEADER *)buf;
2620 size -= sizeof(WINE_CERT_PROP_HEADER);
2621 buf += sizeof(WINE_CERT_PROP_HEADER);
2624 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2627 else if (!hdr->propID)
2629 /* assume a zero prop ID means the data are uninitialized, so
2634 else if (hdr->unknown != 1)
2636 SetLastError(ERROR_FILE_NOT_FOUND);
2639 else if (hdr->propID == propID)
2651 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2652 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2654 const void *context;
2656 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2661 SetLastError(ERROR_END_OF_MEDIA);
2667 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2668 const WINE_CERT_PROP_HEADER *hdr = NULL;
2674 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2676 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2678 type = CERT_STORE_CERTIFICATE_CONTEXT;
2681 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2683 type = CERT_STORE_CRL_CONTEXT;
2686 hdr = CRYPT_findPropID(pbElement, cbElement,
2689 type = CERT_STORE_CTL_CONTEXT;
2693 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2695 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2696 type = CERT_STORE_CERTIFICATE_CONTEXT;
2698 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2700 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2701 type = CERT_STORE_CRL_CONTEXT;
2703 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2705 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2706 type = CERT_STORE_CTL_CONTEXT;
2711 case CERT_STORE_CERTIFICATE_CONTEXT:
2712 contextInterface = &gCertInterface;
2714 case CERT_STORE_CRL_CONTEXT:
2715 contextInterface = &gCRLInterface;
2717 case CERT_STORE_CTL_CONTEXT:
2718 contextInterface = &gCTLInterface;
2721 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2728 context = contextInterface->create(X509_ASN_ENCODING,
2729 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2732 BOOL noMoreProps = FALSE;
2734 while (!noMoreProps && ret)
2736 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2740 const WINE_CERT_PROP_HEADER *hdr =
2741 (const WINE_CERT_PROP_HEADER *)pbElement;
2743 TRACE("prop is %ld\n", hdr->propID);
2744 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2745 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2746 if (cbElement < hdr->cb)
2748 SetLastError(HRESULT_FROM_WIN32(
2749 ERROR_INVALID_PARAMETER));
2752 else if (!hdr->propID)
2754 /* Like in CRYPT_findPropID, stop if the propID is zero
2758 else if (hdr->unknown != 1)
2760 SetLastError(ERROR_FILE_NOT_FOUND);
2763 else if (hdr->propID != CERT_CERT_PROP_ID &&
2764 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2767 /* Have to create a blob for most types, but not
2770 switch (hdr->propID)
2772 case CERT_AUTO_ENROLL_PROP_ID:
2773 case CERT_CTL_USAGE_PROP_ID:
2774 case CERT_DESCRIPTION_PROP_ID:
2775 case CERT_FRIENDLY_NAME_PROP_ID:
2776 case CERT_HASH_PROP_ID:
2777 case CERT_KEY_IDENTIFIER_PROP_ID:
2778 case CERT_MD5_HASH_PROP_ID:
2779 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2780 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2781 case CERT_PVK_FILE_PROP_ID:
2782 case CERT_SIGNATURE_HASH_PROP_ID:
2783 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2784 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2785 case CERT_ENROLLMENT_PROP_ID:
2786 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2787 case CERT_RENEWAL_PROP_ID:
2789 CRYPT_DATA_BLOB blob = { hdr->cb,
2790 (LPBYTE)pbElement };
2792 ret = contextInterface->setProp(context,
2793 hdr->propID, 0, &blob);
2796 case CERT_DATE_STAMP_PROP_ID:
2797 ret = contextInterface->setProp(context,
2798 hdr->propID, 0, pbElement);
2801 FIXME("prop ID %ld: stub\n", hdr->propID);
2804 pbElement += hdr->cb;
2805 cbElement -= hdr->cb;
2813 *pdwContentType = type;
2817 contextInterface->free(context);
2822 __EXCEPT(page_fault)
2824 SetLastError(STATUS_ACCESS_VIOLATION);
2831 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2832 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2833 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2835 const void *context;
2839 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2840 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2841 pdwContentType, ppvContext);
2843 /* Call the internal function, then delete the hashes. Tests show this
2844 * function uses real hash values, not whatever's stored in the hash
2847 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2848 dwContextTypeFlags, &type);
2851 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2855 case CERT_STORE_CERTIFICATE_CONTEXT:
2856 contextInterface = &gCertInterface;
2858 case CERT_STORE_CRL_CONTEXT:
2859 contextInterface = &gCRLInterface;
2861 case CERT_STORE_CTL_CONTEXT:
2862 contextInterface = &gCTLInterface;
2865 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2867 if (contextInterface)
2869 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2870 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2871 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2874 *pdwContentType = type;
2875 ret = contextInterface->addContextToStore(hCertStore, context,
2876 dwAddDisposition, ppvContext);
2877 contextInterface->free(context);
2887 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2889 TRACE("(%p)\n", pCertContext);
2893 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2894 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2896 if (InterlockedDecrement(&ref->context->ref) == 0)
2898 TRACE("%p's ref count is 0, freeing\n", ref->context);
2899 CRYPT_FreeCert(ref->context);
2902 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2903 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2905 store->freeCert(ref);
2911 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2912 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2913 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2915 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2916 dwFlags, dwType, pvPara, pPrevCertContext);
2917 SetLastError(CRYPT_E_NOT_FOUND);
2921 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2922 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2924 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2925 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2926 PWINE_STORE_LIST_ENTRY entry;
2929 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2930 dwUpdateFlags, dwPriority);
2932 if (!collection || !sibling)
2934 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2936 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2939 if (collection->hdr.type != StoreTypeCollection)
2941 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2944 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2946 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2950 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2953 InterlockedIncrement(&sibling->ref);
2954 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2955 entry->store = sibling;
2956 entry->dwUpdateFlags = dwUpdateFlags;
2957 entry->dwPriority = dwPriority;
2958 list_init(&entry->entry);
2959 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2960 EnterCriticalSection(&collection->cs);
2963 PWINE_STORE_LIST_ENTRY cursor;
2966 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2967 WINE_STORE_LIST_ENTRY, entry)
2969 if (cursor->dwPriority < dwPriority)
2971 list_add_before(&cursor->entry, &entry->entry);
2977 list_add_tail(&collection->stores, &entry->entry);
2980 list_add_tail(&collection->stores, &entry->entry);
2981 LeaveCriticalSection(&collection->cs);
2989 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2990 HCERTSTORE hSiblingStore)
2992 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2993 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2994 PWINE_STORE_LIST_ENTRY store, next;
2996 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2998 if (!collection || !sibling)
3000 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3002 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3005 if (collection->hdr.type != StoreTypeCollection)
3007 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3009 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3012 EnterCriticalSection(&collection->cs);
3013 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3014 WINE_STORE_LIST_ENTRY, entry)
3016 if (store->store == sibling)
3018 list_remove(&store->entry);
3019 CertCloseStore(store->store, 0);
3020 CryptMemFree(store);
3024 LeaveCriticalSection(&collection->cs);
3027 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3028 CRYPT_ATTRIBUTE rgAttr[])
3030 PCRYPT_ATTRIBUTE ret = NULL;
3033 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3039 SetLastError(ERROR_INVALID_PARAMETER);
3043 for (i = 0; !ret && i < cAttr; i++)
3044 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3049 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3050 CERT_EXTENSION rgExtensions[])
3052 PCERT_EXTENSION ret = NULL;
3055 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3061 SetLastError(ERROR_INVALID_PARAMETER);
3065 for (i = 0; !ret && i < cExtensions; i++)
3066 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3067 rgExtensions[i].pszObjId))
3068 ret = &rgExtensions[i];
3072 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3074 PCERT_RDN_ATTR ret = NULL;
3077 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3081 SetLastError(ERROR_INVALID_PARAMETER);
3085 for (i = 0; !ret && i < pName->cRDN; i++)
3086 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3087 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3088 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3089 ret = &pName->rgRDN[i].rgRDNAttr[j];
3093 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3094 PCERT_INFO pCertInfo)
3103 GetSystemTime(&sysTime);
3104 SystemTimeToFileTime(&sysTime, &fileTime);
3105 pTimeToVerify = &fileTime;
3107 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3109 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3116 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3117 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3118 DWORD *pcbComputedHash)
3121 HCRYPTHASH hHash = 0;
3123 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3124 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3127 hCryptProv = CRYPT_GetDefaultProvider();
3132 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3135 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3137 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3138 pcbComputedHash, 0);
3139 CryptDestroyHash(hHash);
3145 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName, DWORD dwFlags)
3147 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName), dwFlags);
3151 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
3152 LPCSTR pszFuncName, LPCWSTR pwszDll)
3154 FIXME("stub: %lx %s %s\n", dwEncodingType, debugstr_a(pszFuncName), debugstr_w(pwszDll));