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