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