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