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