EnumThemeColors() and EnumThemeSizes() actually do not return a single
[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 "crypt32_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
40
41 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
42 /* The following aren't defined in wincrypt.h, as they're "reserved" */
43 #define CERT_CERT_PROP_ID 32
44 #define CERT_CRL_PROP_ID  33
45 #define CERT_CTL_PROP_ID  34
46
47 struct WINE_CRYPTCERTSTORE;
48
49 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
50  DWORD dwFlags, const void *pvPara);
51
52 struct _WINE_CERT_CONTEXT_REF;
53
54 /* Called to enumerate the next certificate in a store.  The returned pointer
55  * must be newly allocated (via HeapAlloc):  CertFreeCertificateContext frees
56  * it.
57  */
58 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
59  (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
60
61 struct _WINE_CERT_CONTEXT;
62
63 /* Called to create a new reference to an existing cert context.  Should call
64  * CRYPT_InitCertRef to make sure the reference count is properly updated.
65  * If the store does not provide any additional allocated data (that is, does
66  * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
67  * this.
68  */
69 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
70  (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
71
72 /* Optional, called when a cert context reference is being freed.  Don't free
73  * the ref pointer itself, CertFreeCertificateContext does that.
74  */
75 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
76
77 typedef enum _CertStoreType {
78     StoreTypeMem,
79     StoreTypeCollection,
80     StoreTypeReg,
81     StoreTypeDummy,
82 } CertStoreType;
83
84 /* A cert store is polymorphic through the use of function pointers.  A type
85  * is still needed to distinguish collection stores from other types.
86  * On the function pointers:
87  * - closeStore is called when the store's ref count becomes 0
88  * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
89  * - control is optional, but should be implemented by any store that supports
90  *   persistence
91  */
92 typedef struct WINE_CRYPTCERTSTORE
93 {
94     DWORD                           dwMagic;
95     LONG                            ref;
96     DWORD                           dwOpenFlags;
97     HCRYPTPROV                      cryptProv;
98     CertStoreType                   type;
99     PFN_CERT_STORE_PROV_CLOSE       closeStore;
100     PFN_CERT_STORE_PROV_WRITE_CERT  addCert;
101     CreateRefFunc                   createCertRef;
102     EnumCertFunc                    enumCert;
103     PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
104     FreeCertFunc                    freeCert;   /* optional */
105     PFN_CERT_STORE_PROV_CONTROL     control;    /* optional */
106 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
107
108 /* A certificate context has pointers to data that are owned by this module,
109  * so rather than duplicate the data every time a certificate context is
110  * copied, I keep a reference count to the data.  Thus I have two data
111  * structures, the "true" certificate context (that has the reference count)
112  * and a reference certificate context, that has a pointer to the true context.
113  * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
114  * with the reference version.
115  */
116 typedef struct _WINE_CERT_CONTEXT
117 {
118     CERT_CONTEXT     cert;
119     LONG             ref;
120     CRITICAL_SECTION cs;
121     struct list      extendedProperties;
122 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
123
124 typedef struct _WINE_CERT_CONTEXT_REF
125 {
126     CERT_CONTEXT cert;
127     WINE_CERT_CONTEXT *context;
128 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
129
130 /* An extended certificate property in serialized form is prefixed by this
131  * header.
132  */
133 typedef struct _WINE_CERT_PROP_HEADER
134 {
135     DWORD propID;
136     DWORD unknown; /* always 1 */
137     DWORD cb;
138 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
139
140 /* Stores an extended property in a cert. */
141 typedef struct _WINE_CERT_PROPERTY
142 {
143     WINE_CERT_PROP_HEADER hdr;
144     LPBYTE                pbData;
145     struct list           entry;
146 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
147
148 /* A mem store has a list of these.  They're also returned by the mem store
149  * during enumeration.
150  */
151 typedef struct _WINE_CERT_LIST_ENTRY
152 {
153     WINE_CERT_CONTEXT_REF cert;
154     struct list entry;
155 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
156
157 typedef struct _WINE_MEMSTORE
158 {
159     WINECRYPT_CERTSTORE hdr;
160     CRITICAL_SECTION    cs;
161     struct list         certs;
162 } WINE_MEMSTORE, *PWINE_MEMSTORE;
163
164 /* Like CertGetCertificateContextProperty, but operates directly on the
165  * WINE_CERT_CONTEXT.  Doesn't support special-case properties, since they
166  * are handled by CertGetCertificateContextProperty, and are particular to the
167  * store in which the property exists (which is separate from the context.)
168  */
169 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
170  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
171
172 /* Like CertSetCertificateContextProperty, but operates directly on the
173  * WINE_CERT_CONTEXT.  Doesn't handle special cases, since they're handled by
174  * CertSetCertificateContextProperty anyway.
175  */
176 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
177  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
178
179 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
180  DWORD dwFlags, CertStoreType type)
181 {
182     store->ref = 1;
183     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
184     store->type = type;
185     if (!hCryptProv)
186     {
187         hCryptProv = CRYPT_GetDefaultProvider();
188         dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
189     }
190     store->cryptProv = hCryptProv;
191     store->dwOpenFlags = dwFlags;
192 }
193
194 /* Initializes the reference ref to point to pCertContext, which is assumed to
195  * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
196  * Also sets the hCertStore member of the reference to store.
197  */
198 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
199  PWINE_CERT_CONTEXT context, HCERTSTORE store)
200 {
201     TRACE("(%p, %p)\n", ref, context);
202     memcpy(&ref->cert, context, sizeof(ref->cert));
203     ref->context = context;
204     InterlockedIncrement(&context->ref);
205     ref->cert.hCertStore = store;
206 }
207
208 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
209  HCERTSTORE store)
210 {
211     PWINE_CERT_CONTEXT_REF pCertRef = HeapAlloc(GetProcessHeap(), 0,
212      sizeof(WINE_CERT_CONTEXT_REF));
213
214     if (pCertRef)
215         CRYPT_InitCertRef(pCertRef, context, store);
216     return pCertRef;
217 }
218
219 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
220  DWORD dwAddDisposition)
221 {
222     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
223     BOOL add = FALSE, ret;
224
225     TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
226
227     switch (dwAddDisposition)
228     {
229     case CERT_STORE_ADD_ALWAYS:
230         add = TRUE;
231         break;
232     case CERT_STORE_ADD_NEW:
233     {
234         BYTE hashToAdd[20], hash[20];
235         DWORD size = sizeof(hashToAdd);
236
237         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
238          CERT_HASH_PROP_ID, hashToAdd, &size);
239         if (ret)
240         {
241             PWINE_CERT_LIST_ENTRY cursor;
242
243             /* Add if no cert with the same hash is found. */
244             add = TRUE;
245             EnterCriticalSection(&ms->cs);
246             LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
247             {
248                 size = sizeof(hash);
249                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
250                  CERT_HASH_PROP_ID, hash, &size);
251                 if (ret && !memcmp(hashToAdd, hash, size))
252                 {
253                     TRACE("found matching certificate, not adding\n");
254                     SetLastError(CRYPT_E_EXISTS);
255                     add = FALSE;
256                     break;
257                 }
258             }
259             LeaveCriticalSection(&ms->cs);
260         }
261         break;
262     }
263     case CERT_STORE_ADD_REPLACE_EXISTING:
264     {
265         BYTE hashToAdd[20], hash[20];
266         DWORD size = sizeof(hashToAdd);
267
268         add = TRUE;
269         ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
270          CERT_HASH_PROP_ID, hashToAdd, &size);
271         if (ret)
272         {
273             PWINE_CERT_LIST_ENTRY cursor, next;
274
275             /* Look for existing cert to delete */
276             EnterCriticalSection(&ms->cs);
277             LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
278              WINE_CERT_LIST_ENTRY, entry)
279             {
280                 size = sizeof(hash);
281                 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
282                  CERT_HASH_PROP_ID, hash, &size);
283                 if (ret && !memcmp(hashToAdd, hash, size))
284                 {
285                     TRACE("found matching certificate, replacing\n");
286                     list_remove(&cursor->entry);
287                     CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
288                     break;
289                 }
290             }
291             LeaveCriticalSection(&ms->cs);
292         }
293         break;
294     }
295     default:
296         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
297         add = FALSE;
298     }
299     if (add)
300     {
301         PWINE_CERT_LIST_ENTRY entry = HeapAlloc(GetProcessHeap(), 0,
302          sizeof(WINE_CERT_LIST_ENTRY));
303
304         if (entry)
305         {
306             TRACE("adding %p\n", entry);
307             CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
308             list_init(&entry->entry);
309             EnterCriticalSection(&ms->cs);
310             list_add_tail(&ms->certs, &entry->entry);
311             LeaveCriticalSection(&ms->cs);
312             ret = TRUE;
313         }
314         else
315             ret = FALSE;
316     }
317     else
318         ret = FALSE;
319     return ret;
320 }
321
322 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
323  PWINE_CERT_CONTEXT_REF pPrev)
324 {
325     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
326     PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
327     struct list *listNext;
328
329     TRACE("(%p, %p)\n", store, pPrev);
330     EnterCriticalSection(&ms->cs);
331     if (prevEntry)
332     {
333         listNext = list_next(&ms->certs, &prevEntry->entry);
334         CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
335     }
336     else
337         listNext = list_next(&ms->certs, &ms->certs);
338     if (listNext)
339     {
340         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY));
341         memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
342          sizeof(WINE_CERT_LIST_ENTRY));
343         InterlockedIncrement(&ret->cert.context->ref);
344     }
345     else
346     {
347         SetLastError(CRYPT_E_NOT_FOUND);
348         ret = NULL;
349     }
350     LeaveCriticalSection(&ms->cs);
351
352     TRACE("returning %p\n", ret);
353     return (PWINE_CERT_CONTEXT_REF)ret;
354 }
355
356 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
357  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
358 {
359     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
360     WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
361     PWINE_CERT_LIST_ENTRY cert, next;
362     BOOL ret;
363
364     /* Find the entry associated with the passed-in context, since the
365      * passed-in context may not be a list entry itself (e.g. if it came from
366      * CertDuplicateCertificateContext.)  Pointing to the same context is
367      * a sufficient test of equality.
368      */
369     EnterCriticalSection(&store->cs);
370     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
371      entry)
372     {
373         if (cert->cert.context == ref->context)
374         {
375             TRACE("removing %p\n", cert);
376             /* FIXME: this isn't entirely thread-safe, the entry itself isn't
377              * protected.
378              */
379             list_remove(&cert->entry);
380             cert->entry.prev = cert->entry.next = &store->certs;
381             CertFreeCertificateContext((PCCERT_CONTEXT)cert);
382             break;
383         }
384     }
385     ret = TRUE;
386     LeaveCriticalSection(&store->cs);
387     return ret;
388 }
389
390 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
391 {
392     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
393     PWINE_CERT_LIST_ENTRY cert, next;
394
395     TRACE("(%p, %08lx)\n", store, dwFlags);
396     if (dwFlags)
397         FIXME("Unimplemented flags: %08lx\n", dwFlags);
398
399     /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
400      * pointer if its ref-count reaches zero.  That's okay here because there
401      * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
402      * of the CertListEntry.
403      */
404     LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
405      entry)
406     {
407         TRACE("removing %p\n", cert);
408         list_remove(&cert->entry);
409         CertFreeCertificateContext((PCCERT_CONTEXT)cert);
410     }
411     DeleteCriticalSection(&store->cs);
412     HeapFree(GetProcessHeap(), 0, store);
413 }
414
415 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
416  DWORD dwFlags, const void *pvPara)
417 {
418     PWINE_MEMSTORE store;
419
420     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
421
422     if (dwFlags & CERT_STORE_DELETE_FLAG)
423     {
424         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
425         store = NULL;
426     }
427     else
428     {
429         store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
430          sizeof(WINE_MEMSTORE));
431         if (store)
432         {
433             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
434             store->hdr.closeStore    = CRYPT_MemCloseStore;
435             store->hdr.addCert       = CRYPT_MemAddCert;
436             store->hdr.createCertRef = CRYPT_CreateCertRef;
437             store->hdr.enumCert      = CRYPT_MemEnumCert;
438             store->hdr.deleteCert    = CRYPT_MemDeleteCert;
439             store->hdr.freeCert      = NULL;
440             InitializeCriticalSection(&store->cs);
441             list_init(&store->certs);
442         }
443     }
444     return (PWINECRYPT_CERTSTORE)store;
445 }
446
447 static void WINAPI CRYPT_DummyCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
448 {
449     HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE)hCertStore);
450 }
451
452 static BOOL WINAPI CRYPT_DummyAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
453  DWORD dwAddDisposition)
454 {
455     return FALSE;
456 }
457
458 static PWINE_CERT_CONTEXT_REF CRYPT_DummyEnumCert(PWINECRYPT_CERTSTORE store,
459  PWINE_CERT_CONTEXT_REF pPrev)
460 {
461     return NULL;
462 }
463
464 static BOOL WINAPI CRYPT_DummyDeleteCert(HCERTSTORE hCertStore,
465  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
466 {
467     return TRUE;
468 }
469
470 static WINECRYPT_CERTSTORE *CRYPT_DummyOpenStore(HCRYPTPROV hCryptProv,
471  DWORD dwFlags, const void *pvPara)
472 {
473     PWINECRYPT_CERTSTORE store;
474
475     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
476
477     if (dwFlags & CERT_STORE_DELETE_FLAG)
478     {
479         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
480         store = NULL;
481     }
482     else
483     {
484         store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
485          sizeof(WINECRYPT_CERTSTORE));
486         if (store)
487         {
488             CRYPT_InitStore(store, hCryptProv, dwFlags, StoreTypeDummy);
489             store->closeStore    = CRYPT_DummyCloseStore;
490             store->addCert       = CRYPT_DummyAddCert;
491             store->createCertRef = CRYPT_CreateCertRef;
492             store->enumCert      = CRYPT_DummyEnumCert;
493             store->deleteCert    = CRYPT_DummyDeleteCert;
494             store->freeCert      = NULL;
495         }
496     }
497     return (PWINECRYPT_CERTSTORE)store;
498 }
499
500
501 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
502  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
503  const void* pvPara)
504 {
505     WINECRYPT_CERTSTORE *hcs;
506     StoreOpenFunc openFunc = NULL;
507
508     TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
509           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
510
511     if (!HIWORD(lpszStoreProvider))
512     {
513         switch (LOWORD(lpszStoreProvider))
514         {
515         case (int)CERT_STORE_PROV_MEMORY:
516             openFunc = CRYPT_MemOpenStore;
517             break;
518         case (int)CERT_STORE_PROV_REG:
519         case (int)CERT_STORE_PROV_SYSTEM_A:
520         case (int)CERT_STORE_PROV_SYSTEM_W:
521         case (int)CERT_STORE_PROV_COLLECTION:
522             openFunc = CRYPT_DummyOpenStore;
523             break;
524         default:
525             if (LOWORD(lpszStoreProvider))
526                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
527         }
528     }
529     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
530         openFunc = CRYPT_MemOpenStore;
531     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
532         openFunc = CRYPT_DummyOpenStore;
533     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
534         openFunc = CRYPT_DummyOpenStore;
535     else
536     {
537         FIXME("unimplemented type %s\n", lpszStoreProvider);
538         openFunc = NULL;
539     }
540
541     if (!openFunc)
542     {
543         /* FIXME: need to look for an installed provider for this type */
544         SetLastError(ERROR_FILE_NOT_FOUND);
545         hcs = NULL;
546     }
547     else
548         hcs = openFunc(hCryptProv, dwFlags, pvPara);
549     return (HCERTSTORE)hcs;
550 }
551
552 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
553  LPCSTR szSubSystemProtocol)
554 {
555     return CertOpenStore( CERT_STORE_PROV_SYSTEM_A, 0, 0,
556      CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
557      CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
558 }
559
560 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
561  LPCWSTR szSubSystemProtocol)
562 {
563     return CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, 0,
564      CERT_SYSTEM_STORE_CURRENT_USER | CERT_SYSTEM_STORE_LOCAL_MACHINE |
565      CERT_SYSTEM_STORE_USERS, szSubSystemProtocol );
566 }
567
568 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
569              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
570 {
571     FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, 
572           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
573     return TRUE;
574 }
575
576 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
577   const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
578 {
579     PCRL_CONTEXT pcrl;
580     BYTE* data;
581
582     TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
583
584     /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
585     pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
586     if( !pcrl )
587         return NULL;
588
589     data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
590     if( !data )
591     {
592         HeapFree( GetProcessHeap(), 0, pcrl );
593         return NULL;
594     }
595
596     pcrl->dwCertEncodingType = dwCertEncodingType;
597     pcrl->pbCrlEncoded       = data;
598     pcrl->cbCrlEncoded       = cbCrlEncoded;
599     pcrl->pCrlInfo           = NULL;
600     pcrl->hCertStore         = 0;
601
602     return pcrl;
603 }
604
605 /* Decodes the encoded certificate and creates the certificate context for it.
606  * The reference count is initially zero, so you must create a reference to it
607  * to avoid leaking memory.
608  */
609 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
610  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
611 {
612     PWINE_CERT_CONTEXT cert = NULL;
613     BOOL ret;
614     PCERT_INFO certInfo = NULL;
615     DWORD size = 0;
616
617     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
618      cbCertEncoded);
619
620     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
621      pbCertEncoded, cbCertEncoded,
622      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
623      (BYTE *)&certInfo, &size);
624     if (ret)
625     {
626         BYTE *data = NULL;
627
628         cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
629         if (!cert)
630             goto end;
631         data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
632         if (!data)
633         {
634             HeapFree(GetProcessHeap(), 0, cert);
635             cert = NULL;
636             goto end;
637         }
638         memcpy(data, pbCertEncoded, cbCertEncoded);
639         cert->cert.dwCertEncodingType = dwCertEncodingType;
640         cert->cert.pbCertEncoded      = data;
641         cert->cert.cbCertEncoded      = cbCertEncoded;
642         cert->cert.pCertInfo          = certInfo;
643         cert->cert.hCertStore         = 0;
644         cert->ref = 0;
645         InitializeCriticalSection(&cert->cs);
646         list_init(&cert->extendedProperties);
647     }
648
649 end:
650     return cert;
651 }
652
653 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
654 {
655     PWINE_CERT_PROPERTY prop, next;
656
657     HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
658     LocalFree(context->cert.pCertInfo);
659     HeapFree(GetProcessHeap(), 0, context);
660     DeleteCriticalSection(&context->cs);
661     LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
662      WINE_CERT_PROPERTY, entry)
663     {
664         list_remove(&prop->entry);
665         HeapFree(GetProcessHeap(), 0, prop->pbData);
666         HeapFree(GetProcessHeap(), 0, prop);
667     }
668 }
669
670 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
671  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
672 {
673     PWINE_CERT_CONTEXT cert;
674     PWINE_CERT_CONTEXT_REF ret = NULL;
675
676     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
677      cbCertEncoded);
678
679     cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
680      cbCertEncoded);
681     if (cert)
682         ret = CRYPT_CreateCertRef(cert, 0);
683     return (PCCERT_CONTEXT)ret;
684 }
685
686 /* Since the properties are stored in a list, this is a tad inefficient
687  * (O(n^2)) since I have to find the previous position every time.
688  */
689 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
690  DWORD dwPropId)
691 {
692     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
693     DWORD ret;
694
695     TRACE("(%p, %ld)\n", pCertContext, dwPropId);
696
697     EnterCriticalSection(&ref->context->cs);
698     if (dwPropId)
699     {
700         PWINE_CERT_PROPERTY cursor = NULL;
701
702         LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
703          WINE_CERT_PROPERTY, entry)
704         {
705             if (cursor->hdr.propID == dwPropId)
706                 break;
707         }
708         if (cursor)
709         {
710             if (cursor->entry.next != &ref->context->extendedProperties)
711                 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
712                  entry)->hdr.propID;
713             else
714                 ret = 0;
715         }
716         else
717             ret = 0;
718     }
719     else if (!list_empty(&ref->context->extendedProperties))
720         ret = LIST_ENTRY(ref->context->extendedProperties.next,
721          WINE_CERT_PROPERTY, entry)->hdr.propID;
722     else
723         ret = 0;
724     LeaveCriticalSection(&ref->context->cs);
725     return ret;
726 }
727
728 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
729  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
730 {
731     PWINE_CERT_PROPERTY prop;
732     BOOL ret, found;
733
734     TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
735
736     EnterCriticalSection(&context->cs);
737     ret = FALSE;
738     found = FALSE;
739     LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
740      WINE_CERT_PROPERTY, entry)
741     {
742         if (prop->hdr.propID == dwPropId)
743         {
744             if (!pvData)
745             {
746                 *pcbData = prop->hdr.cb;
747                 ret = TRUE;
748             }
749             else if (*pcbData < prop->hdr.cb)
750             {
751                 SetLastError(ERROR_MORE_DATA);
752                 *pcbData = prop->hdr.cb;
753             }
754             else
755             {
756                 memcpy(pvData, prop->pbData, prop->hdr.cb);
757                 *pcbData = prop->hdr.cb;
758                 ret = TRUE;
759             }
760             found = TRUE;
761         }
762         break;
763     }
764     if (!found)
765     {
766         /* Implicit properties */
767         switch (dwPropId)
768         {
769         case CERT_SHA1_HASH_PROP_ID:
770             ret = CryptHashCertificate(0, CALG_SHA1, 0,
771              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
772              pcbData);
773             if (ret)
774             {
775                 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
776
777                 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
778                  0, &blob);
779             }
780             break;
781         case CERT_KEY_PROV_INFO_PROP_ID:
782         case CERT_MD5_HASH_PROP_ID:
783         case CERT_SIGNATURE_HASH_PROP_ID:
784         case CERT_KEY_IDENTIFIER_PROP_ID:
785         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
786         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
787         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
788             FIXME("implicit property %ld\n", dwPropId);
789             break;
790         }
791     }
792     LeaveCriticalSection(&context->cs);
793     TRACE("returning %d\n", ret);
794     return ret;
795 }
796
797 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
798  DWORD dwPropId, void *pvData, DWORD *pcbData)
799 {
800     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
801     BOOL ret;
802
803     TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
804
805     /* Special cases for invalid/special prop IDs.
806      */
807     switch (dwPropId)
808     {
809     case 0:
810     case CERT_CERT_PROP_ID:
811     case CERT_CRL_PROP_ID:
812     case CERT_CTL_PROP_ID:
813         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
814         return FALSE;
815     case CERT_ACCESS_STATE_PROP_ID:
816         if (!pvData)
817         {
818             *pcbData = sizeof(DWORD);
819             return TRUE;
820         }
821         else if (*pcbData < sizeof(DWORD))
822         {
823             SetLastError(ERROR_MORE_DATA);
824             *pcbData = sizeof(DWORD);
825             return FALSE;
826         }
827         else
828         {
829             DWORD state = 0;
830
831             if (pCertContext->hCertStore)
832             {
833                 PWINECRYPT_CERTSTORE store =
834                  (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
835
836                 /* Take advantage of knowledge of the stores to answer the
837                  * access state question
838                  */
839                 if (store->type != StoreTypeReg ||
840                  !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
841                     state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
842             }
843             *(DWORD *)pvData = state;
844             return TRUE;
845         }
846     }
847
848     ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
849      pvData, pcbData);
850     TRACE("returning %d\n", ret);
851     return ret;
852 }
853
854 /* Copies cbData bytes from pbData to the context's property with ID
855  * dwPropId.
856  */
857 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
858  DWORD dwPropId, const BYTE *pbData, size_t cbData)
859 {
860     BOOL ret = FALSE;
861     LPBYTE data;
862
863     if (cbData)
864     {
865         data = HeapAlloc(GetProcessHeap(), 0, cbData);
866         if (data)
867             memcpy(data, pbData, cbData);
868     }
869     else
870         data = NULL;
871     if (!cbData || data)
872     {
873         PWINE_CERT_PROPERTY prop;
874
875         EnterCriticalSection(&context->cs);
876         LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
877          WINE_CERT_PROPERTY, entry)
878         {
879             if (prop->hdr.propID == dwPropId)
880                 break;
881         }
882         if (prop && prop->entry.next != &context->extendedProperties)
883         {
884             HeapFree(GetProcessHeap(), 0, prop->pbData);
885             prop->hdr.cb = cbData;
886             prop->pbData = cbData ? data : NULL;
887             ret = TRUE;
888         }
889         else
890         {
891             prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
892             if (prop)
893             {
894                 prop->hdr.propID = dwPropId;
895                 prop->hdr.unknown = 1;
896                 prop->hdr.cb = cbData;
897                 list_init(&prop->entry);
898                 prop->pbData = cbData ? data : NULL;
899                 list_add_tail(&context->extendedProperties, &prop->entry);
900                 ret = TRUE;
901             }
902             else
903                 HeapFree(GetProcessHeap(), 0, data);
904         }
905         LeaveCriticalSection(&context->cs);
906     }
907     return ret;
908 }
909
910 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
911  PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
912 {
913     BOOL ret = FALSE;
914
915     TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
916
917     if (!pvData)
918     {
919         PWINE_CERT_PROPERTY prop, next;
920
921         EnterCriticalSection(&context->cs);
922         LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
923          WINE_CERT_PROPERTY, entry)
924         {
925             if (prop->hdr.propID == dwPropId)
926             {
927                 list_remove(&prop->entry);
928                 HeapFree(GetProcessHeap(), 0, prop->pbData);
929                 HeapFree(GetProcessHeap(), 0, prop);
930             }
931         }
932         LeaveCriticalSection(&context->cs);
933         ret = TRUE;
934     }
935     else
936     {
937         switch (dwPropId)
938         {
939         case CERT_AUTO_ENROLL_PROP_ID:
940         case CERT_CTL_USAGE_PROP_ID:
941         case CERT_DESCRIPTION_PROP_ID:
942         case CERT_FRIENDLY_NAME_PROP_ID:
943         case CERT_HASH_PROP_ID:
944         case CERT_KEY_IDENTIFIER_PROP_ID:
945         case CERT_MD5_HASH_PROP_ID:
946         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
947         case CERT_PUBKEY_ALG_PARA_PROP_ID:
948         case CERT_PVK_FILE_PROP_ID:
949         case CERT_SIGNATURE_HASH_PROP_ID:
950         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
951         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
952         case CERT_ENROLLMENT_PROP_ID:
953         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
954         case CERT_RENEWAL_PROP_ID:
955         {
956             PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
957
958             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
959              blob->pbData, blob->cbData);
960             break;
961         }
962         case CERT_DATE_STAMP_PROP_ID:
963             ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
964              pvData, sizeof(FILETIME));
965             break;
966         default:
967             FIXME("%ld: stub\n", dwPropId);
968         }
969     }
970     TRACE("returning %d\n", ret);
971     return ret;
972 }
973
974 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
975  DWORD dwPropId, DWORD dwFlags, const void *pvData)
976 {
977     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
978     BOOL ret;
979
980     TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
981
982     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
983      * crashes on most of these, I'll be safer.
984      */
985     switch (dwPropId)
986     {
987     case 0:
988     case CERT_ACCESS_STATE_PROP_ID:
989     case CERT_CERT_PROP_ID:
990     case CERT_CRL_PROP_ID:
991     case CERT_CTL_PROP_ID:
992         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
993         return FALSE;
994     }
995     ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
996      dwFlags, pvData);
997     TRACE("returning %d\n", ret);
998     return ret;
999 }
1000
1001 /* Only the reference portion of the context is duplicated.  The returned
1002  * context has the cert store set to 0, to prevent the store's certificate free
1003  * function from getting called on partial data.
1004  * FIXME: is this okay?  Needs a test.
1005  */
1006 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
1007  PCCERT_CONTEXT pCertContext)
1008 {
1009     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
1010
1011     TRACE("(%p)\n", pCertContext);
1012     if (ref)
1013     {
1014         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
1015         if (ret)
1016         {
1017             memcpy(ret, ref, sizeof(*ret));
1018             ret->cert.hCertStore = 0;
1019             InterlockedIncrement(&ret->context->ref);
1020         }
1021     }
1022     else
1023         ret = NULL;
1024     return (PCCERT_CONTEXT)ret;
1025 }
1026
1027 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
1028  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
1029  PCCERT_CONTEXT *ppStoreContext)
1030 {
1031     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1032     PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1033     PWINE_CERT_CONTEXT cert;
1034     BOOL ret;
1035
1036     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
1037      dwAddDisposition, ppStoreContext);
1038
1039     /* FIXME: some tests needed to verify return codes */
1040     if (!store)
1041     {
1042         SetLastError(ERROR_INVALID_PARAMETER);
1043         return FALSE;
1044     }
1045     if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1046     {
1047         SetLastError(ERROR_INVALID_PARAMETER);
1048         return FALSE;
1049     }
1050
1051     cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
1052      ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
1053     if (cert)
1054     {
1055         PWINE_CERT_PROPERTY prop;
1056
1057         ret = TRUE;
1058         EnterCriticalSection(&ref->context->cs);
1059         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1060          WINE_CERT_PROPERTY, entry)
1061         {
1062             ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
1063              prop->pbData, prop->hdr.cb);
1064             if (!ret)
1065                 break;
1066         }
1067         LeaveCriticalSection(&ref->context->cs);
1068         if (ret)
1069         {
1070             ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
1071             if (ret && ppStoreContext)
1072                 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
1073                  hCertStore);
1074         }
1075         if (!ret)
1076             CRYPT_FreeCert(cert);
1077     }
1078     else
1079         ret = FALSE;
1080     return ret;
1081 }
1082
1083 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
1084  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
1085  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
1086 {
1087     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1088     BOOL ret;
1089
1090     TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
1091      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
1092
1093     if (!hcs)
1094         ret = FALSE;
1095     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1096         ret = FALSE;
1097     else
1098     {
1099         PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
1100          dwCertEncodingType, pbCertEncoded, cbCertEncoded);
1101
1102         if (cert)
1103         {
1104             ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
1105             if (ret && ppCertContext)
1106                 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
1107                  hCertStore);
1108             if (!ret)
1109                 CRYPT_FreeCert(cert);
1110         }
1111         else
1112             ret = FALSE;
1113     }
1114     return ret;
1115 }
1116
1117 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1118  PCCERT_CONTEXT pPrev)
1119 {
1120     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1121     PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
1122     PCCERT_CONTEXT ret;
1123
1124     TRACE("(%p, %p)\n", hCertStore, pPrev);
1125     if (!hCertStore)
1126         ret = NULL;
1127     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1128         ret = NULL;
1129     else
1130         ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
1131     return ret;
1132 }
1133
1134 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1135 {
1136     BOOL ret;
1137
1138     TRACE("(%p)\n", pCertContext);
1139
1140     if (!pCertContext)
1141         ret = TRUE;
1142     else if (!pCertContext->hCertStore)
1143         ret = TRUE;
1144     else
1145     {
1146         PWINECRYPT_CERTSTORE hcs =
1147          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1148
1149         if (!hcs)
1150             ret = TRUE;
1151         else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1152             ret = FALSE;
1153         else
1154             ret = hcs->deleteCert(hcs, pCertContext, 0);
1155     }
1156     return ret;
1157 }
1158
1159 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
1160  DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
1161  DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
1162 {
1163     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1164      dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
1165      ppCrlContext);
1166     return FALSE;
1167 }
1168
1169 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
1170              PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
1171              PCCRL_CONTEXT* ppStoreContext )
1172 {
1173     FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
1174           dwAddDisposition, ppStoreContext);
1175     return TRUE;
1176 }
1177
1178 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
1179 {
1180     FIXME("%p\n", pCrlContext );
1181
1182     return TRUE;
1183 }
1184
1185 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
1186 {
1187     FIXME("(%p): stub\n", pCrlContext);
1188     return TRUE;
1189 }
1190
1191 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
1192  PCCRL_CONTEXT pPrev)
1193 {
1194     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1195     return NULL;
1196 }
1197
1198 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
1199   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
1200 {
1201     FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
1202      cbCtlEncoded);
1203     return NULL;
1204 }
1205
1206 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
1207  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
1208  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
1209 {
1210     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
1211      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
1212      ppCtlContext);
1213     return FALSE;
1214 }
1215
1216 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
1217  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
1218  PCCTL_CONTEXT* ppStoreContext)
1219 {
1220     FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
1221      dwAddDisposition, ppStoreContext);
1222     return TRUE;
1223 }
1224
1225 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
1226 {
1227     FIXME("(%p): stub\n", pCtlContext );
1228     return TRUE;
1229 }
1230
1231 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
1232 {
1233     FIXME("(%p): stub\n", pCtlContext);
1234     return TRUE;
1235 }
1236
1237 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
1238  PCCTL_CONTEXT pPrev)
1239 {
1240     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
1241     return NULL;
1242 }
1243
1244
1245 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1246 {
1247     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
1248
1249     TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
1250
1251     if( ! hCertStore )
1252         return TRUE;
1253
1254     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
1255         return FALSE;
1256
1257     if (InterlockedDecrement(&hcs->ref) == 0)
1258     {
1259         TRACE("freeing %p\n", hcs);
1260         hcs->dwMagic = 0;
1261         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
1262             CryptReleaseContext(hcs->cryptProv, 0);
1263         hcs->closeStore(hcs, dwFlags);
1264     }
1265     else
1266         TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
1267     return TRUE;
1268 }
1269
1270 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
1271  DWORD dwCtrlType, void const *pvCtrlPara)
1272 {
1273     FIXME("(%p, %08lx, %ld, %p): stub\n", hCertStore, dwFlags, dwCtrlType,
1274      pvCtrlPara);
1275     return TRUE;
1276 }
1277
1278 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1279  DWORD dwPropId, void *pvData, DWORD *pcbData)
1280 {
1281     FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
1282     return FALSE;
1283 }
1284
1285 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
1286  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1287 {
1288     FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
1289      pvData);
1290     return FALSE;
1291 }
1292
1293 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
1294  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1295 {
1296     FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
1297      pcbElement);
1298     return FALSE;
1299 }
1300
1301 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1302  DWORD dwPropId, void *pvData, DWORD *pcbData)
1303 {
1304     FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
1305     return FALSE;
1306 }
1307
1308 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
1309  DWORD dwPropId, DWORD dwFlags, const void *pvData)
1310 {
1311     FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
1312      pvData);
1313     return FALSE;
1314 }
1315
1316 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
1317  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1318 {
1319     FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
1320      pcbElement);
1321     return FALSE;
1322 }
1323
1324 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
1325  DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
1326 {
1327     BOOL ret;
1328
1329     TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
1330      pcbElement);
1331
1332     if (pCertContext)
1333     {
1334         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1335         DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
1336          pCertContext->cbCertEncoded;
1337         PWINE_CERT_PROPERTY prop;
1338
1339         EnterCriticalSection(&ref->context->cs);
1340         LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1341          WINE_CERT_PROPERTY, entry)
1342             bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
1343         if (!pbElement)
1344         {
1345             *pcbElement = bytesNeeded;
1346             ret = TRUE;
1347         }
1348         else if (*pcbElement < bytesNeeded)
1349         {
1350             *pcbElement = bytesNeeded;
1351             SetLastError(ERROR_MORE_DATA);
1352             ret = FALSE;
1353         }
1354         else
1355         {
1356             PWINE_CERT_PROP_HEADER hdr;
1357
1358             LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
1359              WINE_CERT_PROPERTY, entry)
1360             {
1361                 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
1362                 pbElement += sizeof(WINE_CERT_PROP_HEADER);
1363                 if (prop->hdr.cb)
1364                 {
1365                     memcpy(pbElement, prop->pbData, prop->hdr.cb);
1366                     pbElement += prop->hdr.cb;
1367                 }
1368             }
1369             hdr = (PWINE_CERT_PROP_HEADER)pbElement;
1370             hdr->propID = CERT_CERT_PROP_ID;
1371             hdr->unknown = 1;
1372             hdr->cb = pCertContext->cbCertEncoded;
1373             memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
1374              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
1375             ret = TRUE;
1376         }
1377         LeaveCriticalSection(&ref->context->cs);
1378     }
1379     else
1380         ret = FALSE;
1381     return ret;
1382 }
1383
1384 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
1385  const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
1386  DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
1387 {
1388     FIXME("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p): stub\n", hCertStore,
1389      pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
1390      pdwContentType, ppvContext);
1391     return FALSE;
1392 }
1393
1394 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
1395 {
1396     TRACE("(%p)\n", pCertContext);
1397
1398     if (pCertContext)
1399     {
1400         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1401         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
1402
1403         if (InterlockedDecrement(&ref->context->ref) == 0)
1404         {
1405             TRACE("freeing %p\n", ref->context);
1406             CRYPT_FreeCert(ref->context);
1407         }
1408         else
1409             TRACE("%p's ref count is %ld\n", ref->context,
1410              ref->context->ref);
1411         if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
1412          store->freeCert)
1413             store->freeCert(ref);
1414         HeapFree(GetProcessHeap(), 0, ref);
1415     }
1416     return TRUE;
1417 }
1418
1419 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1420                 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
1421                 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
1422 {
1423     FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
1424         dwFlags, dwType, pvPara, pPrevCertContext);
1425     SetLastError(CRYPT_E_NOT_FOUND);
1426     return NULL;
1427 }
1428
1429 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
1430  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
1431 {
1432     FIXME("(%p, %p, %08lx, %ld): stub\n", hCollectionStore, hSiblingStore,
1433      dwUpdateFlags, dwPriority);
1434     return TRUE;
1435 }
1436
1437 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
1438  HCERTSTORE hSiblingStore)
1439 {
1440     FIXME("(%p, %p): stub\n", hCollectionStore, hSiblingStore);
1441 }
1442
1443 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1444  CRYPT_ATTRIBUTE rgAttr[])
1445 {
1446     PCRYPT_ATTRIBUTE ret = NULL;
1447     DWORD i;
1448
1449     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1450
1451     if (!cAttr)
1452         return NULL;
1453     if (!pszObjId)
1454     {
1455         SetLastError(ERROR_INVALID_PARAMETER);
1456         return NULL;
1457     }
1458
1459     for (i = 0; !ret && i < cAttr; i++)
1460         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1461             ret = &rgAttr[i];
1462     return ret;
1463 }
1464
1465 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1466  CERT_EXTENSION rgExtensions[])
1467 {
1468     PCERT_EXTENSION ret = NULL;
1469     DWORD i;
1470
1471     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1472
1473     if (!cExtensions)
1474         return NULL;
1475     if (!pszObjId)
1476     {
1477         SetLastError(ERROR_INVALID_PARAMETER);
1478         return NULL;
1479     }
1480
1481     for (i = 0; !ret && i < cExtensions; i++)
1482         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1483          rgExtensions[i].pszObjId))
1484             ret = &rgExtensions[i];
1485     return ret;
1486 }
1487
1488 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1489 {
1490     PCERT_RDN_ATTR ret = NULL;
1491     DWORD i, j;
1492
1493     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1494
1495     if (!pszObjId)
1496     {
1497         SetLastError(ERROR_INVALID_PARAMETER);
1498         return NULL;
1499     }
1500
1501     for (i = 0; !ret && i < pName->cRDN; i++)
1502         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1503             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1504              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1505                 ret = &pName->rgRDN[i].rgRDNAttr[j];
1506     return ret;
1507 }
1508
1509 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1510  PCERT_INFO pCertInfo)
1511 {
1512     FILETIME fileTime;
1513     LONG ret;
1514
1515     if (!pTimeToVerify)
1516     {
1517         SYSTEMTIME sysTime;
1518
1519         GetSystemTime(&sysTime);
1520         SystemTimeToFileTime(&sysTime, &fileTime);
1521         pTimeToVerify = &fileTime;
1522     }
1523     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1524     {
1525         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1526         if (ret < 0)
1527             ret = 0;
1528     }
1529     return ret;
1530 }
1531
1532 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
1533  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1534  DWORD *pcbComputedHash)
1535 {
1536     BOOL ret = TRUE;
1537     HCRYPTHASH hHash = 0;
1538
1539     TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
1540      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
1541
1542     if (!hCryptProv)
1543         hCryptProv = CRYPT_GetDefaultProvider();
1544     if (!Algid)
1545         Algid = CALG_SHA1;
1546     if (ret)
1547     {
1548         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1549         if (ret)
1550         {
1551             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
1552             if (ret)
1553                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1554                  pcbComputedHash, 0);
1555             CryptDestroyHash(hHash);
1556         }
1557     }
1558     return ret;
1559 }