x11drv: Make UseXVidMode default to yes.
[wine/dibdrv.git] / dlls / crypt32 / store.c
blobf6d190c362ebf60b264ca77ce9ba5ca4b4c94006
1 /*
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
19 * FIXME:
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 * - The concept of physical stores and locations isn't implemented. (This
24 * doesn't mean registry stores et al aren't implemented. See the PSDK for
25 * registering and enumerating physical stores and locations.)
26 * - Many flags, options and whatnot are unimplemented.
29 #include <assert.h>
30 #include <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "winuser.h"
36 #include "wincrypt.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "excpt.h"
40 #include "wine/exception.h"
41 #include "crypt32_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
45 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 /* Some typedefs that make it easier to abstract which type of context we're
48 * working with.
50 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
51 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
52 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
53 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
54 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
55 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
56 DWORD dwAddDisposition, const void **ppContext);
57 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
58 const void *pPrevContext);
59 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
60 DWORD dwPropID, void *pvData, DWORD *pcbData);
61 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
62 DWORD dwPropID, DWORD dwFlags, const void *pvData);
63 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
64 BYTE *pbElement, DWORD *pcbElement);
65 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
66 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
68 /* An abstract context (certificate, CRL, or CTL) interface */
69 typedef struct _WINE_CONTEXT_INTERFACE
71 CreateContextFunc create;
72 AddContextToStoreFunc addContextToStore;
73 AddEncodedContextToStoreFunc addEncodedToStore;
74 EnumContextsInStoreFunc enumContextsInStore;
75 GetContextPropertyFunc getProp;
76 SetContextPropertyFunc setProp;
77 SerializeElementFunc serialize;
78 FreeContextFunc free;
79 DeleteContextFunc deleteFromStore;
80 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
82 static const WINE_CONTEXT_INTERFACE gCertInterface = {
83 (CreateContextFunc)CertCreateCertificateContext,
84 (AddContextToStoreFunc)CertAddCertificateContextToStore,
85 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
86 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
87 (GetContextPropertyFunc)CertGetCertificateContextProperty,
88 (SetContextPropertyFunc)CertSetCertificateContextProperty,
89 (SerializeElementFunc)CertSerializeCertificateStoreElement,
90 (FreeContextFunc)CertFreeCertificateContext,
91 (DeleteContextFunc)CertDeleteCertificateFromStore,
94 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
95 (CreateContextFunc)CertCreateCRLContext,
96 (AddContextToStoreFunc)CertAddCRLContextToStore,
97 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
98 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
99 (GetContextPropertyFunc)CertGetCRLContextProperty,
100 (SetContextPropertyFunc)CertSetCRLContextProperty,
101 (SerializeElementFunc)CertSerializeCRLStoreElement,
102 (FreeContextFunc)CertFreeCRLContext,
103 (DeleteContextFunc)CertDeleteCRLFromStore,
106 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
107 (CreateContextFunc)CertCreateCTLContext,
108 (AddContextToStoreFunc)CertAddCTLContextToStore,
109 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
110 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
111 (GetContextPropertyFunc)CertGetCTLContextProperty,
112 (SetContextPropertyFunc)CertSetCTLContextProperty,
113 (SerializeElementFunc)CertSerializeCTLStoreElement,
114 (FreeContextFunc)CertFreeCTLContext,
115 (DeleteContextFunc)CertDeleteCTLFromStore,
118 struct WINE_CRYPTCERTSTORE;
120 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
121 DWORD dwFlags, const void *pvPara);
123 struct _WINE_CERT_CONTEXT;
125 /* Called to enumerate the next certificate in a store. */
126 typedef struct _WINE_CERT_CONTEXT * (*EnumCertFunc)
127 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT *pPrev);
129 /* Called to add a certificate context to a store. If toReplace is not NULL,
130 * context replaces toReplace in the store, and access checks should not be
131 * performed. Otherwise context is a new context, and it should only be
132 * added if the store allows it. If ppStoreContext is not NULL, the added
133 * context should be returned in *ppStoreContext.
135 typedef BOOL (*AddCertFunc)(struct WINE_CRYPTCERTSTORE *store,
136 struct _WINE_CERT_CONTEXT *context, struct _WINE_CERT_CONTEXT *toReplace,
137 PCCERT_CONTEXT *ppStoreContext);
139 typedef enum _CertStoreType {
140 StoreTypeMem,
141 StoreTypeCollection,
142 StoreTypeProvider,
143 } CertStoreType;
145 /* A cert store is polymorphic through the use of function pointers. A type
146 * is still needed to distinguish collection stores from other types.
147 * On the function pointers:
148 * - closeStore is called when the store's ref count becomes 0
149 * - control is optional, but should be implemented by any store that supports
150 * persistence
152 typedef struct WINE_CRYPTCERTSTORE
154 DWORD dwMagic;
155 LONG ref;
156 DWORD dwOpenFlags;
157 HCRYPTPROV cryptProv;
158 CertStoreType type;
159 PFN_CERT_STORE_PROV_CLOSE closeStore;
160 AddCertFunc addCert;
161 EnumCertFunc enumCert;
162 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
163 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
164 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
166 typedef enum _ContextType {
167 ContextTypeData,
168 ContextTypeLink,
169 } ContextType;
171 /* A certificate context. This is the base type, and the two real types
172 * (data and link) derive from it. Each one can be cast to a PCCERT_CONTEXT.
174 typedef struct _WINE_CERT_CONTEXT
176 CERT_CONTEXT cert;
177 LONG ref;
178 ContextType type;
179 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
180 typedef const struct _WINE_CERT_CONTEXT *PCWINE_CERT_CONTEXT;
182 typedef struct _WINE_CERT_CONTEXT_DATA
184 CERT_CONTEXT cert;
185 LONG ref;
186 ContextType type; /* always ContextTypeData */
187 PCONTEXT_PROPERTY_LIST properties;
188 } WINE_CERT_CONTEXT_DATA, *PWINE_CERT_CONTEXT_DATA;
189 typedef const struct _WINE_CERT_CONTEXT_DATA PCWINE_CERT_CONTEXT_DATA;
191 typedef struct _WINE_CERT_CONTEXT_LINK
193 CERT_CONTEXT cert;
194 LONG ref;
195 ContextType type; /* always ContextTypeLink */
196 PWINE_CERT_CONTEXT linked;
197 } WINE_CERT_CONTEXT_LINK, *PWINE_CERT_CONTEXT_LINK;
198 typedef const struct _WINE_CERT_CONTEXT_LINK PCWINE_CERT_CONTEXT_LINK;
200 /* A mem store has a list of these. They're also returned by the mem store
201 * during enumeration.
203 typedef struct _WINE_CERT_LIST_ENTRY
205 WINE_CERT_CONTEXT_LINK cert;
206 struct list entry;
207 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
209 typedef struct _WINE_MEMSTORE
211 WINECRYPT_CERTSTORE hdr;
212 CRITICAL_SECTION cs;
213 struct list certs;
214 } WINE_MEMSTORE, *PWINE_MEMSTORE;
216 typedef struct _WINE_HASH_TO_DELETE
218 BYTE hash[20];
219 struct list entry;
220 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
222 typedef struct _WINE_REGSTOREINFO
224 DWORD dwOpenFlags;
225 HCRYPTPROV cryptProv;
226 PWINECRYPT_CERTSTORE memStore;
227 HKEY key;
228 BOOL dirty;
229 CRITICAL_SECTION cs;
230 struct list certsToDelete;
231 } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
233 typedef struct _WINE_STORE_LIST_ENTRY
235 PWINECRYPT_CERTSTORE store;
236 DWORD dwUpdateFlags;
237 DWORD dwPriority;
238 struct list entry;
239 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
241 /* Returned by a collection store during enumeration.
242 * Note: relies on the list entry being valid after use, which a number of
243 * conditions might make untrue (reentrancy, closing a collection store before
244 * continuing an enumeration on it, ...). The tests seem to indicate this
245 * sort of unsafety is okay, since Windows isn't well-behaved in these
246 * scenarios either.
248 typedef struct _WINE_COLLECTION_CERT_CONTEXT
250 WINE_CERT_CONTEXT_LINK cert;
251 PWINE_STORE_LIST_ENTRY storeEntry;
252 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
254 typedef struct _WINE_COLLECTIONSTORE
256 WINECRYPT_CERTSTORE hdr;
257 CRITICAL_SECTION cs;
258 struct list stores;
259 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
261 typedef struct _WINE_PROVIDERSTORE
263 WINECRYPT_CERTSTORE hdr;
264 DWORD dwStoreProvFlags;
265 PWINECRYPT_CERTSTORE memStore;
266 HCERTSTOREPROV hStoreProv;
267 PFN_CERT_STORE_PROV_CLOSE provCloseStore;
268 PFN_CERT_STORE_PROV_WRITE_CERT provWriteCert;
269 PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
270 PFN_CERT_STORE_PROV_CONTROL provControl;
271 } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;
273 /* Internal version of CertGetCertificateContextProperty that gets properties
274 * directly from the context (or the context it's linked to, depending on its
275 * type.) Doesn't handle special-case properties, since they are handled by
276 * CertGetCertificateContextProperty, and are particular to the store in which
277 * the property exists (which is separate from the context.)
279 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
280 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
282 /* Internal version of CertSetCertificateContextProperty that sets properties
283 * directly on the context (or the context it's linked to, depending on its
284 * type.) Doesn't handle special cases, since they're handled by
285 * CertSetCertificateContextProperty anyway.
287 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
288 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags,
289 const void *pvData);
291 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
292 DWORD dwFlags, CertStoreType type)
294 store->ref = 1;
295 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
296 store->type = type;
297 if (!hCryptProv)
299 hCryptProv = CRYPT_GetDefaultProvider();
300 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
302 store->cryptProv = hCryptProv;
303 store->dwOpenFlags = dwFlags;
306 /* Initializes the reference ref to point to context, and increments context's
307 * reference count. Also sets the hCertStore member of the reference to store.
309 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_LINK ref,
310 PWINE_CERT_CONTEXT context, HCERTSTORE store)
312 TRACE("(%p, %p)\n", ref, context);
313 memcpy(&ref->cert, context, sizeof(ref->cert));
314 ref->ref = 1;
315 ref->type = ContextTypeLink;
316 ref->linked = context;
317 InterlockedIncrement(&context->ref);
318 TRACE("%p's ref count is %ld\n", context, context->ref);
319 ref->cert.hCertStore = store;
322 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store,
323 PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
324 PCCERT_CONTEXT *ppStoreContext)
326 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
327 PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
328 BOOL ret;
330 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
332 if (entry)
334 PWINE_CERT_LIST_ENTRY existing = (PWINE_CERT_LIST_ENTRY)toReplace;
336 TRACE("adding %p\n", entry);
337 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)cert, store);
338 EnterCriticalSection(&ms->cs);
339 if (existing)
341 entry->entry.prev = existing->entry.prev;
342 entry->entry.next = existing->entry.next;
343 entry->entry.prev->next = &entry->entry;
344 entry->entry.next->prev = &entry->entry;
345 existing->entry.prev = existing->entry.next = &existing->entry;
346 CertFreeCertificateContext((PCCERT_CONTEXT)existing);
348 else
349 list_add_tail(&ms->certs, &entry->entry);
350 LeaveCriticalSection(&ms->cs);
351 if (ppStoreContext)
352 *ppStoreContext =
353 CertDuplicateCertificateContext((PCCERT_CONTEXT)entry);
354 ret = TRUE;
356 else
357 ret = FALSE;
358 TRACE("returning %d\n", ret);
359 return ret;
362 static PWINE_CERT_CONTEXT CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
363 PWINE_CERT_CONTEXT pPrev)
365 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
366 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev;
367 PWINE_CERT_CONTEXT ret;
368 struct list *listNext;
370 TRACE("(%p, %p)\n", store, pPrev);
371 EnterCriticalSection(&ms->cs);
372 if (prevEntry)
374 listNext = list_next(&ms->certs, &prevEntry->entry);
375 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
377 else
378 listNext = list_next(&ms->certs, &ms->certs);
379 if (listNext)
380 ret = (PWINE_CERT_CONTEXT)CertDuplicateCertificateContext(
381 (PCCERT_CONTEXT)LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry));
382 else
384 SetLastError(CRYPT_E_NOT_FOUND);
385 ret = NULL;
387 LeaveCriticalSection(&ms->cs);
389 TRACE("returning %p\n", ret);
390 return ret;
393 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
394 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
396 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
397 PWINE_CERT_LIST_ENTRY cert = (PWINE_CERT_LIST_ENTRY)pCertContext;
398 BOOL ret;
400 /* The passed-in context is itself a list entry, so just remove it. */
401 EnterCriticalSection(&store->cs);
402 list_remove(&cert->entry);
403 ret = CertFreeCertificateContext(pCertContext);
404 LeaveCriticalSection(&store->cs);
405 return ret;
408 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store)
410 PWINE_CERT_LIST_ENTRY cert, next;
412 EnterCriticalSection(&store->cs);
413 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
414 entry)
416 TRACE("removing %p\n", cert);
417 list_remove(&cert->entry);
418 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
420 LeaveCriticalSection(&store->cs);
423 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
425 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
427 TRACE("(%p, %08lx)\n", store, dwFlags);
428 if (dwFlags)
429 FIXME("Unimplemented flags: %08lx\n", dwFlags);
431 CRYPT_MemEmptyStore(store);
432 DeleteCriticalSection(&store->cs);
433 CryptMemFree(store);
436 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
437 DWORD dwFlags, const void *pvPara)
439 PWINE_MEMSTORE store;
441 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
443 if (dwFlags & CERT_STORE_DELETE_FLAG)
445 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
446 store = NULL;
448 else
450 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
451 if (store)
453 memset(store, 0, sizeof(WINE_MEMSTORE));
454 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
455 store->hdr.closeStore = CRYPT_MemCloseStore;
456 store->hdr.addCert = CRYPT_MemAddCert;
457 store->hdr.enumCert = CRYPT_MemEnumCert;
458 store->hdr.deleteCert = CRYPT_MemDeleteCert;
459 store->hdr.control = NULL;
460 InitializeCriticalSection(&store->cs);
461 list_init(&store->certs);
464 return (PWINECRYPT_CERTSTORE)store;
467 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionCreateContextFromChild(
468 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
469 PWINE_CERT_CONTEXT child)
471 PWINE_COLLECTION_CERT_CONTEXT ret =
472 CryptMemAlloc(sizeof(WINE_COLLECTION_CERT_CONTEXT));
474 if (ret)
476 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_LINK)ret, child, store);
477 /* The child has already been addref'd, and CRYPT_InitCertRef does
478 * again, so free child once to get the ref count right. (Not doing so
479 * will leak memory if the caller calls CertFreeCertificateContext
480 * rather than CertEnumCertificatesInStore.)
482 CertFreeCertificateContext((PCCERT_CONTEXT)child);
483 ret->storeEntry = storeEntry;
485 else
486 CertFreeCertificateContext((PCCERT_CONTEXT)child);
487 return ret;
490 static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store,
491 PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
492 PCCERT_CONTEXT *ppStoreContext)
494 BOOL ret;
495 PCCERT_CONTEXT childContext = NULL;
496 PWINE_STORE_LIST_ENTRY storeEntry = NULL;
498 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
500 ret = FALSE;
501 if (toReplace)
503 PWINE_COLLECTION_CERT_CONTEXT existing =
504 (PWINE_COLLECTION_CERT_CONTEXT)toReplace;
506 storeEntry = existing->storeEntry;
507 ret = storeEntry->store->addCert(storeEntry->store, cert,
508 existing->cert.linked, &childContext);
510 else
512 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
513 PWINE_STORE_LIST_ENTRY entry, next;
515 EnterCriticalSection(&cs->cs);
516 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores,
517 WINE_STORE_LIST_ENTRY, entry)
519 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
521 storeEntry = entry;
522 ret = entry->store->addCert(entry->store, cert, NULL,
523 &childContext);
524 break;
527 LeaveCriticalSection(&cs->cs);
528 if (!storeEntry)
529 SetLastError(HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
531 if (ppStoreContext && childContext)
533 *ppStoreContext =
534 (PCCERT_CONTEXT)CRYPT_CollectionCreateContextFromChild(
535 (PWINE_COLLECTIONSTORE)store, storeEntry,
536 (PWINE_CERT_CONTEXT)childContext);
538 CertFreeCertificateContext(childContext);
539 return ret;
542 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
544 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
545 PWINE_STORE_LIST_ENTRY entry, next;
547 TRACE("(%p, %08lx)\n", store, dwFlags);
549 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
550 entry)
552 TRACE("closing %p\n", entry);
553 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
554 CryptMemFree(entry);
556 DeleteCriticalSection(&cs->cs);
557 CryptMemFree(cs);
560 /* Advances a collection enumeration by one cert, if possible, where advancing
561 * means:
562 * - calling the current store's enumeration function once, and returning
563 * the enumerated cert if one is returned
564 * - moving to the next store if the current store has no more items, and
565 * recursively calling itself to get the next item.
566 * Returns NULL if the collection contains no more items or on error.
567 * Assumes the collection store's lock is held.
569 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
570 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
571 PWINE_COLLECTION_CERT_CONTEXT pPrev)
573 PWINE_COLLECTION_CERT_CONTEXT ret;
574 PWINE_CERT_CONTEXT child;
575 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
577 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
579 if (pPrev)
581 /* Ref-counting funny business: "duplicate" (addref) the child, because
582 * the CertFreeCertificateContext(pPrev) below can cause the ref count
583 * to become negative. See comment in
584 * CRYPT_CollectionCreateContextFromChild as well.
586 child = ((PWINE_COLLECTION_CERT_CONTEXT)pPrev)->cert.linked;
587 CertDuplicateCertificateContext((PCCERT_CONTEXT)child);
588 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
589 child);
590 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
591 pPrev = NULL;
593 else
594 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
595 NULL);
596 if (child)
597 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child);
598 else
600 if (storeNext)
602 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
603 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
605 else
607 SetLastError(CRYPT_E_NOT_FOUND);
608 ret = NULL;
611 TRACE("returning %p\n", ret);
612 return ret;
615 static PWINE_CERT_CONTEXT CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store,
616 PWINE_CERT_CONTEXT pPrev)
618 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
619 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
620 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
622 TRACE("(%p, %p)\n", store, pPrev);
624 if (prevEntry)
626 EnterCriticalSection(&cs->cs);
627 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->storeEntry, prevEntry);
628 LeaveCriticalSection(&cs->cs);
630 else
632 EnterCriticalSection(&cs->cs);
633 if (!list_empty(&cs->stores))
635 PWINE_STORE_LIST_ENTRY storeEntry;
637 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
638 entry);
639 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, NULL);
641 else
643 SetLastError(CRYPT_E_NOT_FOUND);
644 ret = NULL;
646 LeaveCriticalSection(&cs->cs);
648 TRACE("returning %p\n", ret);
649 return (PWINE_CERT_CONTEXT)ret;
652 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
653 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
655 PWINE_COLLECTION_CERT_CONTEXT context =
656 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
657 BOOL ret;
659 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
661 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->cert.linked);
662 return ret;
665 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
666 DWORD dwFlags, const void *pvPara)
668 PWINE_COLLECTIONSTORE store;
670 if (dwFlags & CERT_STORE_DELETE_FLAG)
672 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
673 store = NULL;
675 else
677 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
678 if (store)
680 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
681 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
682 StoreTypeCollection);
683 store->hdr.closeStore = CRYPT_CollectionCloseStore;
684 store->hdr.addCert = CRYPT_CollectionAddCert;
685 store->hdr.enumCert = CRYPT_CollectionEnumCert;
686 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
687 InitializeCriticalSection(&store->cs);
688 list_init(&store->stores);
691 return (PWINECRYPT_CERTSTORE)store;
694 static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
696 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
698 TRACE("(%p, %08lx)\n", store, dwFlags);
700 if (store->provCloseStore)
701 store->provCloseStore(store->hStoreProv, dwFlags);
702 if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG))
703 CertCloseStore(store->memStore, dwFlags);
704 CryptMemFree(store);
707 static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store,
708 PWINE_CERT_CONTEXT cert, PWINE_CERT_CONTEXT toReplace,
709 PCCERT_CONTEXT *ppStoreContext)
711 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
712 BOOL ret;
714 TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
716 if (toReplace)
717 ret = ps->memStore->addCert(ps->memStore, cert, toReplace,
718 ppStoreContext);
719 else
721 if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
723 SetLastError(ERROR_ACCESS_DENIED);
724 ret = FALSE;
726 else
728 ret = TRUE;
729 if (ps->provWriteCert)
730 ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
731 CERT_STORE_PROV_WRITE_ADD_FLAG);
732 if (ret)
733 ret = ps->memStore->addCert(ps->memStore, cert, NULL,
734 ppStoreContext);
737 /* dirty trick: replace the returned context's hCertStore with
738 * store.
740 if (ppStoreContext)
741 (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
742 return ret;
745 static PWINE_CERT_CONTEXT CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store,
746 PWINE_CERT_CONTEXT pPrev)
748 PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
749 PWINE_CERT_CONTEXT ret;
751 ret = ps->memStore->enumCert(ps->memStore, pPrev);
752 if (ret)
754 /* same dirty trick: replace the returned context's hCertStore with
755 * store.
757 ret->cert.hCertStore = store;
759 return ret;
762 static BOOL WINAPI CRYPT_ProvDeleteCert(HCERTSTORE hCertStore,
763 PCCERT_CONTEXT cert, DWORD dwFlags)
765 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
766 BOOL ret = TRUE;
768 TRACE("(%p, %p, %08lx)\n", hCertStore, cert, dwFlags);
770 if (store->provDeleteCert)
771 ret = store->provDeleteCert(store->hStoreProv, cert, dwFlags);
772 if (ret)
773 ret = store->memStore->deleteCert(store->memStore, cert, dwFlags);
774 return ret;
777 static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags,
778 DWORD dwCtrlType, void const *pvCtrlPara)
780 PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
781 BOOL ret = TRUE;
783 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
784 pvCtrlPara);
786 if (store->provControl)
787 ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType,
788 pvCtrlPara);
789 return ret;
792 static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv,
793 DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo)
795 PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc(
796 sizeof(WINE_PROVIDERSTORE));
798 if (ret)
800 CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags,
801 StoreTypeProvider);
802 ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags;
803 if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)
805 CertCloseStore(memStore, 0);
806 ret->memStore = NULL;
808 else
809 ret->memStore = memStore;
810 ret->hStoreProv = pProvInfo->hStoreProv;
811 ret->hdr.closeStore = CRYPT_ProvCloseStore;
812 ret->hdr.addCert = CRYPT_ProvAddCert;
813 ret->hdr.enumCert = CRYPT_ProvEnumCert;
814 ret->hdr.deleteCert = CRYPT_ProvDeleteCert;
815 ret->hdr.control = CRYPT_ProvControl;
816 if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
817 ret->provCloseStore =
818 pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC];
819 else
820 ret->provCloseStore = NULL;
821 if (pProvInfo->cStoreProvFunc >
822 CERT_STORE_PROV_WRITE_CERT_FUNC)
823 ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[
824 CERT_STORE_PROV_WRITE_CERT_FUNC];
825 else
826 ret->provWriteCert = NULL;
827 if (pProvInfo->cStoreProvFunc >
828 CERT_STORE_PROV_DELETE_CERT_FUNC)
829 ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[
830 CERT_STORE_PROV_DELETE_CERT_FUNC];
831 else
832 ret->provDeleteCert = NULL;
833 if (pProvInfo->cStoreProvFunc >
834 CERT_STORE_PROV_CONTROL_FUNC)
835 ret->provControl = pProvInfo->rgpvStoreProvFunc[
836 CERT_STORE_PROV_CONTROL_FUNC];
837 else
838 ret->provControl = NULL;
840 return (PWINECRYPT_CERTSTORE)ret;
843 static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
844 DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara)
846 static HCRYPTOIDFUNCSET set = NULL;
847 PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc;
848 HCRYPTOIDFUNCADDR hFunc;
849 PWINECRYPT_CERTSTORE ret = NULL;
851 if (!set)
852 set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
853 CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0,
854 (void **)&provOpenFunc, &hFunc);
855 if (provOpenFunc)
857 CERT_STORE_PROV_INFO provInfo = { 0 };
859 provInfo.cbSize = sizeof(provInfo);
860 if (dwFlags & CERT_STORE_DELETE_FLAG)
861 provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
862 dwFlags, pvPara, NULL, &provInfo);
863 else
865 HCERTSTORE memStore;
867 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
868 CERT_STORE_CREATE_NEW_FLAG, NULL);
869 if (memStore)
871 if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
872 dwFlags, pvPara, memStore, &provInfo))
873 ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
874 &provInfo);
875 else
876 CertCloseStore(memStore, 0);
879 CryptFreeOIDFunctionAddress(hFunc, 0);
881 else
882 SetLastError(ERROR_FILE_NOT_FOUND);
883 return ret;
886 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
888 static const WCHAR fmt[] = { '%','0','2','X',0 };
889 DWORD i;
891 assert(hash);
892 assert(asciiHash);
894 for (i = 0; i < 20; i++)
895 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
898 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
899 0 };
900 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
901 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
902 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
904 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store, HKEY key,
905 DWORD contextType)
907 LONG rc;
908 DWORD index = 0;
909 WCHAR subKeyName[MAX_PATH];
911 do {
912 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
914 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
915 NULL);
916 if (!rc)
918 HKEY subKey;
920 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
921 if (!rc)
923 LPBYTE buf = NULL;
925 size = 0;
926 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
927 if (!rc)
928 buf = CryptMemAlloc(size);
929 if (buf)
931 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
932 &size);
933 if (!rc)
935 const void *context;
936 DWORD addedType;
938 TRACE("Adding cert with hash %s\n",
939 debugstr_w(subKeyName));
940 context = CRYPT_ReadSerializedElement(buf, size,
941 contextType, &addedType);
942 if (context)
944 const WINE_CONTEXT_INTERFACE *contextInterface;
945 BYTE hash[20];
947 switch (addedType)
949 case CERT_STORE_CERTIFICATE_CONTEXT:
950 contextInterface = &gCertInterface;
951 break;
952 case CERT_STORE_CRL_CONTEXT:
953 contextInterface = &gCRLInterface;
954 break;
955 case CERT_STORE_CTL_CONTEXT:
956 contextInterface = &gCTLInterface;
957 break;
958 default:
959 contextInterface = NULL;
961 if (contextInterface)
963 size = sizeof(hash);
964 if (contextInterface->getProp(context,
965 CERT_HASH_PROP_ID, hash, &size))
967 WCHAR asciiHash[20 * 2 + 1];
969 CRYPT_HashToStr(hash, asciiHash);
970 TRACE("comparing %s\n",
971 debugstr_w(asciiHash));
972 TRACE("with %s\n", debugstr_w(subKeyName));
973 if (!lstrcmpW(asciiHash, subKeyName))
975 TRACE("hash matches, adding\n");
976 contextInterface->addContextToStore(
977 store->memStore, context,
978 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
980 else
981 TRACE("hash doesn't match, ignoring\n");
983 contextInterface->free(context);
987 CryptMemFree(buf);
989 RegCloseKey(subKey);
991 /* Ignore intermediate errors, continue enumerating */
992 rc = ERROR_SUCCESS;
994 } while (!rc);
997 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store)
999 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1000 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
1001 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
1002 DWORD i;
1004 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1006 HKEY key;
1007 LONG rc;
1009 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
1010 &key, NULL);
1011 if (!rc)
1013 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
1014 RegCloseKey(key);
1019 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
1020 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
1021 DWORD len)
1023 WCHAR asciiHash[20 * 2 + 1];
1024 LONG rc;
1025 HKEY subKey;
1026 BOOL ret;
1028 CRYPT_HashToStr(hash, asciiHash);
1029 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1030 &subKey, NULL);
1031 if (!rc)
1033 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
1034 RegCloseKey(subKey);
1036 if (!rc)
1037 ret = TRUE;
1038 else
1040 SetLastError(rc);
1041 ret = FALSE;
1043 return ret;
1046 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
1047 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1049 const void *context = NULL;
1050 BOOL ret;
1052 do {
1053 context = contextInterface->enumContextsInStore(memStore, context);
1054 if (context)
1056 BYTE hash[20];
1057 DWORD hashSize = sizeof(hash);
1059 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1060 &hashSize);
1061 if (ret)
1063 DWORD size = 0;
1064 LPBYTE buf = NULL;
1066 ret = contextInterface->serialize(context, 0, NULL, &size);
1067 if (size)
1068 buf = CryptMemAlloc(size);
1069 if (buf)
1071 ret = contextInterface->serialize(context, 0, buf, &size);
1072 if (ret)
1073 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1075 CryptMemFree(buf);
1078 else
1079 ret = TRUE;
1080 } while (ret && context != NULL);
1081 if (context)
1082 contextInterface->free(context);
1083 return ret;
1086 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
1088 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1089 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1090 &gCRLInterface, &gCTLInterface };
1091 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1092 BOOL ret = TRUE;
1093 DWORD i;
1095 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1097 HKEY key;
1098 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1099 KEY_ALL_ACCESS, NULL, &key, NULL);
1101 if (!rc)
1103 if (listToDelete[i])
1105 PWINE_HASH_TO_DELETE toDelete, next;
1106 WCHAR asciiHash[20 * 2 + 1];
1108 EnterCriticalSection(&store->cs);
1109 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1110 WINE_HASH_TO_DELETE, entry)
1112 LONG rc;
1114 CRYPT_HashToStr(toDelete->hash, asciiHash);
1115 TRACE("Removing %s\n", debugstr_w(asciiHash));
1116 rc = RegDeleteKeyW(key, asciiHash);
1117 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1119 SetLastError(rc);
1120 ret = FALSE;
1122 list_remove(&toDelete->entry);
1123 CryptMemFree(toDelete);
1125 LeaveCriticalSection(&store->cs);
1127 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1128 store->memStore);
1129 RegCloseKey(key);
1131 else
1133 SetLastError(rc);
1134 ret = FALSE;
1137 return ret;
1140 /* If force is true or the registry store is dirty, writes the contents of the
1141 * store to the registry.
1143 static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
1145 BOOL ret;
1147 TRACE("(%p, %d)\n", store, force);
1149 if (store->dirty || force)
1150 ret = CRYPT_RegWriteToReg(store);
1151 else
1152 ret = TRUE;
1153 return ret;
1156 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1158 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1160 TRACE("(%p, %08lx)\n", store, dwFlags);
1161 if (dwFlags)
1162 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1164 CRYPT_RegFlushStore(store, FALSE);
1165 RegCloseKey(store->key);
1166 DeleteCriticalSection(&store->cs);
1167 CryptMemFree(store);
1170 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
1171 PCCERT_CONTEXT cert, DWORD dwFlags)
1173 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1174 BOOL ret;
1176 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
1178 if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
1180 store->dirty = TRUE;
1181 ret = TRUE;
1183 else
1184 ret = FALSE;
1185 return ret;
1188 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1189 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1191 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1192 BOOL ret;
1194 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1196 if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
1198 SetLastError(ERROR_ACCESS_DENIED);
1199 ret = FALSE;
1201 else
1203 PWINE_HASH_TO_DELETE toDelete =
1204 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1206 if (toDelete)
1208 DWORD size = sizeof(toDelete->hash);
1210 ret = CertGetCertificateContextProperty(pCertContext,
1211 CERT_HASH_PROP_ID, toDelete->hash, &size);
1212 if (ret)
1214 EnterCriticalSection(&store->cs);
1215 list_add_tail(&store->certsToDelete, &toDelete->entry);
1216 LeaveCriticalSection(&store->cs);
1218 else
1220 CryptMemFree(toDelete);
1221 ret = FALSE;
1224 else
1225 ret = FALSE;
1226 if (ret)
1227 store->dirty = TRUE;
1229 return ret;
1232 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1233 DWORD dwCtrlType, void const *pvCtrlPara)
1235 PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1236 BOOL ret;
1238 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
1239 pvCtrlPara);
1241 switch (dwCtrlType)
1243 case CERT_STORE_CTRL_RESYNC:
1244 CRYPT_RegFlushStore(store, FALSE);
1245 CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1246 CRYPT_RegReadFromReg(store);
1247 ret = TRUE;
1248 break;
1249 case CERT_STORE_CTRL_COMMIT:
1250 ret = CRYPT_RegFlushStore(store,
1251 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1252 break;
1253 default:
1254 FIXME("%ld: stub\n", dwCtrlType);
1255 ret = FALSE;
1257 return ret;
1260 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1261 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1263 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1264 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1265 HKEY hSubKey = 0;
1267 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1269 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1270 if (!dwRet)
1272 /* Find how many subkeys there are */
1273 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1274 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1275 if (!dwRet)
1277 dwMaxSubkeyLen++;
1278 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1280 /* Name too big: alloc a buffer for it */
1281 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1284 if (!lpszName)
1285 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1286 else
1288 /* Recursively delete all the subkeys */
1289 for (i = 0; i < dwKeyCount && !dwRet; i++)
1291 dwSize = dwMaxSubkeyLen;
1292 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1293 NULL, NULL, NULL);
1294 if (!dwRet)
1295 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1298 if (lpszName != szNameBuf)
1300 /* Free buffer if allocated */
1301 CryptMemFree(lpszName);
1306 RegCloseKey(hSubKey);
1307 if (!dwRet)
1308 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1310 return dwRet;
1313 static void *regProvFuncs[] = {
1314 CRYPT_RegCloseStore,
1315 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1316 CRYPT_RegWriteCert,
1317 CRYPT_RegDeleteCert,
1318 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1319 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1320 NULL, /* CERT_STORE_PROV_WRITE_CRL_FUNC */
1321 NULL, /* CERT_STORE_PROV_DELETE_CRL_FUNC */
1322 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1323 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1324 NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1325 NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1326 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1327 CRYPT_RegControl,
1330 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1331 DWORD dwFlags, const void *pvPara)
1333 PWINECRYPT_CERTSTORE store = NULL;
1335 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1337 if (dwFlags & CERT_STORE_DELETE_FLAG)
1339 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1341 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1342 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1343 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1344 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1345 if (rc == ERROR_NO_MORE_ITEMS)
1346 rc = ERROR_SUCCESS;
1347 SetLastError(rc);
1349 else
1351 HKEY key;
1353 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1354 GetCurrentProcess(), (LPHANDLE)&key,
1355 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1356 TRUE, 0))
1358 PWINECRYPT_CERTSTORE memStore;
1360 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1361 if (memStore)
1363 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
1364 sizeof(WINE_REGSTOREINFO));
1366 if (regInfo)
1368 CERT_STORE_PROV_INFO provInfo = { 0 };
1370 regInfo->dwOpenFlags = dwFlags;
1371 regInfo->cryptProv = hCryptProv;
1372 regInfo->memStore = memStore;
1373 regInfo->key = key;
1374 InitializeCriticalSection(&regInfo->cs);
1375 list_init(&regInfo->certsToDelete);
1376 CRYPT_RegReadFromReg(regInfo);
1377 regInfo->dirty = FALSE;
1378 provInfo.cbSize = sizeof(provInfo);
1379 provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
1380 sizeof(regProvFuncs[0]);
1381 provInfo.rgpvStoreProvFunc = regProvFuncs;
1382 provInfo.hStoreProv = regInfo;
1383 store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1384 &provInfo);
1389 TRACE("returning %p\n", store);
1390 return store;
1393 /* FIXME: this isn't complete for the Root store, in which the top-level
1394 * self-signed CA certs reside. Adding a cert to the Root store should present
1395 * the user with a dialog indicating the consequences of doing so, and asking
1396 * the user to confirm whether the cert should be added.
1398 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1399 DWORD dwFlags, const void *pvPara)
1401 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1402 LPCWSTR storeName = (LPCWSTR)pvPara;
1403 LPWSTR storePath;
1404 PWINECRYPT_CERTSTORE store = NULL;
1405 HKEY root;
1406 LPCWSTR base;
1407 BOOL ret;
1409 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1410 debugstr_w((LPCWSTR)pvPara));
1412 if (!pvPara)
1414 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1415 return NULL;
1418 ret = TRUE;
1419 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1421 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1422 root = HKEY_LOCAL_MACHINE;
1423 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1424 break;
1425 case CERT_SYSTEM_STORE_CURRENT_USER:
1426 root = HKEY_CURRENT_USER;
1427 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1428 break;
1429 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1430 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1431 * SystemCertificates
1433 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1434 debugstr_w(storeName));
1435 return NULL;
1436 case CERT_SYSTEM_STORE_SERVICES:
1437 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1438 * SystemCertificates
1440 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1441 debugstr_w(storeName));
1442 return NULL;
1443 case CERT_SYSTEM_STORE_USERS:
1444 /* hku\user sid\Software\Microsoft\SystemCertificates */
1445 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1446 debugstr_w(storeName));
1447 return NULL;
1448 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1449 root = HKEY_CURRENT_USER;
1450 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1451 break;
1452 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1453 root = HKEY_LOCAL_MACHINE;
1454 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1455 break;
1456 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1457 /* hklm\Software\Microsoft\EnterpriseCertificates */
1458 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1459 debugstr_w(storeName));
1460 return NULL;
1461 default:
1462 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1463 return NULL;
1466 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1467 sizeof(WCHAR));
1468 if (storePath)
1470 LONG rc;
1471 HKEY key;
1472 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1473 KEY_ALL_ACCESS;
1475 wsprintfW(storePath, fmt, base, storeName);
1476 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1477 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1478 else
1480 DWORD disp;
1482 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1483 &key, &disp);
1484 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1485 disp == REG_OPENED_EXISTING_KEY)
1487 RegCloseKey(key);
1488 rc = ERROR_FILE_EXISTS;
1491 if (!rc)
1493 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1494 RegCloseKey(key);
1496 else
1497 SetLastError(rc);
1498 CryptMemFree(storePath);
1500 return store;
1503 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1504 DWORD dwFlags, const void *pvPara)
1506 int len;
1507 PWINECRYPT_CERTSTORE ret = NULL;
1509 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1510 debugstr_a((LPCSTR)pvPara));
1512 if (!pvPara)
1514 SetLastError(ERROR_FILE_NOT_FOUND);
1515 return NULL;
1517 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1518 if (len)
1520 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1522 if (storeName)
1524 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1525 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1526 CryptMemFree(storeName);
1529 return ret;
1532 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1533 DWORD dwFlags, const void *pvPara)
1535 HCERTSTORE store = 0;
1536 BOOL ret;
1538 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1539 debugstr_w((LPCWSTR)pvPara));
1541 if (!pvPara)
1543 SetLastError(ERROR_FILE_NOT_FOUND);
1544 return NULL;
1546 /* This returns a different error than system registry stores if the
1547 * location is invalid.
1549 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1551 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1552 case CERT_SYSTEM_STORE_CURRENT_USER:
1553 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1554 case CERT_SYSTEM_STORE_SERVICES:
1555 case CERT_SYSTEM_STORE_USERS:
1556 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1557 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1558 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1559 ret = TRUE;
1560 break;
1561 default:
1562 SetLastError(ERROR_FILE_NOT_FOUND);
1563 ret = FALSE;
1565 if (ret)
1567 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1568 0, hCryptProv, dwFlags, pvPara);
1570 if (regStore)
1572 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1573 CERT_STORE_CREATE_NEW_FLAG, NULL);
1574 CertAddStoreToCollection(store, regStore,
1575 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1576 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1577 CertCloseStore(regStore, 0);
1578 /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1579 * stores.
1581 if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1582 CERT_SYSTEM_STORE_CURRENT_USER)
1584 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
1585 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
1586 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
1587 hCryptProv, dwFlags, pvPara);
1588 if (regStore)
1590 CertAddStoreToCollection(store, regStore,
1591 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1592 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1593 CertCloseStore(regStore, 0);
1598 return (PWINECRYPT_CERTSTORE)store;
1601 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1602 DWORD dwFlags, const void *pvPara)
1604 int len;
1605 PWINECRYPT_CERTSTORE ret = NULL;
1607 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1608 debugstr_a((LPCSTR)pvPara));
1610 if (!pvPara)
1612 SetLastError(ERROR_FILE_NOT_FOUND);
1613 return NULL;
1615 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1616 if (len)
1618 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1620 if (storeName)
1622 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1623 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1624 CryptMemFree(storeName);
1627 return ret;
1630 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1631 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1632 const void* pvPara)
1634 WINECRYPT_CERTSTORE *hcs;
1635 StoreOpenFunc openFunc = NULL;
1637 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1638 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1640 if (!HIWORD(lpszStoreProvider))
1642 switch (LOWORD(lpszStoreProvider))
1644 case (int)CERT_STORE_PROV_MEMORY:
1645 openFunc = CRYPT_MemOpenStore;
1646 break;
1647 case (int)CERT_STORE_PROV_REG:
1648 openFunc = CRYPT_RegOpenStore;
1649 break;
1650 case (int)CERT_STORE_PROV_COLLECTION:
1651 openFunc = CRYPT_CollectionOpenStore;
1652 break;
1653 case (int)CERT_STORE_PROV_SYSTEM_A:
1654 openFunc = CRYPT_SysOpenStoreA;
1655 break;
1656 case (int)CERT_STORE_PROV_SYSTEM_W:
1657 openFunc = CRYPT_SysOpenStoreW;
1658 break;
1659 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1660 openFunc = CRYPT_SysRegOpenStoreA;
1661 break;
1662 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1663 openFunc = CRYPT_SysRegOpenStoreW;
1664 break;
1665 default:
1666 if (LOWORD(lpszStoreProvider))
1667 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1670 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1671 openFunc = CRYPT_MemOpenStore;
1672 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1673 openFunc = CRYPT_SysOpenStoreW;
1674 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1675 openFunc = CRYPT_CollectionOpenStore;
1676 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1677 openFunc = CRYPT_SysRegOpenStoreW;
1678 else
1680 FIXME("unimplemented type %s\n", lpszStoreProvider);
1681 openFunc = NULL;
1684 if (!openFunc)
1685 hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
1686 hCryptProv, dwFlags, pvPara);
1687 else
1688 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1689 return (HCERTSTORE)hcs;
1692 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1693 LPCSTR szSubSystemProtocol)
1695 if (!szSubSystemProtocol)
1697 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1698 return 0;
1700 return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
1701 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1704 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1705 LPCWSTR szSubSystemProtocol)
1707 if (!szSubSystemProtocol)
1709 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1710 return 0;
1712 return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
1713 CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1716 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1717 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1719 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1720 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1721 return TRUE;
1724 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1725 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1727 PCRL_CONTEXT pcrl;
1728 BYTE* data;
1730 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1732 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1733 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1734 if( !pcrl )
1735 return NULL;
1737 data = CryptMemAlloc( cbCrlEncoded );
1738 if( !data )
1740 CryptMemFree( pcrl );
1741 return NULL;
1744 pcrl->dwCertEncodingType = dwCertEncodingType;
1745 pcrl->pbCrlEncoded = data;
1746 pcrl->cbCrlEncoded = cbCrlEncoded;
1747 pcrl->pCrlInfo = NULL;
1748 pcrl->hCertStore = 0;
1750 return pcrl;
1753 /* Decodes the encoded certificate and creates the certificate context for it.
1755 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1756 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1758 PWINE_CERT_CONTEXT_DATA cert = NULL;
1759 BOOL ret;
1760 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1761 PCERT_INFO certInfo = NULL;
1762 DWORD size = 0;
1764 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1765 cbCertEncoded);
1767 /* First try to decode it as a signed cert. */
1768 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1769 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&signedCert, &size);
1770 if (ret)
1772 size = 0;
1773 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1774 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1775 CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&certInfo, &size);
1776 LocalFree(signedCert);
1778 /* Failing that, try it as an unsigned cert */
1779 if (!ret)
1781 size = 0;
1782 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1783 pbCertEncoded, cbCertEncoded,
1784 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1785 (BYTE *)&certInfo, &size);
1787 if (ret)
1789 BYTE *data = NULL;
1791 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_DATA));
1792 if (!cert)
1793 goto end;
1794 data = CryptMemAlloc(cbCertEncoded);
1795 if (!data)
1797 CryptMemFree(cert);
1798 cert = NULL;
1799 goto end;
1801 memcpy(data, pbCertEncoded, cbCertEncoded);
1802 cert->cert.dwCertEncodingType = dwCertEncodingType;
1803 cert->cert.pbCertEncoded = data;
1804 cert->cert.cbCertEncoded = cbCertEncoded;
1805 cert->cert.pCertInfo = certInfo;
1806 cert->cert.hCertStore = 0;
1807 cert->ref = 1;
1808 cert->type = ContextTypeData;
1809 cert->properties = ContextPropertyList_Create();
1812 end:
1813 return (PWINE_CERT_CONTEXT)cert;
1816 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1817 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1819 PWINE_CERT_CONTEXT cert;
1821 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1822 cbCertEncoded);
1824 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1825 cbCertEncoded);
1826 return (PCCERT_CONTEXT)cert;
1829 /* If context is a link, follows it to its linked context (recursively, if
1830 * necessary) and returns the data context associated with the link.
1831 * Otherwise just returns context.
1833 static inline PWINE_CERT_CONTEXT_DATA CertContext_GetDataContext(
1834 PWINE_CERT_CONTEXT context)
1836 PWINE_CERT_CONTEXT ptr = context;
1838 while (ptr && ptr->type == ContextTypeLink)
1839 ptr = ((PWINE_CERT_CONTEXT_LINK)ptr)->linked;
1840 return (ptr && ptr->type == ContextTypeData) ?
1841 (PWINE_CERT_CONTEXT_DATA)ptr : NULL;
1844 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1845 DWORD dwPropId)
1847 PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(
1848 (PWINE_CERT_CONTEXT)pCertContext);
1849 DWORD ret;
1851 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1853 if (linked)
1854 ret = ContextPropertyList_EnumPropIDs(linked->properties, dwPropId);
1855 else
1856 ret = 0;
1857 return ret;
1860 static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId,
1861 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
1862 DWORD *pcbData)
1864 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
1865 pcbData);
1866 if (ret)
1868 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1870 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1871 0, &blob);
1873 return ret;
1876 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1877 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1879 PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context);
1880 BOOL ret;
1881 CRYPT_DATA_BLOB blob;
1883 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1885 if (linked)
1886 ret = ContextPropertyList_FindProperty(linked->properties, dwPropId,
1887 &blob);
1888 else
1889 ret = FALSE;
1890 if (ret)
1892 if (!pvData)
1894 *pcbData = blob.cbData;
1895 ret = TRUE;
1897 else if (*pcbData < blob.cbData)
1899 SetLastError(ERROR_MORE_DATA);
1900 *pcbData = blob.cbData;
1902 else
1904 memcpy(pvData, blob.pbData, blob.cbData);
1905 *pcbData = blob.cbData;
1906 ret = TRUE;
1909 else
1911 /* Implicit properties */
1912 switch (dwPropId)
1914 case CERT_SHA1_HASH_PROP_ID:
1915 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
1916 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1917 pcbData);
1918 break;
1919 case CERT_MD5_HASH_PROP_ID:
1920 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1921 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1922 pcbData);
1923 break;
1924 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1925 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1926 context->cert.pCertInfo->Subject.pbData,
1927 context->cert.pCertInfo->Subject.cbData,
1928 pvData, pcbData);
1929 break;
1930 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1931 ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1932 context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1933 context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
1934 pvData, pcbData);
1935 break;
1936 case CERT_SIGNATURE_HASH_PROP_ID:
1937 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1938 FIXME("implicit property %ld\n", dwPropId);
1939 SetLastError(CRYPT_E_NOT_FOUND);
1940 break;
1941 default:
1942 SetLastError(CRYPT_E_NOT_FOUND);
1945 TRACE("returning %d\n", ret);
1946 return ret;
1949 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1950 DWORD dwPropId, void *pvData, DWORD *pcbData)
1952 BOOL ret;
1954 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1956 /* Special cases for invalid/special prop IDs.
1958 switch (dwPropId)
1960 case 0:
1961 case CERT_CERT_PROP_ID:
1962 case CERT_CRL_PROP_ID:
1963 case CERT_CTL_PROP_ID:
1964 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1965 return FALSE;
1966 case CERT_ACCESS_STATE_PROP_ID:
1967 if (!pvData)
1969 *pcbData = sizeof(DWORD);
1970 return TRUE;
1972 else if (*pcbData < sizeof(DWORD))
1974 SetLastError(ERROR_MORE_DATA);
1975 *pcbData = sizeof(DWORD);
1976 return FALSE;
1978 else
1980 DWORD state = 0;
1982 if (pCertContext->hCertStore)
1984 PWINECRYPT_CERTSTORE store =
1985 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1987 if (!(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1988 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1990 *(DWORD *)pvData = state;
1991 return TRUE;
1995 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext,
1996 dwPropId, pvData, pcbData);
1997 TRACE("returning %d\n", ret);
1998 return ret;
2001 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2002 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2004 PWINE_CERT_CONTEXT_DATA linked = CertContext_GetDataContext(context);
2005 BOOL ret;
2007 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2009 if (!linked)
2010 ret = FALSE;
2011 else if (!pvData)
2013 ContextPropertyList_RemoveProperty(linked->properties, dwPropId);
2014 ret = TRUE;
2016 else
2018 switch (dwPropId)
2020 case CERT_AUTO_ENROLL_PROP_ID:
2021 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
2022 case CERT_DESCRIPTION_PROP_ID:
2023 case CERT_FRIENDLY_NAME_PROP_ID:
2024 case CERT_HASH_PROP_ID:
2025 case CERT_KEY_IDENTIFIER_PROP_ID:
2026 case CERT_MD5_HASH_PROP_ID:
2027 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2028 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2029 case CERT_PVK_FILE_PROP_ID:
2030 case CERT_SIGNATURE_HASH_PROP_ID:
2031 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2032 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
2033 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2034 case CERT_ENROLLMENT_PROP_ID:
2035 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2036 case CERT_RENEWAL_PROP_ID:
2038 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2040 ret = ContextPropertyList_SetProperty(linked->properties, dwPropId,
2041 blob->pbData, blob->cbData);
2042 break;
2044 case CERT_DATE_STAMP_PROP_ID:
2045 ret = ContextPropertyList_SetProperty(linked->properties, dwPropId,
2046 pvData, sizeof(FILETIME));
2047 break;
2048 default:
2049 FIXME("%ld: stub\n", dwPropId);
2050 ret = FALSE;
2053 TRACE("returning %d\n", ret);
2054 return ret;
2057 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2058 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2060 BOOL ret;
2062 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2064 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2065 * crashes on most of these, I'll be safer.
2067 switch (dwPropId)
2069 case 0:
2070 case CERT_ACCESS_STATE_PROP_ID:
2071 case CERT_CERT_PROP_ID:
2072 case CERT_CRL_PROP_ID:
2073 case CERT_CTL_PROP_ID:
2074 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2075 return FALSE;
2077 ret = CRYPT_SetCertificateContextProperty((PWINE_CERT_CONTEXT)pCertContext,
2078 dwPropId, dwFlags, pvData);
2079 TRACE("returning %d\n", ret);
2080 return ret;
2083 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2084 PCCERT_CONTEXT pCertContext)
2086 PWINE_CERT_CONTEXT context = (PWINE_CERT_CONTEXT)pCertContext;
2088 TRACE("(%p)\n", pCertContext);
2089 InterlockedIncrement(&context->ref);
2090 return pCertContext;
2093 static void CertContext_CopyProperties(PCCERT_CONTEXT to, PCCERT_CONTEXT from)
2095 PWINE_CERT_CONTEXT_DATA toData, fromData;
2097 toData = CertContext_GetDataContext((PWINE_CERT_CONTEXT)to);
2098 fromData = CertContext_GetDataContext((PWINE_CERT_CONTEXT)from);
2099 ContextPropertyList_Copy(toData->properties, fromData->properties);
2102 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2103 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2104 PCCERT_CONTEXT *ppStoreContext)
2106 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2107 BOOL ret = TRUE;
2108 PCCERT_CONTEXT toAdd = NULL, existing = NULL;
2110 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2111 dwAddDisposition, ppStoreContext);
2113 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2115 BYTE hashToAdd[20];
2116 DWORD size = sizeof(hashToAdd);
2118 ret = CRYPT_GetCertificateContextProperty(
2119 (PWINE_CERT_CONTEXT)pCertContext, CERT_HASH_PROP_ID, hashToAdd, &size);
2120 if (ret)
2122 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
2124 existing = CertFindCertificateInStore(hCertStore,
2125 pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
2126 NULL);
2130 switch (dwAddDisposition)
2132 case CERT_STORE_ADD_ALWAYS:
2133 toAdd = CertDuplicateCertificateContext(pCertContext);
2134 break;
2135 case CERT_STORE_ADD_NEW:
2136 if (existing)
2138 TRACE("found matching certificate, not adding\n");
2139 SetLastError(CRYPT_E_EXISTS);
2140 ret = FALSE;
2142 else
2143 toAdd = CertDuplicateCertificateContext(pCertContext);
2144 break;
2145 case CERT_STORE_ADD_REPLACE_EXISTING:
2146 toAdd = CertDuplicateCertificateContext(pCertContext);
2147 break;
2148 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2149 toAdd = CertDuplicateCertificateContext(pCertContext);
2150 if (existing)
2151 CertContext_CopyProperties(toAdd, existing);
2152 break;
2153 case CERT_STORE_ADD_USE_EXISTING:
2154 if (existing)
2155 CertContext_CopyProperties(existing, pCertContext);
2156 break;
2157 default:
2158 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
2159 ret = FALSE;
2162 if (toAdd)
2164 ret = store->addCert(store, (PWINE_CERT_CONTEXT)toAdd,
2165 (PWINE_CERT_CONTEXT)existing, ppStoreContext);
2166 CertFreeCertificateContext(toAdd);
2168 CertFreeCertificateContext(existing);
2170 TRACE("returning %d\n", ret);
2171 return ret;
2174 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2175 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2176 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2178 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2179 BOOL ret;
2181 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2182 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2184 if (!hcs)
2185 ret = FALSE;
2186 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2187 ret = FALSE;
2188 else
2190 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2191 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2193 if (cert)
2195 ret = CertAddCertificateContextToStore(hCertStore,
2196 (PCCERT_CONTEXT)cert, dwAddDisposition, ppCertContext);
2197 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
2199 else
2200 ret = FALSE;
2202 return ret;
2205 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2206 PCCERT_CONTEXT pPrev)
2208 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2209 PCCERT_CONTEXT ret;
2211 TRACE("(%p, %p)\n", hCertStore, pPrev);
2212 if (!hCertStore)
2213 ret = NULL;
2214 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2215 ret = NULL;
2216 else
2217 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, (PWINE_CERT_CONTEXT)pPrev);
2218 return ret;
2221 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2223 BOOL ret;
2225 TRACE("(%p)\n", pCertContext);
2227 if (!pCertContext)
2228 ret = TRUE;
2229 else if (!pCertContext->hCertStore)
2231 ret = TRUE;
2232 CertFreeCertificateContext(pCertContext);
2234 else
2236 PWINECRYPT_CERTSTORE hcs =
2237 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2239 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2240 ret = FALSE;
2241 else
2242 ret = hcs->deleteCert(hcs, pCertContext, 0);
2243 CertFreeCertificateContext(pCertContext);
2245 return ret;
2248 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2249 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2250 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2252 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2253 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2254 ppCrlContext);
2255 return FALSE;
2258 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2259 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2260 PCCRL_CONTEXT* ppStoreContext )
2262 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2263 dwAddDisposition, ppStoreContext);
2264 return TRUE;
2267 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2269 FIXME("%p\n", pCrlContext );
2271 return TRUE;
2274 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2276 FIXME("(%p): stub\n", pCrlContext);
2277 return TRUE;
2280 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2281 PCCRL_CONTEXT pPrev)
2283 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2284 return NULL;
2287 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2288 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2290 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2291 cbCtlEncoded);
2292 return NULL;
2295 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2296 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2297 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2299 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2300 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2301 ppCtlContext);
2302 return FALSE;
2305 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2306 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2307 PCCTL_CONTEXT* ppStoreContext)
2309 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2310 dwAddDisposition, ppStoreContext);
2311 return TRUE;
2314 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2316 FIXME("(%p): stub\n", pCtlContext );
2317 return TRUE;
2320 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2322 FIXME("(%p): stub\n", pCtlContext);
2323 return TRUE;
2326 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2327 PCCTL_CONTEXT pPrev)
2329 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2330 return NULL;
2333 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
2335 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2337 TRACE("(%p)\n", hCertStore);
2339 if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
2340 InterlockedIncrement(&hcs->ref);
2341 return hCertStore;
2344 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2346 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2348 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2350 if( ! hCertStore )
2351 return TRUE;
2353 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2354 return FALSE;
2356 if (InterlockedDecrement(&hcs->ref) == 0)
2358 TRACE("%p's ref count is 0, freeing\n", hcs);
2359 hcs->dwMagic = 0;
2360 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2361 CryptReleaseContext(hcs->cryptProv, 0);
2362 hcs->closeStore(hcs, dwFlags);
2364 else
2365 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2366 return TRUE;
2369 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2370 DWORD dwCtrlType, void const *pvCtrlPara)
2372 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2373 BOOL ret;
2375 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2376 pvCtrlPara);
2378 if (!hcs)
2379 ret = FALSE;
2380 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2381 ret = FALSE;
2382 else
2384 if (hcs->control)
2385 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2386 else
2387 ret = TRUE;
2389 return ret;
2392 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2393 DWORD dwPropId, void *pvData, DWORD *pcbData)
2395 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2396 return FALSE;
2399 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2400 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2402 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2403 pvData);
2404 return FALSE;
2407 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2408 DWORD dwPropId, void *pvData, DWORD *pcbData)
2410 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2411 return FALSE;
2414 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2415 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2417 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2418 pvData);
2419 return FALSE;
2422 static void CertDataContext_Free(PWINE_CERT_CONTEXT_DATA context)
2424 CryptMemFree(context->cert.pbCertEncoded);
2425 LocalFree(context->cert.pCertInfo);
2426 ContextPropertyList_Free(context->properties);
2427 CryptMemFree(context);
2430 static void CertLinkContext_Free(PWINE_CERT_CONTEXT_LINK context)
2432 CertFreeCertificateContext((PCCERT_CONTEXT)context->linked);
2433 CryptMemFree(context);
2436 static void CertContext_Release(PWINE_CERT_CONTEXT context)
2438 if (InterlockedDecrement(&context->ref) == 0)
2440 TRACE("freeing %p\n", context);
2441 switch (context->type)
2443 case ContextTypeData:
2444 CertDataContext_Free((PWINE_CERT_CONTEXT_DATA)context);
2445 break;
2446 case ContextTypeLink:
2447 CertLinkContext_Free((PWINE_CERT_CONTEXT_LINK)context);
2448 break;
2449 default:
2450 assert(0);
2453 else
2454 TRACE("%p's ref count is %ld\n", context, context->ref);
2457 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2459 TRACE("(%p)\n", pCertContext);
2461 if (pCertContext)
2462 CertContext_Release((PWINE_CERT_CONTEXT)pCertContext);
2463 return TRUE;
2466 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
2467 DWORD dwFlags, const void *pvPara);
2469 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
2470 DWORD dwFlags, const void *pvPara)
2472 return TRUE;
2475 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
2476 DWORD dwFlags, const void *pvPara)
2478 BOOL ret;
2479 BYTE hash[16];
2480 DWORD size = sizeof(hash);
2482 ret = CertGetCertificateContextProperty(pCertContext,
2483 CERT_MD5_HASH_PROP_ID, hash, &size);
2484 if (ret)
2486 const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
2488 if (size == pHash->cbData)
2489 ret = !memcmp(pHash->pbData, hash, size);
2490 else
2491 ret = FALSE;
2493 return ret;
2496 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
2497 DWORD dwFlags, const void *pvPara)
2499 BOOL ret;
2500 BYTE hash[20];
2501 DWORD size = sizeof(hash);
2503 ret = CertGetCertificateContextProperty(pCertContext,
2504 CERT_SHA1_HASH_PROP_ID, hash, &size);
2505 if (ret)
2507 const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
2509 if (size == pHash->cbData)
2510 ret = !memcmp(pHash->pbData, hash, size);
2511 else
2512 ret = FALSE;
2514 return ret;
2517 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
2518 DWORD dwFlags, const void *pvPara)
2520 const CERT_NAME_BLOB *blob = (const CERT_NAME_BLOB *)pvPara, *toCompare;
2521 BOOL ret;
2523 if (dwType & CERT_INFO_SUBJECT_FLAG)
2524 toCompare = &pCertContext->pCertInfo->Subject;
2525 else
2526 toCompare = &pCertContext->pCertInfo->Issuer;
2527 if (toCompare->cbData == blob->cbData)
2528 ret = !memcmp(toCompare->pbData, blob->pbData, blob->cbData);
2529 else
2530 ret = FALSE;
2531 return ret;
2534 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
2535 DWORD dwType, DWORD dwFlags, const void *pvPara)
2537 const CERT_INFO *pCertInfo = (const CERT_INFO *)pvPara;
2538 BOOL ret;
2540 if (pCertInfo->Issuer.cbData == pCertContext->pCertInfo->Subject.cbData)
2541 ret = !memcmp(pCertInfo->Issuer.pbData,
2542 pCertContext->pCertInfo->Subject.pbData, pCertInfo->Issuer.cbData);
2543 else
2544 ret = FALSE;
2545 return ret;
2548 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2549 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2550 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2552 PCCERT_CONTEXT ret;
2553 CertCompareFunc compare;
2555 TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType,
2556 dwFlags, dwType, pvPara, pPrevCertContext);
2558 switch (dwType >> CERT_COMPARE_SHIFT)
2560 case CERT_COMPARE_ANY:
2561 compare = compare_cert_any;
2562 break;
2563 case CERT_COMPARE_MD5_HASH:
2564 compare = compare_cert_by_md5_hash;
2565 break;
2566 case CERT_COMPARE_SHA1_HASH:
2567 compare = compare_cert_by_sha1_hash;
2568 break;
2569 case CERT_COMPARE_NAME:
2570 compare = compare_cert_by_name;
2571 break;
2572 case CERT_COMPARE_SUBJECT_CERT:
2573 compare = compare_cert_by_subject_cert;
2574 break;
2575 default:
2576 FIXME("find type %08lx unimplemented\n", dwType);
2577 compare = NULL;
2580 if (compare)
2582 BOOL matches = FALSE;
2584 ret = pPrevCertContext;
2585 do {
2586 ret = CertEnumCertificatesInStore(hCertStore, ret);
2587 if (ret)
2588 matches = compare(ret, dwType, dwFlags, pvPara);
2589 } while (ret != NULL && !matches);
2590 if (!ret)
2591 SetLastError(CRYPT_E_NOT_FOUND);
2593 else
2595 SetLastError(CRYPT_E_NOT_FOUND);
2596 ret = NULL;
2598 return ret;
2601 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
2602 DWORD dwCertEncodingType, PCERT_INFO pCertId)
2604 TRACE("(%p, %08lx, %p)\n", hCertStore, dwCertEncodingType, pCertId);
2606 if (!pCertId)
2608 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2609 return NULL;
2611 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
2612 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
2615 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2616 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2618 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2619 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2620 PWINE_STORE_LIST_ENTRY entry;
2621 BOOL ret;
2623 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2624 dwUpdateFlags, dwPriority);
2626 if (!collection || !sibling)
2627 return TRUE;
2628 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2630 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2631 return FALSE;
2633 if (collection->hdr.type != StoreTypeCollection)
2635 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2636 return FALSE;
2638 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2640 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2641 return FALSE;
2644 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2645 if (entry)
2647 InterlockedIncrement(&sibling->ref);
2648 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2649 entry->store = sibling;
2650 entry->dwUpdateFlags = dwUpdateFlags;
2651 entry->dwPriority = dwPriority;
2652 list_init(&entry->entry);
2653 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2654 EnterCriticalSection(&collection->cs);
2655 if (dwPriority)
2657 PWINE_STORE_LIST_ENTRY cursor;
2658 BOOL added = FALSE;
2660 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2661 WINE_STORE_LIST_ENTRY, entry)
2663 if (cursor->dwPriority < dwPriority)
2665 list_add_before(&cursor->entry, &entry->entry);
2666 added = TRUE;
2667 break;
2670 if (!added)
2671 list_add_tail(&collection->stores, &entry->entry);
2673 else
2674 list_add_tail(&collection->stores, &entry->entry);
2675 LeaveCriticalSection(&collection->cs);
2676 ret = TRUE;
2678 else
2679 ret = FALSE;
2680 return ret;
2683 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2684 HCERTSTORE hSiblingStore)
2686 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2687 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2688 PWINE_STORE_LIST_ENTRY store, next;
2690 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2692 if (!collection || !sibling)
2693 return;
2694 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2696 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2697 return;
2699 if (collection->hdr.type != StoreTypeCollection)
2700 return;
2701 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2703 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2704 return;
2706 EnterCriticalSection(&collection->cs);
2707 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2708 WINE_STORE_LIST_ENTRY, entry)
2710 if (store->store == sibling)
2712 list_remove(&store->entry);
2713 CertCloseStore(store->store, 0);
2714 CryptMemFree(store);
2715 break;
2718 LeaveCriticalSection(&collection->cs);