2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004-2006 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 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.
39 #include "wine/debug.h"
40 #include "wine/list.h"
42 #include "wine/exception.h"
43 #include "crypt32_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
47 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
48 /* The following aren't defined in wincrypt.h, as they're "reserved" */
49 #define CERT_CERT_PROP_ID 32
50 #define CERT_CRL_PROP_ID 33
51 #define CERT_CTL_PROP_ID 34
53 /* Some typedefs that make it easier to abstract which type of context we're
56 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
57 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
58 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
59 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
60 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
61 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
62 DWORD dwAddDisposition, const void **ppContext);
63 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
64 const void *pPrevContext);
65 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
66 DWORD dwPropID, void *pvData, DWORD *pcbData);
67 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
68 DWORD dwPropID, DWORD dwFlags, const void *pvData);
69 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
70 BYTE *pbElement, DWORD *pcbElement);
71 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
72 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
74 /* An abstract context (certificate, CRL, or CTL) interface */
75 typedef struct _WINE_CONTEXT_INTERFACE
77 CreateContextFunc create;
78 AddContextToStoreFunc addContextToStore;
79 AddEncodedContextToStoreFunc addEncodedToStore;
80 EnumContextsInStoreFunc enumContextsInStore;
81 GetContextPropertyFunc getProp;
82 SetContextPropertyFunc setProp;
83 SerializeElementFunc serialize;
85 DeleteContextFunc deleteFromStore;
86 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
88 static const WINE_CONTEXT_INTERFACE gCertInterface = {
89 (CreateContextFunc)CertCreateCertificateContext,
90 (AddContextToStoreFunc)CertAddCertificateContextToStore,
91 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
92 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
93 (GetContextPropertyFunc)CertGetCertificateContextProperty,
94 (SetContextPropertyFunc)CertSetCertificateContextProperty,
95 (SerializeElementFunc)CertSerializeCertificateStoreElement,
96 (FreeContextFunc)CertFreeCertificateContext,
97 (DeleteContextFunc)CertDeleteCertificateFromStore,
100 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
101 (CreateContextFunc)CertCreateCRLContext,
102 (AddContextToStoreFunc)CertAddCRLContextToStore,
103 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
104 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
105 (GetContextPropertyFunc)CertGetCRLContextProperty,
106 (SetContextPropertyFunc)CertSetCRLContextProperty,
107 (SerializeElementFunc)CertSerializeCRLStoreElement,
108 (FreeContextFunc)CertFreeCRLContext,
109 (DeleteContextFunc)CertDeleteCRLFromStore,
112 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
113 (CreateContextFunc)CertCreateCTLContext,
114 (AddContextToStoreFunc)CertAddCTLContextToStore,
115 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
116 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
117 (GetContextPropertyFunc)CertGetCTLContextProperty,
118 (SetContextPropertyFunc)CertSetCTLContextProperty,
119 (SerializeElementFunc)CertSerializeCTLStoreElement,
120 (FreeContextFunc)CertFreeCTLContext,
121 (DeleteContextFunc)CertDeleteCTLFromStore,
124 struct WINE_CRYPTCERTSTORE;
126 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
127 DWORD dwFlags, const void *pvPara);
129 struct _WINE_CERT_CONTEXT_REF;
131 /* Called to enumerate the next certificate in a store. The returned pointer
132 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
135 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
136 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
138 struct _WINE_CERT_CONTEXT;
140 /* Called to create a new reference to an existing cert context. Should call
141 * CRYPT_InitCertRef to make sure the reference count is properly updated.
142 * If the store does not provide any additional allocated data (that is, does
143 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
146 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
147 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
149 /* Optional, called when a cert context reference is being freed. Don't free
150 * the ref pointer itself, CertFreeCertificateContext does that.
152 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
154 typedef PCCERT_CONTEXT (*DupCertFunc)(PCCERT_CONTEXT context);
156 typedef enum _CertStoreType {
162 /* A cert store is polymorphic through the use of function pointers. A type
163 * is still needed to distinguish collection stores from other types.
164 * On the function pointers:
165 * - closeStore is called when the store's ref count becomes 0
166 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
167 * - control is optional, but should be implemented by any store that supports
170 typedef struct WINE_CRYPTCERTSTORE
175 HCRYPTPROV cryptProv;
177 PFN_CERT_STORE_PROV_CLOSE closeStore;
178 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
179 CreateRefFunc createCertRef;
180 EnumCertFunc enumCert;
181 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
183 FreeCertFunc freeCert; /* optional */
184 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
185 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
187 /* A certificate context has pointers to data that are owned by this module,
188 * so rather than duplicate the data every time a certificate context is
189 * copied, I keep a reference count to the data. Thus I have two data
190 * structures, the "true" certificate context (that has the reference count)
191 * and a reference certificate context, that has a pointer to the true context.
192 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
193 * with the reference version.
195 typedef struct _WINE_CERT_CONTEXT
200 struct list extendedProperties;
201 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
203 typedef struct _WINE_CERT_CONTEXT_REF
206 WINE_CERT_CONTEXT *context;
207 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
209 /* An extended certificate property in serialized form is prefixed by this
212 typedef struct _WINE_CERT_PROP_HEADER
215 DWORD unknown; /* always 1 */
217 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
219 /* Stores an extended property in a cert. */
220 typedef struct _WINE_CERT_PROPERTY
222 WINE_CERT_PROP_HEADER hdr;
225 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
227 /* A mem store has a list of these. They're also returned by the mem store
228 * during enumeration.
230 typedef struct _WINE_CERT_LIST_ENTRY
232 WINE_CERT_CONTEXT_REF cert;
234 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
236 typedef struct _WINE_MEMSTORE
238 WINECRYPT_CERTSTORE hdr;
241 } WINE_MEMSTORE, *PWINE_MEMSTORE;
243 typedef struct _WINE_HASH_TO_DELETE
247 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
249 /* Returned by a provider store during enumeration. */
250 typedef struct _WINE_PROV_CERT_CONTEXT
252 WINE_CERT_CONTEXT_REF cert;
253 PWINE_CERT_CONTEXT_REF childContext;
254 } WINE_PROV_CERT_CONTEXT, *PWINE_PROV_CERT_CONTEXT;
256 typedef struct _WINE_REGSTOREINFO
259 HCRYPTPROV cryptProv;
260 PWINECRYPT_CERTSTORE memStore;
264 struct list certsToDelete;
265 } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
267 typedef struct _WINE_STORE_LIST_ENTRY
269 PWINECRYPT_CERTSTORE store;
273 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
275 /* Returned by a collection store during enumeration.
276 * Note: relies on the list entry being valid after use, which a number of
277 * conditions might make untrue (reentrancy, closing a collection store before
278 * continuing an enumeration on it, ...). The tests seem to indicate this
279 * sort of unsafety is okay, since Windows isn't well-behaved in these
282 typedef struct _WINE_COLLECTION_CERT_CONTEXT
284 WINE_CERT_CONTEXT_REF cert;
285 PWINE_STORE_LIST_ENTRY storeEntry;
286 PWINE_CERT_CONTEXT_REF childContext;
287 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
289 typedef struct _WINE_COLLECTIONSTORE
291 WINECRYPT_CERTSTORE hdr;
294 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
296 typedef struct _WINE_PROVIDERSTORE
298 WINECRYPT_CERTSTORE hdr;
299 DWORD dwStoreProvFlags;
300 PWINECRYPT_CERTSTORE memStore;
301 HCERTSTOREPROV hStoreProv;
302 PFN_CERT_STORE_PROV_CLOSE provCloseStore;
303 PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert;
304 PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
305 PFN_CERT_STORE_PROV_CONTROL provControl;
306 } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;
308 /* Like CertGetCertificateContextProperty, but operates directly on the
309 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
310 * are handled by CertGetCertificateContextProperty, and are particular to the
311 * store in which the property exists (which is separate from the context.)
313 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
314 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
316 /* Like CertSetCertificateContextProperty, but operates directly on the
317 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
318 * CertSetCertificateContextProperty anyway.
320 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
321 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
323 /* Helper function for store reading functions and
324 * CertAddSerializedElementToStore. Returns a context of the appropriate type
325 * if it can, or NULL otherwise. Doesn't validate any of the properties in
326 * the serialized context (for example, bad hashes are retained.)
327 * *pdwContentType is set to the type of the returned context.
329 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
330 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
332 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
333 DWORD dwFlags, CertStoreType type)
336 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
340 hCryptProv = CRYPT_GetDefaultProvider();
341 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
343 store->cryptProv = hCryptProv;
344 store->dwOpenFlags = dwFlags;
347 /* Initializes the reference ref to point to pCertContext, which is assumed to
348 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
349 * Also sets the hCertStore member of the reference to store.
351 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
352 PWINE_CERT_CONTEXT context, HCERTSTORE store)
354 TRACE("(%p, %p)\n", ref, context);
355 memcpy(&ref->cert, context, sizeof(ref->cert));
356 ref->context = context;
357 InterlockedIncrement(&context->ref);
358 TRACE("%p's ref count is %ld\n", context, context->ref);
359 ref->cert.hCertStore = store;
362 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
365 PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
366 sizeof(WINE_CERT_CONTEXT_REF));
368 TRACE("(%p, %p)\n", context, store);
370 CRYPT_InitCertRef(pCertRef, context, store);
374 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
375 DWORD dwAddDisposition)
377 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
378 BOOL add = FALSE, ret;
380 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
382 switch (dwAddDisposition)
384 case CERT_STORE_ADD_ALWAYS:
387 case CERT_STORE_ADD_NEW:
389 BYTE hashToAdd[20], hash[20];
390 DWORD size = sizeof(hashToAdd);
392 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
393 CERT_HASH_PROP_ID, hashToAdd, &size);
396 PWINE_CERT_LIST_ENTRY cursor;
398 /* Add if no cert with the same hash is found. */
400 EnterCriticalSection(&ms->cs);
401 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
404 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
405 CERT_HASH_PROP_ID, hash, &size);
406 if (ret && !memcmp(hashToAdd, hash, size))
408 TRACE("found matching certificate, not adding\n");
409 SetLastError(CRYPT_E_EXISTS);
414 LeaveCriticalSection(&ms->cs);
418 case CERT_STORE_ADD_REPLACE_EXISTING:
420 BYTE hashToAdd[20], hash[20];
421 DWORD size = sizeof(hashToAdd);
424 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
425 CERT_HASH_PROP_ID, hashToAdd, &size);
428 PWINE_CERT_LIST_ENTRY cursor, next;
430 /* Look for existing cert to delete */
431 EnterCriticalSection(&ms->cs);
432 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
433 WINE_CERT_LIST_ENTRY, entry)
436 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
437 CERT_HASH_PROP_ID, hash, &size);
438 if (ret && !memcmp(hashToAdd, hash, size))
440 TRACE("found matching certificate, replacing\n");
441 list_remove(&cursor->entry);
442 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
446 LeaveCriticalSection(&ms->cs);
451 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
456 PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
457 sizeof(WINE_CERT_LIST_ENTRY));
461 TRACE("adding %p\n", entry);
462 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
463 list_init(&entry->entry);
464 EnterCriticalSection(&ms->cs);
465 list_add_tail(&ms->certs, &entry->entry);
466 LeaveCriticalSection(&ms->cs);
474 TRACE("returning %d\n", ret);
478 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
479 PWINE_CERT_CONTEXT_REF pPrev)
481 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
482 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
483 struct list *listNext;
485 TRACE("(%p, %p)\n", store, pPrev);
486 EnterCriticalSection(&ms->cs);
489 listNext = list_next(&ms->certs, &prevEntry->entry);
490 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
493 listNext = list_next(&ms->certs, &ms->certs);
496 ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
499 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
500 sizeof(WINE_CERT_LIST_ENTRY));
501 InterlockedIncrement(&ret->cert.context->ref);
506 SetLastError(CRYPT_E_NOT_FOUND);
509 LeaveCriticalSection(&ms->cs);
511 TRACE("returning %p\n", ret);
512 return (PWINE_CERT_CONTEXT_REF)ret;
515 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref);
517 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
518 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
520 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
521 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
522 PWINE_CERT_LIST_ENTRY cert, next;
525 /* Find the entry associated with the passed-in context, since the
526 * passed-in context may not be a list entry itself (e.g. if it came from
527 * CertDuplicateCertificateContext.) Pointing to the same context is
528 * a sufficient test of equality.
530 EnterCriticalSection(&store->cs);
531 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
534 if (cert->cert.context == ref->context)
536 TRACE("removing %p\n", cert);
537 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
540 list_remove(&cert->entry);
541 ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
542 cert->entry.prev = cert->entry.next = &store->certs;
546 LeaveCriticalSection(&store->cs);
550 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store)
552 PWINE_CERT_LIST_ENTRY cert, next;
554 EnterCriticalSection(&store->cs);
555 /* Note that CertFreeCertificateContext calls CryptMemFree on the passed-in
556 * pointer if its ref-count reaches zero. That's okay here because there
557 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
558 * of the CertListEntry.
560 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
563 TRACE("removing %p\n", cert);
564 list_remove(&cert->entry);
565 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
567 LeaveCriticalSection(&store->cs);
570 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
572 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
574 TRACE("(%p, %08lx)\n", store, dwFlags);
576 FIXME("Unimplemented flags: %08lx\n", dwFlags);
578 CRYPT_MemEmptyStore(store);
579 DeleteCriticalSection(&store->cs);
583 static PCCERT_CONTEXT CRYPT_MemDupCert(PCCERT_CONTEXT pCertContext)
585 const WINE_CERT_LIST_ENTRY *context =
586 (const WINE_CERT_LIST_ENTRY *)pCertContext;
587 PWINE_CERT_LIST_ENTRY ret;
589 ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
592 memcpy(ret, context, sizeof(WINE_CERT_LIST_ENTRY));
593 InterlockedIncrement(&ret->cert.context->ref);
595 return (PCCERT_CONTEXT)ret;
598 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
599 DWORD dwFlags, const void *pvPara)
601 PWINE_MEMSTORE store;
603 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
605 if (dwFlags & CERT_STORE_DELETE_FLAG)
607 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
612 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
615 memset(store, 0, sizeof(WINE_MEMSTORE));
616 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
617 store->hdr.closeStore = CRYPT_MemCloseStore;
618 store->hdr.addCert = CRYPT_MemAddCert;
619 store->hdr.createCertRef = CRYPT_CreateCertRef;
620 store->hdr.enumCert = CRYPT_MemEnumCert;
621 store->hdr.deleteCert = CRYPT_MemDeleteCert;
622 store->hdr.freeCert = NULL;
623 store->hdr.dupCert = CRYPT_MemDupCert;
624 store->hdr.control = NULL;
625 InitializeCriticalSection(&store->cs);
626 list_init(&store->certs);
629 return (PWINECRYPT_CERTSTORE)store;
632 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
633 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
635 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
636 PWINE_STORE_LIST_ENTRY entry, next;
639 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
642 EnterCriticalSection(&cs->cs);
643 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
646 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
648 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
652 LeaveCriticalSection(&cs->cs);
653 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
657 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
658 PWINE_CERT_CONTEXT context, HCERTSTORE store)
660 PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
661 sizeof(WINE_COLLECTION_CERT_CONTEXT));
665 /* Initialize to empty for now, just make sure the size is right */
666 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
667 ret->storeEntry = NULL;
668 ret->childContext = NULL;
670 return (PWINE_CERT_CONTEXT_REF)ret;
673 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
675 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
676 PWINE_STORE_LIST_ENTRY entry, next;
678 TRACE("(%p, %08lx)\n", store, dwFlags);
680 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
683 TRACE("closing %p\n", entry);
684 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
687 DeleteCriticalSection(&cs->cs);
691 /* Advances a collection enumeration by one cert, if possible, where advancing
693 * - calling the current store's enumeration function once, and returning
694 * the enumerated cert if one is returned
695 * - moving to the next store if the current store has no more items, and
696 * recursively calling itself to get the next item.
697 * Returns NULL if the collection contains no more items or on error.
698 * Assumes the collection store's lock is held.
700 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
701 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
702 PWINE_COLLECTION_CERT_CONTEXT pPrev)
704 PWINE_COLLECTION_CERT_CONTEXT ret;
705 PWINE_CERT_CONTEXT_REF child;
706 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
708 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
710 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
711 pPrev ? pPrev->childContext : NULL);
714 pPrev->childContext = NULL;
715 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
720 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
721 child->context, store);
724 ret->storeEntry = storeEntry;
725 ret->childContext = child;
728 CertFreeCertificateContext((PCCERT_CONTEXT)child);
734 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
735 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
739 SetLastError(CRYPT_E_NOT_FOUND);
743 TRACE("returning %p\n", ret);
747 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
748 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
750 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
751 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
752 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
754 TRACE("(%p, %p)\n", store, pPrev);
758 EnterCriticalSection(&cs->cs);
759 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->storeEntry, prevEntry);
760 LeaveCriticalSection(&cs->cs);
764 EnterCriticalSection(&cs->cs);
765 if (!list_empty(&cs->stores))
767 PWINE_STORE_LIST_ENTRY storeEntry;
769 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
771 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, NULL);
775 SetLastError(CRYPT_E_NOT_FOUND);
778 LeaveCriticalSection(&cs->cs);
780 TRACE("returning %p\n", ret);
781 return (PWINE_CERT_CONTEXT_REF)ret;
784 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
785 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
787 PWINE_COLLECTION_CERT_CONTEXT context =
788 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
791 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
793 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
795 context->childContext = NULL;
799 static PCCERT_CONTEXT CRYPT_CollectionDupCert(PCCERT_CONTEXT pCertContext)
801 const WINE_COLLECTION_CERT_CONTEXT *context =
802 (const WINE_COLLECTION_CERT_CONTEXT *)pCertContext;
803 PWINE_COLLECTION_CERT_CONTEXT ret;
805 ret = CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT));
808 memcpy(ret, context, sizeof(WINE_COLLECTION_CERT_CONTEXT));
809 InterlockedIncrement(&ret->cert.context->ref);
811 return (PCCERT_CONTEXT)ret;
814 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
816 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
818 TRACE("(%p)\n", ref);
820 if (context->childContext)
821 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
824 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
825 DWORD dwFlags, const void *pvPara)
827 PWINE_COLLECTIONSTORE store;
829 if (dwFlags & CERT_STORE_DELETE_FLAG)
831 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
836 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
839 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
840 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
841 StoreTypeCollection);
842 store->hdr.closeStore = CRYPT_CollectionCloseStore;
843 store->hdr.addCert = CRYPT_CollectionAddCert;
844 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
845 store->hdr.enumCert = CRYPT_CollectionEnumCert;
846 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
847 store->hdr.dupCert = CRYPT_CollectionDupCert;
848 store->hdr.freeCert = CRYPT_CollectionFreeCert;
849 InitializeCriticalSection(&store->cs);
850 list_init(&store->stores);
853 return (PWINECRYPT_CERTSTORE)store;
856 static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
858 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
860 TRACE("(%p, %08lx)\n", store, dwFlags);
862 if (store->provCloseStore)
863 store->provCloseStore(store->hStoreProv, dwFlags);
864 if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG))
865 CertCloseStore(store->memStore, dwFlags);
869 static BOOL WINAPI CRYPT_ProvAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
870 DWORD dwAddDisposition)
872 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
875 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
877 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
879 SetLastError(ERROR_ACCESS_DENIED);
885 if (store->provWriteCert)
886 ret = store->provWriteCert(store->hStoreProv, cert,
887 CERT_STORE_PROV_WRITE_ADD_FLAG);
889 ret = store->memStore->addCert(store->memStore, cert,
895 static PWINE_CERT_CONTEXT_REF CRYPT_ProvCreateCertRef(
896 PWINE_CERT_CONTEXT context, HCERTSTORE store)
898 PWINE_PROV_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_PROV_CERT_CONTEXT));
902 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
903 ret->childContext = NULL;
905 return (PWINE_CERT_CONTEXT_REF)ret;
908 static PWINE_CERT_CONTEXT_REF CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store,
909 PWINE_CERT_CONTEXT_REF pPrev)
911 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
912 PWINE_CERT_CONTEXT_REF child;
913 PWINE_PROV_CERT_CONTEXT prev = (PWINE_PROV_CERT_CONTEXT)pPrev, ret = NULL;
915 TRACE("(%p, %p)\n", store, pPrev);
917 child = ps->memStore->enumCert(ps->memStore, prev ? prev->childContext
921 prev->childContext = NULL;
922 CertFreeCertificateContext((PCCERT_CONTEXT)prev);
927 ret = (PWINE_PROV_CERT_CONTEXT)CRYPT_ProvCreateCertRef(child->context,
930 ret->childContext = child;
932 CertFreeCertificateContext((PCCERT_CONTEXT)child);
934 return (PWINE_CERT_CONTEXT_REF)ret;
937 static PCCERT_CONTEXT CRYPT_ProvDupCert(PCCERT_CONTEXT pCertContext)
939 const WINE_PROV_CERT_CONTEXT *context =
940 (const WINE_PROV_CERT_CONTEXT *)pCertContext;
941 PWINE_PROV_CERT_CONTEXT ret;
943 ret = CryptMemAlloc(sizeof(WINE_PROV_CERT_CONTEXT));
946 memcpy(ret, context, sizeof(WINE_PROV_CERT_CONTEXT));
947 InterlockedIncrement(&ret->cert.context->ref);
949 return (PCCERT_CONTEXT)ret;
952 static BOOL WINAPI CRYPT_ProvDeleteCert(HCERTSTORE hCertStore,
953 PCCERT_CONTEXT cert, DWORD dwFlags)
955 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
958 TRACE("(%p, %p, %08lx)\n", hCertStore, cert, dwFlags);
960 if (store->provDeleteCert)
961 ret = store->provDeleteCert(store->hStoreProv, cert, dwFlags);
963 ret = store->memStore->deleteCert(store->memStore, cert, dwFlags);
967 static void CRYPT_ProvFreeCert(PWINE_CERT_CONTEXT_REF ref)
969 PWINE_PROV_CERT_CONTEXT context = (PWINE_PROV_CERT_CONTEXT)ref;
971 TRACE("(%p)\n", ref);
973 if (context->childContext)
974 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
977 static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags,
978 DWORD dwCtrlType, void const *pvCtrlPara)
980 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
983 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
986 if (store->provControl)
987 ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType,
992 static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv,
993 DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo)
995 PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc(
996 sizeof(WINE_PROVIDERSTORE));
1000 CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags,
1002 ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags;
1003 if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)
1005 CertCloseStore(memStore, 0);
1006 ret->memStore = NULL;
1009 ret->memStore = memStore;
1010 ret->hStoreProv = pProvInfo->hStoreProv;
1011 ret->hdr.closeStore = CRYPT_ProvCloseStore;
1012 ret->hdr.addCert = CRYPT_ProvAddCert;
1013 ret->hdr.createCertRef = CRYPT_ProvCreateCertRef;
1014 ret->hdr.enumCert = CRYPT_ProvEnumCert;
1015 ret->hdr.deleteCert = CRYPT_ProvDeleteCert;
1016 ret->hdr.dupCert = CRYPT_ProvDupCert;
1017 ret->hdr.freeCert = CRYPT_ProvFreeCert;
1018 ret->hdr.control = CRYPT_ProvControl;
1019 if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
1020 ret->provCloseStore =
1021 pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC];
1023 ret->provCloseStore = NULL;
1024 if (pProvInfo->cStoreProvFunc >
1025 CERT_STORE_PROV_WRITE_CERT_FUNC)
1026 ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[
1027 CERT_STORE_PROV_WRITE_CERT_FUNC];
1029 ret->provWriteCert = NULL;
1030 if (pProvInfo->cStoreProvFunc >
1031 CERT_STORE_PROV_DELETE_CERT_FUNC)
1032 ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[
1033 CERT_STORE_PROV_DELETE_CERT_FUNC];
1035 ret->provDeleteCert = NULL;
1036 if (pProvInfo->cStoreProvFunc >
1037 CERT_STORE_PROV_CONTROL_FUNC)
1038 ret->provControl = pProvInfo->rgpvStoreProvFunc[
1039 CERT_STORE_PROV_CONTROL_FUNC];
1041 ret->provControl = NULL;
1043 return (PWINECRYPT_CERTSTORE)ret;
1046 static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
1047 DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara)
1049 static HCRYPTOIDFUNCSET set = NULL;
1050 PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc;
1051 HCRYPTOIDFUNCADDR hFunc;
1052 PWINECRYPT_CERTSTORE ret = NULL;
1055 set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
1056 CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0,
1057 (void **)&provOpenFunc, &hFunc);
1060 CERT_STORE_PROV_INFO provInfo = { 0 };
1062 provInfo.cbSize = sizeof(provInfo);
1063 if (dwFlags & CERT_STORE_DELETE_FLAG)
1064 provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
1065 dwFlags, pvPara, NULL, &provInfo);
1068 PWINECRYPT_CERTSTORE memStore;
1070 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1073 if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
1074 dwFlags, pvPara, memStore, &provInfo))
1075 ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1078 CertCloseStore(memStore, 0);
1081 CryptFreeOIDFunctionAddress(hFunc, 0);
1084 SetLastError(ERROR_FILE_NOT_FOUND);
1088 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
1090 static const WCHAR fmt[] = { '%','0','2','X',0 };
1096 for (i = 0; i < 20; i++)
1097 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
1100 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
1102 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
1103 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
1104 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
1106 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store, HKEY key,
1111 WCHAR subKeyName[MAX_PATH];
1114 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
1116 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
1122 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
1128 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
1130 buf = CryptMemAlloc(size);
1133 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
1137 const void *context;
1140 TRACE("Adding cert with hash %s\n",
1141 debugstr_w(subKeyName));
1142 context = CRYPT_ReadSerializedElement(buf, size,
1143 contextType, &addedType);
1146 const WINE_CONTEXT_INTERFACE *contextInterface;
1151 case CERT_STORE_CERTIFICATE_CONTEXT:
1152 contextInterface = &gCertInterface;
1154 case CERT_STORE_CRL_CONTEXT:
1155 contextInterface = &gCRLInterface;
1157 case CERT_STORE_CTL_CONTEXT:
1158 contextInterface = &gCTLInterface;
1161 contextInterface = NULL;
1163 if (contextInterface)
1165 size = sizeof(hash);
1166 if (contextInterface->getProp(context,
1167 CERT_HASH_PROP_ID, hash, &size))
1169 WCHAR asciiHash[20 * 2 + 1];
1171 CRYPT_HashToStr(hash, asciiHash);
1172 TRACE("comparing %s\n",
1173 debugstr_w(asciiHash));
1174 TRACE("with %s\n", debugstr_w(subKeyName));
1175 if (!lstrcmpW(asciiHash, subKeyName))
1177 TRACE("hash matches, adding\n");
1178 contextInterface->addContextToStore(
1179 store->memStore, context,
1180 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
1183 TRACE("hash doesn't match, ignoring\n");
1185 contextInterface->free(context);
1191 RegCloseKey(subKey);
1193 /* Ignore intermediate errors, continue enumerating */
1199 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store)
1201 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1202 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
1203 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
1206 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1211 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
1215 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
1221 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
1222 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
1225 WCHAR asciiHash[20 * 2 + 1];
1230 CRYPT_HashToStr(hash, asciiHash);
1231 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1235 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
1236 RegCloseKey(subKey);
1248 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
1249 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1251 const void *context = NULL;
1255 context = contextInterface->enumContextsInStore(memStore, context);
1259 DWORD hashSize = sizeof(hash);
1261 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1268 ret = contextInterface->serialize(context, 0, NULL, &size);
1270 buf = CryptMemAlloc(size);
1273 ret = contextInterface->serialize(context, 0, buf, &size);
1275 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1282 } while (ret && context != NULL);
1284 contextInterface->free(context);
1288 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
1290 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1291 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1292 &gCRLInterface, &gCTLInterface };
1293 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1297 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1300 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1301 KEY_ALL_ACCESS, NULL, &key, NULL);
1305 if (listToDelete[i])
1307 PWINE_HASH_TO_DELETE toDelete, next;
1308 WCHAR asciiHash[20 * 2 + 1];
1310 EnterCriticalSection(&store->cs);
1311 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1312 WINE_HASH_TO_DELETE, entry)
1316 CRYPT_HashToStr(toDelete->hash, asciiHash);
1317 TRACE("Removing %s\n", debugstr_w(asciiHash));
1318 rc = RegDeleteKeyW(key, asciiHash);
1319 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1324 list_remove(&toDelete->entry);
1325 CryptMemFree(toDelete);
1327 LeaveCriticalSection(&store->cs);
1329 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1342 /* If force is true or the registry store is dirty, writes the contents of the
1343 * store to the registry.
1345 static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
1349 if (store->dirty || force)
1350 ret = CRYPT_RegWriteToReg(store);
1356 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1358 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1360 TRACE("(%p, %08lx)\n", store, dwFlags);
1362 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1364 CRYPT_RegFlushStore(store, FALSE);
1365 RegCloseKey(store->key);
1366 DeleteCriticalSection(&store->cs);
1367 CryptMemFree(store);
1370 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
1371 PCCERT_CONTEXT cert, DWORD dwFlags)
1373 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1376 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
1378 if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
1380 store->dirty = TRUE;
1388 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1389 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1391 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1394 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1396 if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
1398 SetLastError(ERROR_ACCESS_DENIED);
1403 PWINE_HASH_TO_DELETE toDelete =
1404 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1408 DWORD size = sizeof(toDelete->hash);
1410 ret = CertGetCertificateContextProperty(pCertContext,
1411 CERT_HASH_PROP_ID, toDelete->hash, &size);
1414 list_init(&toDelete->entry);
1415 EnterCriticalSection(&store->cs);
1416 list_add_tail(&store->certsToDelete, &toDelete->entry);
1417 LeaveCriticalSection(&store->cs);
1420 CryptMemFree(toDelete);
1425 store->dirty = TRUE;
1430 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1431 DWORD dwCtrlType, void const *pvCtrlPara)
1433 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1438 case CERT_STORE_CTRL_RESYNC:
1439 CRYPT_RegFlushStore(store, FALSE);
1440 CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1441 CRYPT_RegReadFromReg(store);
1444 case CERT_STORE_CTRL_COMMIT:
1445 ret = CRYPT_RegFlushStore(store,
1446 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1449 FIXME("%ld: stub\n", dwCtrlType);
1455 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1456 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1458 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1459 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1462 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1464 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1467 /* Find how many subkeys there are */
1468 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1469 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1473 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1475 /* Name too big: alloc a buffer for it */
1476 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1480 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1483 /* Recursively delete all the subkeys */
1484 for (i = 0; i < dwKeyCount && !dwRet; i++)
1486 dwSize = dwMaxSubkeyLen;
1487 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1490 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1493 if (lpszName != szNameBuf)
1495 /* Free buffer if allocated */
1496 CryptMemFree(lpszName);
1501 RegCloseKey(hSubKey);
1503 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1508 static void *regProvFuncs[] = {
1509 CRYPT_RegCloseStore,
1510 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1512 CRYPT_RegDeleteCert,
1513 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1514 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1515 NULL, /* CERT_STORE_PROV_WRITE_CRL_FUNC */
1516 NULL, /* CERT_STORE_PROV_DELETE_CRL_FUNC */
1517 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1518 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1519 NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1520 NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1521 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1525 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1526 DWORD dwFlags, const void *pvPara)
1528 PWINECRYPT_CERTSTORE store = NULL;
1530 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1532 if (dwFlags & CERT_STORE_DELETE_FLAG)
1534 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1536 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1537 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1538 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1539 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1540 if (rc == ERROR_NO_MORE_ITEMS)
1548 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1549 GetCurrentProcess(), (LPHANDLE)&key,
1550 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1553 PWINECRYPT_CERTSTORE memStore;
1555 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1558 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
1559 sizeof(WINE_REGSTOREINFO));
1563 CERT_STORE_PROV_INFO provInfo = { 0 };
1565 regInfo->dwOpenFlags = dwFlags;
1566 regInfo->cryptProv = hCryptProv;
1567 regInfo->memStore = memStore;
1569 InitializeCriticalSection(®Info->cs);
1570 list_init(®Info->certsToDelete);
1571 CRYPT_RegReadFromReg(regInfo);
1572 regInfo->dirty = FALSE;
1573 provInfo.cbSize = sizeof(provInfo);
1574 provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
1575 sizeof(regProvFuncs[0]);
1576 provInfo.rgpvStoreProvFunc = regProvFuncs;
1577 provInfo.hStoreProv = regInfo;
1578 store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1584 TRACE("returning %p\n", store);
1588 /* FIXME: this isn't complete for the Root store, in which the top-level
1589 * self-signed CA certs reside. Adding a cert to the Root store should present
1590 * the user with a dialog indicating the consequences of doing so, and asking
1591 * the user to confirm whether the cert should be added.
1593 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1594 DWORD dwFlags, const void *pvPara)
1596 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1597 LPCWSTR storeName = (LPCWSTR)pvPara;
1599 PWINECRYPT_CERTSTORE store = NULL;
1604 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1605 debugstr_w((LPCWSTR)pvPara));
1609 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1614 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1616 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1617 root = HKEY_LOCAL_MACHINE;
1618 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1620 case CERT_SYSTEM_STORE_CURRENT_USER:
1621 root = HKEY_CURRENT_USER;
1622 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1624 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1625 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1626 * SystemCertificates
1628 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1629 debugstr_w(storeName));
1631 case CERT_SYSTEM_STORE_SERVICES:
1632 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1633 * SystemCertificates
1635 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1636 debugstr_w(storeName));
1638 case CERT_SYSTEM_STORE_USERS:
1639 /* hku\user sid\Software\Microsoft\SystemCertificates */
1640 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1641 debugstr_w(storeName));
1643 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1644 root = HKEY_CURRENT_USER;
1645 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1647 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1648 root = HKEY_LOCAL_MACHINE;
1649 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1651 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1652 /* hklm\Software\Microsoft\EnterpriseCertificates */
1653 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1654 debugstr_w(storeName));
1657 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1661 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1667 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1670 wsprintfW(storePath, fmt, base, storeName);
1671 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1672 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1677 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1679 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1680 disp == REG_OPENED_EXISTING_KEY)
1683 rc = ERROR_FILE_EXISTS;
1688 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1693 CryptMemFree(storePath);
1698 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1699 DWORD dwFlags, const void *pvPara)
1702 PWINECRYPT_CERTSTORE ret = NULL;
1704 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1705 debugstr_a((LPCSTR)pvPara));
1709 SetLastError(ERROR_FILE_NOT_FOUND);
1712 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1715 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1719 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1720 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1721 CryptMemFree(storeName);
1727 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1728 DWORD dwFlags, const void *pvPara)
1730 HCERTSTORE store = 0;
1733 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1734 debugstr_w((LPCWSTR)pvPara));
1738 SetLastError(ERROR_FILE_NOT_FOUND);
1741 /* This returns a different error than system registry stores if the
1742 * location is invalid.
1744 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1746 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1747 case CERT_SYSTEM_STORE_CURRENT_USER:
1748 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1749 case CERT_SYSTEM_STORE_SERVICES:
1750 case CERT_SYSTEM_STORE_USERS:
1751 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1752 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1753 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1757 SetLastError(ERROR_FILE_NOT_FOUND);
1762 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1763 0, hCryptProv, dwFlags, pvPara);
1767 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1768 CERT_STORE_CREATE_NEW_FLAG, NULL);
1769 CertAddStoreToCollection(store, regStore,
1770 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1771 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1772 CertCloseStore(regStore, 0);
1773 /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1776 if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1777 CERT_SYSTEM_STORE_CURRENT_USER)
1779 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
1780 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
1781 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
1782 hCryptProv, dwFlags, pvPara);
1785 CertAddStoreToCollection(store, regStore,
1786 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1787 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1788 CertCloseStore(regStore, 0);
1793 return (PWINECRYPT_CERTSTORE)store;
1796 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1797 DWORD dwFlags, const void *pvPara)
1800 PWINECRYPT_CERTSTORE ret = NULL;
1802 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1803 debugstr_a((LPCSTR)pvPara));
1807 SetLastError(ERROR_FILE_NOT_FOUND);
1810 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1813 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1817 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1818 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1819 CryptMemFree(storeName);
1825 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1826 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1829 WINECRYPT_CERTSTORE *hcs;
1830 StoreOpenFunc openFunc = NULL;
1832 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1833 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1835 if (!HIWORD(lpszStoreProvider))
1837 switch (LOWORD(lpszStoreProvider))
1839 case (int)CERT_STORE_PROV_MEMORY:
1840 openFunc = CRYPT_MemOpenStore;
1842 case (int)CERT_STORE_PROV_REG:
1843 openFunc = CRYPT_RegOpenStore;
1845 case (int)CERT_STORE_PROV_COLLECTION:
1846 openFunc = CRYPT_CollectionOpenStore;
1848 case (int)CERT_STORE_PROV_SYSTEM_A:
1849 openFunc = CRYPT_SysOpenStoreA;
1851 case (int)CERT_STORE_PROV_SYSTEM_W:
1852 openFunc = CRYPT_SysOpenStoreW;
1854 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1855 openFunc = CRYPT_SysRegOpenStoreA;
1857 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1858 openFunc = CRYPT_SysRegOpenStoreW;
1861 if (LOWORD(lpszStoreProvider))
1862 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1865 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1866 openFunc = CRYPT_MemOpenStore;
1867 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1868 openFunc = CRYPT_SysOpenStoreW;
1869 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1870 openFunc = CRYPT_CollectionOpenStore;
1871 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1872 openFunc = CRYPT_SysRegOpenStoreW;
1875 FIXME("unimplemented type %s\n", lpszStoreProvider);
1880 hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
1881 hCryptProv, dwFlags, pvPara);
1883 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1884 return (HCERTSTORE)hcs;
1887 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1888 LPCSTR szSubSystemProtocol)
1890 if (!szSubSystemProtocol)
1892 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1895 return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
1896 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1899 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1900 LPCWSTR szSubSystemProtocol)
1902 if (!szSubSystemProtocol)
1904 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1907 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
1908 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1911 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1912 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1914 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1915 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1919 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1920 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1925 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1927 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1928 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1932 data = CryptMemAlloc( cbCrlEncoded );
1935 CryptMemFree( pcrl );
1939 pcrl->dwCertEncodingType = dwCertEncodingType;
1940 pcrl->pbCrlEncoded = data;
1941 pcrl->cbCrlEncoded = cbCrlEncoded;
1942 pcrl->pCrlInfo = NULL;
1943 pcrl->hCertStore = 0;
1948 /* Decodes the encoded certificate and creates the certificate context for it.
1949 * The reference count is initially zero, so you must create a reference to it
1950 * to avoid leaking memory.
1952 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1953 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1955 PWINE_CERT_CONTEXT cert = NULL;
1957 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1958 PCERT_INFO certInfo = NULL;
1961 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1964 /* First try to decode it as a signed cert. */
1965 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1966 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&signedCert, &size);
1970 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1971 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1972 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&certInfo, &size);
1973 LocalFree(signedCert);
1975 /* Failing that, try it as an unsigned cert */
1979 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1980 pbCertEncoded, cbCertEncoded,
1981 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1982 (BYTE *)&certInfo, &size);
1988 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1991 data = CryptMemAlloc(cbCertEncoded);
1998 memcpy(data, pbCertEncoded, cbCertEncoded);
1999 cert->cert.dwCertEncodingType = dwCertEncodingType;
2000 cert->cert.pbCertEncoded = data;
2001 cert->cert.cbCertEncoded = cbCertEncoded;
2002 cert->cert.pCertInfo = certInfo;
2003 cert->cert.hCertStore = 0;
2005 InitializeCriticalSection(&cert->cs);
2006 list_init(&cert->extendedProperties);
2013 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
2015 PWINE_CERT_PROPERTY prop, next;
2017 CryptMemFree(context->cert.pbCertEncoded);
2018 LocalFree(context->cert.pCertInfo);
2019 DeleteCriticalSection(&context->cs);
2020 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2021 WINE_CERT_PROPERTY, entry)
2023 list_remove(&prop->entry);
2024 CryptMemFree(prop->pbData);
2027 CryptMemFree(context);
2030 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
2031 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
2033 PWINE_CERT_CONTEXT cert;
2034 PWINE_CERT_CONTEXT_REF ret = NULL;
2036 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
2039 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
2042 ret = CRYPT_CreateCertRef(cert, 0);
2043 return (PCCERT_CONTEXT)ret;
2046 /* Since the properties are stored in a list, this is a tad inefficient
2047 * (O(n^2)) since I have to find the previous position every time.
2049 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
2052 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2055 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
2057 EnterCriticalSection(&ref->context->cs);
2060 PWINE_CERT_PROPERTY cursor = NULL;
2062 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
2063 WINE_CERT_PROPERTY, entry)
2065 if (cursor->hdr.propID == dwPropId)
2070 if (cursor->entry.next != &ref->context->extendedProperties)
2071 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
2079 else if (!list_empty(&ref->context->extendedProperties))
2080 ret = LIST_ENTRY(ref->context->extendedProperties.next,
2081 WINE_CERT_PROPERTY, entry)->hdr.propID;
2084 LeaveCriticalSection(&ref->context->cs);
2088 static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId,
2089 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
2092 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
2096 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
2098 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
2104 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
2105 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
2107 PWINE_CERT_PROPERTY prop;
2110 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
2112 EnterCriticalSection(&context->cs);
2115 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2116 WINE_CERT_PROPERTY, entry)
2118 if (prop->hdr.propID == dwPropId)
2122 *pcbData = prop->hdr.cb;
2125 else if (*pcbData < prop->hdr.cb)
2127 SetLastError(ERROR_MORE_DATA);
2128 *pcbData = prop->hdr.cb;
2132 memcpy(pvData, prop->pbData, prop->hdr.cb);
2133 *pcbData = prop->hdr.cb;
2142 /* Implicit properties */
2145 case CERT_SHA1_HASH_PROP_ID:
2146 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
2147 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
2150 case CERT_MD5_HASH_PROP_ID:
2151 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
2152 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
2155 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
2156 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
2157 context->cert.pCertInfo->Subject.pbData,
2158 context->cert.pCertInfo->Subject.cbData,
2161 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2162 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
2163 context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
2164 context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
2167 case CERT_SIGNATURE_HASH_PROP_ID:
2168 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
2169 FIXME("implicit property %ld\n", dwPropId);
2170 SetLastError(CRYPT_E_NOT_FOUND);
2173 SetLastError(CRYPT_E_NOT_FOUND);
2176 LeaveCriticalSection(&context->cs);
2177 TRACE("returning %d\n", ret);
2181 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2182 DWORD dwPropId, void *pvData, DWORD *pcbData)
2184 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2187 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
2189 /* Special cases for invalid/special prop IDs.
2194 case CERT_CERT_PROP_ID:
2195 case CERT_CRL_PROP_ID:
2196 case CERT_CTL_PROP_ID:
2197 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2199 case CERT_ACCESS_STATE_PROP_ID:
2202 *pcbData = sizeof(DWORD);
2205 else if (*pcbData < sizeof(DWORD))
2207 SetLastError(ERROR_MORE_DATA);
2208 *pcbData = sizeof(DWORD);
2215 if (pCertContext->hCertStore)
2217 PWINECRYPT_CERTSTORE store =
2218 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2220 if (!(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2221 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2223 *(DWORD *)pvData = state;
2228 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2230 TRACE("returning %d\n", ret);
2234 /* Copies cbData bytes from pbData to the context's property with ID
2237 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2238 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2245 data = CryptMemAlloc(cbData);
2247 memcpy(data, pbData, cbData);
2251 if (!cbData || data)
2253 PWINE_CERT_PROPERTY prop;
2256 EnterCriticalSection(&context->cs);
2257 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2258 WINE_CERT_PROPERTY, entry)
2260 if (prop->hdr.propID == dwPropId)
2268 CryptMemFree(prop->pbData);
2269 prop->hdr.cb = cbData;
2270 prop->pbData = data;
2275 prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2278 prop->hdr.propID = dwPropId;
2279 prop->hdr.unknown = 1;
2280 prop->hdr.cb = cbData;
2281 list_init(&prop->entry);
2282 prop->pbData = data;
2283 list_add_tail(&context->extendedProperties, &prop->entry);
2289 LeaveCriticalSection(&context->cs);
2294 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2295 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2299 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2303 PWINE_CERT_PROPERTY prop, next;
2305 EnterCriticalSection(&context->cs);
2306 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2307 WINE_CERT_PROPERTY, entry)
2309 if (prop->hdr.propID == dwPropId)
2311 list_remove(&prop->entry);
2312 CryptMemFree(prop->pbData);
2316 LeaveCriticalSection(&context->cs);
2323 case CERT_AUTO_ENROLL_PROP_ID:
2324 case CERT_CTL_USAGE_PROP_ID:
2325 case CERT_DESCRIPTION_PROP_ID:
2326 case CERT_FRIENDLY_NAME_PROP_ID:
2327 case CERT_HASH_PROP_ID:
2328 case CERT_KEY_IDENTIFIER_PROP_ID:
2329 case CERT_MD5_HASH_PROP_ID:
2330 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2331 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2332 case CERT_PVK_FILE_PROP_ID:
2333 case CERT_SIGNATURE_HASH_PROP_ID:
2334 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2335 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
2336 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2337 case CERT_ENROLLMENT_PROP_ID:
2338 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2339 case CERT_RENEWAL_PROP_ID:
2341 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2343 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2344 blob->pbData, blob->cbData);
2347 case CERT_DATE_STAMP_PROP_ID:
2348 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2349 pvData, sizeof(FILETIME));
2352 FIXME("%ld: stub\n", dwPropId);
2355 TRACE("returning %d\n", ret);
2359 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2360 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2362 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2365 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2367 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2368 * crashes on most of these, I'll be safer.
2373 case CERT_ACCESS_STATE_PROP_ID:
2374 case CERT_CERT_PROP_ID:
2375 case CERT_CRL_PROP_ID:
2376 case CERT_CTL_PROP_ID:
2377 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2380 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2382 TRACE("returning %d\n", ret);
2386 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2387 PCCERT_CONTEXT pCertContext)
2391 TRACE("(%p)\n", pCertContext);
2392 if (pCertContext->hCertStore)
2394 PWINECRYPT_CERTSTORE store =
2395 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2397 ret = store->dupCert(pCertContext);
2401 PWINE_CERT_CONTEXT_REF context = (PWINE_CERT_CONTEXT_REF)pCertContext,
2404 ref = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2407 memcpy(ref, context, sizeof(*ret));
2408 ref->cert.hCertStore = 0;
2409 InterlockedIncrement(&ref->context->ref);
2410 ret = (PCCERT_CONTEXT)ref;
2415 return (PCCERT_CONTEXT)ret;
2418 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2419 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2420 PCCERT_CONTEXT *ppStoreContext)
2422 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2423 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2424 PWINE_CERT_CONTEXT cert;
2427 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2428 dwAddDisposition, ppStoreContext);
2430 /* FIXME: some tests needed to verify return codes */
2433 SetLastError(ERROR_INVALID_PARAMETER);
2436 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2438 SetLastError(ERROR_INVALID_PARAMETER);
2442 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2443 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2446 PWINE_CERT_PROPERTY prop;
2449 EnterCriticalSection(&ref->context->cs);
2450 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2451 WINE_CERT_PROPERTY, entry)
2453 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2454 prop->pbData, prop->hdr.cb);
2458 LeaveCriticalSection(&ref->context->cs);
2461 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2462 if (ret && ppStoreContext)
2463 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2467 CRYPT_FreeCert(cert);
2474 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2475 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2476 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2478 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2481 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2482 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2486 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2490 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2491 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2495 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2496 if (ret && ppCertContext)
2497 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2500 CRYPT_FreeCert(cert);
2508 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2509 PCCERT_CONTEXT pPrev)
2511 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2512 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2515 TRACE("(%p, %p)\n", hCertStore, pPrev);
2518 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2521 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2525 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2529 TRACE("(%p)\n", pCertContext);
2533 else if (!pCertContext->hCertStore)
2536 CertFreeCertificateContext(pCertContext);
2540 PWINECRYPT_CERTSTORE hcs =
2541 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2543 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2546 ret = hcs->deleteCert(hcs, pCertContext, 0);
2547 CertFreeCertificateContext(pCertContext);
2552 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2553 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2554 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2556 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2557 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2562 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2563 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2564 PCCRL_CONTEXT* ppStoreContext )
2566 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2567 dwAddDisposition, ppStoreContext);
2571 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2573 FIXME("%p\n", pCrlContext );
2578 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2580 FIXME("(%p): stub\n", pCrlContext);
2584 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2585 PCCRL_CONTEXT pPrev)
2587 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2591 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2592 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2594 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2599 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2600 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2601 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2603 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2604 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2609 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2610 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2611 PCCTL_CONTEXT* ppStoreContext)
2613 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2614 dwAddDisposition, ppStoreContext);
2618 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2620 FIXME("(%p): stub\n", pCtlContext );
2624 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2626 FIXME("(%p): stub\n", pCtlContext);
2630 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2631 PCCTL_CONTEXT pPrev)
2633 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2638 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2640 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2642 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2647 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2650 if (InterlockedDecrement(&hcs->ref) == 0)
2652 TRACE("%p's ref count is 0, freeing\n", hcs);
2654 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2655 CryptReleaseContext(hcs->cryptProv, 0);
2656 hcs->closeStore(hcs, dwFlags);
2659 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2663 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2664 DWORD dwCtrlType, void const *pvCtrlPara)
2666 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2669 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2674 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2679 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2686 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2687 DWORD dwPropId, void *pvData, DWORD *pcbData)
2689 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2693 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2694 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2696 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2701 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2702 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2704 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2709 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2710 DWORD dwPropId, void *pvData, DWORD *pcbData)
2712 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2716 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2717 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2719 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2724 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2725 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2727 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2732 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2733 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2737 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2742 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2743 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2744 pCertContext->cbCertEncoded;
2745 PWINE_CERT_PROPERTY prop;
2747 EnterCriticalSection(&ref->context->cs);
2748 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2749 WINE_CERT_PROPERTY, entry)
2750 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2753 *pcbElement = bytesNeeded;
2756 else if (*pcbElement < bytesNeeded)
2758 *pcbElement = bytesNeeded;
2759 SetLastError(ERROR_MORE_DATA);
2764 PWINE_CERT_PROP_HEADER hdr;
2766 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2767 WINE_CERT_PROPERTY, entry)
2769 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2770 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2773 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2774 pbElement += prop->hdr.cb;
2777 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2778 hdr->propID = CERT_CERT_PROP_ID;
2780 hdr->cb = pCertContext->cbCertEncoded;
2781 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2782 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2785 LeaveCriticalSection(&ref->context->cs);
2792 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2793 * to its header if a valid header is found, NULL if not. Valid means the
2794 * length of thte property won't overrun buf, and the unknown field is 1.
2796 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2797 DWORD size, DWORD propID)
2799 const WINE_CERT_PROP_HEADER *ret = NULL;
2802 while (size && !ret && !done)
2804 if (size < sizeof(WINE_CERT_PROP_HEADER))
2806 SetLastError(CRYPT_E_FILE_ERROR);
2811 const WINE_CERT_PROP_HEADER *hdr =
2812 (const WINE_CERT_PROP_HEADER *)buf;
2814 size -= sizeof(WINE_CERT_PROP_HEADER);
2815 buf += sizeof(WINE_CERT_PROP_HEADER);
2818 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2821 else if (!hdr->propID)
2823 /* assume a zero prop ID means the data are uninitialized, so
2828 else if (hdr->unknown != 1)
2830 SetLastError(ERROR_FILE_NOT_FOUND);
2833 else if (hdr->propID == propID)
2845 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2846 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2848 const void *context;
2850 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2855 SetLastError(ERROR_END_OF_MEDIA);
2861 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2862 const WINE_CERT_PROP_HEADER *hdr = NULL;
2868 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2870 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2872 type = CERT_STORE_CERTIFICATE_CONTEXT;
2875 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2877 type = CERT_STORE_CRL_CONTEXT;
2880 hdr = CRYPT_findPropID(pbElement, cbElement,
2883 type = CERT_STORE_CTL_CONTEXT;
2887 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2889 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2890 type = CERT_STORE_CERTIFICATE_CONTEXT;
2892 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2894 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2895 type = CERT_STORE_CRL_CONTEXT;
2897 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2899 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2900 type = CERT_STORE_CTL_CONTEXT;
2905 case CERT_STORE_CERTIFICATE_CONTEXT:
2906 contextInterface = &gCertInterface;
2908 case CERT_STORE_CRL_CONTEXT:
2909 contextInterface = &gCRLInterface;
2911 case CERT_STORE_CTL_CONTEXT:
2912 contextInterface = &gCTLInterface;
2915 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2922 context = contextInterface->create(X509_ASN_ENCODING,
2923 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2926 BOOL noMoreProps = FALSE;
2928 while (!noMoreProps && ret)
2930 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2934 const WINE_CERT_PROP_HEADER *hdr =
2935 (const WINE_CERT_PROP_HEADER *)pbElement;
2937 TRACE("prop is %ld\n", hdr->propID);
2938 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2939 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2940 if (cbElement < hdr->cb)
2942 SetLastError(HRESULT_FROM_WIN32(
2943 ERROR_INVALID_PARAMETER));
2946 else if (!hdr->propID)
2948 /* Like in CRYPT_findPropID, stop if the propID is zero
2952 else if (hdr->unknown != 1)
2954 SetLastError(ERROR_FILE_NOT_FOUND);
2957 else if (hdr->propID != CERT_CERT_PROP_ID &&
2958 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2961 /* Have to create a blob for most types, but not
2964 switch (hdr->propID)
2966 case CERT_AUTO_ENROLL_PROP_ID:
2967 case CERT_CTL_USAGE_PROP_ID:
2968 case CERT_DESCRIPTION_PROP_ID:
2969 case CERT_FRIENDLY_NAME_PROP_ID:
2970 case CERT_HASH_PROP_ID:
2971 case CERT_KEY_IDENTIFIER_PROP_ID:
2972 case CERT_MD5_HASH_PROP_ID:
2973 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2974 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2975 case CERT_PVK_FILE_PROP_ID:
2976 case CERT_SIGNATURE_HASH_PROP_ID:
2977 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2978 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2979 case CERT_ENROLLMENT_PROP_ID:
2980 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2981 case CERT_RENEWAL_PROP_ID:
2983 CRYPT_DATA_BLOB blob = { hdr->cb,
2984 (LPBYTE)pbElement };
2986 ret = contextInterface->setProp(context,
2987 hdr->propID, 0, &blob);
2990 case CERT_DATE_STAMP_PROP_ID:
2991 ret = contextInterface->setProp(context,
2992 hdr->propID, 0, pbElement);
2995 FIXME("prop ID %ld: stub\n", hdr->propID);
2998 pbElement += hdr->cb;
2999 cbElement -= hdr->cb;
3007 *pdwContentType = type;
3011 contextInterface->free(context);
3018 SetLastError(STATUS_ACCESS_VIOLATION);
3025 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
3026 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
3027 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
3029 const void *context;
3033 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
3034 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
3035 pdwContentType, ppvContext);
3037 /* Call the internal function, then delete the hashes. Tests show this
3038 * function uses real hash values, not whatever's stored in the hash
3041 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
3042 dwContextTypeFlags, &type);
3045 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
3049 case CERT_STORE_CERTIFICATE_CONTEXT:
3050 contextInterface = &gCertInterface;
3052 case CERT_STORE_CRL_CONTEXT:
3053 contextInterface = &gCRLInterface;
3055 case CERT_STORE_CTL_CONTEXT:
3056 contextInterface = &gCTLInterface;
3059 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3061 if (contextInterface)
3063 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
3064 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
3065 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
3068 *pdwContentType = type;
3069 ret = contextInterface->addContextToStore(hCertStore, context,
3070 dwAddDisposition, ppvContext);
3071 contextInterface->free(context);
3081 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref)
3083 if (InterlockedDecrement(&ref->context->ref) == 0)
3085 TRACE("%p's ref count is 0, freeing\n", ref->context);
3086 CRYPT_FreeCert(ref->context);
3089 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
3092 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
3094 TRACE("(%p)\n", pCertContext);
3098 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
3099 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
3101 CRYPT_UnrefCertificateContext(ref);
3102 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
3104 store->freeCert(ref);
3105 TRACE("freeing %p\n", ref);
3111 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
3112 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
3113 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
3115 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
3116 dwFlags, dwType, pvPara, pPrevCertContext);
3117 SetLastError(CRYPT_E_NOT_FOUND);
3121 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
3122 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
3124 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
3125 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
3126 PWINE_STORE_LIST_ENTRY entry;
3129 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
3130 dwUpdateFlags, dwPriority);
3132 if (!collection || !sibling)
3134 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3136 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3139 if (collection->hdr.type != StoreTypeCollection)
3141 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3144 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3146 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3150 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
3153 InterlockedIncrement(&sibling->ref);
3154 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
3155 entry->store = sibling;
3156 entry->dwUpdateFlags = dwUpdateFlags;
3157 entry->dwPriority = dwPriority;
3158 list_init(&entry->entry);
3159 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
3160 EnterCriticalSection(&collection->cs);
3163 PWINE_STORE_LIST_ENTRY cursor;
3166 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
3167 WINE_STORE_LIST_ENTRY, entry)
3169 if (cursor->dwPriority < dwPriority)
3171 list_add_before(&cursor->entry, &entry->entry);
3177 list_add_tail(&collection->stores, &entry->entry);
3180 list_add_tail(&collection->stores, &entry->entry);
3181 LeaveCriticalSection(&collection->cs);
3189 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
3190 HCERTSTORE hSiblingStore)
3192 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
3193 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
3194 PWINE_STORE_LIST_ENTRY store, next;
3196 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
3198 if (!collection || !sibling)
3200 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3202 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3205 if (collection->hdr.type != StoreTypeCollection)
3207 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3209 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3212 EnterCriticalSection(&collection->cs);
3213 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3214 WINE_STORE_LIST_ENTRY, entry)
3216 if (store->store == sibling)
3218 list_remove(&store->entry);
3219 CertCloseStore(store->store, 0);
3220 CryptMemFree(store);
3224 LeaveCriticalSection(&collection->cs);