kernel: Add some more tests for FindFirstChangeNotification.
[wine] / dlls / crypt32 / cert.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2004,2005 Juan Lang
4  *
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.
9  *
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.
14  *
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
18  *
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  * - Opening a cert store provider should be morphed to support loading
24  *   external DLLs.
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.
29  */
30 #include <assert.h>
31 #include <stdarg.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "winuser.h"
37 #include "wincrypt.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
40 #include "excpt.h"
41 #include "wine/exception.h"
42 #include "crypt32_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
45
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
51
52 /* Some typedefs that make it easier to abstract which type of context we're
53  * working with.
54  */
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);
72
73 /* An abstract context (certificate, CRL, or CTL) interface */
74 typedef struct _WINE_CONTEXT_INTERFACE
75 {
76     CreateContextFunc            create;
77     AddContextToStoreFunc        addContextToStore;
78     AddEncodedContextToStoreFunc addEncodedToStore;
79     EnumContextsInStoreFunc      enumContextsInStore;
80     GetContextPropertyFunc       getProp;
81     SetContextPropertyFunc       setProp;
82     SerializeElementFunc         serialize;
83     FreeContextFunc              free;
84     DeleteContextFunc            deleteFromStore;
85 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
86
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,
97 };
98
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,
109 };
110
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,
121 };
122
123 struct WINE_CRYPTCERTSTORE;
124
125 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
126  DWORD dwFlags, const void *pvPara);
127
128 struct _WINE_CERT_CONTEXT_REF;
129
130 /* Called to enumerate the next certificate in a store.  The returned pointer
131  * must be newly allocated (via CryptMemAlloc):  CertFreeCertificateContext
132  * frees it.
133  */
134 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
135  (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
136
137 struct _WINE_CERT_CONTEXT;
138
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
143  * this.
144  */
145 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
146  (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
147
148 /* Optional, called when a cert context reference is being freed.  Don't free
149  * the ref pointer itself, CertFreeCertificateContext does that.
150  */
151 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
152
153 typedef enum _CertStoreType {
154     StoreTypeMem,
155     StoreTypeCollection,
156     StoreTypeReg,
157     StoreTypeDummy,
158 } CertStoreType;
159
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
166  *   persistence
167  */
168 typedef struct WINE_CRYPTCERTSTORE
169 {
170     DWORD                           dwMagic;
171     LONG                            ref;
172     DWORD                           dwOpenFlags;
173     HCRYPTPROV                      cryptProv;
174     CertStoreType                   type;
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;
183
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.
191  */
192 typedef struct _WINE_CERT_CONTEXT
193 {
194     CERT_CONTEXT     cert;
195     LONG             ref;
196     CRITICAL_SECTION cs;
197     struct list      extendedProperties;
198 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
199
200 typedef struct _WINE_CERT_CONTEXT_REF
201 {
202     CERT_CONTEXT cert;
203     WINE_CERT_CONTEXT *context;
204 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
205
206 /* An extended certificate property in serialized form is prefixed by this
207  * header.
208  */
209 typedef struct _WINE_CERT_PROP_HEADER
210 {
211     DWORD propID;
212     DWORD unknown; /* always 1 */
213     DWORD cb;
214 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
215
216 /* Stores an extended property in a cert. */
217 typedef struct _WINE_CERT_PROPERTY
218 {
219     WINE_CERT_PROP_HEADER hdr;
220     LPBYTE                pbData;
221     struct list           entry;
222 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
223
224 /* A mem store has a list of these.  They're also returned by the mem store
225  * during enumeration.
226  */
227 typedef struct _WINE_CERT_LIST_ENTRY
228 {
229     WINE_CERT_CONTEXT_REF cert;
230     struct list entry;
231 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
232
233 typedef struct _WINE_MEMSTORE
234 {
235     WINECRYPT_CERTSTORE hdr;
236     CRITICAL_SECTION    cs;
237     struct list         certs;
238 } WINE_MEMSTORE, *PWINE_MEMSTORE;
239
240 typedef struct _WINE_HASH_TO_DELETE
241 {
242     BYTE        hash[20];
243     struct list entry;
244 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
245
246 /* Returned by a reg store during enumeration. */
247 typedef struct _WINE_REG_CERT_CONTEXT
248 {
249     WINE_CERT_CONTEXT_REF  cert;
250     PWINE_CERT_CONTEXT_REF childContext;
251 } WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT;
252
253 typedef struct _WINE_REGSTORE
254 {
255     WINECRYPT_CERTSTORE  hdr;
256     PWINECRYPT_CERTSTORE memStore;
257     HKEY                 key;
258     BOOL                 dirty;
259     CRITICAL_SECTION     cs;
260     struct list          certsToDelete;
261 } WINE_REGSTORE, *PWINE_REGSTORE;
262
263 typedef struct _WINE_STORE_LIST_ENTRY
264 {
265     PWINECRYPT_CERTSTORE store;
266     DWORD                dwUpdateFlags;
267     DWORD                dwPriority;
268     struct list          entry;
269 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
270
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
276  * scenarios either.
277  */
278 typedef struct _WINE_COLLECTION_CERT_CONTEXT
279 {
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;
284
285 typedef struct _WINE_COLLECTIONSTORE
286 {
287     WINECRYPT_CERTSTORE hdr;
288     CRITICAL_SECTION    cs;
289     struct list         stores;
290 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
291
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.)
296  */
297 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
298  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
299
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.
303  */
304 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
305  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
306
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.
312  */
313 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
314  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
315
316 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
317  DWORD dwFlags, CertStoreType type)
318 {
319     store->ref = 1;
320     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
321     store->type = type;
322     if (!hCryptProv)
323     {
324         hCryptProv = CRYPT_GetDefaultProvider();
325         dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
326     }
327     store->cryptProv = hCryptProv;
328     store->dwOpenFlags = dwFlags;
329 }
330
331 /* Initializes the reference ref to point to pCertContext, which is assumed to
332  * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
333  * Also sets the hCertStore member of the reference to store.
334  */
335 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
336  PWINE_CERT_CONTEXT context, HCERTSTORE store)
337 {
338     TRACE("(%p, %p)\n", ref, context);
339     memcpy(&ref->cert, context, sizeof(ref->cert));
340     ref->context = context;
341     InterlockedIncrement(&context->ref);
342     TRACE("%p's ref count is %ld\n", context, context->ref);
343     ref->cert.hCertStore = store;
344 }
345
346 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
347  HCERTSTORE store)
348 {
349     PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
350      sizeof(WINE_CERT_CONTEXT_REF));
351
352     TRACE("(%p, %p)\n", context, store);
353     if (pCertRef)
354         CRYPT_InitCertRef(pCertRef, context, store);
355     return pCertRef;
356 }
357
358 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
359  DWORD dwAddDisposition)
360 {
361     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
362     BOOL add = FALSE, ret;
363
364     TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
365
366     switch (dwAddDisposition)
367     {
368     case CERT_STORE_ADD_ALWAYS:
369         add = TRUE;
370         break;
371     case CERT_STORE_ADD_NEW:
372     {
373         BYTE hashToAdd[20], hash[20];
374         DWORD size = sizeof(hashToAdd);
375
376         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
377          CERT_HASH_PROP_ID, hashToAdd, &size);
378         if (ret)
379         {
380             PWINE_CERT_LIST_ENTRY cursor;
381
382             /* Add if no cert with the same hash is found. */
383             add = TRUE;
384             EnterCriticalSection(&ms->cs);
385             LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
386             {
387                 size = sizeof(hash);
388                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
389                  CERT_HASH_PROP_ID, hash, &size);
390                 if (ret && !memcmp(hashToAdd, hash, size))
391                 {
392                     TRACE("found matching certificate, not adding\n");
393                     SetLastError(CRYPT_E_EXISTS);
394                     add = FALSE;
395                     break;
396                 }
397             }
398             LeaveCriticalSection(&ms->cs);
399         }
400         break;
401     }
402     case CERT_STORE_ADD_REPLACE_EXISTING:
403     {
404         BYTE hashToAdd[20], hash[20];
405         DWORD size = sizeof(hashToAdd);
406
407         add = TRUE;
408         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
409          CERT_HASH_PROP_ID, hashToAdd, &size);
410         if (ret)
411         {
412             PWINE_CERT_LIST_ENTRY cursor, next;
413
414             /* Look for existing cert to delete */
415             EnterCriticalSection(&ms->cs);
416             LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
417              WINE_CERT_LIST_ENTRY, entry)
418             {
419                 size = sizeof(hash);
420                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
421                  CERT_HASH_PROP_ID, hash, &size);
422                 if (ret && !memcmp(hashToAdd, hash, size))
423                 {
424                     TRACE("found matching certificate, replacing\n");
425                     list_remove(&cursor->entry);
426                     CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
427                     break;
428                 }
429             }
430             LeaveCriticalSection(&ms->cs);
431         }
432         break;
433     }
434     default:
435         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
436         add = FALSE;
437     }
438     if (add)
439     {
440         PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
441          sizeof(WINE_CERT_LIST_ENTRY));
442
443         if (entry)
444         {
445             TRACE("adding %p\n", entry);
446             CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
447             list_init(&entry->entry);
448             EnterCriticalSection(&ms->cs);
449             list_add_tail(&ms->certs, &entry->entry);
450             LeaveCriticalSection(&ms->cs);
451             ret = TRUE;
452         }
453         else
454             ret = FALSE;
455     }
456     else
457         ret = FALSE;
458     TRACE("returning %d\n", ret);
459     return ret;
460 }
461
462 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
463  PWINE_CERT_CONTEXT_REF pPrev)
464 {
465     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
466     PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
467     struct list *listNext;
468
469     TRACE("(%p, %p)\n", store, pPrev);
470     EnterCriticalSection(&ms->cs);
471     if (prevEntry)
472     {
473         listNext = list_next(&ms->certs, &prevEntry->entry);
474         CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
475     }
476     else
477         listNext = list_next(&ms->certs, &ms->certs);
478     if (listNext)
479     {
480         ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
481         if (ret)
482         {
483             memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
484              sizeof(WINE_CERT_LIST_ENTRY));
485             InterlockedIncrement(&ret->cert.context->ref);
486         }
487     }
488     else
489     {
490         SetLastError(CRYPT_E_NOT_FOUND);
491         ret = NULL;
492     }
493     LeaveCriticalSection(&ms->cs);
494
495     TRACE("returning %p\n", ret);
496     return (PWINE_CERT_CONTEXT_REF)ret;
497 }
498
499 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref);
500
501 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
502  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
503 {
504     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
505     WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
506     PWINE_CERT_LIST_ENTRY cert, next;
507     BOOL ret = TRUE;
508
509     /* Find the entry associated with the passed-in context, since the
510      * passed-in context may not be a list entry itself (e.g. if it came from
511      * CertDuplicateCertificateContext.)  Pointing to the same context is
512      * a sufficient test of equality.
513      */
514     EnterCriticalSection(&store->cs);
515     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
516      entry)
517     {
518         if (cert->cert.context == ref->context)
519         {
520             TRACE("removing %p\n", cert);
521             /* FIXME: this isn't entirely thread-safe, the entry itself isn't
522              * protected.
523              */
524             list_remove(&cert->entry);
525             /* FIXME: generally I should do the following, otherwise there is
526              * a memory leak.  But doing so when called by
527              * CertDeleteCertificateFromStore results in a double free, so
528              * leaving commented for now.
529             ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
530              */
531             cert->entry.prev = cert->entry.next = &store->certs;
532             break;
533         }
534     }
535     LeaveCriticalSection(&store->cs);
536     return ret;
537 }
538
539 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
540 {
541     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
542     PWINE_CERT_LIST_ENTRY cert, next;
543
544     TRACE("(%p, %08lx)\n", store, dwFlags);
545     if (dwFlags)
546         FIXME("Unimplemented flags: %08lx\n", dwFlags);
547
548     /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
549      * pointer if its ref-count reaches zero.  That's okay here because there
550      * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
551      * of the CertListEntry.
552      */
553     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
554      entry)
555     {
556         TRACE("removing %p\n", cert);
557         list_remove(&cert->entry);
558         CertFreeCertificateContext((PCCERT_CONTEXT)cert);
559     }
560     DeleteCriticalSection(&store->cs);
561     CryptMemFree(store);
562 }
563
564 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
565  DWORD dwFlags, const void *pvPara)
566 {
567     PWINE_MEMSTORE store;
568
569     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
570
571     if (dwFlags & CERT_STORE_DELETE_FLAG)
572     {
573         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
574         store = NULL;
575     }
576     else
577     {
578         store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
579         if (store)
580         {
581             memset(store, 0, sizeof(WINE_MEMSTORE));
582             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
583             store->hdr.closeStore    = CRYPT_MemCloseStore;
584             store->hdr.addCert       = CRYPT_MemAddCert;
585             store->hdr.createCertRef = CRYPT_CreateCertRef;
586             store->hdr.enumCert      = CRYPT_MemEnumCert;
587             store->hdr.deleteCert    = CRYPT_MemDeleteCert;
588             store->hdr.freeCert      = NULL;
589             InitializeCriticalSection(&store->cs);
590             list_init(&store->certs);
591         }
592     }
593     return (PWINECRYPT_CERTSTORE)store;
594 }
595
596 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
597  PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
598 {
599     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
600     PWINE_STORE_LIST_ENTRY entry, next;
601     BOOL ret;
602
603     TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
604
605     ret = FALSE;
606     EnterCriticalSection(&cs->cs);
607     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
608      entry)
609     {
610         if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
611         {
612             ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
613             break;
614         }
615     }
616     LeaveCriticalSection(&cs->cs);
617     SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
618     return ret;
619 }
620
621 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
622  PWINE_CERT_CONTEXT context, HCERTSTORE store)
623 {
624     PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
625      sizeof(WINE_COLLECTION_CERT_CONTEXT));
626
627     if (ret)
628     {
629         /* Initialize to empty for now, just make sure the size is right */
630         CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
631         ret->entry = NULL;
632         ret->childContext = NULL;
633     }
634     return (PWINE_CERT_CONTEXT_REF)ret;
635 }
636
637 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
638 {
639     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
640     PWINE_STORE_LIST_ENTRY entry, next;
641
642     TRACE("(%p, %08lx)\n", store, dwFlags);
643
644     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
645      entry)
646     {
647         TRACE("closing %p\n", entry);
648         CertCloseStore((HCERTSTORE)entry->store, dwFlags);
649         CryptMemFree(entry);
650     }
651     DeleteCriticalSection(&cs->cs);
652     CryptMemFree(cs);
653 }
654
655 /* Advances a collection enumeration by one cert, if possible, where advancing
656  * means:
657  * - calling the current store's enumeration function once, and returning
658  *   the enumerated cert if one is returned
659  * - moving to the next store if the current store has no more items, and
660  *   recursively calling itself to get the next item.
661  * Returns NULL if the collection contains no more items or on error.
662  * Assumes the collection store's lock is held.
663  */
664 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
665  PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
666  PWINE_COLLECTION_CERT_CONTEXT pPrev)
667 {
668     PWINE_COLLECTION_CERT_CONTEXT ret;
669     PWINE_CERT_CONTEXT_REF child;
670     struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
671
672     TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
673
674     child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
675      pPrev ? pPrev->childContext : NULL);
676     if (pPrev)
677     {
678         pPrev->childContext = NULL;
679         CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
680         pPrev = NULL;
681     }
682     if (child)
683     {
684         ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
685          child->context, store);
686         if (ret)
687         {
688             ret->entry = storeEntry;
689             ret->childContext = child;
690         }
691         else
692             CertFreeCertificateContext((PCCERT_CONTEXT)child);
693     }
694     else
695     {
696         if (storeNext)
697         {
698             storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
699             ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
700         }
701         else
702         {
703             SetLastError(CRYPT_E_NOT_FOUND);
704             ret = NULL;
705         }
706     }
707     TRACE("returning %p\n", ret);
708     return ret;
709 }
710
711 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
712  PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
713 {
714     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
715     PWINE_COLLECTION_CERT_CONTEXT prevEntry =
716      (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
717
718     TRACE("(%p, %p)\n", store, pPrev);
719
720     if (prevEntry)
721     {
722         EnterCriticalSection(&cs->cs);
723         ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
724         LeaveCriticalSection(&cs->cs);
725     }
726     else
727     {
728         EnterCriticalSection(&cs->cs);
729         if (!list_empty(&cs->stores))
730         {
731             PWINE_STORE_LIST_ENTRY storeEntry;
732
733             storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
734              entry);
735             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
736         }
737         else
738         {
739             SetLastError(CRYPT_E_NOT_FOUND);
740             ret = NULL;
741         }
742         LeaveCriticalSection(&cs->cs);
743     }
744     TRACE("returning %p\n", ret);
745     return (PWINE_CERT_CONTEXT_REF)ret;
746 }
747
748 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
749  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
750 {
751     PWINE_COLLECTION_CERT_CONTEXT context =
752      (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
753     BOOL ret;
754
755     TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
756
757     ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
758     if (ret)
759         context->childContext = NULL;
760     return ret;
761 }
762
763 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
764 {
765     PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
766
767     TRACE("(%p)\n", ref);
768
769     if (context->childContext)
770         CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
771 }
772
773 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
774  DWORD dwFlags, const void *pvPara)
775 {
776     PWINE_COLLECTIONSTORE store;
777
778     if (dwFlags & CERT_STORE_DELETE_FLAG)
779     {
780         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
781         store = NULL;
782     }
783     else
784     {
785         store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
786         if (store)
787         {
788             memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
789             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
790              StoreTypeCollection);
791             store->hdr.closeStore    = CRYPT_CollectionCloseStore;
792             store->hdr.addCert       = CRYPT_CollectionAddCert;
793             store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
794             store->hdr.enumCert      = CRYPT_CollectionEnumCert;
795             store->hdr.deleteCert    = CRYPT_CollectionDeleteCert;
796             store->hdr.freeCert      = CRYPT_CollectionFreeCert;
797             InitializeCriticalSection(&store->cs);
798             list_init(&store->stores);
799         }
800     }
801     return (PWINECRYPT_CERTSTORE)store;
802 }
803
804 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
805 {
806     static const WCHAR fmt[] = { '%','0','2','X',0 };
807     DWORD i;
808
809     assert(hash);
810     assert(asciiHash);
811
812     for (i = 0; i < 20; i++)
813         wsprintfW(asciiHash + i * 2, fmt, hash[i]);
814 }
815
816 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
817  0 };
818 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
819 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
820 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
821
822 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
823  DWORD contextType)
824 {
825     LONG rc;
826     DWORD index = 0;
827     WCHAR subKeyName[MAX_PATH];
828
829     do {
830         DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
831
832         rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
833          NULL);
834         if (!rc)
835         {
836             HKEY subKey;
837
838             rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
839             if (!rc)
840             {
841                 LPBYTE buf = NULL;
842
843                 size = 0;
844                 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
845                 if (!rc)
846                     buf = CryptMemAlloc(size);
847                 if (buf)
848                 {
849                     rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
850                      &size);
851                     if (!rc)
852                     {
853                         const void *context;
854                         DWORD addedType;
855
856                         TRACE("Adding cert with hash %s\n",
857                          debugstr_w(subKeyName));
858                         context = CRYPT_ReadSerializedElement(buf, size,
859                          contextType, &addedType);
860                         if (context)
861                         {
862                             const WINE_CONTEXT_INTERFACE *contextInterface;
863                             BYTE hash[20];
864
865                             switch (addedType)
866                             {
867                             case CERT_STORE_CERTIFICATE_CONTEXT:
868                                 contextInterface = &gCertInterface;
869                                 break;
870                             case CERT_STORE_CRL_CONTEXT:
871                                 contextInterface = &gCRLInterface;
872                                 break;
873                             case CERT_STORE_CTL_CONTEXT:
874                                 contextInterface = &gCTLInterface;
875                                 break;
876                             default:
877                                 contextInterface = NULL;
878                             }
879                             if (contextInterface)
880                             {
881                                 size = sizeof(hash);
882                                 if (contextInterface->getProp(context,
883                                  CERT_HASH_PROP_ID, hash, &size))
884                                 {
885                                     WCHAR asciiHash[20 * 2 + 1];
886
887                                     CRYPT_HashToStr(hash, asciiHash);
888                                     TRACE("comparing %s\n",
889                                      debugstr_w(asciiHash));
890                                     TRACE("with %s\n", debugstr_w(subKeyName));
891                                     if (!lstrcmpW(asciiHash, subKeyName))
892                                     {
893                                         TRACE("hash matches, adding\n");
894                                         contextInterface->addContextToStore(
895                                          store, context,
896                                          CERT_STORE_ADD_REPLACE_EXISTING, NULL);
897                                     }
898                                     else
899                                         TRACE("hash doesn't match, ignoring\n");
900                                 }
901                                 contextInterface->free(context);
902                             }
903                         }
904                     }
905                     CryptMemFree(buf);
906                 }
907                 RegCloseKey(subKey);
908             }
909             /* Ignore intermediate errors, continue enumerating */
910             rc = ERROR_SUCCESS;
911         }
912     } while (!rc);
913 }
914
915 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
916 {
917     static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
918     static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
919      CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
920     DWORD i;
921
922     for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
923     {
924         HKEY key;
925         LONG rc;
926
927         rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
928          &key, NULL);
929         if (!rc)
930         {
931             CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
932             RegCloseKey(key);
933         }
934     }
935 }
936
937 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
938 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
939  DWORD len)
940 {
941     WCHAR asciiHash[20 * 2 + 1];
942     LONG rc;
943     HKEY subKey;
944     BOOL ret;
945
946     CRYPT_HashToStr(hash, asciiHash);
947     rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
948      &subKey, NULL);
949     if (!rc)
950     {
951         rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
952         RegCloseKey(subKey);
953     }
954     if (!rc)
955         ret = TRUE;
956     else
957     {
958         SetLastError(rc);
959         ret = FALSE;
960     }
961     return ret;
962 }
963
964 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
965  const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
966 {
967     const void *context = NULL;
968     BOOL ret;
969
970     do {
971         context = contextInterface->enumContextsInStore(memStore, context);
972         if (context)
973         {
974             BYTE hash[20];
975             DWORD hashSize = sizeof(hash);
976
977             ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
978              &hashSize);
979             if (ret)
980             {
981                 DWORD size = 0;
982                 LPBYTE buf = NULL;
983
984                 ret = contextInterface->serialize(context, 0, NULL, &size);
985                 if (size)
986                     buf = CryptMemAlloc(size);
987                 if (buf)
988                 {
989                     ret = contextInterface->serialize(context, 0, buf, &size);
990                     if (ret)
991                         ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
992                 }
993                 CryptMemFree(buf);
994             }
995         }
996         else
997             ret = TRUE;
998     } while (ret && context != NULL);
999     if (context)
1000         contextInterface->free(context);
1001     return ret;
1002 }
1003
1004 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1005 {
1006     static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1007     static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1008      &gCRLInterface, &gCTLInterface };
1009     struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1010     BOOL ret = TRUE;
1011     DWORD i;
1012
1013     for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1014     {
1015         HKEY key;
1016         LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1017          KEY_ALL_ACCESS, NULL, &key, NULL);
1018
1019         if (!rc)
1020         {
1021             if (listToDelete[i])
1022             {
1023                 PWINE_HASH_TO_DELETE toDelete, next;
1024                 WCHAR asciiHash[20 * 2 + 1];
1025
1026                 EnterCriticalSection(&store->cs);
1027                 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1028                  WINE_HASH_TO_DELETE, entry)
1029                 {
1030                     LONG rc;
1031
1032                     CRYPT_HashToStr(toDelete->hash, asciiHash);
1033                     TRACE("Removing %s\n", debugstr_w(asciiHash));
1034                     rc = RegDeleteKeyW(key, asciiHash);
1035                     if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1036                     {
1037                         SetLastError(rc);
1038                         ret = FALSE;
1039                     }
1040                     list_remove(&toDelete->entry);
1041                     CryptMemFree(toDelete);
1042                 }
1043                 LeaveCriticalSection(&store->cs);
1044             }
1045             ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1046              store->memStore);
1047             RegCloseKey(key);
1048         }
1049         else
1050         {
1051             SetLastError(rc);
1052             ret = FALSE;
1053         }
1054     }
1055     return ret;
1056 }
1057
1058 /* If force is true or the registry store is dirty, writes the contents of the
1059  * store to the registry.
1060  */
1061 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1062 {
1063     BOOL ret;
1064
1065     if (store->dirty || force)
1066         ret = CRYPT_RegWriteToReg(store);
1067     else
1068         ret = TRUE;
1069     return ret;
1070 }
1071
1072 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1073 {
1074     PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1075
1076     TRACE("(%p, %08lx)\n", store, dwFlags);
1077     if (dwFlags)
1078         FIXME("Unimplemented flags: %08lx\n", dwFlags);
1079
1080     CRYPT_RegFlushStore(store, FALSE);
1081     /* certsToDelete should already be cleared by this point */
1082     store->memStore->closeStore(store->memStore, 0);
1083     RegCloseKey(store->key);
1084     DeleteCriticalSection(&store->cs);
1085     CryptMemFree(store);
1086 }
1087
1088 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1089  DWORD dwAddDisposition)
1090 {
1091     PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1092     BOOL ret;
1093
1094     TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1095
1096     if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1097     {
1098         SetLastError(ERROR_ACCESS_DENIED);
1099         ret = FALSE;
1100     }
1101     else
1102     {
1103         ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1104         if (ret)
1105             store->dirty = TRUE;
1106     }
1107     return ret;
1108 }
1109
1110 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1111  PWINE_CERT_CONTEXT context, HCERTSTORE store)
1112 {
1113     PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
1114
1115     if (ret)
1116     {
1117         CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1118         ret->childContext = NULL;
1119     }
1120     return (PWINE_CERT_CONTEXT_REF)ret;
1121 }
1122
1123 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1124  PWINE_CERT_CONTEXT_REF pPrev)
1125 {
1126     PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1127     PWINE_CERT_CONTEXT_REF child;
1128     PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1129
1130     TRACE("(%p, %p)\n", store, pPrev);
1131
1132     child = rs->memStore->enumCert(rs->memStore, prev ? prev->childContext
1133      : NULL);
1134     if (prev)
1135     {
1136         prev->childContext = NULL;
1137         CertFreeCertificateContext((PCCERT_CONTEXT)prev);
1138         prev = NULL;
1139     }
1140     if (child)
1141     {
1142         ret = (PWINE_REG_CERT_CONTEXT)CRYPT_RegCreateCertRef(child->context,
1143          store);
1144         if (ret)
1145             ret->childContext = child;
1146         else
1147             CertFreeCertificateContext((PCCERT_CONTEXT)child);
1148     }
1149     return (PWINE_CERT_CONTEXT_REF)ret;
1150 }
1151
1152 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1153  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1154 {
1155     PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1156     BOOL ret;
1157
1158     TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1159
1160     if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1161     {
1162         SetLastError(ERROR_ACCESS_DENIED);
1163         ret = FALSE;
1164     }
1165     else
1166     {
1167         PWINE_HASH_TO_DELETE toDelete =
1168          CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1169
1170         if (toDelete)
1171         {
1172             DWORD size = sizeof(toDelete->hash);
1173
1174             ret = CertGetCertificateContextProperty(pCertContext,
1175              CERT_HASH_PROP_ID, toDelete->hash, &size);
1176             if (ret)
1177             {
1178                 list_init(&toDelete->entry);
1179                 EnterCriticalSection(&store->cs);
1180                 list_add_tail(&store->certsToDelete, &toDelete->entry);
1181                 LeaveCriticalSection(&store->cs);
1182                 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1183                  dwFlags);
1184             }
1185             else
1186                 CryptMemFree(toDelete);
1187         }
1188         else
1189             ret = FALSE;
1190         if (ret)
1191             store->dirty = TRUE;
1192     }
1193     return ret;
1194 }
1195
1196 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1197 {
1198     PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1199
1200     TRACE("(%p)\n", ref);
1201
1202     if (context->childContext)
1203         CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1204 }
1205
1206 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1207  DWORD dwCtrlType, void const *pvCtrlPara)
1208 {
1209     PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1210     BOOL ret;
1211
1212     switch (dwCtrlType)
1213     {
1214     case CERT_STORE_CTRL_RESYNC:
1215         CRYPT_RegFlushStore(store, FALSE);
1216         store->memStore->closeStore(store->memStore, 0);
1217         store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1218          store->hdr.dwOpenFlags, NULL);
1219         if (store->memStore)
1220         {
1221             CRYPT_RegReadFromReg(store);
1222             ret = TRUE;
1223         }
1224         else
1225             ret = FALSE;
1226         break;
1227     case CERT_STORE_CTRL_COMMIT:
1228         ret = CRYPT_RegFlushStore(store,
1229          dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1230         break;
1231     default:
1232         FIXME("%ld: stub\n", dwCtrlType);
1233         ret = FALSE;
1234     }
1235     return ret;
1236 }
1237
1238 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1239 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1240 {
1241     DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1242     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1243     HKEY hSubKey = 0;
1244
1245     TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1246
1247     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1248     if (!dwRet)
1249     {
1250         /* Find how many subkeys there are */
1251         dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1252          &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1253         if (!dwRet)
1254         {
1255             dwMaxSubkeyLen++;
1256             if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1257             {
1258                 /* Name too big: alloc a buffer for it */
1259                 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1260             }
1261
1262             if (!lpszName)
1263                 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1264             else
1265             {
1266                 /* Recursively delete all the subkeys */
1267                 for (i = 0; i < dwKeyCount && !dwRet; i++)
1268                 {
1269                     dwSize = dwMaxSubkeyLen;
1270                     dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1271                      NULL, NULL, NULL);
1272                     if (!dwRet)
1273                         dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1274                 }
1275
1276                 if (lpszName != szNameBuf)
1277                 {
1278                     /* Free buffer if allocated */
1279                     CryptMemFree(lpszName);
1280                 }
1281             }
1282         }
1283
1284         RegCloseKey(hSubKey);
1285         if (!dwRet)
1286             dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1287     }
1288     return dwRet;
1289 }
1290
1291 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1292  DWORD dwFlags, const void *pvPara)
1293 {
1294     PWINE_REGSTORE store = NULL;
1295
1296     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1297
1298     if (dwFlags & CERT_STORE_DELETE_FLAG)
1299     {
1300         DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1301
1302         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1303             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1304         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1305             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1306         if (rc == ERROR_NO_MORE_ITEMS)
1307             rc = ERROR_SUCCESS;
1308         SetLastError(rc);
1309     }
1310     else
1311     {
1312         HKEY key;
1313
1314         if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1315          GetCurrentProcess(), (LPHANDLE)&key,
1316          dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1317          TRUE, 0))
1318         {
1319             PWINECRYPT_CERTSTORE memStore;
1320
1321             memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1322             if (memStore)
1323             {
1324                 store = CryptMemAlloc(sizeof(WINE_REGSTORE));
1325                 if (store)
1326                 {
1327                     memset(store, 0, sizeof(WINE_REGSTORE));
1328                     CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1329                      StoreTypeReg);
1330                     store->hdr.closeStore    = CRYPT_RegCloseStore;
1331                     store->hdr.addCert       = CRYPT_RegAddCert;
1332                     store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1333                     store->hdr.enumCert      = CRYPT_RegEnumCert;
1334                     store->hdr.deleteCert    = CRYPT_RegDeleteCert;
1335                     store->hdr.freeCert      = CRYPT_RegFreeCert;
1336                     store->hdr.control       = CRYPT_RegControl;
1337                     store->memStore          = memStore;
1338                     store->key               = key;
1339                     InitializeCriticalSection(&store->cs);
1340                     list_init(&store->certsToDelete);
1341                     CRYPT_RegReadFromReg(store);
1342                     store->dirty = FALSE;
1343                 }
1344             }
1345         }
1346     }
1347     TRACE("returning %p\n", store);
1348     return (WINECRYPT_CERTSTORE *)store;
1349 }
1350
1351 /* FIXME: this isn't complete for the Root store, in which the top-level
1352  * self-signed CA certs reside.  Adding a cert to the Root store should present
1353  * the user with a dialog indicating the consequences of doing so, and asking
1354  * the user to confirm whether the cert should be added.
1355  */
1356 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1357  DWORD dwFlags, const void *pvPara)
1358 {
1359     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1360     LPCWSTR storeName = (LPCWSTR)pvPara;
1361     LPWSTR storePath;
1362     PWINECRYPT_CERTSTORE store = NULL;
1363     HKEY root;
1364     LPCWSTR base;
1365     BOOL ret;
1366
1367     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1368      debugstr_w((LPCWSTR)pvPara));
1369
1370     if (!pvPara)
1371     {
1372         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1373         return NULL;
1374     }
1375
1376     ret = TRUE;
1377     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1378     {
1379     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1380         root = HKEY_LOCAL_MACHINE;
1381         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1382         break;
1383     case CERT_SYSTEM_STORE_CURRENT_USER:
1384         root = HKEY_CURRENT_USER;
1385         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1386         break;
1387     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1388         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1389          * SystemCertificates
1390          */
1391         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1392          debugstr_w(storeName));
1393         return NULL;
1394     case CERT_SYSTEM_STORE_SERVICES:
1395         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1396          * SystemCertificates
1397          */
1398         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1399          debugstr_w(storeName));
1400         return NULL;
1401     case CERT_SYSTEM_STORE_USERS:
1402         /* hku\user sid\Software\Microsoft\SystemCertificates */
1403         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1404          debugstr_w(storeName));
1405         return NULL;
1406     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1407         root = HKEY_CURRENT_USER;
1408         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1409         break;
1410     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1411         root = HKEY_LOCAL_MACHINE;
1412         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1413         break;
1414     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1415         /* hklm\Software\Microsoft\EnterpriseCertificates */
1416         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1417          debugstr_w(storeName));
1418         return NULL;
1419     default:
1420         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1421         return NULL;
1422     }
1423
1424     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1425      sizeof(WCHAR));
1426     if (storePath)
1427     {
1428         LONG rc;
1429         HKEY key;
1430         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1431             KEY_ALL_ACCESS;
1432
1433         wsprintfW(storePath, fmt, base, storeName);
1434         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1435             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1436         else
1437         {
1438             DWORD disp;
1439
1440             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1441                                  &key, &disp);
1442             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1443                 disp == REG_OPENED_EXISTING_KEY)
1444             {
1445                 RegCloseKey(key);
1446                 rc = ERROR_FILE_EXISTS;
1447             }
1448         }
1449         if (!rc)
1450         {
1451             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1452             RegCloseKey(key);
1453         }
1454         else
1455             SetLastError(rc);
1456         CryptMemFree(storePath);
1457     }
1458     return store;
1459 }
1460
1461 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1462  DWORD dwFlags, const void *pvPara)
1463 {
1464     int len;
1465     PWINECRYPT_CERTSTORE ret = NULL;
1466
1467     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1468      debugstr_a((LPCSTR)pvPara));
1469
1470     if (!pvPara)
1471     {
1472         SetLastError(ERROR_FILE_NOT_FOUND);
1473         return NULL;
1474     }
1475     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1476     if (len)
1477     {
1478         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1479
1480         if (storeName)
1481         {
1482             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1483             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1484             CryptMemFree(storeName);
1485         }
1486     }
1487     return ret;
1488 }
1489
1490 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1491  DWORD dwFlags, const void *pvPara)
1492 {
1493     HCERTSTORE store = 0;
1494     BOOL ret;
1495
1496     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1497      debugstr_w((LPCWSTR)pvPara));
1498
1499     if (!pvPara)
1500     {
1501         SetLastError(ERROR_FILE_NOT_FOUND);
1502         return NULL;
1503     }
1504     /* This returns a different error than system registry stores if the
1505      * location is invalid.
1506      */
1507     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1508     {
1509     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1510     case CERT_SYSTEM_STORE_CURRENT_USER:
1511     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1512     case CERT_SYSTEM_STORE_SERVICES:
1513     case CERT_SYSTEM_STORE_USERS:
1514     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1515     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1516     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1517         ret = TRUE;
1518         break;
1519     default:
1520         SetLastError(ERROR_FILE_NOT_FOUND);
1521         ret = FALSE;
1522     }
1523     if (ret)
1524     {
1525         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1526          0, hCryptProv, dwFlags, pvPara);
1527
1528         if (regStore)
1529         {
1530             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1531              CERT_STORE_CREATE_NEW_FLAG, NULL);
1532             if (store)
1533             {
1534                 CertAddStoreToCollection(store, regStore,
1535                  dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1536                  CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1537                 CertCloseStore(regStore, 0);
1538             }
1539         }
1540     }
1541     return (PWINECRYPT_CERTSTORE)store;
1542 }
1543
1544 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1545  DWORD dwFlags, const void *pvPara)
1546 {
1547     int len;
1548     PWINECRYPT_CERTSTORE ret = NULL;
1549
1550     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1551      debugstr_a((LPCSTR)pvPara));
1552
1553     if (!pvPara)
1554     {
1555         SetLastError(ERROR_FILE_NOT_FOUND);
1556         return NULL;
1557     }
1558     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1559     if (len)
1560     {
1561         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1562
1563         if (storeName)
1564         {
1565             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1566             ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1567             CryptMemFree(storeName);
1568         }
1569     }
1570     return ret;
1571 }
1572
1573 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1574  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1575  const void* pvPara)
1576 {
1577     WINECRYPT_CERTSTORE *hcs;
1578     StoreOpenFunc openFunc = NULL;
1579
1580     TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1581           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1582
1583     if (!HIWORD(lpszStoreProvider))
1584     {
1585         switch (LOWORD(lpszStoreProvider))
1586         {
1587         case (int)CERT_STORE_PROV_MEMORY:
1588             openFunc = CRYPT_MemOpenStore;
1589             break;
1590         case (int)CERT_STORE_PROV_REG:
1591             openFunc = CRYPT_RegOpenStore;
1592             break;
1593         case (int)CERT_STORE_PROV_COLLECTION:
1594             openFunc = CRYPT_CollectionOpenStore;
1595             break;
1596         case (int)CERT_STORE_PROV_SYSTEM_A:
1597             openFunc = CRYPT_SysOpenStoreA;
1598             break;
1599         case (int)CERT_STORE_PROV_SYSTEM_W:
1600             openFunc = CRYPT_SysOpenStoreW;
1601             break;
1602         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1603             openFunc = CRYPT_SysRegOpenStoreA;
1604             break;
1605         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1606             openFunc = CRYPT_SysRegOpenStoreW;
1607             break;
1608         default:
1609             if (LOWORD(lpszStoreProvider))
1610                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1611         }
1612     }
1613     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1614         openFunc = CRYPT_MemOpenStore;
1615     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1616         openFunc = CRYPT_SysOpenStoreW;
1617     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1618         openFunc = CRYPT_CollectionOpenStore;
1619     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1620         openFunc = CRYPT_SysRegOpenStoreW;
1621     else
1622     {
1623         FIXME("unimplemented type %s\n", lpszStoreProvider);
1624         openFunc = NULL;
1625     }
1626
1627     if (!openFunc)
1628     {
1629         /* FIXME: need to look for an installed provider for this type */
1630         SetLastError(ERROR_FILE_NOT_FOUND);
1631         hcs = NULL;
1632     }
1633     else
1634         hcs = openFunc(hCryptProv, dwFlags, pvPara);
1635     return (HCERTSTORE)hcs;
1636 }
1637
1638 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1639  LPCSTR szSubSystemProtocol)
1640 {
1641     HCERTSTORE ret = 0;
1642
1643     if (szSubSystemProtocol)
1644     {
1645         int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1646          0);
1647         LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR));
1648
1649         if (param)
1650         {
1651             MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1652             ret = CertOpenSystemStoreW(hProv, param);
1653             CryptMemFree(param);
1654         }
1655     }
1656     else
1657         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1658     return ret;
1659 }
1660
1661 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1662  LPCWSTR szSubSystemProtocol)
1663 {
1664     HCERTSTORE ret;
1665
1666     if (!szSubSystemProtocol)
1667     {
1668         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1669         return 0;
1670     }
1671
1672     /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1673      * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1674      * it fails.
1675      */
1676     ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1677      CERT_STORE_CREATE_NEW_FLAG, NULL);
1678     if (ret)
1679     {
1680         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1681          0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1682
1683         if (store)
1684         {
1685             CertAddStoreToCollection(ret, store,
1686              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1687             CertCloseStore(store, 0);
1688         }
1689         store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1690          0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1691         if (store)
1692         {
1693             CertAddStoreToCollection(ret, store,
1694              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1695             CertCloseStore(store, 0);
1696         }
1697     }
1698     return ret;
1699 }
1700
1701 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1702              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1703 {
1704     FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, 
1705           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1706     return TRUE;
1707 }
1708
1709 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1710   const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1711 {
1712     PCRL_CONTEXT pcrl;
1713     BYTE* data;
1714
1715     TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1716
1717     /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1718     pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1719     if( !pcrl )
1720         return NULL;
1721
1722     data = CryptMemAlloc( cbCrlEncoded );
1723     if( !data )
1724     {
1725         CryptMemFree( pcrl );
1726         return NULL;
1727     }
1728
1729     pcrl->dwCertEncodingType = dwCertEncodingType;
1730     pcrl->pbCrlEncoded       = data;
1731     pcrl->cbCrlEncoded       = cbCrlEncoded;
1732     pcrl->pCrlInfo           = NULL;
1733     pcrl->hCertStore         = 0;
1734
1735     return pcrl;
1736 }
1737
1738 /* Decodes the encoded certificate and creates the certificate context for it.
1739  * The reference count is initially zero, so you must create a reference to it
1740  * to avoid leaking memory.
1741  */
1742 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1743  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1744 {
1745     PWINE_CERT_CONTEXT cert = NULL;
1746     BOOL ret;
1747     PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1748     PCERT_INFO certInfo = NULL;
1749     DWORD size = 0;
1750
1751     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1752      cbCertEncoded);
1753
1754     /* First try to decode it as a signed cert. */
1755     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1756      cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1757      (BYTE *)&signedCert, &size);
1758     if (ret)
1759     {
1760         size = 0;
1761         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1762          signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1763          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1764          (BYTE *)&certInfo, &size);
1765         LocalFree(signedCert);
1766     }
1767     /* Failing that, try it as an unsigned cert */
1768     if (!ret)
1769     {
1770         size = 0;
1771         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1772          pbCertEncoded, cbCertEncoded,
1773          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1774          (BYTE *)&certInfo, &size);
1775     }
1776     if (ret)
1777     {
1778         BYTE *data = NULL;
1779
1780         cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1781         if (!cert)
1782             goto end;
1783         data = CryptMemAlloc(cbCertEncoded);
1784         if (!data)
1785         {
1786             CryptMemFree(cert);
1787             cert = NULL;
1788             goto end;
1789         }
1790         memcpy(data, pbCertEncoded, cbCertEncoded);
1791         cert->cert.dwCertEncodingType = dwCertEncodingType;
1792         cert->cert.pbCertEncoded      = data;
1793         cert->cert.cbCertEncoded      = cbCertEncoded;
1794         cert->cert.pCertInfo          = certInfo;
1795         cert->cert.hCertStore         = 0;
1796         cert->ref = 0;
1797         InitializeCriticalSection(&cert->cs);
1798         list_init(&cert->extendedProperties);
1799     }
1800
1801 end:
1802     return cert;
1803 }
1804
1805 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1806 {
1807     PWINE_CERT_PROPERTY prop, next;
1808
1809     CryptMemFree(context->cert.pbCertEncoded);
1810     LocalFree(context->cert.pCertInfo);
1811     DeleteCriticalSection(&context->cs);
1812     LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1813      WINE_CERT_PROPERTY, entry)
1814     {
1815         list_remove(&prop->entry);
1816         CryptMemFree(prop->pbData);
1817         CryptMemFree(prop);
1818     }
1819     CryptMemFree(context);
1820 }
1821
1822 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1823  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1824 {
1825     PWINE_CERT_CONTEXT cert;
1826     PWINE_CERT_CONTEXT_REF ret = NULL;
1827
1828     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1829      cbCertEncoded);
1830
1831     cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1832      cbCertEncoded);
1833     if (cert)
1834         ret = CRYPT_CreateCertRef(cert, 0);
1835     return (PCCERT_CONTEXT)ret;
1836 }
1837
1838 /* Since the properties are stored in a list, this is a tad inefficient
1839  * (O(n^2)) since I have to find the previous position every time.
1840  */
1841 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1842  DWORD dwPropId)
1843 {
1844     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1845     DWORD ret;
1846
1847     TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1848
1849     EnterCriticalSection(&ref->context->cs);
1850     if (dwPropId)
1851     {
1852         PWINE_CERT_PROPERTY cursor = NULL;
1853
1854         LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1855          WINE_CERT_PROPERTY, entry)
1856         {
1857             if (cursor->hdr.propID == dwPropId)
1858                 break;
1859         }
1860         if (cursor)
1861         {
1862             if (cursor->entry.next != &ref->context->extendedProperties)
1863                 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1864                  entry)->hdr.propID;
1865             else
1866                 ret = 0;
1867         }
1868         else
1869             ret = 0;
1870     }
1871     else if (!list_empty(&ref->context->extendedProperties))
1872         ret = LIST_ENTRY(ref->context->extendedProperties.next,
1873          WINE_CERT_PROPERTY, entry)->hdr.propID;
1874     else
1875         ret = 0;
1876     LeaveCriticalSection(&ref->context->cs);
1877     return ret;
1878 }
1879
1880 static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId,
1881  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
1882  DWORD *pcbData)
1883 {
1884     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
1885      pcbData);
1886     if (ret)
1887     {
1888         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1889
1890         ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1891          0, &blob);
1892     }
1893     return ret;
1894 }
1895
1896 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1897  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1898 {
1899     PWINE_CERT_PROPERTY prop;
1900     BOOL ret, found;
1901
1902     TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1903
1904     EnterCriticalSection(&context->cs);
1905     ret = FALSE;
1906     found = FALSE;
1907     LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1908      WINE_CERT_PROPERTY, entry)
1909     {
1910         if (prop->hdr.propID == dwPropId)
1911         {
1912             if (!pvData)
1913             {
1914                 *pcbData = prop->hdr.cb;
1915                 ret = TRUE;
1916             }
1917             else if (*pcbData < prop->hdr.cb)
1918             {
1919                 SetLastError(ERROR_MORE_DATA);
1920                 *pcbData = prop->hdr.cb;
1921             }
1922             else
1923             {
1924                 memcpy(pvData, prop->pbData, prop->hdr.cb);
1925                 *pcbData = prop->hdr.cb;
1926                 ret = TRUE;
1927             }
1928             found = TRUE;
1929         }
1930         break;
1931     }
1932     if (!found)
1933     {
1934         /* Implicit properties */
1935         switch (dwPropId)
1936         {
1937         case CERT_SHA1_HASH_PROP_ID:
1938             ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
1939              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1940              pcbData);
1941             break;
1942         case CERT_MD5_HASH_PROP_ID:
1943             ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1944              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1945              pcbData);
1946             break;
1947         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1948             ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1949              context->cert.pCertInfo->Subject.pbData,
1950              context->cert.pCertInfo->Subject.cbData,
1951              pvData, pcbData);
1952             break;
1953         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1954             ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
1955              context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
1956              context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
1957              pvData, pcbData);
1958             break;
1959         case CERT_SIGNATURE_HASH_PROP_ID:
1960         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1961             FIXME("implicit property %ld\n", dwPropId);
1962             SetLastError(CRYPT_E_NOT_FOUND);
1963             break;
1964         default:
1965             SetLastError(CRYPT_E_NOT_FOUND);
1966         }
1967     }
1968     LeaveCriticalSection(&context->cs);
1969     TRACE("returning %d\n", ret);
1970     return ret;
1971 }
1972
1973 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1974  DWORD dwPropId, void *pvData, DWORD *pcbData)
1975 {
1976     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1977     BOOL ret;
1978
1979     TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1980
1981     /* Special cases for invalid/special prop IDs.
1982      */
1983     switch (dwPropId)
1984     {
1985     case 0:
1986     case CERT_CERT_PROP_ID:
1987     case CERT_CRL_PROP_ID:
1988     case CERT_CTL_PROP_ID:
1989         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1990         return FALSE;
1991     case CERT_ACCESS_STATE_PROP_ID:
1992         if (!pvData)
1993         {
1994             *pcbData = sizeof(DWORD);
1995             return TRUE;
1996         }
1997         else if (*pcbData < sizeof(DWORD))
1998         {
1999             SetLastError(ERROR_MORE_DATA);
2000             *pcbData = sizeof(DWORD);
2001             return FALSE;
2002         }
2003         else
2004         {
2005             DWORD state = 0;
2006
2007             if (pCertContext->hCertStore)
2008             {
2009                 PWINECRYPT_CERTSTORE store =
2010                  (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2011
2012                 /* Take advantage of knowledge of the stores to answer the
2013                  * access state question
2014                  */
2015                 if (store->type != StoreTypeReg ||
2016                  !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2017                     state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2018             }
2019             *(DWORD *)pvData = state;
2020             return TRUE;
2021         }
2022     }
2023
2024     ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2025      pvData, pcbData);
2026     TRACE("returning %d\n", ret);
2027     return ret;
2028 }
2029
2030 /* Copies cbData bytes from pbData to the context's property with ID
2031  * dwPropId.
2032  */
2033 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2034  DWORD dwPropId, const BYTE *pbData, size_t cbData)
2035 {
2036     BOOL ret = FALSE;
2037     LPBYTE data;
2038
2039     if (cbData)
2040     {
2041         data = CryptMemAlloc(cbData);
2042         if (data)
2043             memcpy(data, pbData, cbData);
2044     }
2045     else
2046         data = NULL;
2047     if (!cbData || data)
2048     {
2049         PWINE_CERT_PROPERTY prop;
2050
2051         EnterCriticalSection(&context->cs);
2052         LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2053          WINE_CERT_PROPERTY, entry)
2054         {
2055             if (prop->hdr.propID == dwPropId)
2056                 break;
2057         }
2058         if (prop && prop->entry.next != &context->extendedProperties)
2059         {
2060             CryptMemFree(prop->pbData);
2061             prop->hdr.cb = cbData;
2062             prop->pbData = cbData ? data : NULL;
2063             ret = TRUE;
2064         }
2065         else
2066         {
2067             prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2068             if (prop)
2069             {
2070                 prop->hdr.propID = dwPropId;
2071                 prop->hdr.unknown = 1;
2072                 prop->hdr.cb = cbData;
2073                 list_init(&prop->entry);
2074                 prop->pbData = cbData ? data : NULL;
2075                 list_add_tail(&context->extendedProperties, &prop->entry);
2076                 ret = TRUE;
2077             }
2078             else
2079                 CryptMemFree(data);
2080         }
2081         LeaveCriticalSection(&context->cs);
2082     }
2083     return ret;
2084 }
2085
2086 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2087  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2088 {
2089     BOOL ret = FALSE;
2090
2091     TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2092
2093     if (!pvData)
2094     {
2095         PWINE_CERT_PROPERTY prop, next;
2096
2097         EnterCriticalSection(&context->cs);
2098         LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2099          WINE_CERT_PROPERTY, entry)
2100         {
2101             if (prop->hdr.propID == dwPropId)
2102             {
2103                 list_remove(&prop->entry);
2104                 CryptMemFree(prop->pbData);
2105                 CryptMemFree(prop);
2106             }
2107         }
2108         LeaveCriticalSection(&context->cs);
2109         ret = TRUE;
2110     }
2111     else
2112     {
2113         switch (dwPropId)
2114         {
2115         case CERT_AUTO_ENROLL_PROP_ID:
2116         case CERT_CTL_USAGE_PROP_ID:
2117         case CERT_DESCRIPTION_PROP_ID:
2118         case CERT_FRIENDLY_NAME_PROP_ID:
2119         case CERT_HASH_PROP_ID:
2120         case CERT_KEY_IDENTIFIER_PROP_ID:
2121         case CERT_MD5_HASH_PROP_ID:
2122         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2123         case CERT_PUBKEY_ALG_PARA_PROP_ID:
2124         case CERT_PVK_FILE_PROP_ID:
2125         case CERT_SIGNATURE_HASH_PROP_ID:
2126         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2127         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
2128         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2129         case CERT_ENROLLMENT_PROP_ID:
2130         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2131         case CERT_RENEWAL_PROP_ID:
2132         {
2133             PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2134
2135             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2136              blob->pbData, blob->cbData);
2137             break;
2138         }
2139         case CERT_DATE_STAMP_PROP_ID:
2140             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2141              pvData, sizeof(FILETIME));
2142             break;
2143         default:
2144             FIXME("%ld: stub\n", dwPropId);
2145         }
2146     }
2147     TRACE("returning %d\n", ret);
2148     return ret;
2149 }
2150
2151 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2152  DWORD dwPropId, DWORD dwFlags, const void *pvData)
2153 {
2154     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2155     BOOL ret;
2156
2157     TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2158
2159     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
2160      * crashes on most of these, I'll be safer.
2161      */
2162     switch (dwPropId)
2163     {
2164     case 0:
2165     case CERT_ACCESS_STATE_PROP_ID:
2166     case CERT_CERT_PROP_ID:
2167     case CERT_CRL_PROP_ID:
2168     case CERT_CTL_PROP_ID:
2169         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2170         return FALSE;
2171     }
2172     ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2173      dwFlags, pvData);
2174     TRACE("returning %d\n", ret);
2175     return ret;
2176 }
2177
2178 /* Only the reference portion of the context is duplicated.  The returned
2179  * context has the cert store set to 0, to prevent the store's certificate free
2180  * function from getting called on partial data.
2181  * FIXME: is this okay?  Needs a test.
2182  */
2183 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2184  PCCERT_CONTEXT pCertContext)
2185 {
2186     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2187
2188     TRACE("(%p)\n", pCertContext);
2189     if (ref)
2190     {
2191         ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2192         if (ret)
2193         {
2194             memcpy(ret, ref, sizeof(*ret));
2195             ret->cert.hCertStore = 0;
2196             InterlockedIncrement(&ret->context->ref);
2197         }
2198     }
2199     else
2200         ret = NULL;
2201     return (PCCERT_CONTEXT)ret;
2202 }
2203
2204 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2205  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2206  PCCERT_CONTEXT *ppStoreContext)
2207 {
2208     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2209     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2210     PWINE_CERT_CONTEXT cert;
2211     BOOL ret;
2212
2213     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2214      dwAddDisposition, ppStoreContext);
2215
2216     /* FIXME: some tests needed to verify return codes */
2217     if (!store)
2218     {
2219         SetLastError(ERROR_INVALID_PARAMETER);
2220         return FALSE;
2221     }
2222     if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2223     {
2224         SetLastError(ERROR_INVALID_PARAMETER);
2225         return FALSE;
2226     }
2227
2228     cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2229      ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2230     if (cert)
2231     {
2232         PWINE_CERT_PROPERTY prop;
2233
2234         ret = TRUE;
2235         EnterCriticalSection(&ref->context->cs);
2236         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2237          WINE_CERT_PROPERTY, entry)
2238         {
2239             ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2240              prop->pbData, prop->hdr.cb);
2241             if (!ret)
2242                 break;
2243         }
2244         LeaveCriticalSection(&ref->context->cs);
2245         if (ret)
2246         {
2247             ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2248             if (ret && ppStoreContext)
2249                 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2250                  hCertStore);
2251         }
2252         if (!ret)
2253             CRYPT_FreeCert(cert);
2254     }
2255     else
2256         ret = FALSE;
2257     return ret;
2258 }
2259
2260 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2261  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2262  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2263 {
2264     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2265     BOOL ret;
2266
2267     TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2268      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2269
2270     if (!hcs)
2271         ret = FALSE;
2272     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2273         ret = FALSE;
2274     else
2275     {
2276         PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2277          dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2278
2279         if (cert)
2280         {
2281             ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2282             if (ret && ppCertContext)
2283                 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2284                  hCertStore);
2285             if (!ret)
2286                 CRYPT_FreeCert(cert);
2287         }
2288         else
2289             ret = FALSE;
2290     }
2291     return ret;
2292 }
2293
2294 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2295  PCCERT_CONTEXT pPrev)
2296 {
2297     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2298     PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2299     PCCERT_CONTEXT ret;
2300
2301     TRACE("(%p, %p)\n", hCertStore, pPrev);
2302     if (!hCertStore)
2303         ret = NULL;
2304     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2305         ret = NULL;
2306     else
2307         ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2308     return ret;
2309 }
2310
2311 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2312 {
2313     BOOL ret;
2314
2315     TRACE("(%p)\n", pCertContext);
2316
2317     if (!pCertContext)
2318         ret = TRUE;
2319     else if (!pCertContext->hCertStore)
2320     {
2321         ret = TRUE;
2322         CertFreeCertificateContext(pCertContext);
2323     }
2324     else
2325     {
2326         PWINECRYPT_CERTSTORE hcs =
2327          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2328
2329         if (!hcs)
2330             ret = TRUE;
2331         else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2332             ret = FALSE;
2333         else
2334         {
2335             ret = hcs->deleteCert(hcs, pCertContext, 0);
2336             if (ret)
2337                 CertFreeCertificateContext(pCertContext);
2338         }
2339     }
2340     return ret;
2341 }
2342
2343 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2344  DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2345  DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2346 {
2347     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2348      dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2349      ppCrlContext);
2350     return FALSE;
2351 }
2352
2353 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2354              PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2355              PCCRL_CONTEXT* ppStoreContext )
2356 {
2357     FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2358           dwAddDisposition, ppStoreContext);
2359     return TRUE;
2360 }
2361
2362 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2363 {
2364     FIXME("%p\n", pCrlContext );
2365
2366     return TRUE;
2367 }
2368
2369 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2370 {
2371     FIXME("(%p): stub\n", pCrlContext);
2372     return TRUE;
2373 }
2374
2375 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2376  PCCRL_CONTEXT pPrev)
2377 {
2378     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2379     return NULL;
2380 }
2381
2382 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2383   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2384 {
2385     FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2386      cbCtlEncoded);
2387     return NULL;
2388 }
2389
2390 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2391  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2392  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2393 {
2394     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2395      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2396      ppCtlContext);
2397     return FALSE;
2398 }
2399
2400 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2401  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2402  PCCTL_CONTEXT* ppStoreContext)
2403 {
2404     FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2405      dwAddDisposition, ppStoreContext);
2406     return TRUE;
2407 }
2408
2409 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2410 {
2411     FIXME("(%p): stub\n", pCtlContext );
2412     return TRUE;
2413 }
2414
2415 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2416 {
2417     FIXME("(%p): stub\n", pCtlContext);
2418     return TRUE;
2419 }
2420
2421 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2422  PCCTL_CONTEXT pPrev)
2423 {
2424     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2425     return NULL;
2426 }
2427
2428
2429 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2430 {
2431     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2432
2433     TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2434
2435     if( ! hCertStore )
2436         return TRUE;
2437
2438     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2439         return FALSE;
2440
2441     if (InterlockedDecrement(&hcs->ref) == 0)
2442     {
2443         TRACE("%p's ref count is 0, freeing\n", hcs);
2444         hcs->dwMagic = 0;
2445         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2446             CryptReleaseContext(hcs->cryptProv, 0);
2447         hcs->closeStore(hcs, dwFlags);
2448     }
2449     else
2450         TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2451     return TRUE;
2452 }
2453
2454 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2455  DWORD dwCtrlType, void const *pvCtrlPara)
2456 {
2457     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2458     BOOL ret;
2459
2460     TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2461      pvCtrlPara);
2462
2463     if (!hcs)
2464         ret = FALSE;
2465     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2466         ret = FALSE;
2467     else
2468     {
2469         if (hcs->control)
2470             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2471         else
2472             ret = TRUE;
2473     }
2474     return ret;
2475 }
2476
2477 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2478  DWORD dwPropId, void *pvData, DWORD *pcbData)
2479 {
2480     FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2481     return FALSE;
2482 }
2483
2484 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2485  DWORD dwPropId, DWORD dwFlags, const void *pvData)
2486 {
2487     FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2488      pvData);
2489     return FALSE;
2490 }
2491
2492 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2493  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2494 {
2495     FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2496      pcbElement);
2497     return FALSE;
2498 }
2499
2500 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2501  DWORD dwPropId, void *pvData, DWORD *pcbData)
2502 {
2503     FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2504     return FALSE;
2505 }
2506
2507 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2508  DWORD dwPropId, DWORD dwFlags, const void *pvData)
2509 {
2510     FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2511      pvData);
2512     return FALSE;
2513 }
2514
2515 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2516  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2517 {
2518     FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2519      pcbElement);
2520     return FALSE;
2521 }
2522
2523 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2524  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2525 {
2526     BOOL ret;
2527
2528     TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2529      pcbElement);
2530
2531     if (pCertContext)
2532     {
2533         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2534         DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2535          pCertContext->cbCertEncoded;
2536         PWINE_CERT_PROPERTY prop;
2537
2538         EnterCriticalSection(&ref->context->cs);
2539         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2540          WINE_CERT_PROPERTY, entry)
2541             bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2542         if (!pbElement)
2543         {
2544             *pcbElement = bytesNeeded;
2545             ret = TRUE;
2546         }
2547         else if (*pcbElement < bytesNeeded)
2548         {
2549             *pcbElement = bytesNeeded;
2550             SetLastError(ERROR_MORE_DATA);
2551             ret = FALSE;
2552         }
2553         else
2554         {
2555             PWINE_CERT_PROP_HEADER hdr;
2556
2557             LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2558              WINE_CERT_PROPERTY, entry)
2559             {
2560                 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2561                 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2562                 if (prop->hdr.cb)
2563                 {
2564                     memcpy(pbElement, prop->pbData, prop->hdr.cb);
2565                     pbElement += prop->hdr.cb;
2566                 }
2567             }
2568             hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2569             hdr->propID = CERT_CERT_PROP_ID;
2570             hdr->unknown = 1;
2571             hdr->cb = pCertContext->cbCertEncoded;
2572             memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2573              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2574             ret = TRUE;
2575         }
2576         LeaveCriticalSection(&ref->context->cs);
2577     }
2578     else
2579         ret = FALSE;
2580     return ret;
2581 }
2582
2583 /* Looks for the property with ID propID in the buffer buf.  Returns a pointer
2584  * to its header if a valid header is found, NULL if not.  Valid means the
2585  * length of thte property won't overrun buf, and the unknown field is 1.
2586  */
2587 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2588  DWORD size, DWORD propID)
2589 {
2590     const WINE_CERT_PROP_HEADER *ret = NULL;
2591     BOOL done = FALSE;
2592
2593     while (size && !ret && !done)
2594     {
2595         if (size < sizeof(WINE_CERT_PROP_HEADER))
2596         {
2597             SetLastError(CRYPT_E_FILE_ERROR);
2598             done = TRUE;
2599         }
2600         else
2601         {
2602             const WINE_CERT_PROP_HEADER *hdr =
2603              (const WINE_CERT_PROP_HEADER *)buf;
2604
2605             size -= sizeof(WINE_CERT_PROP_HEADER);
2606             buf += sizeof(WINE_CERT_PROP_HEADER);
2607             if (size < hdr->cb)
2608             {
2609                 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2610                 done = TRUE;
2611             }
2612             else if (!hdr->propID)
2613             {
2614                 /* assume a zero prop ID means the data are uninitialized, so
2615                  * stop looking.
2616                  */
2617                 done = TRUE;
2618             }
2619             else if (hdr->unknown != 1)
2620             {
2621                 SetLastError(ERROR_FILE_NOT_FOUND);
2622                 done = TRUE;
2623             }
2624             else if (hdr->propID == propID)
2625                 ret = hdr;
2626             else
2627             {
2628                 buf += hdr->cb;
2629                 size -= hdr->cb;
2630             }
2631         }
2632     }
2633     return ret;
2634 }
2635
2636 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2637  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2638 {
2639     const void *context;
2640
2641     TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2642      pdwContentType);
2643
2644     if (!cbElement)
2645     {
2646         SetLastError(ERROR_END_OF_MEDIA);
2647         return NULL;
2648     }
2649
2650     __TRY
2651     {
2652         const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2653         const WINE_CERT_PROP_HEADER *hdr = NULL;
2654         DWORD type = 0;
2655         BOOL ret;
2656
2657         ret = TRUE;
2658         context = NULL;
2659         if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2660         {
2661             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2662             if (hdr)
2663                 type = CERT_STORE_CERTIFICATE_CONTEXT;
2664             else
2665             {
2666                 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2667                 if (hdr)
2668                     type = CERT_STORE_CRL_CONTEXT;
2669                 else
2670                 {
2671                     hdr = CRYPT_findPropID(pbElement, cbElement,
2672                      CERT_CTL_PROP_ID);
2673                     if (hdr)
2674                         type = CERT_STORE_CTL_CONTEXT;
2675                 }
2676             }
2677         }
2678         else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2679         {
2680             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2681             type = CERT_STORE_CERTIFICATE_CONTEXT;
2682         }
2683         else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2684         {
2685             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2686             type = CERT_STORE_CRL_CONTEXT;
2687         }
2688         else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2689         {
2690             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2691             type = CERT_STORE_CTL_CONTEXT;
2692         }
2693
2694         switch (type)
2695         {
2696         case CERT_STORE_CERTIFICATE_CONTEXT:
2697             contextInterface = &gCertInterface;
2698             break;
2699         case CERT_STORE_CRL_CONTEXT:
2700             contextInterface = &gCRLInterface;
2701             break;
2702         case CERT_STORE_CTL_CONTEXT:
2703             contextInterface = &gCTLInterface;
2704             break;
2705         default:
2706             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2707             ret = FALSE;
2708         }
2709         if (!hdr)
2710             ret = FALSE;
2711
2712         if (ret)
2713             context = contextInterface->create(X509_ASN_ENCODING,
2714              (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2715         if (ret && context)
2716         {
2717             BOOL noMoreProps = FALSE;
2718
2719             while (!noMoreProps && ret)
2720             {
2721                 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2722                     ret = FALSE;
2723                 else
2724                 {
2725                     const WINE_CERT_PROP_HEADER *hdr =
2726                      (const WINE_CERT_PROP_HEADER *)pbElement;
2727
2728                     TRACE("prop is %ld\n", hdr->propID);
2729                     cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2730                     pbElement += sizeof(WINE_CERT_PROP_HEADER);
2731                     if (cbElement < hdr->cb)
2732                     {
2733                         SetLastError(HRESULT_FROM_WIN32(
2734                          ERROR_INVALID_PARAMETER));
2735                         ret = FALSE;
2736                     }
2737                     else if (!hdr->propID)
2738                     {
2739                         /* Like in CRYPT_findPropID, stop if the propID is zero
2740                          */
2741                         noMoreProps = TRUE;
2742                     }
2743                     else if (hdr->unknown != 1)
2744                     {
2745                         SetLastError(ERROR_FILE_NOT_FOUND);
2746                         ret = FALSE;
2747                     }
2748                     else if (hdr->propID != CERT_CERT_PROP_ID &&
2749                      hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2750                      CERT_CTL_PROP_ID)
2751                     {
2752                         /* Have to create a blob for most types, but not
2753                          * for all.. arghh.
2754                          */
2755                         switch (hdr->propID)
2756                         {
2757                         case CERT_AUTO_ENROLL_PROP_ID:
2758                         case CERT_CTL_USAGE_PROP_ID:
2759                         case CERT_DESCRIPTION_PROP_ID:
2760                         case CERT_FRIENDLY_NAME_PROP_ID:
2761                         case CERT_HASH_PROP_ID:
2762                         case CERT_KEY_IDENTIFIER_PROP_ID:
2763                         case CERT_MD5_HASH_PROP_ID:
2764                         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2765                         case CERT_PUBKEY_ALG_PARA_PROP_ID:
2766                         case CERT_PVK_FILE_PROP_ID:
2767                         case CERT_SIGNATURE_HASH_PROP_ID:
2768                         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2769                         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2770                         case CERT_ENROLLMENT_PROP_ID:
2771                         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2772                         case CERT_RENEWAL_PROP_ID:
2773                         {
2774                             CRYPT_DATA_BLOB blob = { hdr->cb,
2775                              (LPBYTE)pbElement };
2776
2777                             ret = contextInterface->setProp(context,
2778                              hdr->propID, 0, &blob);
2779                             break;
2780                         }
2781                         case CERT_DATE_STAMP_PROP_ID:
2782                             ret = contextInterface->setProp(context,
2783                              hdr->propID, 0, pbElement);
2784                             break;
2785                         default:
2786                             FIXME("prop ID %ld: stub\n", hdr->propID);
2787                         }
2788                     }
2789                     pbElement += hdr->cb;
2790                     cbElement -= hdr->cb;
2791                     if (!cbElement)
2792                         noMoreProps = TRUE;
2793                 }
2794             }
2795             if (ret)
2796             {
2797                 if (pdwContentType)
2798                     *pdwContentType = type;
2799             }
2800             else
2801             {
2802                 contextInterface->free(context);
2803                 context = NULL;
2804             }
2805         }
2806     }
2807     __EXCEPT_PAGE_FAULT
2808     {
2809         SetLastError(STATUS_ACCESS_VIOLATION);
2810         context = NULL;
2811     }
2812     __ENDTRY
2813     return context;
2814 }
2815
2816 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2817  const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2818  DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2819 {
2820     const void *context;
2821     DWORD type;
2822     BOOL ret;
2823
2824     TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2825      pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2826      pdwContentType, ppvContext);
2827
2828     /* Call the internal function, then delete the hashes.  Tests show this
2829      * function uses real hash values, not whatever's stored in the hash
2830      * property.
2831      */
2832     context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2833      dwContextTypeFlags, &type);
2834     if (context)
2835     {
2836         const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2837
2838         switch (type)
2839         {
2840         case CERT_STORE_CERTIFICATE_CONTEXT:
2841             contextInterface = &gCertInterface;
2842             break;
2843         case CERT_STORE_CRL_CONTEXT:
2844             contextInterface = &gCRLInterface;
2845             break;
2846         case CERT_STORE_CTL_CONTEXT:
2847             contextInterface = &gCTLInterface;
2848             break;
2849         default:
2850             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2851         }
2852         if (contextInterface)
2853         {
2854             contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2855             contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2856             contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2857              NULL);
2858             if (pdwContentType)
2859                 *pdwContentType = type;
2860             ret = contextInterface->addContextToStore(hCertStore, context,
2861              dwAddDisposition, ppvContext);
2862             contextInterface->free(context);
2863         }
2864         else
2865             ret = FALSE;
2866     }
2867     else
2868         ret = FALSE;
2869     return ret;
2870 }
2871
2872 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref)
2873 {
2874     if (InterlockedDecrement(&ref->context->ref) == 0)
2875     {
2876         TRACE("%p's ref count is 0, freeing\n", ref->context);
2877         CRYPT_FreeCert(ref->context);
2878     }
2879     else
2880         TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2881 }
2882
2883 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2884 {
2885     TRACE("(%p)\n", pCertContext);
2886
2887     if (pCertContext)
2888     {
2889         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2890         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2891
2892         CRYPT_UnrefCertificateContext(ref);
2893         if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2894          store->freeCert)
2895             store->freeCert(ref);
2896         TRACE("freeing %p\n", ref);
2897         CryptMemFree(ref);
2898     }
2899     return TRUE;
2900 }
2901
2902 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2903                 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2904                 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2905 {
2906     FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2907         dwFlags, dwType, pvPara, pPrevCertContext);
2908     SetLastError(CRYPT_E_NOT_FOUND);
2909     return NULL;
2910 }
2911
2912 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2913  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2914 {
2915     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2916     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2917     PWINE_STORE_LIST_ENTRY entry;
2918     BOOL ret;
2919
2920     TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2921      dwUpdateFlags, dwPriority);
2922
2923     if (!collection || !sibling)
2924         return TRUE;
2925     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2926     {
2927         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2928         return FALSE;
2929     }
2930     if (collection->hdr.type != StoreTypeCollection)
2931     {
2932         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2933         return FALSE;
2934     }
2935     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2936     {
2937         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2938         return FALSE;
2939     }
2940
2941     entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2942     if (entry)
2943     {
2944         InterlockedIncrement(&sibling->ref);
2945         TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2946         entry->store = sibling;
2947         entry->dwUpdateFlags = dwUpdateFlags;
2948         entry->dwPriority = dwPriority;
2949         list_init(&entry->entry);
2950         TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2951         EnterCriticalSection(&collection->cs);
2952         if (dwPriority)
2953         {
2954             PWINE_STORE_LIST_ENTRY cursor;
2955             BOOL added = FALSE;
2956
2957             LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2958              WINE_STORE_LIST_ENTRY, entry)
2959             {
2960                 if (cursor->dwPriority < dwPriority)
2961                 {
2962                     list_add_before(&cursor->entry, &entry->entry);
2963                     added = TRUE;
2964                     break;
2965                 }
2966             }
2967             if (!added)
2968                 list_add_tail(&collection->stores, &entry->entry);
2969         }
2970         else
2971             list_add_tail(&collection->stores, &entry->entry);
2972         LeaveCriticalSection(&collection->cs);
2973         ret = TRUE;
2974     }
2975     else
2976         ret = FALSE;
2977     return ret;
2978 }
2979
2980 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2981  HCERTSTORE hSiblingStore)
2982 {
2983     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2984     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2985     PWINE_STORE_LIST_ENTRY store, next;
2986
2987     TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2988
2989     if (!collection || !sibling)
2990         return;
2991     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2992     {
2993         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2994         return;
2995     }
2996     if (collection->hdr.type != StoreTypeCollection)
2997         return;
2998     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2999     {
3000         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3001         return;
3002     }
3003     EnterCriticalSection(&collection->cs);
3004     LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3005      WINE_STORE_LIST_ENTRY, entry)
3006     {
3007         if (store->store == sibling)
3008         {
3009             list_remove(&store->entry);
3010             CertCloseStore(store->store, 0);
3011             CryptMemFree(store);
3012             break;
3013         }
3014     }
3015     LeaveCriticalSection(&collection->cs);
3016 }
3017
3018 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3019  CRYPT_ATTRIBUTE rgAttr[])
3020 {
3021     PCRYPT_ATTRIBUTE ret = NULL;
3022     DWORD i;
3023
3024     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3025
3026     if (!cAttr)
3027         return NULL;
3028     if (!pszObjId)
3029     {
3030         SetLastError(ERROR_INVALID_PARAMETER);
3031         return NULL;
3032     }
3033
3034     for (i = 0; !ret && i < cAttr; i++)
3035         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3036             ret = &rgAttr[i];
3037     return ret;
3038 }
3039
3040 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3041  CERT_EXTENSION rgExtensions[])
3042 {
3043     PCERT_EXTENSION ret = NULL;
3044     DWORD i;
3045
3046     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3047
3048     if (!cExtensions)
3049         return NULL;
3050     if (!pszObjId)
3051     {
3052         SetLastError(ERROR_INVALID_PARAMETER);
3053         return NULL;
3054     }
3055
3056     for (i = 0; !ret && i < cExtensions; i++)
3057         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3058          rgExtensions[i].pszObjId))
3059             ret = &rgExtensions[i];
3060     return ret;
3061 }
3062
3063 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3064 {
3065     PCERT_RDN_ATTR ret = NULL;
3066     DWORD i, j;
3067
3068     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3069
3070     if (!pszObjId)
3071     {
3072         SetLastError(ERROR_INVALID_PARAMETER);
3073         return NULL;
3074     }
3075
3076     for (i = 0; !ret && i < pName->cRDN; i++)
3077         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3078             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3079              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3080                 ret = &pName->rgRDN[i].rgRDNAttr[j];
3081     return ret;
3082 }
3083
3084 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3085  PCERT_INFO pCertInfo)
3086 {
3087     FILETIME fileTime;
3088     LONG ret;
3089
3090     if (!pTimeToVerify)
3091     {
3092         SYSTEMTIME sysTime;
3093
3094         GetSystemTime(&sysTime);
3095         SystemTimeToFileTime(&sysTime, &fileTime);
3096         pTimeToVerify = &fileTime;
3097     }
3098     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3099     {
3100         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3101         if (ret < 0)
3102             ret = 0;
3103     }
3104     return ret;
3105 }
3106
3107 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3108  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3109  DWORD *pcbComputedHash)
3110 {
3111     BOOL ret = TRUE;
3112     HCRYPTHASH hHash = 0;
3113
3114     TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3115      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3116
3117     if (!hCryptProv)
3118         hCryptProv = CRYPT_GetDefaultProvider();
3119     if (!Algid)
3120         Algid = CALG_SHA1;
3121     if (ret)
3122     {
3123         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3124         if (ret)
3125         {
3126             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3127             if (ret)
3128                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3129                  pcbComputedHash, 0);
3130             CryptDestroyHash(hHash);
3131         }
3132     }
3133     return ret;
3134 }
3135
3136 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3137  DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
3138  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
3139  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
3140 {
3141     BOOL ret;
3142     ALG_ID algID;
3143     HCRYPTHASH hHash;
3144
3145     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
3146      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
3147      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
3148
3149     algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
3150     if (!algID)
3151     {
3152         SetLastError(NTE_BAD_ALGID);
3153         return FALSE;
3154     }
3155     if (!hCryptProv)
3156     {
3157         SetLastError(ERROR_INVALID_PARAMETER);
3158         return FALSE;
3159     }
3160
3161     ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
3162     if (ret)
3163     {
3164         ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
3165         if (ret)
3166             ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
3167              pcbSignature);
3168         CryptDestroyHash(hHash);
3169     }
3170     return ret;
3171 }
3172
3173 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
3174  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
3175  PCERT_PUBLIC_KEY_INFO pPublicKey)
3176 {
3177     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
3178      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
3179      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
3180 }
3181
3182 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
3183  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
3184  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
3185 {
3186     BOOL ret = TRUE;
3187     CRYPT_DATA_BLOB subjectBlob;
3188
3189     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
3190      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
3191      dwFlags, pvReserved);
3192
3193     switch (dwSubjectType)
3194     {
3195     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
3196     {
3197         PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
3198
3199         subjectBlob.pbData = blob->pbData;
3200         subjectBlob.cbData = blob->cbData;
3201         break;
3202     }
3203     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
3204     {
3205         PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
3206
3207         subjectBlob.pbData = context->pbCertEncoded;
3208         subjectBlob.cbData = context->cbCertEncoded;
3209         break;
3210     }
3211     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
3212     {
3213         PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
3214
3215         subjectBlob.pbData = context->pbCrlEncoded;
3216         subjectBlob.cbData = context->cbCrlEncoded;
3217         break;
3218     }
3219     default:
3220         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3221         ret = FALSE;
3222     }
3223
3224     if (ret)
3225     {
3226         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
3227         DWORD size = 0;
3228
3229         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
3230          subjectBlob.pbData, subjectBlob.cbData,
3231          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3232          (BYTE *)&signedCert, &size);
3233         if (ret)
3234         {
3235             switch (dwIssuerType)
3236             {
3237             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
3238             {
3239                 PCERT_PUBLIC_KEY_INFO pubKeyInfo =
3240                  (PCERT_PUBLIC_KEY_INFO)pvIssuer;
3241                 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
3242
3243                 if (algID)
3244                 {
3245                     HCRYPTKEY key;
3246
3247                     ret = CryptImportPublicKeyInfoEx(hCryptProv,
3248                      dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
3249                     if (ret)
3250                     {
3251                         HCRYPTHASH hash;
3252
3253                         ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
3254                         if (ret)
3255                         {
3256                             ret = CryptHashData(hash,
3257                              signedCert->ToBeSigned.pbData,
3258                              signedCert->ToBeSigned.cbData, 0);
3259                             if (ret)
3260                             {
3261                                 ret = CryptVerifySignatureW(hash,
3262                                  signedCert->Signature.pbData,
3263                                  signedCert->Signature.cbData, key, NULL, 0);
3264                             }
3265                             CryptDestroyHash(hash);
3266                         }
3267                         CryptDestroyKey(key);
3268                     }
3269                 }
3270                 else
3271                 {
3272                     SetLastError(NTE_BAD_ALGID);
3273                     ret = FALSE;
3274                 }
3275                 break;
3276             }
3277             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
3278             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
3279                 FIXME("issuer type %ld: stub\n", dwIssuerType);
3280                 ret = FALSE;
3281                 break;
3282             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
3283                 if (pvIssuer)
3284                 {
3285                     SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3286                     ret = FALSE;
3287                 }
3288                 else
3289                 {
3290                     FIXME("unimplemented for NULL signer\n");
3291                     SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3292                     ret = FALSE;
3293                 }
3294                 break;
3295             default:
3296                 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3297                 ret = FALSE;
3298             }
3299             LocalFree(signedCert);
3300         }
3301     }
3302     return ret;
3303 }
3304
3305 BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara,
3306           DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
3307           BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
3308 {
3309     FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n",
3310         pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
3311         pbDecoded, pcbDecoded, ppSignerCert);
3312     return FALSE;
3313 }