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