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 TRACE("%p's ref count is %ld\n", context, context->ref);
351 ref->cert.hCertStore = store;
354 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
357 PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
358 sizeof(WINE_CERT_CONTEXT_REF));
360 TRACE("(%p, %p)\n", context, store);
362 CRYPT_InitCertRef(pCertRef, context, store);
366 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
367 DWORD dwAddDisposition)
369 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
370 BOOL add = FALSE, ret;
372 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
374 switch (dwAddDisposition)
376 case CERT_STORE_ADD_ALWAYS:
379 case CERT_STORE_ADD_NEW:
381 BYTE hashToAdd[20], hash[20];
382 DWORD size = sizeof(hashToAdd);
384 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
385 CERT_HASH_PROP_ID, hashToAdd, &size);
388 PWINE_CERT_LIST_ENTRY cursor;
390 /* Add if no cert with the same hash is found. */
392 EnterCriticalSection(&ms->cs);
393 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
396 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
397 CERT_HASH_PROP_ID, hash, &size);
398 if (ret && !memcmp(hashToAdd, hash, size))
400 TRACE("found matching certificate, not adding\n");
401 SetLastError(CRYPT_E_EXISTS);
406 LeaveCriticalSection(&ms->cs);
410 case CERT_STORE_ADD_REPLACE_EXISTING:
412 BYTE hashToAdd[20], hash[20];
413 DWORD size = sizeof(hashToAdd);
416 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
417 CERT_HASH_PROP_ID, hashToAdd, &size);
420 PWINE_CERT_LIST_ENTRY cursor, next;
422 /* Look for existing cert to delete */
423 EnterCriticalSection(&ms->cs);
424 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
425 WINE_CERT_LIST_ENTRY, entry)
428 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
429 CERT_HASH_PROP_ID, hash, &size);
430 if (ret && !memcmp(hashToAdd, hash, size))
432 TRACE("found matching certificate, replacing\n");
433 list_remove(&cursor->entry);
434 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
438 LeaveCriticalSection(&ms->cs);
443 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
448 PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
449 sizeof(WINE_CERT_LIST_ENTRY));
453 TRACE("adding %p\n", entry);
454 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
455 list_init(&entry->entry);
456 EnterCriticalSection(&ms->cs);
457 list_add_tail(&ms->certs, &entry->entry);
458 LeaveCriticalSection(&ms->cs);
466 TRACE("returning %d\n", ret);
470 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
471 PWINE_CERT_CONTEXT_REF pPrev)
473 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
474 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
475 struct list *listNext;
477 TRACE("(%p, %p)\n", store, pPrev);
478 EnterCriticalSection(&ms->cs);
481 listNext = list_next(&ms->certs, &prevEntry->entry);
482 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
485 listNext = list_next(&ms->certs, &ms->certs);
488 ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
491 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
492 sizeof(WINE_CERT_LIST_ENTRY));
493 InterlockedIncrement(&ret->cert.context->ref);
498 SetLastError(CRYPT_E_NOT_FOUND);
501 LeaveCriticalSection(&ms->cs);
503 TRACE("returning %p\n", ret);
504 return (PWINE_CERT_CONTEXT_REF)ret;
507 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref);
509 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
510 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
512 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
513 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
514 PWINE_CERT_LIST_ENTRY cert, next;
517 /* Find the entry associated with the passed-in context, since the
518 * passed-in context may not be a list entry itself (e.g. if it came from
519 * CertDuplicateCertificateContext.) Pointing to the same context is
520 * a sufficient test of equality.
522 EnterCriticalSection(&store->cs);
523 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
526 if (cert->cert.context == ref->context)
528 TRACE("removing %p\n", cert);
529 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
532 list_remove(&cert->entry);
533 /* FIXME: generally I should do the following, otherwise there is
534 * a memory leak. But doing so when called by
535 * CertDeleteCertificateFromStore results in a double free, so
536 * leaving commented for now.
537 ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
539 cert->entry.prev = cert->entry.next = &store->certs;
543 LeaveCriticalSection(&store->cs);
547 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
549 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
550 PWINE_CERT_LIST_ENTRY cert, next;
552 TRACE("(%p, %08lx)\n", store, dwFlags);
554 FIXME("Unimplemented flags: %08lx\n", dwFlags);
556 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
557 * pointer if its ref-count reaches zero. That's okay here because there
558 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
559 * of the CertListEntry.
561 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
564 TRACE("removing %p\n", cert);
565 list_remove(&cert->entry);
566 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
568 DeleteCriticalSection(&store->cs);
572 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
573 DWORD dwFlags, const void *pvPara)
575 PWINE_MEMSTORE store;
577 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
579 if (dwFlags & CERT_STORE_DELETE_FLAG)
581 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
586 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
589 memset(store, 0, sizeof(WINE_MEMSTORE));
590 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
591 store->hdr.closeStore = CRYPT_MemCloseStore;
592 store->hdr.addCert = CRYPT_MemAddCert;
593 store->hdr.createCertRef = CRYPT_CreateCertRef;
594 store->hdr.enumCert = CRYPT_MemEnumCert;
595 store->hdr.deleteCert = CRYPT_MemDeleteCert;
596 store->hdr.freeCert = NULL;
597 InitializeCriticalSection(&store->cs);
598 list_init(&store->certs);
601 return (PWINECRYPT_CERTSTORE)store;
604 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
605 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
607 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
608 PWINE_STORE_LIST_ENTRY entry, next;
611 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
614 EnterCriticalSection(&cs->cs);
615 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
618 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
620 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
624 LeaveCriticalSection(&cs->cs);
625 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
629 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
630 PWINE_CERT_CONTEXT context, HCERTSTORE store)
632 PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
633 sizeof(WINE_COLLECTION_CERT_CONTEXT));
637 /* Initialize to empty for now, just make sure the size is right */
638 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
640 ret->childContext = NULL;
642 return (PWINE_CERT_CONTEXT_REF)ret;
645 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
647 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
648 PWINE_STORE_LIST_ENTRY entry, next;
650 TRACE("(%p, %08lx)\n", store, dwFlags);
652 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
655 TRACE("closing %p\n", entry);
656 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
659 DeleteCriticalSection(&cs->cs);
663 /* Advances a collection enumeration by one cert, if possible, where advancing
665 * - calling the current store's enumeration function once, and returning
666 * the enumerated cert if one is returned
667 * - moving to the next store if the current store has no more items, and
668 * recursively calling itself to get the next item.
669 * Returns NULL if the collection contains no more items or on error.
670 * Assumes the collection store's lock is held.
672 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
673 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
674 PWINE_COLLECTION_CERT_CONTEXT pPrev)
676 PWINE_COLLECTION_CERT_CONTEXT ret;
677 PWINE_CERT_CONTEXT_REF child;
678 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
680 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
682 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
683 pPrev ? pPrev->childContext : NULL);
686 pPrev->childContext = NULL;
687 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
692 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
693 child->context, store);
696 ret->entry = storeEntry;
697 ret->childContext = child;
700 CertFreeCertificateContext((PCCERT_CONTEXT)child);
706 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
707 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
711 SetLastError(CRYPT_E_NOT_FOUND);
715 TRACE("returning %p\n", ret);
719 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
720 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
722 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
723 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
724 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
726 TRACE("(%p, %p)\n", store, pPrev);
730 EnterCriticalSection(&cs->cs);
731 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
732 LeaveCriticalSection(&cs->cs);
736 EnterCriticalSection(&cs->cs);
737 if (!list_empty(&cs->stores))
739 PWINE_STORE_LIST_ENTRY storeEntry;
741 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
743 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
747 SetLastError(CRYPT_E_NOT_FOUND);
750 LeaveCriticalSection(&cs->cs);
752 TRACE("returning %p\n", ret);
753 return (PWINE_CERT_CONTEXT_REF)ret;
756 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
757 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
759 PWINE_COLLECTION_CERT_CONTEXT context =
760 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
763 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
765 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
767 context->childContext = NULL;
771 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
773 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
775 TRACE("(%p)\n", ref);
777 if (context->childContext)
778 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
781 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
782 DWORD dwFlags, const void *pvPara)
784 PWINE_COLLECTIONSTORE store;
786 if (dwFlags & CERT_STORE_DELETE_FLAG)
788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
793 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
796 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
797 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
798 StoreTypeCollection);
799 store->hdr.closeStore = CRYPT_CollectionCloseStore;
800 store->hdr.addCert = CRYPT_CollectionAddCert;
801 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
802 store->hdr.enumCert = CRYPT_CollectionEnumCert;
803 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
804 store->hdr.freeCert = CRYPT_CollectionFreeCert;
805 InitializeCriticalSection(&store->cs);
806 list_init(&store->stores);
809 return (PWINECRYPT_CERTSTORE)store;
812 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
814 static const WCHAR fmt[] = { '%','0','2','X',0 };
820 for (i = 0; i < 20; i++)
821 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
824 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
826 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
827 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
828 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
830 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
835 WCHAR subKeyName[MAX_PATH];
838 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
840 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
846 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
852 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
854 buf = CryptMemAlloc(size);
857 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
864 TRACE("Adding cert with hash %s\n",
865 debugstr_w(subKeyName));
866 context = CRYPT_ReadSerializedElement(buf, size,
867 contextType, &addedType);
870 const WINE_CONTEXT_INTERFACE *contextInterface;
875 case CERT_STORE_CERTIFICATE_CONTEXT:
876 contextInterface = &gCertInterface;
878 case CERT_STORE_CRL_CONTEXT:
879 contextInterface = &gCRLInterface;
881 case CERT_STORE_CTL_CONTEXT:
882 contextInterface = &gCTLInterface;
885 contextInterface = NULL;
887 if (contextInterface)
890 if (contextInterface->getProp(context,
891 CERT_HASH_PROP_ID, hash, &size))
893 WCHAR asciiHash[20 * 2 + 1];
895 CRYPT_HashToStr(hash, asciiHash);
896 TRACE("comparing %s\n",
897 debugstr_w(asciiHash));
898 TRACE("with %s\n", debugstr_w(subKeyName));
899 if (!lstrcmpW(asciiHash, subKeyName))
901 TRACE("hash matches, adding\n");
902 contextInterface->addContextToStore(
904 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
907 TRACE("hash doesn't match, ignoring\n");
909 contextInterface->free(context);
917 /* Ignore intermediate errors, continue enumerating */
923 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
925 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
926 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
927 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
930 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
935 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
939 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
945 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
946 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
949 WCHAR asciiHash[20 * 2 + 1];
954 CRYPT_HashToStr(hash, asciiHash);
955 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
959 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
972 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
973 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
975 const void *context = NULL;
979 context = contextInterface->enumContextsInStore(memStore, context);
983 DWORD hashSize = sizeof(hash);
985 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
992 ret = contextInterface->serialize(context, 0, NULL, &size);
994 buf = CryptMemAlloc(size);
997 ret = contextInterface->serialize(context, 0, buf, &size);
999 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1006 } while (ret && context != NULL);
1008 contextInterface->free(context);
1012 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1014 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1015 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1016 &gCRLInterface, &gCTLInterface };
1017 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1021 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1024 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1025 KEY_ALL_ACCESS, NULL, &key, NULL);
1029 if (listToDelete[i])
1031 PWINE_HASH_TO_DELETE toDelete, next;
1032 WCHAR asciiHash[20 * 2 + 1];
1034 EnterCriticalSection(&store->cs);
1035 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1036 WINE_HASH_TO_DELETE, entry)
1040 CRYPT_HashToStr(toDelete->hash, asciiHash);
1041 TRACE("Removing %s\n", debugstr_w(asciiHash));
1042 rc = RegDeleteKeyW(key, asciiHash);
1043 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1048 list_remove(&toDelete->entry);
1049 CryptMemFree(toDelete);
1051 LeaveCriticalSection(&store->cs);
1053 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1066 /* If force is true or the registry store is dirty, writes the contents of the
1067 * store to the registry.
1069 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1073 if (store->dirty || force)
1074 ret = CRYPT_RegWriteToReg(store);
1080 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1082 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1084 TRACE("(%p, %08lx)\n", store, dwFlags);
1086 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1088 CRYPT_RegFlushStore(store, FALSE);
1089 /* certsToDelete should already be cleared by this point */
1090 store->memStore->closeStore(store->memStore, 0);
1091 RegCloseKey(store->key);
1092 DeleteCriticalSection(&store->cs);
1093 CryptMemFree(store);
1096 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1097 DWORD dwAddDisposition)
1099 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1102 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1104 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1106 SetLastError(ERROR_ACCESS_DENIED);
1111 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1113 store->dirty = TRUE;
1118 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1119 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1121 PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
1125 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1126 ret->childContext = NULL;
1128 return (PWINE_CERT_CONTEXT_REF)ret;
1131 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1132 PWINE_CERT_CONTEXT_REF pPrev)
1134 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1135 PWINE_CERT_CONTEXT_REF child;
1136 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1138 TRACE("(%p, %p)\n", store, pPrev);
1140 child = rs->memStore->enumCert(rs->memStore, prev ? prev->childContext
1144 prev->childContext = NULL;
1145 CertFreeCertificateContext((PCCERT_CONTEXT)prev);
1150 ret = (PWINE_REG_CERT_CONTEXT)CRYPT_RegCreateCertRef(child->context,
1153 ret->childContext = child;
1155 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1157 return (PWINE_CERT_CONTEXT_REF)ret;
1160 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1161 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1163 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1166 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1168 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1170 SetLastError(ERROR_ACCESS_DENIED);
1175 PWINE_HASH_TO_DELETE toDelete =
1176 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1180 DWORD size = sizeof(toDelete->hash);
1182 ret = CertGetCertificateContextProperty(pCertContext,
1183 CERT_HASH_PROP_ID, toDelete->hash, &size);
1186 list_init(&toDelete->entry);
1187 EnterCriticalSection(&store->cs);
1188 list_add_tail(&store->certsToDelete, &toDelete->entry);
1189 LeaveCriticalSection(&store->cs);
1190 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1194 CryptMemFree(toDelete);
1199 store->dirty = TRUE;
1204 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1206 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1208 TRACE("(%p)\n", ref);
1210 if (context->childContext)
1211 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1214 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1215 DWORD dwCtrlType, void const *pvCtrlPara)
1217 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1222 case CERT_STORE_CTRL_RESYNC:
1223 CRYPT_RegFlushStore(store, FALSE);
1224 store->memStore->closeStore(store->memStore, 0);
1225 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1226 store->hdr.dwOpenFlags, NULL);
1227 if (store->memStore)
1229 CRYPT_RegReadFromReg(store);
1235 case CERT_STORE_CTRL_COMMIT:
1236 ret = CRYPT_RegFlushStore(store,
1237 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1240 FIXME("%ld: stub\n", dwCtrlType);
1246 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1247 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1249 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1250 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1253 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1255 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1258 /* Find how many subkeys there are */
1259 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1260 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1264 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1266 /* Name too big: alloc a buffer for it */
1267 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1271 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1274 /* Recursively delete all the subkeys */
1275 for (i = 0; i < dwKeyCount && !dwRet; i++)
1277 dwSize = dwMaxSubkeyLen;
1278 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1281 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1284 if (lpszName != szNameBuf)
1286 /* Free buffer if allocated */
1287 CryptMemFree(lpszName);
1292 RegCloseKey(hSubKey);
1294 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1299 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1300 DWORD dwFlags, const void *pvPara)
1302 PWINE_REGSTORE store = NULL;
1304 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1306 if (dwFlags & CERT_STORE_DELETE_FLAG)
1308 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1310 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1311 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1312 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1313 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1314 if (rc == ERROR_NO_MORE_ITEMS)
1322 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1323 GetCurrentProcess(), (LPHANDLE)&key,
1324 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1327 PWINECRYPT_CERTSTORE memStore;
1329 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1332 store = CryptMemAlloc(sizeof(WINE_REGSTORE));
1335 memset(store, 0, sizeof(WINE_REGSTORE));
1336 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1338 store->hdr.closeStore = CRYPT_RegCloseStore;
1339 store->hdr.addCert = CRYPT_RegAddCert;
1340 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1341 store->hdr.enumCert = CRYPT_RegEnumCert;
1342 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1343 store->hdr.freeCert = CRYPT_RegFreeCert;
1344 store->hdr.control = CRYPT_RegControl;
1345 store->memStore = memStore;
1347 InitializeCriticalSection(&store->cs);
1348 list_init(&store->certsToDelete);
1349 CRYPT_RegReadFromReg(store);
1350 store->dirty = FALSE;
1355 TRACE("returning %p\n", store);
1356 return (WINECRYPT_CERTSTORE *)store;
1359 /* FIXME: this isn't complete for the Root store, in which the top-level
1360 * self-signed CA certs reside. Adding a cert to the Root store should present
1361 * the user with a dialog indicating the consequences of doing so, and asking
1362 * the user to confirm whether the cert should be added.
1364 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1365 DWORD dwFlags, const void *pvPara)
1367 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1368 LPCWSTR storeName = (LPCWSTR)pvPara;
1370 PWINECRYPT_CERTSTORE store = NULL;
1375 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1376 debugstr_w((LPCWSTR)pvPara));
1380 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1385 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1387 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1388 root = HKEY_LOCAL_MACHINE;
1389 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1391 case CERT_SYSTEM_STORE_CURRENT_USER:
1392 root = HKEY_CURRENT_USER;
1393 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1395 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1396 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1397 * SystemCertificates
1399 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1400 debugstr_w(storeName));
1402 case CERT_SYSTEM_STORE_SERVICES:
1403 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1404 * SystemCertificates
1406 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1407 debugstr_w(storeName));
1409 case CERT_SYSTEM_STORE_USERS:
1410 /* hku\user sid\Software\Microsoft\SystemCertificates */
1411 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1412 debugstr_w(storeName));
1414 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1415 root = HKEY_CURRENT_USER;
1416 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1418 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1419 root = HKEY_LOCAL_MACHINE;
1420 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1423 /* hklm\Software\Microsoft\EnterpriseCertificates */
1424 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1425 debugstr_w(storeName));
1428 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1432 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1438 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1441 wsprintfW(storePath, fmt, base, storeName);
1442 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1443 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1448 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1450 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1451 disp == REG_OPENED_EXISTING_KEY)
1454 rc = ERROR_FILE_EXISTS;
1459 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1464 CryptMemFree(storePath);
1469 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1470 DWORD dwFlags, const void *pvPara)
1473 PWINECRYPT_CERTSTORE ret = NULL;
1475 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1476 debugstr_a((LPCSTR)pvPara));
1480 SetLastError(ERROR_FILE_NOT_FOUND);
1483 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1486 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1490 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1491 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1492 CryptMemFree(storeName);
1498 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1499 DWORD dwFlags, const void *pvPara)
1501 HCERTSTORE store = 0;
1504 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1505 debugstr_w((LPCWSTR)pvPara));
1509 SetLastError(ERROR_FILE_NOT_FOUND);
1512 /* This returns a different error than system registry stores if the
1513 * location is invalid.
1515 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1517 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1518 case CERT_SYSTEM_STORE_CURRENT_USER:
1519 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1520 case CERT_SYSTEM_STORE_SERVICES:
1521 case CERT_SYSTEM_STORE_USERS:
1522 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1523 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1524 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1528 SetLastError(ERROR_FILE_NOT_FOUND);
1533 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1534 0, hCryptProv, dwFlags, pvPara);
1538 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1539 CERT_STORE_CREATE_NEW_FLAG, NULL);
1542 CertAddStoreToCollection(store, regStore,
1543 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1544 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1545 CertCloseStore(regStore, 0);
1549 return (PWINECRYPT_CERTSTORE)store;
1552 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1553 DWORD dwFlags, const void *pvPara)
1556 PWINECRYPT_CERTSTORE ret = NULL;
1558 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1559 debugstr_a((LPCSTR)pvPara));
1563 SetLastError(ERROR_FILE_NOT_FOUND);
1566 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1569 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1573 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1574 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1575 CryptMemFree(storeName);
1581 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1582 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1585 WINECRYPT_CERTSTORE *hcs;
1586 StoreOpenFunc openFunc = NULL;
1588 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1589 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1591 if (!HIWORD(lpszStoreProvider))
1593 switch (LOWORD(lpszStoreProvider))
1595 case (int)CERT_STORE_PROV_MEMORY:
1596 openFunc = CRYPT_MemOpenStore;
1598 case (int)CERT_STORE_PROV_REG:
1599 openFunc = CRYPT_RegOpenStore;
1601 case (int)CERT_STORE_PROV_COLLECTION:
1602 openFunc = CRYPT_CollectionOpenStore;
1604 case (int)CERT_STORE_PROV_SYSTEM_A:
1605 openFunc = CRYPT_SysOpenStoreA;
1607 case (int)CERT_STORE_PROV_SYSTEM_W:
1608 openFunc = CRYPT_SysOpenStoreW;
1610 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1611 openFunc = CRYPT_SysRegOpenStoreA;
1613 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1614 openFunc = CRYPT_SysRegOpenStoreW;
1617 if (LOWORD(lpszStoreProvider))
1618 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1621 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1622 openFunc = CRYPT_MemOpenStore;
1623 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1624 openFunc = CRYPT_SysOpenStoreW;
1625 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1626 openFunc = CRYPT_CollectionOpenStore;
1627 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1628 openFunc = CRYPT_SysRegOpenStoreW;
1631 FIXME("unimplemented type %s\n", lpszStoreProvider);
1637 /* FIXME: need to look for an installed provider for this type */
1638 SetLastError(ERROR_FILE_NOT_FOUND);
1642 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1643 return (HCERTSTORE)hcs;
1646 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1647 LPCSTR szSubSystemProtocol)
1651 if (szSubSystemProtocol)
1653 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1655 LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR));
1659 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1660 ret = CertOpenSystemStoreW(hProv, param);
1661 CryptMemFree(param);
1665 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1669 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1670 LPCWSTR szSubSystemProtocol)
1674 if (!szSubSystemProtocol)
1676 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1680 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1681 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1684 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1685 CERT_STORE_CREATE_NEW_FLAG, NULL);
1688 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1689 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1693 CertAddStoreToCollection(ret, store,
1694 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1695 CertCloseStore(store, 0);
1697 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1698 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1701 CertAddStoreToCollection(ret, store,
1702 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1703 CertCloseStore(store, 0);
1709 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1710 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1712 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1713 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1717 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1718 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1723 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1725 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1726 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1730 data = CryptMemAlloc( cbCrlEncoded );
1733 CryptMemFree( pcrl );
1737 pcrl->dwCertEncodingType = dwCertEncodingType;
1738 pcrl->pbCrlEncoded = data;
1739 pcrl->cbCrlEncoded = cbCrlEncoded;
1740 pcrl->pCrlInfo = NULL;
1741 pcrl->hCertStore = 0;
1746 /* Decodes the encoded certificate and creates the certificate context for it.
1747 * The reference count is initially zero, so you must create a reference to it
1748 * to avoid leaking memory.
1750 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1751 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1753 PWINE_CERT_CONTEXT cert = NULL;
1755 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1756 PCERT_INFO certInfo = NULL;
1759 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1762 /* First try to decode it as a signed cert. */
1763 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1764 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1765 (BYTE *)&signedCert, &size);
1769 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1770 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1771 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1772 (BYTE *)&certInfo, &size);
1773 LocalFree(signedCert);
1775 /* Failing that, try it as an unsigned cert */
1779 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1780 pbCertEncoded, cbCertEncoded,
1781 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1782 (BYTE *)&certInfo, &size);
1788 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1791 data = CryptMemAlloc(cbCertEncoded);
1798 memcpy(data, pbCertEncoded, cbCertEncoded);
1799 cert->cert.dwCertEncodingType = dwCertEncodingType;
1800 cert->cert.pbCertEncoded = data;
1801 cert->cert.cbCertEncoded = cbCertEncoded;
1802 cert->cert.pCertInfo = certInfo;
1803 cert->cert.hCertStore = 0;
1805 InitializeCriticalSection(&cert->cs);
1806 list_init(&cert->extendedProperties);
1813 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1815 PWINE_CERT_PROPERTY prop, next;
1817 CryptMemFree(context->cert.pbCertEncoded);
1818 LocalFree(context->cert.pCertInfo);
1819 DeleteCriticalSection(&context->cs);
1820 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1821 WINE_CERT_PROPERTY, entry)
1823 list_remove(&prop->entry);
1824 CryptMemFree(prop->pbData);
1827 CryptMemFree(context);
1830 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1831 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1833 PWINE_CERT_CONTEXT cert;
1834 PWINE_CERT_CONTEXT_REF ret = NULL;
1836 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1839 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1842 ret = CRYPT_CreateCertRef(cert, 0);
1843 return (PCCERT_CONTEXT)ret;
1846 /* Since the properties are stored in a list, this is a tad inefficient
1847 * (O(n^2)) since I have to find the previous position every time.
1849 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1852 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1855 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1857 EnterCriticalSection(&ref->context->cs);
1860 PWINE_CERT_PROPERTY cursor = NULL;
1862 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1863 WINE_CERT_PROPERTY, entry)
1865 if (cursor->hdr.propID == dwPropId)
1870 if (cursor->entry.next != &ref->context->extendedProperties)
1871 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1879 else if (!list_empty(&ref->context->extendedProperties))
1880 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1881 WINE_CERT_PROPERTY, entry)->hdr.propID;
1884 LeaveCriticalSection(&ref->context->cs);
1888 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1889 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1891 PWINE_CERT_PROPERTY prop;
1894 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1896 EnterCriticalSection(&context->cs);
1899 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1900 WINE_CERT_PROPERTY, entry)
1902 if (prop->hdr.propID == dwPropId)
1906 *pcbData = prop->hdr.cb;
1909 else if (*pcbData < prop->hdr.cb)
1911 SetLastError(ERROR_MORE_DATA);
1912 *pcbData = prop->hdr.cb;
1916 memcpy(pvData, prop->pbData, prop->hdr.cb);
1917 *pcbData = prop->hdr.cb;
1926 /* Implicit properties */
1929 case CERT_SHA1_HASH_PROP_ID:
1930 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1931 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1935 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1937 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1941 case CERT_KEY_PROV_INFO_PROP_ID:
1942 case CERT_MD5_HASH_PROP_ID:
1943 case CERT_SIGNATURE_HASH_PROP_ID:
1944 case CERT_KEY_IDENTIFIER_PROP_ID:
1945 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1946 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1947 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1948 FIXME("implicit property %ld\n", dwPropId);
1952 LeaveCriticalSection(&context->cs);
1953 TRACE("returning %d\n", ret);
1957 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1958 DWORD dwPropId, void *pvData, DWORD *pcbData)
1960 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1963 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1965 /* Special cases for invalid/special prop IDs.
1970 case CERT_CERT_PROP_ID:
1971 case CERT_CRL_PROP_ID:
1972 case CERT_CTL_PROP_ID:
1973 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1975 case CERT_ACCESS_STATE_PROP_ID:
1978 *pcbData = sizeof(DWORD);
1981 else if (*pcbData < sizeof(DWORD))
1983 SetLastError(ERROR_MORE_DATA);
1984 *pcbData = sizeof(DWORD);
1991 if (pCertContext->hCertStore)
1993 PWINECRYPT_CERTSTORE store =
1994 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1996 /* Take advantage of knowledge of the stores to answer the
1997 * access state question
1999 if (store->type != StoreTypeReg ||
2000 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2001 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2003 *(DWORD *)pvData = state;
2008 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2010 TRACE("returning %d\n", ret);
2014 /* Copies cbData bytes from pbData to the context's property with ID
2017 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2018 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2025 data = CryptMemAlloc(cbData);
2027 memcpy(data, pbData, cbData);
2031 if (!cbData || data)
2033 PWINE_CERT_PROPERTY prop;
2035 EnterCriticalSection(&context->cs);
2036 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2037 WINE_CERT_PROPERTY, entry)
2039 if (prop->hdr.propID == dwPropId)
2042 if (prop && prop->entry.next != &context->extendedProperties)
2044 CryptMemFree(prop->pbData);
2045 prop->hdr.cb = cbData;
2046 prop->pbData = cbData ? data : NULL;
2051 prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2054 prop->hdr.propID = dwPropId;
2055 prop->hdr.unknown = 1;
2056 prop->hdr.cb = cbData;
2057 list_init(&prop->entry);
2058 prop->pbData = cbData ? data : NULL;
2059 list_add_tail(&context->extendedProperties, &prop->entry);
2065 LeaveCriticalSection(&context->cs);
2070 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2071 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2075 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2079 PWINE_CERT_PROPERTY prop, next;
2081 EnterCriticalSection(&context->cs);
2082 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2083 WINE_CERT_PROPERTY, entry)
2085 if (prop->hdr.propID == dwPropId)
2087 list_remove(&prop->entry);
2088 CryptMemFree(prop->pbData);
2092 LeaveCriticalSection(&context->cs);
2099 case CERT_AUTO_ENROLL_PROP_ID:
2100 case CERT_CTL_USAGE_PROP_ID:
2101 case CERT_DESCRIPTION_PROP_ID:
2102 case CERT_FRIENDLY_NAME_PROP_ID:
2103 case CERT_HASH_PROP_ID:
2104 case CERT_KEY_IDENTIFIER_PROP_ID:
2105 case CERT_MD5_HASH_PROP_ID:
2106 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2107 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2108 case CERT_PVK_FILE_PROP_ID:
2109 case CERT_SIGNATURE_HASH_PROP_ID:
2110 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2111 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2112 case CERT_ENROLLMENT_PROP_ID:
2113 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2114 case CERT_RENEWAL_PROP_ID:
2116 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2118 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2119 blob->pbData, blob->cbData);
2122 case CERT_DATE_STAMP_PROP_ID:
2123 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2124 pvData, sizeof(FILETIME));
2127 FIXME("%ld: stub\n", dwPropId);
2130 TRACE("returning %d\n", ret);
2134 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2135 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2137 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2140 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2142 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2143 * crashes on most of these, I'll be safer.
2148 case CERT_ACCESS_STATE_PROP_ID:
2149 case CERT_CERT_PROP_ID:
2150 case CERT_CRL_PROP_ID:
2151 case CERT_CTL_PROP_ID:
2152 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2155 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2157 TRACE("returning %d\n", ret);
2161 /* Only the reference portion of the context is duplicated. The returned
2162 * context has the cert store set to 0, to prevent the store's certificate free
2163 * function from getting called on partial data.
2164 * FIXME: is this okay? Needs a test.
2166 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2167 PCCERT_CONTEXT pCertContext)
2169 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2171 TRACE("(%p)\n", pCertContext);
2174 ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2177 memcpy(ret, ref, sizeof(*ret));
2178 ret->cert.hCertStore = 0;
2179 InterlockedIncrement(&ret->context->ref);
2184 return (PCCERT_CONTEXT)ret;
2187 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2188 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2189 PCCERT_CONTEXT *ppStoreContext)
2191 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2192 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2193 PWINE_CERT_CONTEXT cert;
2196 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2197 dwAddDisposition, ppStoreContext);
2199 /* FIXME: some tests needed to verify return codes */
2202 SetLastError(ERROR_INVALID_PARAMETER);
2205 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2207 SetLastError(ERROR_INVALID_PARAMETER);
2211 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2212 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2215 PWINE_CERT_PROPERTY prop;
2218 EnterCriticalSection(&ref->context->cs);
2219 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2220 WINE_CERT_PROPERTY, entry)
2222 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2223 prop->pbData, prop->hdr.cb);
2227 LeaveCriticalSection(&ref->context->cs);
2230 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2231 if (ret && ppStoreContext)
2232 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2236 CRYPT_FreeCert(cert);
2243 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2244 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2245 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2247 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2250 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2251 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2255 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2259 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2260 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2264 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2265 if (ret && ppCertContext)
2266 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2269 CRYPT_FreeCert(cert);
2277 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2278 PCCERT_CONTEXT pPrev)
2280 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2281 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2284 TRACE("(%p, %p)\n", hCertStore, pPrev);
2287 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2290 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2294 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2298 TRACE("(%p)\n", pCertContext);
2302 else if (!pCertContext->hCertStore)
2305 CertFreeCertificateContext(pCertContext);
2309 PWINECRYPT_CERTSTORE hcs =
2310 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2314 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2318 ret = hcs->deleteCert(hcs, pCertContext, 0);
2320 CertFreeCertificateContext(pCertContext);
2326 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2327 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2328 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2330 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2331 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2336 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2337 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2338 PCCRL_CONTEXT* ppStoreContext )
2340 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2341 dwAddDisposition, ppStoreContext);
2345 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2347 FIXME("%p\n", pCrlContext );
2352 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2354 FIXME("(%p): stub\n", pCrlContext);
2358 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2359 PCCRL_CONTEXT pPrev)
2361 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2365 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2366 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2368 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2373 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2374 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2375 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2377 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2378 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2383 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2384 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2385 PCCTL_CONTEXT* ppStoreContext)
2387 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2388 dwAddDisposition, ppStoreContext);
2392 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2394 FIXME("(%p): stub\n", pCtlContext );
2398 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2400 FIXME("(%p): stub\n", pCtlContext);
2404 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2405 PCCTL_CONTEXT pPrev)
2407 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2412 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2414 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2416 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2421 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2424 if (InterlockedDecrement(&hcs->ref) == 0)
2426 TRACE("%p's ref count is 0, freeing\n", hcs);
2428 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2429 CryptReleaseContext(hcs->cryptProv, 0);
2430 hcs->closeStore(hcs, dwFlags);
2433 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2437 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2438 DWORD dwCtrlType, void const *pvCtrlPara)
2440 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2443 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2448 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2453 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2460 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2461 DWORD dwPropId, void *pvData, DWORD *pcbData)
2463 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2467 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2468 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2470 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2475 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2476 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2478 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2483 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2484 DWORD dwPropId, void *pvData, DWORD *pcbData)
2486 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2490 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2491 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2493 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2498 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2499 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2501 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2506 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2507 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2511 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2516 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2517 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2518 pCertContext->cbCertEncoded;
2519 PWINE_CERT_PROPERTY prop;
2521 EnterCriticalSection(&ref->context->cs);
2522 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2523 WINE_CERT_PROPERTY, entry)
2524 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2527 *pcbElement = bytesNeeded;
2530 else if (*pcbElement < bytesNeeded)
2532 *pcbElement = bytesNeeded;
2533 SetLastError(ERROR_MORE_DATA);
2538 PWINE_CERT_PROP_HEADER hdr;
2540 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2541 WINE_CERT_PROPERTY, entry)
2543 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2544 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2547 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2548 pbElement += prop->hdr.cb;
2551 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2552 hdr->propID = CERT_CERT_PROP_ID;
2554 hdr->cb = pCertContext->cbCertEncoded;
2555 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2556 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2559 LeaveCriticalSection(&ref->context->cs);
2566 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2567 * to its header if a valid header is found, NULL if not. Valid means the
2568 * length of thte property won't overrun buf, and the unknown field is 1.
2570 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2571 DWORD size, DWORD propID)
2573 const WINE_CERT_PROP_HEADER *ret = NULL;
2576 while (size && !ret && !done)
2578 if (size < sizeof(WINE_CERT_PROP_HEADER))
2580 SetLastError(CRYPT_E_FILE_ERROR);
2585 const WINE_CERT_PROP_HEADER *hdr =
2586 (const WINE_CERT_PROP_HEADER *)buf;
2588 size -= sizeof(WINE_CERT_PROP_HEADER);
2589 buf += sizeof(WINE_CERT_PROP_HEADER);
2592 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2595 else if (!hdr->propID)
2597 /* assume a zero prop ID means the data are uninitialized, so
2602 else if (hdr->unknown != 1)
2604 SetLastError(ERROR_FILE_NOT_FOUND);
2607 else if (hdr->propID == propID)
2619 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2620 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2622 const void *context;
2624 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2629 SetLastError(ERROR_END_OF_MEDIA);
2635 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2636 const WINE_CERT_PROP_HEADER *hdr = NULL;
2642 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2644 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2646 type = CERT_STORE_CERTIFICATE_CONTEXT;
2649 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2651 type = CERT_STORE_CRL_CONTEXT;
2654 hdr = CRYPT_findPropID(pbElement, cbElement,
2657 type = CERT_STORE_CTL_CONTEXT;
2661 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2663 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2664 type = CERT_STORE_CERTIFICATE_CONTEXT;
2666 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2668 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2669 type = CERT_STORE_CRL_CONTEXT;
2671 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2673 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2674 type = CERT_STORE_CTL_CONTEXT;
2679 case CERT_STORE_CERTIFICATE_CONTEXT:
2680 contextInterface = &gCertInterface;
2682 case CERT_STORE_CRL_CONTEXT:
2683 contextInterface = &gCRLInterface;
2685 case CERT_STORE_CTL_CONTEXT:
2686 contextInterface = &gCTLInterface;
2689 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2696 context = contextInterface->create(X509_ASN_ENCODING,
2697 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2700 BOOL noMoreProps = FALSE;
2702 while (!noMoreProps && ret)
2704 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2708 const WINE_CERT_PROP_HEADER *hdr =
2709 (const WINE_CERT_PROP_HEADER *)pbElement;
2711 TRACE("prop is %ld\n", hdr->propID);
2712 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2713 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2714 if (cbElement < hdr->cb)
2716 SetLastError(HRESULT_FROM_WIN32(
2717 ERROR_INVALID_PARAMETER));
2720 else if (!hdr->propID)
2722 /* Like in CRYPT_findPropID, stop if the propID is zero
2726 else if (hdr->unknown != 1)
2728 SetLastError(ERROR_FILE_NOT_FOUND);
2731 else if (hdr->propID != CERT_CERT_PROP_ID &&
2732 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2735 /* Have to create a blob for most types, but not
2738 switch (hdr->propID)
2740 case CERT_AUTO_ENROLL_PROP_ID:
2741 case CERT_CTL_USAGE_PROP_ID:
2742 case CERT_DESCRIPTION_PROP_ID:
2743 case CERT_FRIENDLY_NAME_PROP_ID:
2744 case CERT_HASH_PROP_ID:
2745 case CERT_KEY_IDENTIFIER_PROP_ID:
2746 case CERT_MD5_HASH_PROP_ID:
2747 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2748 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2749 case CERT_PVK_FILE_PROP_ID:
2750 case CERT_SIGNATURE_HASH_PROP_ID:
2751 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2752 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2753 case CERT_ENROLLMENT_PROP_ID:
2754 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2755 case CERT_RENEWAL_PROP_ID:
2757 CRYPT_DATA_BLOB blob = { hdr->cb,
2758 (LPBYTE)pbElement };
2760 ret = contextInterface->setProp(context,
2761 hdr->propID, 0, &blob);
2764 case CERT_DATE_STAMP_PROP_ID:
2765 ret = contextInterface->setProp(context,
2766 hdr->propID, 0, pbElement);
2769 FIXME("prop ID %ld: stub\n", hdr->propID);
2772 pbElement += hdr->cb;
2773 cbElement -= hdr->cb;
2781 *pdwContentType = type;
2785 contextInterface->free(context);
2790 __EXCEPT(page_fault)
2792 SetLastError(STATUS_ACCESS_VIOLATION);
2799 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2800 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2801 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2803 const void *context;
2807 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2808 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2809 pdwContentType, ppvContext);
2811 /* Call the internal function, then delete the hashes. Tests show this
2812 * function uses real hash values, not whatever's stored in the hash
2815 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2816 dwContextTypeFlags, &type);
2819 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2823 case CERT_STORE_CERTIFICATE_CONTEXT:
2824 contextInterface = &gCertInterface;
2826 case CERT_STORE_CRL_CONTEXT:
2827 contextInterface = &gCRLInterface;
2829 case CERT_STORE_CTL_CONTEXT:
2830 contextInterface = &gCTLInterface;
2833 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2835 if (contextInterface)
2837 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2838 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2839 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2842 *pdwContentType = type;
2843 ret = contextInterface->addContextToStore(hCertStore, context,
2844 dwAddDisposition, ppvContext);
2845 contextInterface->free(context);
2855 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref)
2857 if (InterlockedDecrement(&ref->context->ref) == 0)
2859 TRACE("%p's ref count is 0, freeing\n", ref->context);
2860 CRYPT_FreeCert(ref->context);
2863 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2866 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2868 TRACE("(%p)\n", pCertContext);
2872 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2873 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2875 CRYPT_UnrefCertificateContext(ref);
2876 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2878 store->freeCert(ref);
2879 TRACE("freeing %p\n", ref);
2885 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2886 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2887 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2889 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2890 dwFlags, dwType, pvPara, pPrevCertContext);
2891 SetLastError(CRYPT_E_NOT_FOUND);
2895 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2896 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2898 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2899 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2900 PWINE_STORE_LIST_ENTRY entry;
2903 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2904 dwUpdateFlags, dwPriority);
2906 if (!collection || !sibling)
2908 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2910 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2913 if (collection->hdr.type != StoreTypeCollection)
2915 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2918 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2920 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2924 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2927 InterlockedIncrement(&sibling->ref);
2928 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2929 entry->store = sibling;
2930 entry->dwUpdateFlags = dwUpdateFlags;
2931 entry->dwPriority = dwPriority;
2932 list_init(&entry->entry);
2933 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2934 EnterCriticalSection(&collection->cs);
2937 PWINE_STORE_LIST_ENTRY cursor;
2940 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2941 WINE_STORE_LIST_ENTRY, entry)
2943 if (cursor->dwPriority < dwPriority)
2945 list_add_before(&cursor->entry, &entry->entry);
2951 list_add_tail(&collection->stores, &entry->entry);
2954 list_add_tail(&collection->stores, &entry->entry);
2955 LeaveCriticalSection(&collection->cs);
2963 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2964 HCERTSTORE hSiblingStore)
2966 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2967 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2968 PWINE_STORE_LIST_ENTRY store, next;
2970 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2972 if (!collection || !sibling)
2974 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2976 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2979 if (collection->hdr.type != StoreTypeCollection)
2981 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2983 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2986 EnterCriticalSection(&collection->cs);
2987 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2988 WINE_STORE_LIST_ENTRY, entry)
2990 if (store->store == sibling)
2992 list_remove(&store->entry);
2993 CertCloseStore(store->store, 0);
2994 CryptMemFree(store);
2998 LeaveCriticalSection(&collection->cs);
3001 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3002 CRYPT_ATTRIBUTE rgAttr[])
3004 PCRYPT_ATTRIBUTE ret = NULL;
3007 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3013 SetLastError(ERROR_INVALID_PARAMETER);
3017 for (i = 0; !ret && i < cAttr; i++)
3018 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3023 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3024 CERT_EXTENSION rgExtensions[])
3026 PCERT_EXTENSION ret = NULL;
3029 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3035 SetLastError(ERROR_INVALID_PARAMETER);
3039 for (i = 0; !ret && i < cExtensions; i++)
3040 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3041 rgExtensions[i].pszObjId))
3042 ret = &rgExtensions[i];
3046 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3048 PCERT_RDN_ATTR ret = NULL;
3051 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3055 SetLastError(ERROR_INVALID_PARAMETER);
3059 for (i = 0; !ret && i < pName->cRDN; i++)
3060 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3061 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3062 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3063 ret = &pName->rgRDN[i].rgRDNAttr[j];
3067 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3068 PCERT_INFO pCertInfo)
3077 GetSystemTime(&sysTime);
3078 SystemTimeToFileTime(&sysTime, &fileTime);
3079 pTimeToVerify = &fileTime;
3081 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3083 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3090 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3091 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3092 DWORD *pcbComputedHash)
3095 HCRYPTHASH hHash = 0;
3097 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3098 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3101 hCryptProv = CRYPT_GetDefaultProvider();
3106 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3109 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3111 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3112 pcbComputedHash, 0);
3113 CryptDestroyHash(hHash);
3119 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3120 DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
3121 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
3122 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
3128 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
3129 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
3130 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
3132 algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
3135 SetLastError(NTE_BAD_ALGID);
3140 SetLastError(ERROR_INVALID_PARAMETER);
3144 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
3147 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
3149 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
3151 CryptDestroyHash(hHash);
3156 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
3157 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
3158 PCERT_PUBLIC_KEY_INFO pPublicKey)
3160 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
3161 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
3162 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
3165 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
3166 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
3167 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
3170 CRYPT_DATA_BLOB subjectBlob;
3172 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
3173 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
3174 dwFlags, pvReserved);
3176 switch (dwSubjectType)
3178 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
3180 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
3182 subjectBlob.pbData = blob->pbData;
3183 subjectBlob.cbData = blob->cbData;
3186 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
3188 PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
3190 subjectBlob.pbData = context->pbCertEncoded;
3191 subjectBlob.cbData = context->cbCertEncoded;
3194 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
3196 PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
3198 subjectBlob.pbData = context->pbCrlEncoded;
3199 subjectBlob.cbData = context->cbCrlEncoded;
3203 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3209 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
3212 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
3213 subjectBlob.pbData, subjectBlob.cbData,
3214 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3215 (BYTE *)&signedCert, &size);
3218 switch (dwIssuerType)
3220 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
3222 PCERT_PUBLIC_KEY_INFO pubKeyInfo =
3223 (PCERT_PUBLIC_KEY_INFO)pvIssuer;
3224 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
3230 ret = CryptImportPublicKeyInfoEx(hCryptProv,
3231 dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
3236 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
3239 ret = CryptHashData(hash,
3240 signedCert->ToBeSigned.pbData,
3241 signedCert->ToBeSigned.cbData, 0);
3244 ret = CryptVerifySignatureW(hash,
3245 signedCert->Signature.pbData,
3246 signedCert->Signature.cbData, key, NULL, 0);
3248 CryptDestroyHash(hash);
3250 CryptDestroyKey(key);
3255 SetLastError(NTE_BAD_ALGID);
3260 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
3261 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
3262 FIXME("issuer type %ld: stub\n", dwIssuerType);
3265 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
3268 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3273 FIXME("unimplemented for NULL signer\n");
3274 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3279 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3282 LocalFree(signedCert);
3288 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName, DWORD dwFlags)
3290 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName), dwFlags);
3291 return (HCRYPTOIDFUNCSET)0xbaadf00d;
3294 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
3295 LPCSTR pszFuncName, LPCWSTR pwszDll)
3297 FIXME("stub: %lx %s %s\n", dwEncodingType, debugstr_a(pszFuncName), debugstr_w(pwszDll));
3301 BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara,
3302 DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
3303 BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
3305 FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n",
3306 pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
3307 pbDecoded, pcbDecoded, ppSignerCert);