Implement CertAddSerializedElementToStore.
[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 <stdarg.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winreg.h"
34 #include "wincrypt.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "excpt.h"
38 #include "wine/exception.h"
39 #include "crypt32_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
42
43 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
44 /* The following aren't defined in wincrypt.h, as they're "reserved" */
45 #define CERT_CERT_PROP_ID 32
46 #define CERT_CRL_PROP_ID  33
47 #define CERT_CTL_PROP_ID  34
48
49 /* Some typedefs that make it easier to abstract which type of context we're
50  * working with.
51  */
52 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
53  const BYTE *pbCertEncoded, DWORD cbCertEncoded);
54 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
55  const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
56 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
57  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
58  DWORD dwAddDisposition, const void **ppContext);
59 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
60  const void *pPrevContext);
61 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
62  DWORD dwPropID, void *pvData, DWORD *pcbData);
63 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
64  DWORD dwPropID, DWORD dwFlags, const void *pvData);
65 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
66  BYTE *pbElement, DWORD *pcbElement);
67 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
68 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
69
70 /* An abstract context (certificate, CRL, or CTL) interface */
71 typedef struct _WINE_CONTEXT_INTERFACE
72 {
73     CreateContextFunc            create;
74     AddContextToStoreFunc        addContextToStore;
75     AddEncodedContextToStoreFunc addEncodedToStore;
76     EnumContextsInStoreFunc      enumContextsInStore;
77     GetContextPropertyFunc       getProp;
78     SetContextPropertyFunc       setProp;
79     SerializeElementFunc         serialize;
80     FreeContextFunc              free;
81     DeleteContextFunc            deleteFromStore;
82 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
83
84 static const WINE_CONTEXT_INTERFACE gCertInterface = {
85     (CreateContextFunc)CertCreateCertificateContext,
86     (AddContextToStoreFunc)CertAddCertificateContextToStore,
87     (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
88     (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
89     (GetContextPropertyFunc)CertGetCertificateContextProperty,
90     (SetContextPropertyFunc)CertSetCertificateContextProperty,
91     (SerializeElementFunc)CertSerializeCertificateStoreElement,
92     (FreeContextFunc)CertFreeCertificateContext,
93     (DeleteContextFunc)CertDeleteCertificateFromStore,
94 };
95
96 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
97     (CreateContextFunc)CertCreateCRLContext,
98     (AddContextToStoreFunc)CertAddCRLContextToStore,
99     (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
100     (EnumContextsInStoreFunc)CertEnumCRLsInStore,
101     (GetContextPropertyFunc)CertGetCRLContextProperty,
102     (SetContextPropertyFunc)CertSetCRLContextProperty,
103     (SerializeElementFunc)CertSerializeCRLStoreElement,
104     (FreeContextFunc)CertFreeCRLContext,
105     (DeleteContextFunc)CertDeleteCRLFromStore,
106 };
107
108 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
109     (CreateContextFunc)CertCreateCTLContext,
110     (AddContextToStoreFunc)CertAddCTLContextToStore,
111     (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
112     (EnumContextsInStoreFunc)CertEnumCTLsInStore,
113     (GetContextPropertyFunc)CertGetCTLContextProperty,
114     (SetContextPropertyFunc)CertSetCTLContextProperty,
115     (SerializeElementFunc)CertSerializeCTLStoreElement,
116     (FreeContextFunc)CertFreeCTLContext,
117     (DeleteContextFunc)CertDeleteCTLFromStore,
118 };
119
120 struct WINE_CRYPTCERTSTORE;
121
122 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
123  DWORD dwFlags, const void *pvPara);
124
125 struct _WINE_CERT_CONTEXT_REF;
126
127 /* Called to enumerate the next certificate in a store.  The returned pointer
128  * must be newly allocated (via HeapAlloc):  CertFreeCertificateContext frees
129  * it.
130  */
131 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
132  (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
133
134 struct _WINE_CERT_CONTEXT;
135
136 /* Called to create a new reference to an existing cert context.  Should call
137  * CRYPT_InitCertRef to make sure the reference count is properly updated.
138  * If the store does not provide any additional allocated data (that is, does
139  * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
140  * this.
141  */
142 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
143  (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
144
145 /* Optional, called when a cert context reference is being freed.  Don't free
146  * the ref pointer itself, CertFreeCertificateContext does that.
147  */
148 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
149
150 typedef enum _CertStoreType {
151     StoreTypeMem,
152     StoreTypeCollection,
153     StoreTypeReg,
154     StoreTypeDummy,
155 } CertStoreType;
156
157 /* A cert store is polymorphic through the use of function pointers.  A type
158  * is still needed to distinguish collection stores from other types.
159  * On the function pointers:
160  * - closeStore is called when the store's ref count becomes 0
161  * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
162  * - control is optional, but should be implemented by any store that supports
163  *   persistence
164  */
165 typedef struct WINE_CRYPTCERTSTORE
166 {
167     DWORD                           dwMagic;
168     LONG                            ref;
169     DWORD                           dwOpenFlags;
170     HCRYPTPROV                      cryptProv;
171     CertStoreType                   type;
172     PFN_CERT_STORE_PROV_CLOSE       closeStore;
173     PFN_CERT_STORE_PROV_WRITE_CERT  addCert;
174     CreateRefFunc                   createCertRef;
175     EnumCertFunc                    enumCert;
176     PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
177     FreeCertFunc                    freeCert;   /* optional */
178     PFN_CERT_STORE_PROV_CONTROL     control;    /* optional */
179 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
180
181 /* A certificate context has pointers to data that are owned by this module,
182  * so rather than duplicate the data every time a certificate context is
183  * copied, I keep a reference count to the data.  Thus I have two data
184  * structures, the "true" certificate context (that has the reference count)
185  * and a reference certificate context, that has a pointer to the true context.
186  * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
187  * with the reference version.
188  */
189 typedef struct _WINE_CERT_CONTEXT
190 {
191     CERT_CONTEXT     cert;
192     LONG             ref;
193     CRITICAL_SECTION cs;
194     struct list      extendedProperties;
195 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
196
197 typedef struct _WINE_CERT_CONTEXT_REF
198 {
199     CERT_CONTEXT cert;
200     WINE_CERT_CONTEXT *context;
201 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
202
203 /* An extended certificate property in serialized form is prefixed by this
204  * header.
205  */
206 typedef struct _WINE_CERT_PROP_HEADER
207 {
208     DWORD propID;
209     DWORD unknown; /* always 1 */
210     DWORD cb;
211 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
212
213 /* Stores an extended property in a cert. */
214 typedef struct _WINE_CERT_PROPERTY
215 {
216     WINE_CERT_PROP_HEADER hdr;
217     LPBYTE                pbData;
218     struct list           entry;
219 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
220
221 /* A mem store has a list of these.  They're also returned by the mem store
222  * during enumeration.
223  */
224 typedef struct _WINE_CERT_LIST_ENTRY
225 {
226     WINE_CERT_CONTEXT_REF cert;
227     struct list entry;
228 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
229
230 typedef struct _WINE_MEMSTORE
231 {
232     WINECRYPT_CERTSTORE hdr;
233     CRITICAL_SECTION    cs;
234     struct list         certs;
235 } WINE_MEMSTORE, *PWINE_MEMSTORE;
236
237 typedef struct _WINE_STORE_LIST_ENTRY
238 {
239     PWINECRYPT_CERTSTORE store;
240     DWORD                dwUpdateFlags;
241     DWORD                dwPriority;
242     struct list          entry;
243 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
244
245 /* Returned by a collection store during enumeration.
246  * Note: relies on the list entry being valid after use, which a number of
247  * conditions might make untrue (reentrancy, closing a collection store before
248  * continuing an enumeration on it, ...).  The tests seem to indicate this
249  * sort of unsafety is okay, since Windows isn't well-behaved in these
250  * scenarios either.
251  */
252 typedef struct _WINE_COLLECTION_CERT_CONTEXT
253 {
254     WINE_CERT_CONTEXT_REF  cert;
255     PWINE_STORE_LIST_ENTRY entry;
256     PWINE_CERT_CONTEXT_REF childContext;
257 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
258
259 typedef struct _WINE_COLLECTIONSTORE
260 {
261     WINECRYPT_CERTSTORE hdr;
262     CRITICAL_SECTION    cs;
263     struct list         stores;
264 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
265
266 /* Like CertGetCertificateContextProperty, but operates directly on the
267  * WINE_CERT_CONTEXT.  Doesn't support special-case properties, since they
268  * are handled by CertGetCertificateContextProperty, and are particular to the
269  * store in which the property exists (which is separate from the context.)
270  */
271 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
272  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
273
274 /* Like CertSetCertificateContextProperty, but operates directly on the
275  * WINE_CERT_CONTEXT.  Doesn't handle special cases, since they're handled by
276  * CertSetCertificateContextProperty anyway.
277  */
278 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
279  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
280
281 /* Helper function for store reading functions and
282  * CertAddSerializedElementToStore.  Returns a context of the appropriate type
283  * if it can, or NULL otherwise.  Doesn't validate any of the properties in
284  * the serialized context (for example, bad hashes are retained.)
285  * *pdwContentType is set to the type of the returned context.
286  */
287 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
288  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
289
290 /* filter for page-fault exceptions */
291 static WINE_EXCEPTION_FILTER(page_fault)
292 {
293     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
294         return EXCEPTION_EXECUTE_HANDLER;
295     return EXCEPTION_CONTINUE_SEARCH;
296 }
297
298 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
299  DWORD dwFlags, CertStoreType type)
300 {
301     store->ref = 1;
302     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
303     store->type = type;
304     if (!hCryptProv)
305     {
306         hCryptProv = CRYPT_GetDefaultProvider();
307         dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
308     }
309     store->cryptProv = hCryptProv;
310     store->dwOpenFlags = dwFlags;
311 }
312
313 /* Initializes the reference ref to point to pCertContext, which is assumed to
314  * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
315  * Also sets the hCertStore member of the reference to store.
316  */
317 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
318  PWINE_CERT_CONTEXT context, HCERTSTORE store)
319 {
320     TRACE("(%p, %p)\n", ref, context);
321     memcpy(&ref->cert, context, sizeof(ref->cert));
322     ref->context = context;
323     InterlockedIncrement(&context->ref);
324     ref->cert.hCertStore = store;
325 }
326
327 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
328  HCERTSTORE store)
329 {
330     PWINE_CERT_CONTEXT_REF pCertRef = HeapAlloc(GetProcessHeap(), 0,
331      sizeof(WINE_CERT_CONTEXT_REF));
332
333     if (pCertRef)
334         CRYPT_InitCertRef(pCertRef, context, store);
335     return pCertRef;
336 }
337
338 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
339  DWORD dwAddDisposition)
340 {
341     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
342     BOOL add = FALSE, ret;
343
344     TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
345
346     switch (dwAddDisposition)
347     {
348     case CERT_STORE_ADD_ALWAYS:
349         add = TRUE;
350         break;
351     case CERT_STORE_ADD_NEW:
352     {
353         BYTE hashToAdd[20], hash[20];
354         DWORD size = sizeof(hashToAdd);
355
356         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
357          CERT_HASH_PROP_ID, hashToAdd, &size);
358         if (ret)
359         {
360             PWINE_CERT_LIST_ENTRY cursor;
361
362             /* Add if no cert with the same hash is found. */
363             add = TRUE;
364             EnterCriticalSection(&ms->cs);
365             LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
366             {
367                 size = sizeof(hash);
368                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
369                  CERT_HASH_PROP_ID, hash, &size);
370                 if (ret && !memcmp(hashToAdd, hash, size))
371                 {
372                     TRACE("found matching certificate, not adding\n");
373                     SetLastError(CRYPT_E_EXISTS);
374                     add = FALSE;
375                     break;
376                 }
377             }
378             LeaveCriticalSection(&ms->cs);
379         }
380         break;
381     }
382     case CERT_STORE_ADD_REPLACE_EXISTING:
383     {
384         BYTE hashToAdd[20], hash[20];
385         DWORD size = sizeof(hashToAdd);
386
387         add = TRUE;
388         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
389          CERT_HASH_PROP_ID, hashToAdd, &size);
390         if (ret)
391         {
392             PWINE_CERT_LIST_ENTRY cursor, next;
393
394             /* Look for existing cert to delete */
395             EnterCriticalSection(&ms->cs);
396             LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
397              WINE_CERT_LIST_ENTRY, entry)
398             {
399                 size = sizeof(hash);
400                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
401                  CERT_HASH_PROP_ID, hash, &size);
402                 if (ret && !memcmp(hashToAdd, hash, size))
403                 {
404                     TRACE("found matching certificate, replacing\n");
405                     list_remove(&cursor->entry);
406                     CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
407                     break;
408                 }
409             }
410             LeaveCriticalSection(&ms->cs);
411         }
412         break;
413     }
414     default:
415         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
416         add = FALSE;
417     }
418     if (add)
419     {
420         PWINE_CERT_LIST_ENTRY entry = HeapAlloc(GetProcessHeap(), 0,
421          sizeof(WINE_CERT_LIST_ENTRY));
422
423         if (entry)
424         {
425             TRACE("adding %p\n", entry);
426             CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
427             list_init(&entry->entry);
428             EnterCriticalSection(&ms->cs);
429             list_add_tail(&ms->certs, &entry->entry);
430             LeaveCriticalSection(&ms->cs);
431             ret = TRUE;
432         }
433         else
434             ret = FALSE;
435     }
436     else
437         ret = FALSE;
438     return ret;
439 }
440
441 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
442  PWINE_CERT_CONTEXT_REF pPrev)
443 {
444     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
445     PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
446     struct list *listNext;
447
448     TRACE("(%p, %p)\n", store, pPrev);
449     EnterCriticalSection(&ms->cs);
450     if (prevEntry)
451     {
452         listNext = list_next(&ms->certs, &prevEntry->entry);
453         CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
454     }
455     else
456         listNext = list_next(&ms->certs, &ms->certs);
457     if (listNext)
458     {
459         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY));
460         memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
461          sizeof(WINE_CERT_LIST_ENTRY));
462         InterlockedIncrement(&ret->cert.context->ref);
463     }
464     else
465     {
466         SetLastError(CRYPT_E_NOT_FOUND);
467         ret = NULL;
468     }
469     LeaveCriticalSection(&ms->cs);
470
471     TRACE("returning %p\n", ret);
472     return (PWINE_CERT_CONTEXT_REF)ret;
473 }
474
475 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
476  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
477 {
478     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
479     WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
480     PWINE_CERT_LIST_ENTRY cert, next;
481     BOOL ret;
482
483     /* Find the entry associated with the passed-in context, since the
484      * passed-in context may not be a list entry itself (e.g. if it came from
485      * CertDuplicateCertificateContext.)  Pointing to the same context is
486      * a sufficient test of equality.
487      */
488     EnterCriticalSection(&store->cs);
489     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
490      entry)
491     {
492         if (cert->cert.context == ref->context)
493         {
494             TRACE("removing %p\n", cert);
495             /* FIXME: this isn't entirely thread-safe, the entry itself isn't
496              * protected.
497              */
498             list_remove(&cert->entry);
499             cert->entry.prev = cert->entry.next = &store->certs;
500             CertFreeCertificateContext((PCCERT_CONTEXT)cert);
501             break;
502         }
503     }
504     ret = TRUE;
505     LeaveCriticalSection(&store->cs);
506     return ret;
507 }
508
509 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
510 {
511     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
512     PWINE_CERT_LIST_ENTRY cert, next;
513
514     TRACE("(%p, %08lx)\n", store, dwFlags);
515     if (dwFlags)
516         FIXME("Unimplemented flags: %08lx\n", dwFlags);
517
518     /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
519      * pointer if its ref-count reaches zero.  That's okay here because there
520      * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
521      * of the CertListEntry.
522      */
523     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
524      entry)
525     {
526         TRACE("removing %p\n", cert);
527         list_remove(&cert->entry);
528         CertFreeCertificateContext((PCCERT_CONTEXT)cert);
529     }
530     DeleteCriticalSection(&store->cs);
531     HeapFree(GetProcessHeap(), 0, store);
532 }
533
534 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
535  DWORD dwFlags, const void *pvPara)
536 {
537     PWINE_MEMSTORE store;
538
539     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
540
541     if (dwFlags & CERT_STORE_DELETE_FLAG)
542     {
543         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
544         store = NULL;
545     }
546     else
547     {
548         store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
549          sizeof(WINE_MEMSTORE));
550         if (store)
551         {
552             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
553             store->hdr.closeStore    = CRYPT_MemCloseStore;
554             store->hdr.addCert       = CRYPT_MemAddCert;
555             store->hdr.createCertRef = CRYPT_CreateCertRef;
556             store->hdr.enumCert      = CRYPT_MemEnumCert;
557             store->hdr.deleteCert    = CRYPT_MemDeleteCert;
558             store->hdr.freeCert      = NULL;
559             InitializeCriticalSection(&store->cs);
560             list_init(&store->certs);
561         }
562     }
563     return (PWINECRYPT_CERTSTORE)store;
564 }
565
566 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
567  PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
568 {
569     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
570     PWINE_STORE_LIST_ENTRY entry, next;
571     BOOL ret;
572
573     TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
574
575     ret = FALSE;
576     EnterCriticalSection(&cs->cs);
577     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
578      entry)
579     {
580         if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
581         {
582             ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
583             break;
584         }
585     }
586     LeaveCriticalSection(&cs->cs);
587     SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
588     return ret;
589 }
590
591 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
592  PWINE_CERT_CONTEXT context, HCERTSTORE store)
593 {
594     PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
595      sizeof(WINE_COLLECTION_CERT_CONTEXT));
596
597     if (ret)
598     {
599         /* Initialize to empty for now, just make sure the size is right */
600         CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
601         ret->entry = NULL;
602         ret->childContext = NULL;
603     }
604     return (PWINE_CERT_CONTEXT_REF)ret;
605 }
606
607 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
608 {
609     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
610     PWINE_STORE_LIST_ENTRY entry, next;
611
612     TRACE("(%p, %08lx)\n", store, dwFlags);
613
614     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
615      entry)
616     {
617         TRACE("closing %p\n", entry);
618         CertCloseStore((HCERTSTORE)entry->store, dwFlags);
619         HeapFree(GetProcessHeap(), 0, entry);
620     }
621     DeleteCriticalSection(&cs->cs);
622     HeapFree(GetProcessHeap(), 0, cs);
623 }
624
625 /* Advances a collection enumeration by one cert, if possible, where advancing
626  * means:
627  * - calling the current store's enumeration function once, and returning
628  *   the enumerated cert if one is returned
629  * - moving to the next store if the current store has no more items, and
630  *   recursively calling itself to get the next item.
631  * Returns NULL if the collection contains no more items or on error.
632  * Assumes the collection store's lock is held.
633  */
634 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
635  PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
636  PWINE_COLLECTION_CERT_CONTEXT pPrev)
637 {
638     PWINE_COLLECTION_CERT_CONTEXT ret;
639     PWINE_CERT_CONTEXT_REF child;
640
641     TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
642
643     if (pPrev)
644     {
645         child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
646          pPrev->childContext);
647         if (child)
648         {
649             ret = pPrev;
650             memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
651             ret->cert.cert.hCertStore = (HCERTSTORE)store;
652             InterlockedIncrement(&ret->cert.context->ref);
653             ret->childContext = child;
654         }
655         else
656         {
657             struct list *storeNext = list_next(&store->stores,
658              &storeEntry->entry);
659
660             pPrev->childContext = NULL;
661             CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
662             if (storeNext)
663             {
664                 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
665                  entry);
666                 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
667             }
668             else
669             {
670                 SetLastError(CRYPT_E_NOT_FOUND);
671                 ret = NULL;
672             }
673         }
674     }
675     else
676     {
677         child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
678          NULL);
679         if (child)
680         {
681             ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
682              child->context, store);
683             if (ret)
684             {
685                 ret->entry = storeEntry;
686                 ret->childContext = child;
687             }
688             else
689                 CertFreeCertificateContext((PCCERT_CONTEXT)child);
690         }
691         else
692         {
693             struct list *storeNext = list_next(&store->stores,
694              &storeEntry->entry);
695
696             if (storeNext)
697             {
698                 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
699                  entry);
700                 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
701             }
702             else
703             {
704                 SetLastError(CRYPT_E_NOT_FOUND);
705                 ret = NULL;
706             }
707         }
708     }
709     TRACE("returning %p\n", ret);
710     return ret;
711 }
712
713 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
714  PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
715 {
716     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
717     PWINE_COLLECTION_CERT_CONTEXT prevEntry =
718      (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
719
720     TRACE("(%p, %p)\n", store, pPrev);
721
722     if (prevEntry)
723     {
724         EnterCriticalSection(&cs->cs);
725         ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
726         LeaveCriticalSection(&cs->cs);
727     }
728     else
729     {
730         EnterCriticalSection(&cs->cs);
731         if (!list_empty(&cs->stores))
732         {
733             PWINE_STORE_LIST_ENTRY storeEntry;
734
735             storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
736              entry);
737             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
738         }
739         else
740         {
741             SetLastError(CRYPT_E_NOT_FOUND);
742             ret = NULL;
743         }
744         LeaveCriticalSection(&cs->cs);
745     }
746     TRACE("returning %p\n", ret);
747     return (PWINE_CERT_CONTEXT_REF)ret;
748 }
749
750 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
751  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
752 {
753     PWINE_COLLECTION_CERT_CONTEXT context =
754      (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
755     BOOL ret;
756
757     TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
758
759     ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
760     if (ret)
761     {
762         context->childContext = NULL;
763         CertFreeCertificateContext((PCCERT_CONTEXT)context);
764     }
765     return ret;
766 }
767
768 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
769 {
770     PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
771
772     TRACE("(%p)\n", ref);
773
774     if (context->childContext)
775         CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
776 }
777
778 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
779  DWORD dwFlags, const void *pvPara)
780 {
781     PWINE_COLLECTIONSTORE store;
782
783     if (dwFlags & CERT_STORE_DELETE_FLAG)
784     {
785         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
786         store = NULL;
787     }
788     else
789     {
790         store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
791          sizeof(WINE_COLLECTIONSTORE));
792         if (store)
793         {
794             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
795              StoreTypeCollection);
796             store->hdr.closeStore    = CRYPT_CollectionCloseStore;
797             store->hdr.addCert       = CRYPT_CollectionAddCert;
798             store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
799             store->hdr.enumCert      = CRYPT_CollectionEnumCert;
800             store->hdr.deleteCert    = CRYPT_CollectionDeleteCert;
801             store->hdr.freeCert      = CRYPT_CollectionFreeCert;
802             InitializeCriticalSection(&store->cs);
803             list_init(&store->stores);
804         }
805     }
806     return (PWINECRYPT_CERTSTORE)store;
807 }
808
809 static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
810 {
811     HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore);
812 }
813
814 static BOOL WINAPI CRYPT_DummyAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
815  DWORD dwAddDisposition)
816 {
817     return FALSE;
818 }
819
820 static PWINE_CERT_CONTEXT_REF CRYPT_DummyEnumCert(PWINECRYPT_CERTSTORE store,
821  PWINE_CERT_CONTEXT_REF pPrev)
822 {
823     return NULL;
824 }
825
826 static BOOL WINAPI CRYPT_DummyDeleteCert(HCERTSTORE hCertStore,
827  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
828 {
829     return TRUE;
830 }
831
832 static WINECRYPT_CERTSTORE *CRYPT_DummyOpenStore(HCRYPTPROV hCryptProv,
833  DWORD dwFlags, const void *pvPara)
834 {
835     PWINECRYPT_CERTSTORE store;
836
837     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
838
839     if (dwFlags & CERT_STORE_DELETE_FLAG)
840     {
841         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
842         store = NULL;
843     }
844     else
845     {
846         store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
847          sizeof(WINECRYPT_CERTSTORE));
848         if (store)
849         {
850             CRYPT_InitStore(store, hCryptProv, dwFlags, StoreTypeDummy);
851             store->closeStore    = CRYPT_DummyCloseStore;
852             store->addCert       = CRYPT_DummyAddCert;
853             store->createCertRef = CRYPT_CreateCertRef;
854             store->enumCert      = CRYPT_DummyEnumCert;
855             store->deleteCert    = CRYPT_DummyDeleteCert;
856             store->freeCert      = NULL;
857         }
858     }
859     return (PWINECRYPT_CERTSTORE)store;
860 }
861
862
863 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
864  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
865  const void* pvPara)
866 {
867     WINECRYPT_CERTSTORE *hcs;
868     StoreOpenFunc openFunc = NULL;
869
870     TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
871           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
872
873     if (!HIWORD(lpszStoreProvider))
874     {
875         switch (LOWORD(lpszStoreProvider))
876         {
877         case (int)CERT_STORE_PROV_MEMORY:
878             openFunc = CRYPT_MemOpenStore;
879             break;
880         case (int)CERT_STORE_PROV_COLLECTION:
881             openFunc = CRYPT_CollectionOpenStore;
882             break;
883         case (int)CERT_STORE_PROV_REG:
884         case (int)CERT_STORE_PROV_SYSTEM_A:
885         case (int)CERT_STORE_PROV_SYSTEM_W:
886             openFunc = CRYPT_DummyOpenStore;
887             break;
888         default:
889             if (LOWORD(lpszStoreProvider))
890                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
891         }
892     }
893     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
894         openFunc = CRYPT_MemOpenStore;
895     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
896         openFunc = CRYPT_DummyOpenStore;
897     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
898         openFunc = CRYPT_CollectionOpenStore;
899     else
900     {
901         FIXME("unimplemented type %s\n", lpszStoreProvider);
902         openFunc = NULL;
903     }
904
905     if (!openFunc)
906     {
907         /* FIXME: need to look for an installed provider for this type */
908         SetLastError(ERROR_FILE_NOT_FOUND);
909         hcs = NULL;
910     }
911     else
912         hcs = openFunc(hCryptProv, dwFlags, pvPara);
913     return (HCERTSTORE)hcs;
914 }
915
916 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
917  LPCSTR szSubSystemProtocol)
918 {
919     return CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, 0,
920      CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
921      CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
922 }
923
924 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
925  LPCWSTR szSubSystemProtocol)
926 {
927     return CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, 0,
928      CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
929      CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
930 }
931
932 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
933              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
934 {
935     FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, 
936           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
937     return TRUE;
938 }
939
940 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
941   const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
942 {
943     PCRL_CONTEXT pcrl;
944     BYTE* data;
945
946     TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
947
948     /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
949     pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
950     if( !pcrl )
951         return NULL;
952
953     data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
954     if( !data )
955     {
956         HeapFree( GetProcessHeap(), 0, pcrl );
957         return NULL;
958     }
959
960     pcrl->dwCertEncodingType = dwCertEncodingType;
961     pcrl->pbCrlEncoded       = data;
962     pcrl->cbCrlEncoded       = cbCrlEncoded;
963     pcrl->pCrlInfo           = NULL;
964     pcrl->hCertStore         = 0;
965
966     return pcrl;
967 }
968
969 /* Decodes the encoded certificate and creates the certificate context for it.
970  * The reference count is initially zero, so you must create a reference to it
971  * to avoid leaking memory.
972  */
973 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
974  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
975 {
976     PWINE_CERT_CONTEXT cert = NULL;
977     BOOL ret;
978     PCERT_INFO certInfo = NULL;
979     DWORD size = 0;
980
981     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
982      cbCertEncoded);
983
984     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
985      pbCertEncoded, cbCertEncoded,
986      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
987      (BYTE *)&certInfo, &size);
988     if (ret)
989     {
990         BYTE *data = NULL;
991
992         cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
993         if (!cert)
994             goto end;
995         data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
996         if (!data)
997         {
998             HeapFree(GetProcessHeap(), 0, cert);
999             cert = NULL;
1000             goto end;
1001         }
1002         memcpy(data, pbCertEncoded, cbCertEncoded);
1003         cert->cert.dwCertEncodingType = dwCertEncodingType;
1004         cert->cert.pbCertEncoded      = data;
1005         cert->cert.cbCertEncoded      = cbCertEncoded;
1006         cert->cert.pCertInfo          = certInfo;
1007         cert->cert.hCertStore         = 0;
1008         cert->ref = 0;
1009         InitializeCriticalSection(&cert->cs);
1010         list_init(&cert->extendedProperties);
1011     }
1012
1013 end:
1014     return cert;
1015 }
1016
1017 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1018 {
1019     PWINE_CERT_PROPERTY prop, next;
1020
1021     HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
1022     LocalFree(context->cert.pCertInfo);
1023     HeapFree(GetProcessHeap(), 0, context);
1024     DeleteCriticalSection(&context->cs);
1025     LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1026      WINE_CERT_PROPERTY, entry)
1027     {
1028         list_remove(&prop->entry);
1029         HeapFree(GetProcessHeap(), 0, prop->pbData);
1030         HeapFree(GetProcessHeap(), 0, prop);
1031     }
1032 }
1033
1034 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1035  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1036 {
1037     PWINE_CERT_CONTEXT cert;
1038     PWINE_CERT_CONTEXT_REF ret = NULL;
1039
1040     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1041      cbCertEncoded);
1042
1043     cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1044      cbCertEncoded);
1045     if (cert)
1046         ret = CRYPT_CreateCertRef(cert, 0);
1047     return (PCCERT_CONTEXT)ret;
1048 }
1049
1050 /* Since the properties are stored in a list, this is a tad inefficient
1051  * (O(n^2)) since I have to find the previous position every time.
1052  */
1053 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1054  DWORD dwPropId)
1055 {
1056     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1057     DWORD ret;
1058
1059     TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1060
1061     EnterCriticalSection(&ref->context->cs);
1062     if (dwPropId)
1063     {
1064         PWINE_CERT_PROPERTY cursor = NULL;
1065
1066         LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1067          WINE_CERT_PROPERTY, entry)
1068         {
1069             if (cursor->hdr.propID == dwPropId)
1070                 break;
1071         }
1072         if (cursor)
1073         {
1074             if (cursor->entry.next != &ref->context->extendedProperties)
1075                 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1076                  entry)->hdr.propID;
1077             else
1078                 ret = 0;
1079         }
1080         else
1081             ret = 0;
1082     }
1083     else if (!list_empty(&ref->context->extendedProperties))
1084         ret = LIST_ENTRY(ref->context->extendedProperties.next,
1085          WINE_CERT_PROPERTY, entry)->hdr.propID;
1086     else
1087         ret = 0;
1088     LeaveCriticalSection(&ref->context->cs);
1089     return ret;
1090 }
1091
1092 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1093  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1094 {
1095     PWINE_CERT_PROPERTY prop;
1096     BOOL ret, found;
1097
1098     TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1099
1100     EnterCriticalSection(&context->cs);
1101     ret = FALSE;
1102     found = FALSE;
1103     LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1104      WINE_CERT_PROPERTY, entry)
1105     {
1106         if (prop->hdr.propID == dwPropId)
1107         {
1108             if (!pvData)
1109             {
1110                 *pcbData = prop->hdr.cb;
1111                 ret = TRUE;
1112             }
1113             else if (*pcbData < prop->hdr.cb)
1114             {
1115                 SetLastError(ERROR_MORE_DATA);
1116                 *pcbData = prop->hdr.cb;
1117             }
1118             else
1119             {
1120                 memcpy(pvData, prop->pbData, prop->hdr.cb);
1121                 *pcbData = prop->hdr.cb;
1122                 ret = TRUE;
1123             }
1124             found = TRUE;
1125         }
1126         break;
1127     }
1128     if (!found)
1129     {
1130         /* Implicit properties */
1131         switch (dwPropId)
1132         {
1133         case CERT_SHA1_HASH_PROP_ID:
1134             ret = CryptHashCertificate(0, CALG_SHA1, 0,
1135              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1136              pcbData);
1137             if (ret)
1138             {
1139                 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1140
1141                 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1142                  0, &blob);
1143             }
1144             break;
1145         case CERT_KEY_PROV_INFO_PROP_ID:
1146         case CERT_MD5_HASH_PROP_ID:
1147         case CERT_SIGNATURE_HASH_PROP_ID:
1148         case CERT_KEY_IDENTIFIER_PROP_ID:
1149         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1150         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1151         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1152             FIXME("implicit property %ld\n", dwPropId);
1153             break;
1154         }
1155     }
1156     LeaveCriticalSection(&context->cs);
1157     TRACE("returning %d\n", ret);
1158     return ret;
1159 }
1160
1161 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1162  DWORD dwPropId, void *pvData, DWORD *pcbData)
1163 {
1164     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1165     BOOL ret;
1166
1167     TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1168
1169     /* Special cases for invalid/special prop IDs.
1170      */
1171     switch (dwPropId)
1172     {
1173     case 0:
1174     case CERT_CERT_PROP_ID:
1175     case CERT_CRL_PROP_ID:
1176     case CERT_CTL_PROP_ID:
1177         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1178         return FALSE;
1179     case CERT_ACCESS_STATE_PROP_ID:
1180         if (!pvData)
1181         {
1182             *pcbData = sizeof(DWORD);
1183             return TRUE;
1184         }
1185         else if (*pcbData < sizeof(DWORD))
1186         {
1187             SetLastError(ERROR_MORE_DATA);
1188             *pcbData = sizeof(DWORD);
1189             return FALSE;
1190         }
1191         else
1192         {
1193             DWORD state = 0;
1194
1195             if (pCertContext->hCertStore)
1196             {
1197                 PWINECRYPT_CERTSTORE store =
1198                  (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1199
1200                 /* Take advantage of knowledge of the stores to answer the
1201                  * access state question
1202                  */
1203                 if (store->type != StoreTypeReg ||
1204                  !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1205                     state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1206             }
1207             *(DWORD *)pvData = state;
1208             return TRUE;
1209         }
1210     }
1211
1212     ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
1213      pvData, pcbData);
1214     TRACE("returning %d\n", ret);
1215     return ret;
1216 }
1217
1218 /* Copies cbData bytes from pbData to the context's property with ID
1219  * dwPropId.
1220  */
1221 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
1222  DWORD dwPropId, const BYTE *pbData, size_t cbData)
1223 {
1224     BOOL ret = FALSE;
1225     LPBYTE data;
1226
1227     if (cbData)
1228     {
1229         data = HeapAlloc(GetProcessHeap(), 0, cbData);
1230         if (data)
1231             memcpy(data, pbData, cbData);
1232     }
1233     else
1234         data = NULL;
1235     if (!cbData || data)
1236     {
1237         PWINE_CERT_PROPERTY prop;
1238
1239         EnterCriticalSection(&context->cs);
1240         LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1241          WINE_CERT_PROPERTY, entry)
1242         {
1243             if (prop->hdr.propID == dwPropId)
1244                 break;
1245         }
1246         if (prop && prop->entry.next != &context->extendedProperties)
1247         {
1248             HeapFree(GetProcessHeap(), 0, prop->pbData);
1249             prop->hdr.cb = cbData;
1250             prop->pbData = cbData ? data : NULL;
1251             ret = TRUE;
1252         }
1253         else
1254         {
1255             prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
1256             if (prop)
1257             {
1258                 prop->hdr.propID = dwPropId;
1259                 prop->hdr.unknown = 1;
1260                 prop->hdr.cb = cbData;
1261                 list_init(&prop->entry);
1262                 prop->pbData = cbData ? data : NULL;
1263                 list_add_tail(&context->extendedProperties, &prop->entry);
1264                 ret = TRUE;
1265             }
1266             else
1267                 HeapFree(GetProcessHeap(), 0, data);
1268         }
1269         LeaveCriticalSection(&context->cs);
1270     }
1271     return ret;
1272 }
1273
1274 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
1275  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
1276 {
1277     BOOL ret = FALSE;
1278
1279     TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
1280
1281     if (!pvData)
1282     {
1283         PWINE_CERT_PROPERTY prop, next;
1284
1285         EnterCriticalSection(&context->cs);
1286         LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1287          WINE_CERT_PROPERTY, entry)
1288         {
1289             if (prop->hdr.propID == dwPropId)
1290             {
1291                 list_remove(&prop->entry);
1292                 HeapFree(GetProcessHeap(), 0, prop->pbData);
1293                 HeapFree(GetProcessHeap(), 0, prop);
1294             }
1295         }
1296         LeaveCriticalSection(&context->cs);
1297         ret = TRUE;
1298     }
1299     else
1300     {
1301         switch (dwPropId)
1302         {
1303         case CERT_AUTO_ENROLL_PROP_ID:
1304         case CERT_CTL_USAGE_PROP_ID:
1305         case CERT_DESCRIPTION_PROP_ID:
1306         case CERT_FRIENDLY_NAME_PROP_ID:
1307         case CERT_HASH_PROP_ID:
1308         case CERT_KEY_IDENTIFIER_PROP_ID:
1309         case CERT_MD5_HASH_PROP_ID:
1310         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
1311         case CERT_PUBKEY_ALG_PARA_PROP_ID:
1312         case CERT_PVK_FILE_PROP_ID:
1313         case CERT_SIGNATURE_HASH_PROP_ID:
1314         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
1315         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1316         case CERT_ENROLLMENT_PROP_ID:
1317         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
1318         case CERT_RENEWAL_PROP_ID:
1319         {
1320             PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
1321
1322             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
1323              blob->pbData, blob->cbData);
1324             break;
1325         }
1326         case CERT_DATE_STAMP_PROP_ID:
1327             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
1328              pvData, sizeof(FILETIME));
1329             break;
1330         default:
1331             FIXME("%ld: stub\n", dwPropId);
1332         }
1333     }
1334     TRACE("returning %d\n", ret);
1335     return ret;
1336 }
1337
1338 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1339  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1340 {
1341     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1342     BOOL ret;
1343
1344     TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
1345
1346     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
1347      * crashes on most of these, I'll be safer.
1348      */
1349     switch (dwPropId)
1350     {
1351     case 0:
1352     case CERT_ACCESS_STATE_PROP_ID:
1353     case CERT_CERT_PROP_ID:
1354     case CERT_CRL_PROP_ID:
1355     case CERT_CTL_PROP_ID:
1356         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1357         return FALSE;
1358     }
1359     ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
1360      dwFlags, pvData);
1361     TRACE("returning %d\n", ret);
1362     return ret;
1363 }
1364
1365 /* Only the reference portion of the context is duplicated.  The returned
1366  * context has the cert store set to 0, to prevent the store's certificate free
1367  * function from getting called on partial data.
1368  * FIXME: is this okay?  Needs a test.
1369  */
1370 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
1371  PCCERT_CONTEXT pCertContext)
1372 {
1373     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
1374
1375     TRACE("(%p)\n", pCertContext);
1376     if (ref)
1377     {
1378         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
1379         if (ret)
1380         {
1381             memcpy(ret, ref, sizeof(*ret));
1382             ret->cert.hCertStore = 0;
1383             InterlockedIncrement(&ret->context->ref);
1384         }
1385     }
1386     else
1387         ret = NULL;
1388     return (PCCERT_CONTEXT)ret;
1389 }
1390
1391 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
1392  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
1393  PCCERT_CONTEXT *ppStoreContext)
1394 {
1395     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1396     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1397     PWINE_CERT_CONTEXT cert;
1398     BOOL ret;
1399
1400     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
1401      dwAddDisposition, ppStoreContext);
1402
1403     /* FIXME: some tests needed to verify return codes */
1404     if (!store)
1405     {
1406         SetLastError(ERROR_INVALID_PARAMETER);
1407         return FALSE;
1408     }
1409     if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1410     {
1411         SetLastError(ERROR_INVALID_PARAMETER);
1412         return FALSE;
1413     }
1414
1415     cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
1416      ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
1417     if (cert)
1418     {
1419         PWINE_CERT_PROPERTY prop;
1420
1421         ret = TRUE;
1422         EnterCriticalSection(&ref->context->cs);
1423         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1424          WINE_CERT_PROPERTY, entry)
1425         {
1426             ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
1427              prop->pbData, prop->hdr.cb);
1428             if (!ret)
1429                 break;
1430         }
1431         LeaveCriticalSection(&ref->context->cs);
1432         if (ret)
1433         {
1434             ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
1435             if (ret && ppStoreContext)
1436                 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
1437                  hCertStore);
1438         }
1439         if (!ret)
1440             CRYPT_FreeCert(cert);
1441     }
1442     else
1443         ret = FALSE;
1444     return ret;
1445 }
1446
1447 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
1448  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
1449  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
1450 {
1451     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1452     BOOL ret;
1453
1454     TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
1455      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
1456
1457     if (!hcs)
1458         ret = FALSE;
1459     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1460         ret = FALSE;
1461     else
1462     {
1463         PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
1464          dwCertEncodingType, pbCertEncoded, cbCertEncoded);
1465
1466         if (cert)
1467         {
1468             ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
1469             if (ret && ppCertContext)
1470                 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
1471                  hCertStore);
1472             if (!ret)
1473                 CRYPT_FreeCert(cert);
1474         }
1475         else
1476             ret = FALSE;
1477     }
1478     return ret;
1479 }
1480
1481 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1482  PCCERT_CONTEXT pPrev)
1483 {
1484     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1485     PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
1486     PCCERT_CONTEXT ret;
1487
1488     TRACE("(%p, %p)\n", hCertStore, pPrev);
1489     if (!hCertStore)
1490         ret = NULL;
1491     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1492         ret = NULL;
1493     else
1494         ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
1495     return ret;
1496 }
1497
1498 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1499 {
1500     BOOL ret;
1501
1502     TRACE("(%p)\n", pCertContext);
1503
1504     if (!pCertContext)
1505         ret = TRUE;
1506     else if (!pCertContext->hCertStore)
1507         ret = TRUE;
1508     else
1509     {
1510         PWINECRYPT_CERTSTORE hcs =
1511          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1512
1513         if (!hcs)
1514             ret = TRUE;
1515         else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1516             ret = FALSE;
1517         else
1518             ret = hcs->deleteCert(hcs, pCertContext, 0);
1519     }
1520     return ret;
1521 }
1522
1523 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
1524  DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
1525  DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
1526 {
1527     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1528      dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
1529      ppCrlContext);
1530     return FALSE;
1531 }
1532
1533 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
1534              PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
1535              PCCRL_CONTEXT* ppStoreContext )
1536 {
1537     FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
1538           dwAddDisposition, ppStoreContext);
1539     return TRUE;
1540 }
1541
1542 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
1543 {
1544     FIXME("%p\n", pCrlContext );
1545
1546     return TRUE;
1547 }
1548
1549 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1550 {
1551     FIXME("(%p): stub\n", pCrlContext);
1552     return TRUE;
1553 }
1554
1555 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1556  PCCRL_CONTEXT pPrev)
1557 {
1558     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1559     return NULL;
1560 }
1561
1562 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1563   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1564 {
1565     FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
1566      cbCtlEncoded);
1567     return NULL;
1568 }
1569
1570 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1571  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1572  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1573 {
1574     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1575      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1576      ppCtlContext);
1577     return FALSE;
1578 }
1579
1580 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1581  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1582  PCCTL_CONTEXT* ppStoreContext)
1583 {
1584     FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
1585      dwAddDisposition, ppStoreContext);
1586     return TRUE;
1587 }
1588
1589 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1590 {
1591     FIXME("(%p): stub\n", pCtlContext );
1592     return TRUE;
1593 }
1594
1595 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1596 {
1597     FIXME("(%p): stub\n", pCtlContext);
1598     return TRUE;
1599 }
1600
1601 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1602  PCCTL_CONTEXT pPrev)
1603 {
1604     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1605     return NULL;
1606 }
1607
1608
1609 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1610 {
1611     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1612
1613     TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
1614
1615     if( ! hCertStore )
1616         return TRUE;
1617
1618     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1619         return FALSE;
1620
1621     if (InterlockedDecrement(&hcs->ref) == 0)
1622     {
1623         TRACE("freeing %p\n", hcs);
1624         hcs->dwMagic = 0;
1625         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
1626             CryptReleaseContext(hcs->cryptProv, 0);
1627         hcs->closeStore(hcs, dwFlags);
1628     }
1629     else
1630         TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
1631     return TRUE;
1632 }
1633
1634 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1635  DWORD dwCtrlType, void const *pvCtrlPara)
1636 {
1637     FIXME("(%p, %08lx, %ld, %p): stub\n", hCertStore, dwFlags, dwCtrlType,
1638      pvCtrlPara);
1639     return TRUE;
1640 }
1641
1642 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1643  DWORD dwPropId, void *pvData, DWORD *pcbData)
1644 {
1645     FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
1646     return FALSE;
1647 }
1648
1649 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1650  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1651 {
1652     FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
1653      pvData);
1654     return FALSE;
1655 }
1656
1657 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
1658  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1659 {
1660     FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
1661      pcbElement);
1662     return FALSE;
1663 }
1664
1665 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1666  DWORD dwPropId, void *pvData, DWORD *pcbData)
1667 {
1668     FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1669     return FALSE;
1670 }
1671
1672 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1673  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1674 {
1675     FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1676      pvData);
1677     return FALSE;
1678 }
1679
1680 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
1681  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1682 {
1683     FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
1684      pcbElement);
1685     return FALSE;
1686 }
1687
1688 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
1689  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1690 {
1691     BOOL ret;
1692
1693     TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
1694      pcbElement);
1695
1696     if (pCertContext)
1697     {
1698         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1699         DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
1700          pCertContext->cbCertEncoded;
1701         PWINE_CERT_PROPERTY prop;
1702
1703         EnterCriticalSection(&ref->context->cs);
1704         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1705          WINE_CERT_PROPERTY, entry)
1706             bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
1707         if (!pbElement)
1708         {
1709             *pcbElement = bytesNeeded;
1710             ret = TRUE;
1711         }
1712         else if (*pcbElement < bytesNeeded)
1713         {
1714             *pcbElement = bytesNeeded;
1715             SetLastError(ERROR_MORE_DATA);
1716             ret = FALSE;
1717         }
1718         else
1719         {
1720             PWINE_CERT_PROP_HEADER hdr;
1721
1722             LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1723              WINE_CERT_PROPERTY, entry)
1724             {
1725                 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
1726                 pbElement += sizeof(WINE_CERT_PROP_HEADER);
1727                 if (prop->hdr.cb)
1728                 {
1729                     memcpy(pbElement, prop->pbData, prop->hdr.cb);
1730                     pbElement += prop->hdr.cb;
1731                 }
1732             }
1733             hdr = (PWINE_CERT_PROP_HEADER)pbElement;
1734             hdr->propID = CERT_CERT_PROP_ID;
1735             hdr->unknown = 1;
1736             hdr->cb = pCertContext->cbCertEncoded;
1737             memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
1738              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
1739             ret = TRUE;
1740         }
1741         LeaveCriticalSection(&ref->context->cs);
1742     }
1743     else
1744         ret = FALSE;
1745     return ret;
1746 }
1747
1748 /* Looks for the property with ID propID in the buffer buf.  Returns a pointer
1749  * to its header if a valid header is found, NULL if not.  Valid means the
1750  * length of thte property won't overrun buf, and the unknown field is 1.
1751  */
1752 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
1753  DWORD size, DWORD propID)
1754 {
1755     const WINE_CERT_PROP_HEADER *ret = NULL;
1756     BOOL done = FALSE;
1757
1758     while (size && !ret && !done)
1759     {
1760         if (size < sizeof(WINE_CERT_PROP_HEADER))
1761         {
1762             SetLastError(CRYPT_E_FILE_ERROR);
1763             done = TRUE;
1764         }
1765         else
1766         {
1767             const WINE_CERT_PROP_HEADER *hdr =
1768              (const WINE_CERT_PROP_HEADER *)buf;
1769
1770             size -= sizeof(WINE_CERT_PROP_HEADER);
1771             buf += sizeof(WINE_CERT_PROP_HEADER);
1772             if (size < hdr->cb)
1773             {
1774                 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1775                 done = TRUE;
1776             }
1777             else if (!hdr->propID)
1778             {
1779                 /* assume a zero prop ID means the data are uninitialized, so
1780                  * stop looking.
1781                  */
1782                 done = TRUE;
1783             }
1784             else if (hdr->unknown != 1)
1785             {
1786                 SetLastError(ERROR_FILE_NOT_FOUND);
1787                 done = TRUE;
1788             }
1789             else if (hdr->propID == propID)
1790                 ret = hdr;
1791             else
1792             {
1793                 buf += hdr->cb;
1794                 size -= hdr->cb;
1795             }
1796         }
1797     }
1798     return ret;
1799 }
1800
1801 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
1802  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
1803 {
1804     const void *context = NULL;
1805
1806     TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
1807      pdwContentType);
1808
1809     if (!cbElement)
1810     {
1811         SetLastError(ERROR_END_OF_MEDIA);
1812         return NULL;
1813     }
1814
1815     __TRY
1816     {
1817         const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
1818         const WINE_CERT_PROP_HEADER *hdr = NULL;
1819         DWORD type = 0;
1820         BOOL ret;
1821
1822         ret = TRUE;
1823         if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
1824         {
1825             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
1826             if (hdr)
1827                 type = CERT_STORE_CERTIFICATE_CONTEXT;
1828             else
1829             {
1830                 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
1831                 if (hdr)
1832                     type = CERT_STORE_CRL_CONTEXT;
1833                 else
1834                 {
1835                     hdr = CRYPT_findPropID(pbElement, cbElement,
1836                      CERT_CTL_PROP_ID);
1837                     if (hdr)
1838                         type = CERT_STORE_CTL_CONTEXT;
1839                 }
1840             }
1841         }
1842         else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
1843         {
1844             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
1845             type = CERT_STORE_CERTIFICATE_CONTEXT;
1846         }
1847         else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
1848         {
1849             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
1850             type = CERT_STORE_CRL_CONTEXT;
1851         }
1852         else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
1853         {
1854             hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
1855             type = CERT_STORE_CTL_CONTEXT;
1856         }
1857
1858         switch (type)
1859         {
1860         case CERT_STORE_CERTIFICATE_CONTEXT:
1861             contextInterface = &gCertInterface;
1862             break;
1863         case CERT_STORE_CRL_CONTEXT:
1864             contextInterface = &gCRLInterface;
1865             break;
1866         case CERT_STORE_CTL_CONTEXT:
1867             contextInterface = &gCTLInterface;
1868             break;
1869         default:
1870             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1871             ret = FALSE;
1872         }
1873         if (!hdr)
1874             ret = FALSE;
1875
1876         if (ret)
1877             context = contextInterface->create(X509_ASN_ENCODING,
1878              (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
1879         if (ret && context)
1880         {
1881             BOOL noMoreProps = FALSE;
1882
1883             while (!noMoreProps && ret)
1884             {
1885                 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
1886                     ret = FALSE;
1887                 else
1888                 {
1889                     const WINE_CERT_PROP_HEADER *hdr =
1890                      (const WINE_CERT_PROP_HEADER *)pbElement;
1891
1892                     TRACE("prop is %ld\n", hdr->propID);
1893                     cbElement -= sizeof(WINE_CERT_PROP_HEADER);
1894                     pbElement += sizeof(WINE_CERT_PROP_HEADER);
1895                     if (cbElement < hdr->cb)
1896                     {
1897                         SetLastError(HRESULT_FROM_WIN32(
1898                          ERROR_INVALID_PARAMETER));
1899                         ret = FALSE;
1900                     }
1901                     else if (!hdr->propID)
1902                     {
1903                         /* Like in CRYPT_findPropID, stop if the propID is zero
1904                          */
1905                         noMoreProps = TRUE;
1906                     }
1907                     else if (hdr->unknown != 1)
1908                     {
1909                         SetLastError(ERROR_FILE_NOT_FOUND);
1910                         ret = FALSE;
1911                     }
1912                     else if (hdr->propID != CERT_CERT_PROP_ID &&
1913                      hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
1914                      CERT_CTL_PROP_ID)
1915                     {
1916                         /* Have to create a blob for most types, but not
1917                          * for all.. arghh.
1918                          */
1919                         switch (hdr->propID)
1920                         {
1921                         case CERT_AUTO_ENROLL_PROP_ID:
1922                         case CERT_CTL_USAGE_PROP_ID:
1923                         case CERT_DESCRIPTION_PROP_ID:
1924                         case CERT_FRIENDLY_NAME_PROP_ID:
1925                         case CERT_HASH_PROP_ID:
1926                         case CERT_KEY_IDENTIFIER_PROP_ID:
1927                         case CERT_MD5_HASH_PROP_ID:
1928                         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
1929                         case CERT_PUBKEY_ALG_PARA_PROP_ID:
1930                         case CERT_PVK_FILE_PROP_ID:
1931                         case CERT_SIGNATURE_HASH_PROP_ID:
1932                         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
1933                         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1934                         case CERT_ENROLLMENT_PROP_ID:
1935                         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
1936                         case CERT_RENEWAL_PROP_ID:
1937                         {
1938                             CRYPT_DATA_BLOB blob = { hdr->cb,
1939                              (LPBYTE)pbElement };
1940
1941                             ret = contextInterface->setProp(context,
1942                              hdr->propID, 0, &blob);
1943                             break;
1944                         }
1945                         case CERT_DATE_STAMP_PROP_ID:
1946                             ret = contextInterface->setProp(context,
1947                              hdr->propID, 0, pbElement);
1948                             break;
1949                         default:
1950                             FIXME("prop ID %ld: stub\n", hdr->propID);
1951                         }
1952                     }
1953                     pbElement += hdr->cb;
1954                     cbElement -= hdr->cb;
1955                     if (!cbElement)
1956                         noMoreProps = TRUE;
1957                 }
1958             }
1959             if (ret)
1960             {
1961                 if (pdwContentType)
1962                     *pdwContentType = type;
1963             }
1964             else
1965             {
1966                 contextInterface->free(context);
1967                 context = NULL;
1968             }
1969         }
1970     }
1971     __EXCEPT(page_fault)
1972     {
1973         SetLastError(STATUS_ACCESS_VIOLATION);
1974         context = NULL;
1975     }
1976     __ENDTRY
1977     return context;
1978 }
1979
1980 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
1981  const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
1982  DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
1983 {
1984     const void *context;
1985     DWORD type;
1986     BOOL ret;
1987
1988     TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
1989      pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
1990      pdwContentType, ppvContext);
1991
1992     /* Call the internal function, then delete the hashes.  Tests show this
1993      * function uses real hash values, not whatever's stored in the hash
1994      * property.
1995      */
1996     context = CRYPT_ReadSerializedElement(pbElement, cbElement,
1997      dwContextTypeFlags, &type);
1998     if (context)
1999     {
2000         const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2001
2002         switch (type)
2003         {
2004         case CERT_STORE_CERTIFICATE_CONTEXT:
2005             contextInterface = &gCertInterface;
2006             break;
2007         case CERT_STORE_CRL_CONTEXT:
2008             contextInterface = &gCRLInterface;
2009             break;
2010         case CERT_STORE_CTL_CONTEXT:
2011             contextInterface = &gCTLInterface;
2012             break;
2013         default:
2014             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2015         }
2016         if (contextInterface)
2017         {
2018             contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2019             contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2020             contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2021              NULL);
2022             if (pdwContentType)
2023                 *pdwContentType = type;
2024             ret = contextInterface->addContextToStore(hCertStore, context,
2025              dwAddDisposition, ppvContext);
2026             contextInterface->free(context);
2027         }
2028         else
2029             ret = FALSE;
2030     }
2031     else
2032         ret = FALSE;
2033     return ret;
2034 }
2035
2036 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2037 {
2038     TRACE("(%p)\n", pCertContext);
2039
2040     if (pCertContext)
2041     {
2042         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2043         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2044
2045         if (InterlockedDecrement(&ref->context->ref) == 0)
2046         {
2047             TRACE("freeing %p\n", ref->context);
2048             CRYPT_FreeCert(ref->context);
2049         }
2050         else
2051             TRACE("%p's ref count is %ld\n", ref->context,
2052              ref->context->ref);
2053         if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2054          store->freeCert)
2055             store->freeCert(ref);
2056         HeapFree(GetProcessHeap(), 0, ref);
2057     }
2058     return TRUE;
2059 }
2060
2061 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2062                 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2063                 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2064 {
2065     FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2066         dwFlags, dwType, pvPara, pPrevCertContext);
2067     SetLastError(CRYPT_E_NOT_FOUND);
2068     return NULL;
2069 }
2070
2071 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2072  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2073 {
2074     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2075     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2076     PWINE_STORE_LIST_ENTRY entry;
2077     BOOL ret;
2078
2079     TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2080      dwUpdateFlags, dwPriority);
2081
2082     if (!collection || !sibling)
2083         return TRUE;
2084     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2085     {
2086         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2087         return FALSE;
2088     }
2089     if (collection->hdr.type != StoreTypeCollection)
2090     {
2091         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2092         return FALSE;
2093     }
2094     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2095     {
2096         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2097         return FALSE;
2098     }
2099
2100     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
2101     if (entry)
2102     {
2103         InterlockedIncrement(&sibling->ref);
2104         TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2105         entry->store = sibling;
2106         entry->dwUpdateFlags = dwUpdateFlags;
2107         entry->dwPriority = dwPriority;
2108         list_init(&entry->entry);
2109         TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2110         EnterCriticalSection(&collection->cs);
2111         if (dwPriority)
2112         {
2113             PWINE_STORE_LIST_ENTRY cursor;
2114             BOOL added = FALSE;
2115
2116             LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2117              WINE_STORE_LIST_ENTRY, entry)
2118             {
2119                 if (cursor->dwPriority < dwPriority)
2120                 {
2121                     list_add_before(&cursor->entry, &entry->entry);
2122                     added = TRUE;
2123                     break;
2124                 }
2125             }
2126             if (!added)
2127                 list_add_tail(&collection->stores, &entry->entry);
2128         }
2129         else
2130             list_add_tail(&collection->stores, &entry->entry);
2131         LeaveCriticalSection(&collection->cs);
2132         ret = TRUE;
2133     }
2134     else
2135         ret = FALSE;
2136     return ret;
2137 }
2138
2139 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2140  HCERTSTORE hSiblingStore)
2141 {
2142     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2143     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2144     PWINE_STORE_LIST_ENTRY store, next;
2145
2146     TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2147
2148     if (!collection || !sibling)
2149         return;
2150     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2151     {
2152         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2153         return;
2154     }
2155     if (collection->hdr.type != StoreTypeCollection)
2156         return;
2157     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2158     {
2159         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2160         return;
2161     }
2162     EnterCriticalSection(&collection->cs);
2163     LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2164      WINE_STORE_LIST_ENTRY, entry)
2165     {
2166         if (store->store == sibling)
2167         {
2168             list_remove(&store->entry);
2169             CertCloseStore(store->store, 0);
2170             HeapFree(GetProcessHeap(), 0, store);
2171             break;
2172         }
2173     }
2174     LeaveCriticalSection(&collection->cs);
2175 }
2176
2177 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
2178  CRYPT_ATTRIBUTE rgAttr[])
2179 {
2180     PCRYPT_ATTRIBUTE ret = NULL;
2181     DWORD i;
2182
2183     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
2184
2185     if (!cAttr)
2186         return NULL;
2187     if (!pszObjId)
2188     {
2189         SetLastError(ERROR_INVALID_PARAMETER);
2190         return NULL;
2191     }
2192
2193     for (i = 0; !ret && i < cAttr; i++)
2194         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
2195             ret = &rgAttr[i];
2196     return ret;
2197 }
2198
2199 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2200  CERT_EXTENSION rgExtensions[])
2201 {
2202     PCERT_EXTENSION ret = NULL;
2203     DWORD i;
2204
2205     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2206
2207     if (!cExtensions)
2208         return NULL;
2209     if (!pszObjId)
2210     {
2211         SetLastError(ERROR_INVALID_PARAMETER);
2212         return NULL;
2213     }
2214
2215     for (i = 0; !ret && i < cExtensions; i++)
2216         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
2217          rgExtensions[i].pszObjId))
2218             ret = &rgExtensions[i];
2219     return ret;
2220 }
2221
2222 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2223 {
2224     PCERT_RDN_ATTR ret = NULL;
2225     DWORD i, j;
2226
2227     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2228
2229     if (!pszObjId)
2230     {
2231         SetLastError(ERROR_INVALID_PARAMETER);
2232         return NULL;
2233     }
2234
2235     for (i = 0; !ret && i < pName->cRDN; i++)
2236         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2237             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2238              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2239                 ret = &pName->rgRDN[i].rgRDNAttr[j];
2240     return ret;
2241 }
2242
2243 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2244  PCERT_INFO pCertInfo)
2245 {
2246     FILETIME fileTime;
2247     LONG ret;
2248
2249     if (!pTimeToVerify)
2250     {
2251         SYSTEMTIME sysTime;
2252
2253         GetSystemTime(&sysTime);
2254         SystemTimeToFileTime(&sysTime, &fileTime);
2255         pTimeToVerify = &fileTime;
2256     }
2257     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2258     {
2259         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2260         if (ret < 0)
2261             ret = 0;
2262     }
2263     return ret;
2264 }
2265
2266 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
2267  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2268  DWORD *pcbComputedHash)
2269 {
2270     BOOL ret = TRUE;
2271     HCRYPTHASH hHash = 0;
2272
2273     TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
2274      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2275
2276     if (!hCryptProv)
2277         hCryptProv = CRYPT_GetDefaultProvider();
2278     if (!Algid)
2279         Algid = CALG_SHA1;
2280     if (ret)
2281     {
2282         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2283         if (ret)
2284         {
2285             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2286             if (ret)
2287                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2288                  pcbComputedHash, 0);
2289             CryptDestroyHash(hHash);
2290         }
2291     }
2292     return ret;
2293 }