- implement system stores
[wine/dcerpc.git] / dlls / crypt32 / cert.c
blob86080b40461f1a7bfb76288c6b63c43fd135a942
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004,2005 Juan Lang
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.
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.
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
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.
30 #include <assert.h>
31 #include <stdarg.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "winuser.h"
37 #include "wincrypt.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
40 #include "excpt.h"
41 #include "wine/exception.h"
42 #include "crypt32_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
46 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 /* The following aren't defined in wincrypt.h, as they're "reserved" */
48 #define CERT_CERT_PROP_ID 32
49 #define CERT_CRL_PROP_ID 33
50 #define CERT_CTL_PROP_ID 34
52 /* Some typedefs that make it easier to abstract which type of context we're
53 * working with.
55 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
56 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
57 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
58 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
59 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
60 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
61 DWORD dwAddDisposition, const void **ppContext);
62 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
63 const void *pPrevContext);
64 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
65 DWORD dwPropID, void *pvData, DWORD *pcbData);
66 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
67 DWORD dwPropID, DWORD dwFlags, const void *pvData);
68 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
69 BYTE *pbElement, DWORD *pcbElement);
70 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
71 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
73 /* An abstract context (certificate, CRL, or CTL) interface */
74 typedef struct _WINE_CONTEXT_INTERFACE
76 CreateContextFunc create;
77 AddContextToStoreFunc addContextToStore;
78 AddEncodedContextToStoreFunc addEncodedToStore;
79 EnumContextsInStoreFunc enumContextsInStore;
80 GetContextPropertyFunc getProp;
81 SetContextPropertyFunc setProp;
82 SerializeElementFunc serialize;
83 FreeContextFunc free;
84 DeleteContextFunc deleteFromStore;
85 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
87 static const WINE_CONTEXT_INTERFACE gCertInterface = {
88 (CreateContextFunc)CertCreateCertificateContext,
89 (AddContextToStoreFunc)CertAddCertificateContextToStore,
90 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
91 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
92 (GetContextPropertyFunc)CertGetCertificateContextProperty,
93 (SetContextPropertyFunc)CertSetCertificateContextProperty,
94 (SerializeElementFunc)CertSerializeCertificateStoreElement,
95 (FreeContextFunc)CertFreeCertificateContext,
96 (DeleteContextFunc)CertDeleteCertificateFromStore,
99 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
100 (CreateContextFunc)CertCreateCRLContext,
101 (AddContextToStoreFunc)CertAddCRLContextToStore,
102 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
103 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
104 (GetContextPropertyFunc)CertGetCRLContextProperty,
105 (SetContextPropertyFunc)CertSetCRLContextProperty,
106 (SerializeElementFunc)CertSerializeCRLStoreElement,
107 (FreeContextFunc)CertFreeCRLContext,
108 (DeleteContextFunc)CertDeleteCRLFromStore,
111 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
112 (CreateContextFunc)CertCreateCTLContext,
113 (AddContextToStoreFunc)CertAddCTLContextToStore,
114 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
115 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
116 (GetContextPropertyFunc)CertGetCTLContextProperty,
117 (SetContextPropertyFunc)CertSetCTLContextProperty,
118 (SerializeElementFunc)CertSerializeCTLStoreElement,
119 (FreeContextFunc)CertFreeCTLContext,
120 (DeleteContextFunc)CertDeleteCTLFromStore,
123 struct WINE_CRYPTCERTSTORE;
125 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
126 DWORD dwFlags, const void *pvPara);
128 struct _WINE_CERT_CONTEXT_REF;
130 /* Called to enumerate the next certificate in a store. The returned pointer
131 * must be newly allocated (via HeapAlloc): CertFreeCertificateContext frees
132 * it.
134 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
135 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
137 struct _WINE_CERT_CONTEXT;
139 /* Called to create a new reference to an existing cert context. Should call
140 * CRYPT_InitCertRef to make sure the reference count is properly updated.
141 * If the store does not provide any additional allocated data (that is, does
142 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
143 * this.
145 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
146 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
148 /* Optional, called when a cert context reference is being freed. Don't free
149 * the ref pointer itself, CertFreeCertificateContext does that.
151 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
153 typedef enum _CertStoreType {
154 StoreTypeMem,
155 StoreTypeCollection,
156 StoreTypeReg,
157 StoreTypeDummy,
158 } CertStoreType;
160 /* A cert store is polymorphic through the use of function pointers. A type
161 * is still needed to distinguish collection stores from other types.
162 * On the function pointers:
163 * - closeStore is called when the store's ref count becomes 0
164 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
165 * - control is optional, but should be implemented by any store that supports
166 * persistence
168 typedef struct WINE_CRYPTCERTSTORE
170 DWORD dwMagic;
171 LONG ref;
172 DWORD dwOpenFlags;
173 HCRYPTPROV cryptProv;
174 CertStoreType type;
175 PFN_CERT_STORE_PROV_CLOSE closeStore;
176 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
177 CreateRefFunc createCertRef;
178 EnumCertFunc enumCert;
179 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
180 FreeCertFunc freeCert; /* optional */
181 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
182 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
184 /* A certificate context has pointers to data that are owned by this module,
185 * so rather than duplicate the data every time a certificate context is
186 * copied, I keep a reference count to the data. Thus I have two data
187 * structures, the "true" certificate context (that has the reference count)
188 * and a reference certificate context, that has a pointer to the true context.
189 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
190 * with the reference version.
192 typedef struct _WINE_CERT_CONTEXT
194 CERT_CONTEXT cert;
195 LONG ref;
196 CRITICAL_SECTION cs;
197 struct list extendedProperties;
198 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
200 typedef struct _WINE_CERT_CONTEXT_REF
202 CERT_CONTEXT cert;
203 WINE_CERT_CONTEXT *context;
204 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
206 /* An extended certificate property in serialized form is prefixed by this
207 * header.
209 typedef struct _WINE_CERT_PROP_HEADER
211 DWORD propID;
212 DWORD unknown; /* always 1 */
213 DWORD cb;
214 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
216 /* Stores an extended property in a cert. */
217 typedef struct _WINE_CERT_PROPERTY
219 WINE_CERT_PROP_HEADER hdr;
220 LPBYTE pbData;
221 struct list entry;
222 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
224 /* A mem store has a list of these. They're also returned by the mem store
225 * during enumeration.
227 typedef struct _WINE_CERT_LIST_ENTRY
229 WINE_CERT_CONTEXT_REF cert;
230 struct list entry;
231 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
233 typedef struct _WINE_MEMSTORE
235 WINECRYPT_CERTSTORE hdr;
236 CRITICAL_SECTION cs;
237 struct list certs;
238 } WINE_MEMSTORE, *PWINE_MEMSTORE;
240 typedef struct _WINE_HASH_TO_DELETE
242 BYTE hash[20];
243 struct list entry;
244 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
246 /* Returned by a reg store during enumeration. */
247 typedef struct _WINE_REG_CERT_CONTEXT
249 WINE_CERT_CONTEXT_REF cert;
250 PWINE_CERT_CONTEXT_REF childContext;
251 } WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT;
253 typedef struct _WINE_REGSTORE
255 WINECRYPT_CERTSTORE hdr;
256 PWINECRYPT_CERTSTORE memStore;
257 HKEY key;
258 BOOL dirty;
259 CRITICAL_SECTION cs;
260 struct list certsToDelete;
261 } WINE_REGSTORE, *PWINE_REGSTORE;
263 typedef struct _WINE_STORE_LIST_ENTRY
265 PWINECRYPT_CERTSTORE store;
266 DWORD dwUpdateFlags;
267 DWORD dwPriority;
268 struct list entry;
269 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
271 /* Returned by a collection store during enumeration.
272 * Note: relies on the list entry being valid after use, which a number of
273 * conditions might make untrue (reentrancy, closing a collection store before
274 * continuing an enumeration on it, ...). The tests seem to indicate this
275 * sort of unsafety is okay, since Windows isn't well-behaved in these
276 * scenarios either.
278 typedef struct _WINE_COLLECTION_CERT_CONTEXT
280 WINE_CERT_CONTEXT_REF cert;
281 PWINE_STORE_LIST_ENTRY entry;
282 PWINE_CERT_CONTEXT_REF childContext;
283 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
285 typedef struct _WINE_COLLECTIONSTORE
287 WINECRYPT_CERTSTORE hdr;
288 CRITICAL_SECTION cs;
289 struct list stores;
290 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
292 /* Like CertGetCertificateContextProperty, but operates directly on the
293 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
294 * are handled by CertGetCertificateContextProperty, and are particular to the
295 * store in which the property exists (which is separate from the context.)
297 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
298 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
300 /* Like CertSetCertificateContextProperty, but operates directly on the
301 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
302 * CertSetCertificateContextProperty anyway.
304 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
305 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
307 /* Helper function for store reading functions and
308 * CertAddSerializedElementToStore. Returns a context of the appropriate type
309 * if it can, or NULL otherwise. Doesn't validate any of the properties in
310 * the serialized context (for example, bad hashes are retained.)
311 * *pdwContentType is set to the type of the returned context.
313 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
314 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
316 /* filter for page-fault exceptions */
317 static WINE_EXCEPTION_FILTER(page_fault)
319 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
320 return EXCEPTION_EXECUTE_HANDLER;
321 return EXCEPTION_CONTINUE_SEARCH;
324 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
325 DWORD dwFlags, CertStoreType type)
327 store->ref = 1;
328 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
329 store->type = type;
330 if (!hCryptProv)
332 hCryptProv = CRYPT_GetDefaultProvider();
333 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
335 store->cryptProv = hCryptProv;
336 store->dwOpenFlags = dwFlags;
339 /* Initializes the reference ref to point to pCertContext, which is assumed to
340 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
341 * Also sets the hCertStore member of the reference to store.
343 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
344 PWINE_CERT_CONTEXT context, HCERTSTORE store)
346 TRACE("(%p, %p)\n", ref, context);
347 memcpy(&ref->cert, context, sizeof(ref->cert));
348 ref->context = context;
349 InterlockedIncrement(&context->ref);
350 ref->cert.hCertStore = store;
353 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
354 HCERTSTORE store)
356 PWINE_CERT_CONTEXT_REF pCertRef = HeapAlloc(GetProcessHeap(), 0,
357 sizeof(WINE_CERT_CONTEXT_REF));
359 if (pCertRef)
360 CRYPT_InitCertRef(pCertRef, context, store);
361 return pCertRef;
364 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
365 DWORD dwAddDisposition)
367 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
368 BOOL add = FALSE, ret;
370 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
372 switch (dwAddDisposition)
374 case CERT_STORE_ADD_ALWAYS:
375 add = TRUE;
376 break;
377 case CERT_STORE_ADD_NEW:
379 BYTE hashToAdd[20], hash[20];
380 DWORD size = sizeof(hashToAdd);
382 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
383 CERT_HASH_PROP_ID, hashToAdd, &size);
384 if (ret)
386 PWINE_CERT_LIST_ENTRY cursor;
388 /* Add if no cert with the same hash is found. */
389 add = TRUE;
390 EnterCriticalSection(&ms->cs);
391 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
393 size = sizeof(hash);
394 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
395 CERT_HASH_PROP_ID, hash, &size);
396 if (ret && !memcmp(hashToAdd, hash, size))
398 TRACE("found matching certificate, not adding\n");
399 SetLastError(CRYPT_E_EXISTS);
400 add = FALSE;
401 break;
404 LeaveCriticalSection(&ms->cs);
406 break;
408 case CERT_STORE_ADD_REPLACE_EXISTING:
410 BYTE hashToAdd[20], hash[20];
411 DWORD size = sizeof(hashToAdd);
413 add = TRUE;
414 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
415 CERT_HASH_PROP_ID, hashToAdd, &size);
416 if (ret)
418 PWINE_CERT_LIST_ENTRY cursor, next;
420 /* Look for existing cert to delete */
421 EnterCriticalSection(&ms->cs);
422 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &ms->certs,
423 WINE_CERT_LIST_ENTRY, entry)
425 size = sizeof(hash);
426 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
427 CERT_HASH_PROP_ID, hash, &size);
428 if (ret && !memcmp(hashToAdd, hash, size))
430 TRACE("found matching certificate, replacing\n");
431 list_remove(&cursor->entry);
432 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
433 break;
436 LeaveCriticalSection(&ms->cs);
438 break;
440 default:
441 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
442 add = FALSE;
444 if (add)
446 PWINE_CERT_LIST_ENTRY entry = HeapAlloc(GetProcessHeap(), 0,
447 sizeof(WINE_CERT_LIST_ENTRY));
449 if (entry)
451 TRACE("adding %p\n", entry);
452 CRYPT_InitCertRef(&entry->cert, (PWINE_CERT_CONTEXT)pCert, store);
453 list_init(&entry->entry);
454 EnterCriticalSection(&ms->cs);
455 list_add_tail(&ms->certs, &entry->entry);
456 LeaveCriticalSection(&ms->cs);
457 ret = TRUE;
459 else
460 ret = FALSE;
462 else
463 ret = FALSE;
464 return ret;
467 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
468 PWINE_CERT_CONTEXT_REF pPrev)
470 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
471 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
472 struct list *listNext;
474 TRACE("(%p, %p)\n", store, pPrev);
475 EnterCriticalSection(&ms->cs);
476 if (prevEntry)
478 listNext = list_next(&ms->certs, &prevEntry->entry);
479 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
481 else
482 listNext = list_next(&ms->certs, &ms->certs);
483 if (listNext)
485 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY));
486 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
487 sizeof(WINE_CERT_LIST_ENTRY));
488 InterlockedIncrement(&ret->cert.context->ref);
490 else
492 SetLastError(CRYPT_E_NOT_FOUND);
493 ret = NULL;
495 LeaveCriticalSection(&ms->cs);
497 TRACE("returning %p\n", ret);
498 return (PWINE_CERT_CONTEXT_REF)ret;
501 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
502 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
504 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
505 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
506 PWINE_CERT_LIST_ENTRY cert, next;
507 BOOL ret;
509 /* Find the entry associated with the passed-in context, since the
510 * passed-in context may not be a list entry itself (e.g. if it came from
511 * CertDuplicateCertificateContext.) Pointing to the same context is
512 * a sufficient test of equality.
514 EnterCriticalSection(&store->cs);
515 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
516 entry)
518 if (cert->cert.context == ref->context)
520 TRACE("removing %p\n", cert);
521 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
522 * protected.
524 list_remove(&cert->entry);
525 cert->entry.prev = cert->entry.next = &store->certs;
526 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
527 break;
530 ret = TRUE;
531 LeaveCriticalSection(&store->cs);
532 return ret;
535 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
537 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
538 PWINE_CERT_LIST_ENTRY cert, next;
540 TRACE("(%p, %08lx)\n", store, dwFlags);
541 if (dwFlags)
542 FIXME("Unimplemented flags: %08lx\n", dwFlags);
544 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
545 * pointer if its ref-count reaches zero. That's okay here because there
546 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
547 * of the CertListEntry.
549 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
550 entry)
552 TRACE("removing %p\n", cert);
553 list_remove(&cert->entry);
554 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
556 DeleteCriticalSection(&store->cs);
557 HeapFree(GetProcessHeap(), 0, store);
560 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
561 DWORD dwFlags, const void *pvPara)
563 PWINE_MEMSTORE store;
565 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
567 if (dwFlags & CERT_STORE_DELETE_FLAG)
569 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
570 store = NULL;
572 else
574 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
575 sizeof(WINE_MEMSTORE));
576 if (store)
578 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
579 store->hdr.closeStore = CRYPT_MemCloseStore;
580 store->hdr.addCert = CRYPT_MemAddCert;
581 store->hdr.createCertRef = CRYPT_CreateCertRef;
582 store->hdr.enumCert = CRYPT_MemEnumCert;
583 store->hdr.deleteCert = CRYPT_MemDeleteCert;
584 store->hdr.freeCert = NULL;
585 InitializeCriticalSection(&store->cs);
586 list_init(&store->certs);
589 return (PWINECRYPT_CERTSTORE)store;
592 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
593 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
595 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
596 PWINE_STORE_LIST_ENTRY entry, next;
597 BOOL ret;
599 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
601 ret = FALSE;
602 EnterCriticalSection(&cs->cs);
603 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
604 entry)
606 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
608 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
609 break;
612 LeaveCriticalSection(&cs->cs);
613 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
614 return ret;
617 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
618 PWINE_CERT_CONTEXT context, HCERTSTORE store)
620 PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
621 sizeof(WINE_COLLECTION_CERT_CONTEXT));
623 if (ret)
625 /* Initialize to empty for now, just make sure the size is right */
626 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
627 ret->entry = NULL;
628 ret->childContext = NULL;
630 return (PWINE_CERT_CONTEXT_REF)ret;
633 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
635 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
636 PWINE_STORE_LIST_ENTRY entry, next;
638 TRACE("(%p, %08lx)\n", store, dwFlags);
640 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
641 entry)
643 TRACE("closing %p\n", entry);
644 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
645 HeapFree(GetProcessHeap(), 0, entry);
647 DeleteCriticalSection(&cs->cs);
648 HeapFree(GetProcessHeap(), 0, cs);
651 /* Advances a collection enumeration by one cert, if possible, where advancing
652 * means:
653 * - calling the current store's enumeration function once, and returning
654 * the enumerated cert if one is returned
655 * - moving to the next store if the current store has no more items, and
656 * recursively calling itself to get the next item.
657 * Returns NULL if the collection contains no more items or on error.
658 * Assumes the collection store's lock is held.
660 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
661 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
662 PWINE_COLLECTION_CERT_CONTEXT pPrev)
664 PWINE_COLLECTION_CERT_CONTEXT ret;
665 PWINE_CERT_CONTEXT_REF child;
667 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
669 if (pPrev)
671 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
672 pPrev->childContext);
673 if (child)
675 ret = pPrev;
676 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
677 ret->cert.cert.hCertStore = (HCERTSTORE)store;
678 InterlockedIncrement(&ret->cert.context->ref);
679 ret->childContext = child;
681 else
683 struct list *storeNext = list_next(&store->stores,
684 &storeEntry->entry);
686 pPrev->childContext = NULL;
687 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
688 if (storeNext)
690 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
691 entry);
692 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
694 else
696 SetLastError(CRYPT_E_NOT_FOUND);
697 ret = NULL;
701 else
703 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
704 NULL);
705 if (child)
707 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
708 child->context, store);
709 if (ret)
711 ret->entry = storeEntry;
712 ret->childContext = child;
714 else
715 CertFreeCertificateContext((PCCERT_CONTEXT)child);
717 else
719 struct list *storeNext = list_next(&store->stores,
720 &storeEntry->entry);
722 if (storeNext)
724 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
725 entry);
726 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
728 else
730 SetLastError(CRYPT_E_NOT_FOUND);
731 ret = NULL;
735 TRACE("returning %p\n", ret);
736 return ret;
739 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
740 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
742 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
743 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
744 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
746 TRACE("(%p, %p)\n", store, pPrev);
748 if (prevEntry)
750 EnterCriticalSection(&cs->cs);
751 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
752 LeaveCriticalSection(&cs->cs);
754 else
756 EnterCriticalSection(&cs->cs);
757 if (!list_empty(&cs->stores))
759 PWINE_STORE_LIST_ENTRY storeEntry;
761 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
762 entry);
763 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
765 else
767 SetLastError(CRYPT_E_NOT_FOUND);
768 ret = NULL;
770 LeaveCriticalSection(&cs->cs);
772 TRACE("returning %p\n", ret);
773 return (PWINE_CERT_CONTEXT_REF)ret;
776 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
777 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
779 PWINE_COLLECTION_CERT_CONTEXT context =
780 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
781 BOOL ret;
783 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
785 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
786 if (ret)
788 context->childContext = NULL;
789 CertFreeCertificateContext((PCCERT_CONTEXT)context);
791 return ret;
794 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
796 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
798 TRACE("(%p)\n", ref);
800 if (context->childContext)
801 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
804 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
805 DWORD dwFlags, const void *pvPara)
807 PWINE_COLLECTIONSTORE store;
809 if (dwFlags & CERT_STORE_DELETE_FLAG)
811 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
812 store = NULL;
814 else
816 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
817 sizeof(WINE_COLLECTIONSTORE));
818 if (store)
820 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
821 StoreTypeCollection);
822 store->hdr.closeStore = CRYPT_CollectionCloseStore;
823 store->hdr.addCert = CRYPT_CollectionAddCert;
824 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
825 store->hdr.enumCert = CRYPT_CollectionEnumCert;
826 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
827 store->hdr.freeCert = CRYPT_CollectionFreeCert;
828 InitializeCriticalSection(&store->cs);
829 list_init(&store->stores);
832 return (PWINECRYPT_CERTSTORE)store;
835 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
837 static const WCHAR fmt[] = { '%','0','2','X',0 };
838 DWORD i;
840 assert(hash);
841 assert(asciiHash);
843 for (i = 0; i < 20; i++)
844 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
847 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
848 0 };
849 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
850 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
851 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
853 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
854 DWORD contextType)
856 LONG rc;
857 DWORD index = 0;
858 WCHAR subKeyName[MAX_PATH];
860 do {
861 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
863 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
864 NULL);
865 if (!rc)
867 HKEY subKey;
869 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
870 if (!rc)
872 LPBYTE buf = NULL;
874 size = 0;
875 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
876 if (!rc)
877 buf = HeapAlloc(GetProcessHeap(), 0, size);
878 if (buf)
880 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
881 &size);
882 if (!rc)
884 const void *context;
885 DWORD addedType;
887 TRACE("Adding cert with hash %s\n",
888 debugstr_w(subKeyName));
889 context = CRYPT_ReadSerializedElement(buf, size,
890 contextType, &addedType);
891 if (context)
893 const WINE_CONTEXT_INTERFACE *contextInterface;
894 BYTE hash[20];
896 switch (addedType)
898 case CERT_STORE_CERTIFICATE_CONTEXT:
899 contextInterface = &gCertInterface;
900 break;
901 case CERT_STORE_CRL_CONTEXT:
902 contextInterface = &gCRLInterface;
903 break;
904 case CERT_STORE_CTL_CONTEXT:
905 contextInterface = &gCTLInterface;
906 break;
907 default:
908 contextInterface = NULL;
910 if (contextInterface)
912 size = sizeof(hash);
913 if (contextInterface->getProp(context,
914 CERT_HASH_PROP_ID, hash, &size))
916 WCHAR asciiHash[20 * 2 + 1];
918 CRYPT_HashToStr(hash, asciiHash);
919 TRACE("comparing %s\n",
920 debugstr_w(asciiHash));
921 TRACE("with %s\n", debugstr_w(subKeyName));
922 if (!lstrcmpW(asciiHash, subKeyName))
924 TRACE("hash matches, adding\n");
925 contextInterface->addContextToStore(
926 store, context,
927 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
929 else
931 TRACE("hash doesn't match, ignoring\n");
932 contextInterface->free(context);
938 HeapFree(GetProcessHeap(), 0, buf);
940 RegCloseKey(subKey);
942 /* Ignore intermediate errors, continue enumerating */
943 rc = ERROR_SUCCESS;
945 } while (!rc);
948 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
950 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
951 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
952 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
953 DWORD i;
955 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
957 HKEY key;
958 LONG rc;
960 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
961 &key, NULL);
962 if (!rc)
964 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
965 RegCloseKey(key);
970 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
971 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
972 DWORD len)
974 WCHAR asciiHash[20 * 2 + 1];
975 LONG rc;
976 HKEY subKey;
977 BOOL ret;
979 CRYPT_HashToStr(hash, asciiHash);
980 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
981 &subKey, NULL);
982 if (!rc)
984 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
985 RegCloseKey(subKey);
987 if (!rc)
988 ret = TRUE;
989 else
991 SetLastError(rc);
992 ret = FALSE;
994 return ret;
997 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
998 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1000 const void *context = NULL;
1001 BOOL ret;
1003 do {
1004 context = contextInterface->enumContextsInStore(memStore, context);
1005 if (context)
1007 BYTE hash[20];
1008 DWORD hashSize = sizeof(hash);
1010 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1011 &hashSize);
1012 if (ret)
1014 DWORD size = 0;
1015 LPBYTE buf = NULL;
1017 ret = contextInterface->serialize(context, 0, NULL, &size);
1018 if (size)
1019 buf = HeapAlloc(GetProcessHeap(), 0, size);
1020 if (buf)
1022 ret = contextInterface->serialize(context, 0, buf, &size);
1023 if (ret)
1024 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1026 HeapFree(GetProcessHeap(), 0, buf);
1029 else
1030 ret = TRUE;
1031 } while (ret && context != NULL);
1032 if (context)
1033 contextInterface->free(context);
1034 return ret;
1037 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1039 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1040 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1041 &gCRLInterface, &gCTLInterface };
1042 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1043 BOOL ret = TRUE;
1044 DWORD i;
1046 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1048 HKEY key;
1049 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1050 KEY_ALL_ACCESS, NULL, &key, NULL);
1052 if (!rc)
1054 if (listToDelete[i])
1056 PWINE_HASH_TO_DELETE toDelete, next;
1057 WCHAR asciiHash[20 * 2 + 1];
1059 EnterCriticalSection(&store->cs);
1060 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1061 WINE_HASH_TO_DELETE, entry)
1063 LONG rc;
1065 CRYPT_HashToStr(toDelete->hash, asciiHash);
1066 TRACE("Removing %s\n", debugstr_w(asciiHash));
1067 rc = RegDeleteKeyW(key, asciiHash);
1068 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1070 SetLastError(rc);
1071 ret = FALSE;
1073 list_remove(&toDelete->entry);
1074 HeapFree(GetProcessHeap(), 0, toDelete);
1076 LeaveCriticalSection(&store->cs);
1078 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1079 store->memStore);
1080 RegCloseKey(key);
1082 else
1084 SetLastError(rc);
1085 ret = FALSE;
1088 return ret;
1091 /* If force is true or the registry store is dirty, writes the contents of the
1092 * store to the registry.
1094 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1096 BOOL ret;
1098 if (store->dirty || force)
1099 ret = CRYPT_RegWriteToReg(store);
1100 else
1101 ret = TRUE;
1102 return ret;
1105 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1107 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1109 TRACE("(%p, %08lx)\n", store, dwFlags);
1110 if (dwFlags)
1111 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1113 CRYPT_RegFlushStore(store, FALSE);
1114 /* certsToDelete should already be cleared by this point */
1115 store->memStore->closeStore(store->memStore, 0);
1116 RegCloseKey(store->key);
1117 DeleteCriticalSection(&store->cs);
1118 HeapFree(GetProcessHeap(), 0, store);
1121 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1122 DWORD dwAddDisposition)
1124 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1125 BOOL ret;
1127 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1129 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1131 SetLastError(ERROR_ACCESS_DENIED);
1132 ret = FALSE;
1134 else
1136 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1137 if (ret)
1138 store->dirty = TRUE;
1140 return ret;
1143 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1144 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1146 PWINE_REG_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
1147 sizeof(WINE_REG_CERT_CONTEXT));
1149 if (ret)
1151 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1152 ret->childContext = NULL;
1154 return (PWINE_CERT_CONTEXT_REF)ret;
1157 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1158 PWINE_CERT_CONTEXT_REF pPrev)
1160 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1161 PWINE_CERT_CONTEXT_REF child;
1162 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1164 TRACE("(%p, %p)\n", store, pPrev);
1166 if (pPrev)
1168 child = rs->memStore->enumCert(rs->memStore, prev->childContext);
1169 if (child)
1171 ret = (PWINE_REG_CERT_CONTEXT)pPrev;
1172 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1173 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1174 InterlockedIncrement(&ret->cert.context->ref);
1175 ret->childContext = child;
1178 else
1180 child = rs->memStore->enumCert(rs->memStore, NULL);
1181 if (child)
1183 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_REG_CERT_CONTEXT));
1185 if (ret)
1187 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1188 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1189 InterlockedIncrement(&ret->cert.context->ref);
1190 ret->childContext = child;
1192 else
1193 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1196 return (PWINE_CERT_CONTEXT_REF)ret;
1199 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1200 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1202 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1203 BOOL ret;
1205 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1207 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1209 SetLastError(ERROR_ACCESS_DENIED);
1210 ret = FALSE;
1212 else
1214 PWINE_HASH_TO_DELETE toDelete =
1215 HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HASH_TO_DELETE));
1217 if (toDelete)
1219 DWORD size = sizeof(toDelete->hash);
1221 ret = CertGetCertificateContextProperty(pCertContext,
1222 CERT_HASH_PROP_ID, toDelete->hash, &size);
1223 if (ret)
1225 list_init(&toDelete->entry);
1226 EnterCriticalSection(&store->cs);
1227 list_add_tail(&store->certsToDelete, &toDelete->entry);
1228 LeaveCriticalSection(&store->cs);
1229 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1230 dwFlags);
1232 else
1233 HeapFree(GetProcessHeap(), 0, toDelete);
1235 else
1236 ret = FALSE;
1237 if (ret)
1238 store->dirty = TRUE;
1240 return ret;
1243 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1245 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1247 TRACE("(%p)\n", ref);
1249 if (context->childContext)
1250 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1253 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1254 DWORD dwCtrlType, void const *pvCtrlPara)
1256 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1257 BOOL ret;
1259 switch (dwCtrlType)
1261 case CERT_STORE_CTRL_RESYNC:
1262 CRYPT_RegFlushStore(store, FALSE);
1263 store->memStore->closeStore(store->memStore, 0);
1264 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1265 store->hdr.dwOpenFlags, NULL);
1266 if (store->memStore)
1268 CRYPT_RegReadFromReg(store);
1269 ret = TRUE;
1271 else
1272 ret = FALSE;
1273 break;
1274 case CERT_STORE_CTRL_COMMIT:
1275 ret = CRYPT_RegFlushStore(store,
1276 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1277 break;
1278 default:
1279 FIXME("%ld: stub\n", dwCtrlType);
1280 ret = FALSE;
1282 return ret;
1285 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1286 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1288 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1289 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1290 HKEY hSubKey = 0;
1292 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1294 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1295 if (!dwRet)
1297 /* Find how many subkeys there are */
1298 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1299 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1300 if (!dwRet)
1302 dwMaxSubkeyLen++;
1303 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1305 /* Name too big: alloc a buffer for it */
1306 lpszName = HeapAlloc(GetProcessHeap(), 0,
1307 dwMaxSubkeyLen*sizeof(WCHAR));
1310 if (!lpszName)
1311 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1312 else
1314 /* Recursively delete all the subkeys */
1315 for (i = 0; i < dwKeyCount && !dwRet; i++)
1317 dwSize = dwMaxSubkeyLen;
1318 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1319 NULL, NULL, NULL);
1320 if (!dwRet)
1321 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1324 if (lpszName != szNameBuf)
1326 /* Free buffer if allocated */
1327 HeapFree(GetProcessHeap(), 0, lpszName);
1332 RegCloseKey(hSubKey);
1333 if (!dwRet)
1334 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1336 return dwRet;
1339 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1340 DWORD dwFlags, const void *pvPara)
1342 PWINE_REGSTORE store = NULL;
1344 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1346 if (dwFlags & CERT_STORE_DELETE_FLAG)
1348 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1350 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1351 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1352 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1353 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1354 if (rc == ERROR_NO_MORE_ITEMS)
1355 rc = ERROR_SUCCESS;
1356 SetLastError(rc);
1358 else
1360 HKEY key;
1362 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1363 GetCurrentProcess(), (LPHANDLE)&key,
1364 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1365 TRUE, 0))
1367 PWINECRYPT_CERTSTORE memStore;
1369 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1370 if (memStore)
1372 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1373 sizeof(WINE_REGSTORE));
1374 if (store)
1376 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1377 StoreTypeReg);
1378 store->hdr.closeStore = CRYPT_RegCloseStore;
1379 store->hdr.addCert = CRYPT_RegAddCert;
1380 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1381 store->hdr.enumCert = CRYPT_RegEnumCert;
1382 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1383 store->hdr.freeCert = CRYPT_RegFreeCert;
1384 store->hdr.control = CRYPT_RegControl;
1385 store->memStore = memStore;
1386 store->key = key;
1387 InitializeCriticalSection(&store->cs);
1388 list_init(&store->certsToDelete);
1389 CRYPT_RegReadFromReg(store);
1390 store->dirty = FALSE;
1395 TRACE("returning %p\n", store);
1396 return (WINECRYPT_CERTSTORE *)store;
1399 /* FIXME: this isn't complete for the Root store, in which the top-level
1400 * self-signed CA certs reside. Adding a cert to the Root store should present
1401 * the user with a dialog indicating the consequences of doing so, and asking
1402 * the user to confirm whether the cert should be added.
1404 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1405 DWORD dwFlags, const void *pvPara)
1407 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1408 LPCWSTR storeName = (LPCWSTR)pvPara;
1409 LPWSTR storePath;
1410 PWINECRYPT_CERTSTORE store = NULL;
1411 HKEY root;
1412 LPCWSTR base;
1413 BOOL ret;
1415 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1416 debugstr_w((LPCWSTR)pvPara));
1418 if (!pvPara)
1420 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1421 return NULL;
1424 ret = TRUE;
1425 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1427 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1428 root = HKEY_LOCAL_MACHINE;
1429 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1430 break;
1431 case CERT_SYSTEM_STORE_CURRENT_USER:
1432 root = HKEY_CURRENT_USER;
1433 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1434 break;
1435 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1436 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1437 * SystemCertificates
1439 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1440 debugstr_w(storeName));
1441 return NULL;
1442 case CERT_SYSTEM_STORE_SERVICES:
1443 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1444 * SystemCertificates
1446 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1447 debugstr_w(storeName));
1448 return NULL;
1449 case CERT_SYSTEM_STORE_USERS:
1450 /* hku\user sid\Software\Microsoft\SystemCertificates */
1451 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1452 debugstr_w(storeName));
1453 return NULL;
1454 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1455 root = HKEY_CURRENT_USER;
1456 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1457 break;
1458 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1459 root = HKEY_LOCAL_MACHINE;
1460 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1461 break;
1462 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1463 /* hklm\Software\Microsoft\EnterpriseCertificates */
1464 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1465 debugstr_w(storeName));
1466 return NULL;
1467 default:
1468 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1469 return NULL;
1472 storePath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(base) +
1473 lstrlenW(storeName) + 2) * sizeof(WCHAR));
1474 if (storePath)
1476 LONG rc;
1477 HKEY key;
1478 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1479 KEY_ALL_ACCESS;
1481 wsprintfW(storePath, fmt, base, storeName);
1482 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1483 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1484 else
1486 DWORD disp;
1488 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1489 &key, &disp);
1490 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1491 disp == REG_OPENED_EXISTING_KEY)
1493 RegCloseKey(key);
1494 rc = ERROR_FILE_EXISTS;
1497 if (!rc)
1499 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1500 RegCloseKey(key);
1502 else
1503 SetLastError(rc);
1504 HeapFree(GetProcessHeap(), 0, storePath);
1506 return store;
1509 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1510 DWORD dwFlags, const void *pvPara)
1512 int len;
1513 PWINECRYPT_CERTSTORE ret = NULL;
1515 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1516 debugstr_a((LPCSTR)pvPara));
1518 if (!pvPara)
1520 SetLastError(ERROR_FILE_NOT_FOUND);
1521 return NULL;
1523 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1524 if (len)
1526 LPWSTR storeName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1528 if (storeName)
1530 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1531 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1532 HeapFree(GetProcessHeap(), 0, storeName);
1535 return ret;
1538 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1539 DWORD dwFlags, const void *pvPara)
1541 HCERTSTORE store = 0;
1542 BOOL ret;
1544 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1545 debugstr_w((LPCWSTR)pvPara));
1547 if (!pvPara)
1549 SetLastError(ERROR_FILE_NOT_FOUND);
1550 return NULL;
1552 /* This returns a different error than system registry stores if the
1553 * location is invalid.
1555 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1557 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1558 case CERT_SYSTEM_STORE_CURRENT_USER:
1559 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1560 case CERT_SYSTEM_STORE_SERVICES:
1561 case CERT_SYSTEM_STORE_USERS:
1562 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1563 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1564 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1565 ret = TRUE;
1566 break;
1567 default:
1568 SetLastError(ERROR_FILE_NOT_FOUND);
1569 ret = FALSE;
1571 if (ret)
1573 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1574 0, hCryptProv, dwFlags, pvPara);
1576 if (regStore)
1578 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1579 CERT_STORE_CREATE_NEW_FLAG, NULL);
1580 if (store)
1582 CertAddStoreToCollection(store, regStore,
1583 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1584 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1585 CertCloseStore(regStore, 0);
1589 return (PWINECRYPT_CERTSTORE)store;
1592 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1593 DWORD dwFlags, const void *pvPara)
1595 int len;
1596 PWINECRYPT_CERTSTORE ret = NULL;
1598 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1599 debugstr_a((LPCSTR)pvPara));
1601 if (!pvPara)
1603 SetLastError(ERROR_FILE_NOT_FOUND);
1604 return NULL;
1606 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1607 if (len)
1609 LPWSTR storeName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1611 if (storeName)
1613 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1614 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1615 HeapFree(GetProcessHeap(), 0, storeName);
1618 return ret;
1621 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1622 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1623 const void* pvPara)
1625 WINECRYPT_CERTSTORE *hcs;
1626 StoreOpenFunc openFunc = NULL;
1628 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1629 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1631 if (!HIWORD(lpszStoreProvider))
1633 switch (LOWORD(lpszStoreProvider))
1635 case (int)CERT_STORE_PROV_MEMORY:
1636 openFunc = CRYPT_MemOpenStore;
1637 break;
1638 case (int)CERT_STORE_PROV_REG:
1639 openFunc = CRYPT_RegOpenStore;
1640 break;
1641 case (int)CERT_STORE_PROV_COLLECTION:
1642 openFunc = CRYPT_CollectionOpenStore;
1643 break;
1644 case (int)CERT_STORE_PROV_SYSTEM_A:
1645 openFunc = CRYPT_SysOpenStoreA;
1646 break;
1647 case (int)CERT_STORE_PROV_SYSTEM_W:
1648 openFunc = CRYPT_SysOpenStoreW;
1649 break;
1650 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1651 openFunc = CRYPT_SysRegOpenStoreA;
1652 break;
1653 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1654 openFunc = CRYPT_SysRegOpenStoreW;
1655 break;
1656 default:
1657 if (LOWORD(lpszStoreProvider))
1658 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1661 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1662 openFunc = CRYPT_MemOpenStore;
1663 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1664 openFunc = CRYPT_SysOpenStoreW;
1665 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1666 openFunc = CRYPT_CollectionOpenStore;
1667 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1668 openFunc = CRYPT_SysRegOpenStoreW;
1669 else
1671 FIXME("unimplemented type %s\n", lpszStoreProvider);
1672 openFunc = NULL;
1675 if (!openFunc)
1677 /* FIXME: need to look for an installed provider for this type */
1678 SetLastError(ERROR_FILE_NOT_FOUND);
1679 hcs = NULL;
1681 else
1682 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1683 return (HCERTSTORE)hcs;
1686 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1687 LPCSTR szSubSystemProtocol)
1689 HCERTSTORE ret = 0;
1691 if (szSubSystemProtocol)
1693 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1695 LPWSTR param = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1697 if (param)
1699 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1700 ret = CertOpenSystemStoreW(hProv, param);
1701 HeapFree(GetProcessHeap(), 0, param);
1704 else
1705 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1706 return ret;
1709 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1710 LPCWSTR szSubSystemProtocol)
1712 HCERTSTORE ret;
1714 if (!szSubSystemProtocol)
1716 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1717 return 0;
1720 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1721 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1722 * it fails.
1724 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1725 CERT_STORE_CREATE_NEW_FLAG, NULL);
1726 if (ret)
1728 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1729 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1731 if (store)
1733 CertAddStoreToCollection(ret, store,
1734 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1735 CertCloseStore(store, 0);
1737 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1738 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1739 if (store)
1741 CertAddStoreToCollection(ret, store,
1742 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1743 CertCloseStore(store, 0);
1746 return ret;
1749 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1750 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1752 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1753 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1754 return TRUE;
1757 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1758 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1760 PCRL_CONTEXT pcrl;
1761 BYTE* data;
1763 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1765 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1766 pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
1767 if( !pcrl )
1768 return NULL;
1770 data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
1771 if( !data )
1773 HeapFree( GetProcessHeap(), 0, pcrl );
1774 return NULL;
1777 pcrl->dwCertEncodingType = dwCertEncodingType;
1778 pcrl->pbCrlEncoded = data;
1779 pcrl->cbCrlEncoded = cbCrlEncoded;
1780 pcrl->pCrlInfo = NULL;
1781 pcrl->hCertStore = 0;
1783 return pcrl;
1786 /* Decodes the encoded certificate and creates the certificate context for it.
1787 * The reference count is initially zero, so you must create a reference to it
1788 * to avoid leaking memory.
1790 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1791 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1793 PWINE_CERT_CONTEXT cert = NULL;
1794 BOOL ret;
1795 PCERT_INFO certInfo = NULL;
1796 DWORD size = 0;
1798 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1799 cbCertEncoded);
1801 /* First try to decode it as a signed cert. */
1802 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1803 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1804 (BYTE *)&certInfo, &size);
1805 /* Failing that, try it as an unsigned cert */
1806 if (!ret)
1807 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1808 pbCertEncoded, cbCertEncoded,
1809 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1810 (BYTE *)&certInfo, &size);
1811 if (ret)
1813 BYTE *data = NULL;
1815 cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
1816 if (!cert)
1817 goto end;
1818 data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
1819 if (!data)
1821 HeapFree(GetProcessHeap(), 0, cert);
1822 cert = NULL;
1823 goto end;
1825 memcpy(data, pbCertEncoded, cbCertEncoded);
1826 cert->cert.dwCertEncodingType = dwCertEncodingType;
1827 cert->cert.pbCertEncoded = data;
1828 cert->cert.cbCertEncoded = cbCertEncoded;
1829 cert->cert.pCertInfo = certInfo;
1830 cert->cert.hCertStore = 0;
1831 cert->ref = 0;
1832 InitializeCriticalSection(&cert->cs);
1833 list_init(&cert->extendedProperties);
1836 end:
1837 return cert;
1840 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1842 PWINE_CERT_PROPERTY prop, next;
1844 HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
1845 LocalFree(context->cert.pCertInfo);
1846 DeleteCriticalSection(&context->cs);
1847 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1848 WINE_CERT_PROPERTY, entry)
1850 list_remove(&prop->entry);
1851 HeapFree(GetProcessHeap(), 0, prop->pbData);
1852 HeapFree(GetProcessHeap(), 0, prop);
1854 HeapFree(GetProcessHeap(), 0, context);
1857 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1858 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1860 PWINE_CERT_CONTEXT cert;
1861 PWINE_CERT_CONTEXT_REF ret = NULL;
1863 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1864 cbCertEncoded);
1866 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1867 cbCertEncoded);
1868 if (cert)
1869 ret = CRYPT_CreateCertRef(cert, 0);
1870 return (PCCERT_CONTEXT)ret;
1873 /* Since the properties are stored in a list, this is a tad inefficient
1874 * (O(n^2)) since I have to find the previous position every time.
1876 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1877 DWORD dwPropId)
1879 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1880 DWORD ret;
1882 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1884 EnterCriticalSection(&ref->context->cs);
1885 if (dwPropId)
1887 PWINE_CERT_PROPERTY cursor = NULL;
1889 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1890 WINE_CERT_PROPERTY, entry)
1892 if (cursor->hdr.propID == dwPropId)
1893 break;
1895 if (cursor)
1897 if (cursor->entry.next != &ref->context->extendedProperties)
1898 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1899 entry)->hdr.propID;
1900 else
1901 ret = 0;
1903 else
1904 ret = 0;
1906 else if (!list_empty(&ref->context->extendedProperties))
1907 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1908 WINE_CERT_PROPERTY, entry)->hdr.propID;
1909 else
1910 ret = 0;
1911 LeaveCriticalSection(&ref->context->cs);
1912 return ret;
1915 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1916 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1918 PWINE_CERT_PROPERTY prop;
1919 BOOL ret, found;
1921 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1923 EnterCriticalSection(&context->cs);
1924 ret = FALSE;
1925 found = FALSE;
1926 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1927 WINE_CERT_PROPERTY, entry)
1929 if (prop->hdr.propID == dwPropId)
1931 if (!pvData)
1933 *pcbData = prop->hdr.cb;
1934 ret = TRUE;
1936 else if (*pcbData < prop->hdr.cb)
1938 SetLastError(ERROR_MORE_DATA);
1939 *pcbData = prop->hdr.cb;
1941 else
1943 memcpy(pvData, prop->pbData, prop->hdr.cb);
1944 *pcbData = prop->hdr.cb;
1945 ret = TRUE;
1947 found = TRUE;
1949 break;
1951 if (!found)
1953 /* Implicit properties */
1954 switch (dwPropId)
1956 case CERT_SHA1_HASH_PROP_ID:
1957 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1958 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1959 pcbData);
1960 if (ret)
1962 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1964 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1965 0, &blob);
1967 break;
1968 case CERT_KEY_PROV_INFO_PROP_ID:
1969 case CERT_MD5_HASH_PROP_ID:
1970 case CERT_SIGNATURE_HASH_PROP_ID:
1971 case CERT_KEY_IDENTIFIER_PROP_ID:
1972 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1973 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1974 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1975 FIXME("implicit property %ld\n", dwPropId);
1976 break;
1979 LeaveCriticalSection(&context->cs);
1980 TRACE("returning %d\n", ret);
1981 return ret;
1984 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1985 DWORD dwPropId, void *pvData, DWORD *pcbData)
1987 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1988 BOOL ret;
1990 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1992 /* Special cases for invalid/special prop IDs.
1994 switch (dwPropId)
1996 case 0:
1997 case CERT_CERT_PROP_ID:
1998 case CERT_CRL_PROP_ID:
1999 case CERT_CTL_PROP_ID:
2000 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2001 return FALSE;
2002 case CERT_ACCESS_STATE_PROP_ID:
2003 if (!pvData)
2005 *pcbData = sizeof(DWORD);
2006 return TRUE;
2008 else if (*pcbData < sizeof(DWORD))
2010 SetLastError(ERROR_MORE_DATA);
2011 *pcbData = sizeof(DWORD);
2012 return FALSE;
2014 else
2016 DWORD state = 0;
2018 if (pCertContext->hCertStore)
2020 PWINECRYPT_CERTSTORE store =
2021 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2023 /* Take advantage of knowledge of the stores to answer the
2024 * access state question
2026 if (store->type != StoreTypeReg ||
2027 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2028 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2030 *(DWORD *)pvData = state;
2031 return TRUE;
2035 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2036 pvData, pcbData);
2037 TRACE("returning %d\n", ret);
2038 return ret;
2041 /* Copies cbData bytes from pbData to the context's property with ID
2042 * dwPropId.
2044 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2045 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2047 BOOL ret = FALSE;
2048 LPBYTE data;
2050 if (cbData)
2052 data = HeapAlloc(GetProcessHeap(), 0, cbData);
2053 if (data)
2054 memcpy(data, pbData, cbData);
2056 else
2057 data = NULL;
2058 if (!cbData || data)
2060 PWINE_CERT_PROPERTY prop;
2062 EnterCriticalSection(&context->cs);
2063 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2064 WINE_CERT_PROPERTY, entry)
2066 if (prop->hdr.propID == dwPropId)
2067 break;
2069 if (prop && prop->entry.next != &context->extendedProperties)
2071 HeapFree(GetProcessHeap(), 0, prop->pbData);
2072 prop->hdr.cb = cbData;
2073 prop->pbData = cbData ? data : NULL;
2074 ret = TRUE;
2076 else
2078 prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
2079 if (prop)
2081 prop->hdr.propID = dwPropId;
2082 prop->hdr.unknown = 1;
2083 prop->hdr.cb = cbData;
2084 list_init(&prop->entry);
2085 prop->pbData = cbData ? data : NULL;
2086 list_add_tail(&context->extendedProperties, &prop->entry);
2087 ret = TRUE;
2089 else
2090 HeapFree(GetProcessHeap(), 0, data);
2092 LeaveCriticalSection(&context->cs);
2094 return ret;
2097 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2098 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2100 BOOL ret = FALSE;
2102 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2104 if (!pvData)
2106 PWINE_CERT_PROPERTY prop, next;
2108 EnterCriticalSection(&context->cs);
2109 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2110 WINE_CERT_PROPERTY, entry)
2112 if (prop->hdr.propID == dwPropId)
2114 list_remove(&prop->entry);
2115 HeapFree(GetProcessHeap(), 0, prop->pbData);
2116 HeapFree(GetProcessHeap(), 0, prop);
2119 LeaveCriticalSection(&context->cs);
2120 ret = TRUE;
2122 else
2124 switch (dwPropId)
2126 case CERT_AUTO_ENROLL_PROP_ID:
2127 case CERT_CTL_USAGE_PROP_ID:
2128 case CERT_DESCRIPTION_PROP_ID:
2129 case CERT_FRIENDLY_NAME_PROP_ID:
2130 case CERT_HASH_PROP_ID:
2131 case CERT_KEY_IDENTIFIER_PROP_ID:
2132 case CERT_MD5_HASH_PROP_ID:
2133 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2134 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2135 case CERT_PVK_FILE_PROP_ID:
2136 case CERT_SIGNATURE_HASH_PROP_ID:
2137 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2138 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2139 case CERT_ENROLLMENT_PROP_ID:
2140 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2141 case CERT_RENEWAL_PROP_ID:
2143 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2145 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2146 blob->pbData, blob->cbData);
2147 break;
2149 case CERT_DATE_STAMP_PROP_ID:
2150 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2151 pvData, sizeof(FILETIME));
2152 break;
2153 default:
2154 FIXME("%ld: stub\n", dwPropId);
2157 TRACE("returning %d\n", ret);
2158 return ret;
2161 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2162 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2164 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2165 BOOL ret;
2167 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2169 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2170 * crashes on most of these, I'll be safer.
2172 switch (dwPropId)
2174 case 0:
2175 case CERT_ACCESS_STATE_PROP_ID:
2176 case CERT_CERT_PROP_ID:
2177 case CERT_CRL_PROP_ID:
2178 case CERT_CTL_PROP_ID:
2179 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2180 return FALSE;
2182 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2183 dwFlags, pvData);
2184 TRACE("returning %d\n", ret);
2185 return ret;
2188 /* Only the reference portion of the context is duplicated. The returned
2189 * context has the cert store set to 0, to prevent the store's certificate free
2190 * function from getting called on partial data.
2191 * FIXME: is this okay? Needs a test.
2193 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2194 PCCERT_CONTEXT pCertContext)
2196 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2198 TRACE("(%p)\n", pCertContext);
2199 if (ref)
2201 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
2202 if (ret)
2204 memcpy(ret, ref, sizeof(*ret));
2205 ret->cert.hCertStore = 0;
2206 InterlockedIncrement(&ret->context->ref);
2209 else
2210 ret = NULL;
2211 return (PCCERT_CONTEXT)ret;
2214 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2215 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2216 PCCERT_CONTEXT *ppStoreContext)
2218 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2219 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2220 PWINE_CERT_CONTEXT cert;
2221 BOOL ret;
2223 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2224 dwAddDisposition, ppStoreContext);
2226 /* FIXME: some tests needed to verify return codes */
2227 if (!store)
2229 SetLastError(ERROR_INVALID_PARAMETER);
2230 return FALSE;
2232 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2234 SetLastError(ERROR_INVALID_PARAMETER);
2235 return FALSE;
2238 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2239 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2240 if (cert)
2242 PWINE_CERT_PROPERTY prop;
2244 ret = TRUE;
2245 EnterCriticalSection(&ref->context->cs);
2246 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2247 WINE_CERT_PROPERTY, entry)
2249 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2250 prop->pbData, prop->hdr.cb);
2251 if (!ret)
2252 break;
2254 LeaveCriticalSection(&ref->context->cs);
2255 if (ret)
2257 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2258 if (ret && ppStoreContext)
2259 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2260 hCertStore);
2262 if (!ret)
2263 CRYPT_FreeCert(cert);
2265 else
2266 ret = FALSE;
2267 return ret;
2270 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2271 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2272 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2274 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2275 BOOL ret;
2277 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2278 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2280 if (!hcs)
2281 ret = FALSE;
2282 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2283 ret = FALSE;
2284 else
2286 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2287 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2289 if (cert)
2291 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2292 if (ret && ppCertContext)
2293 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2294 hCertStore);
2295 if (!ret)
2296 CRYPT_FreeCert(cert);
2298 else
2299 ret = FALSE;
2301 return ret;
2304 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2305 PCCERT_CONTEXT pPrev)
2307 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2308 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2309 PCCERT_CONTEXT ret;
2311 TRACE("(%p, %p)\n", hCertStore, pPrev);
2312 if (!hCertStore)
2313 ret = NULL;
2314 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2315 ret = NULL;
2316 else
2317 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2318 return ret;
2321 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2323 BOOL ret;
2325 TRACE("(%p)\n", pCertContext);
2327 if (!pCertContext)
2328 ret = TRUE;
2329 else if (!pCertContext->hCertStore)
2330 ret = TRUE;
2331 else
2333 PWINECRYPT_CERTSTORE hcs =
2334 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2336 if (!hcs)
2337 ret = TRUE;
2338 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2339 ret = FALSE;
2340 else
2341 ret = hcs->deleteCert(hcs, pCertContext, 0);
2343 return ret;
2346 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2347 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2348 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2350 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2351 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2352 ppCrlContext);
2353 return FALSE;
2356 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2357 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2358 PCCRL_CONTEXT* ppStoreContext )
2360 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2361 dwAddDisposition, ppStoreContext);
2362 return TRUE;
2365 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2367 FIXME("%p\n", pCrlContext );
2369 return TRUE;
2372 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2374 FIXME("(%p): stub\n", pCrlContext);
2375 return TRUE;
2378 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2379 PCCRL_CONTEXT pPrev)
2381 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2382 return NULL;
2385 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2386 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2388 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2389 cbCtlEncoded);
2390 return NULL;
2393 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2394 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2395 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2397 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2398 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2399 ppCtlContext);
2400 return FALSE;
2403 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2404 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2405 PCCTL_CONTEXT* ppStoreContext)
2407 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2408 dwAddDisposition, ppStoreContext);
2409 return TRUE;
2412 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2414 FIXME("(%p): stub\n", pCtlContext );
2415 return TRUE;
2418 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2420 FIXME("(%p): stub\n", pCtlContext);
2421 return TRUE;
2424 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2425 PCCTL_CONTEXT pPrev)
2427 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2428 return NULL;
2432 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2434 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2436 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2438 if( ! hCertStore )
2439 return TRUE;
2441 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2442 return FALSE;
2444 if (InterlockedDecrement(&hcs->ref) == 0)
2446 TRACE("freeing %p\n", hcs);
2447 hcs->dwMagic = 0;
2448 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2449 CryptReleaseContext(hcs->cryptProv, 0);
2450 hcs->closeStore(hcs, dwFlags);
2452 else
2453 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2454 return TRUE;
2457 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2458 DWORD dwCtrlType, void const *pvCtrlPara)
2460 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2461 BOOL ret;
2463 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2464 pvCtrlPara);
2466 if (!hcs)
2467 ret = FALSE;
2468 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2469 ret = FALSE;
2470 else
2472 if (hcs->control)
2473 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2474 else
2475 ret = TRUE;
2477 return ret;
2480 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2481 DWORD dwPropId, void *pvData, DWORD *pcbData)
2483 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2484 return FALSE;
2487 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2488 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2490 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2491 pvData);
2492 return FALSE;
2495 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2496 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2498 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2499 pcbElement);
2500 return FALSE;
2503 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2504 DWORD dwPropId, void *pvData, DWORD *pcbData)
2506 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2507 return FALSE;
2510 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2511 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2513 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2514 pvData);
2515 return FALSE;
2518 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2519 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2521 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2522 pcbElement);
2523 return FALSE;
2526 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2527 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2529 BOOL ret;
2531 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2532 pcbElement);
2534 if (pCertContext)
2536 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2537 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2538 pCertContext->cbCertEncoded;
2539 PWINE_CERT_PROPERTY prop;
2541 EnterCriticalSection(&ref->context->cs);
2542 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2543 WINE_CERT_PROPERTY, entry)
2544 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2545 if (!pbElement)
2547 *pcbElement = bytesNeeded;
2548 ret = TRUE;
2550 else if (*pcbElement < bytesNeeded)
2552 *pcbElement = bytesNeeded;
2553 SetLastError(ERROR_MORE_DATA);
2554 ret = FALSE;
2556 else
2558 PWINE_CERT_PROP_HEADER hdr;
2560 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2561 WINE_CERT_PROPERTY, entry)
2563 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2564 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2565 if (prop->hdr.cb)
2567 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2568 pbElement += prop->hdr.cb;
2571 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2572 hdr->propID = CERT_CERT_PROP_ID;
2573 hdr->unknown = 1;
2574 hdr->cb = pCertContext->cbCertEncoded;
2575 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2576 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2577 ret = TRUE;
2579 LeaveCriticalSection(&ref->context->cs);
2581 else
2582 ret = FALSE;
2583 return ret;
2586 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2587 * to its header if a valid header is found, NULL if not. Valid means the
2588 * length of thte property won't overrun buf, and the unknown field is 1.
2590 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2591 DWORD size, DWORD propID)
2593 const WINE_CERT_PROP_HEADER *ret = NULL;
2594 BOOL done = FALSE;
2596 while (size && !ret && !done)
2598 if (size < sizeof(WINE_CERT_PROP_HEADER))
2600 SetLastError(CRYPT_E_FILE_ERROR);
2601 done = TRUE;
2603 else
2605 const WINE_CERT_PROP_HEADER *hdr =
2606 (const WINE_CERT_PROP_HEADER *)buf;
2608 size -= sizeof(WINE_CERT_PROP_HEADER);
2609 buf += sizeof(WINE_CERT_PROP_HEADER);
2610 if (size < hdr->cb)
2612 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2613 done = TRUE;
2615 else if (!hdr->propID)
2617 /* assume a zero prop ID means the data are uninitialized, so
2618 * stop looking.
2620 done = TRUE;
2622 else if (hdr->unknown != 1)
2624 SetLastError(ERROR_FILE_NOT_FOUND);
2625 done = TRUE;
2627 else if (hdr->propID == propID)
2628 ret = hdr;
2629 else
2631 buf += hdr->cb;
2632 size -= hdr->cb;
2636 return ret;
2639 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2640 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2642 const void *context;
2644 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2645 pdwContentType);
2647 if (!cbElement)
2649 SetLastError(ERROR_END_OF_MEDIA);
2650 return NULL;
2653 __TRY
2655 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2656 const WINE_CERT_PROP_HEADER *hdr = NULL;
2657 DWORD type = 0;
2658 BOOL ret;
2660 ret = TRUE;
2661 context = NULL;
2662 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2664 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2665 if (hdr)
2666 type = CERT_STORE_CERTIFICATE_CONTEXT;
2667 else
2669 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2670 if (hdr)
2671 type = CERT_STORE_CRL_CONTEXT;
2672 else
2674 hdr = CRYPT_findPropID(pbElement, cbElement,
2675 CERT_CTL_PROP_ID);
2676 if (hdr)
2677 type = CERT_STORE_CTL_CONTEXT;
2681 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2683 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2684 type = CERT_STORE_CERTIFICATE_CONTEXT;
2686 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2688 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2689 type = CERT_STORE_CRL_CONTEXT;
2691 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2693 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2694 type = CERT_STORE_CTL_CONTEXT;
2697 switch (type)
2699 case CERT_STORE_CERTIFICATE_CONTEXT:
2700 contextInterface = &gCertInterface;
2701 break;
2702 case CERT_STORE_CRL_CONTEXT:
2703 contextInterface = &gCRLInterface;
2704 break;
2705 case CERT_STORE_CTL_CONTEXT:
2706 contextInterface = &gCTLInterface;
2707 break;
2708 default:
2709 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2710 ret = FALSE;
2712 if (!hdr)
2713 ret = FALSE;
2715 if (ret)
2716 context = contextInterface->create(X509_ASN_ENCODING,
2717 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2718 if (ret && context)
2720 BOOL noMoreProps = FALSE;
2722 while (!noMoreProps && ret)
2724 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2725 ret = FALSE;
2726 else
2728 const WINE_CERT_PROP_HEADER *hdr =
2729 (const WINE_CERT_PROP_HEADER *)pbElement;
2731 TRACE("prop is %ld\n", hdr->propID);
2732 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2733 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2734 if (cbElement < hdr->cb)
2736 SetLastError(HRESULT_FROM_WIN32(
2737 ERROR_INVALID_PARAMETER));
2738 ret = FALSE;
2740 else if (!hdr->propID)
2742 /* Like in CRYPT_findPropID, stop if the propID is zero
2744 noMoreProps = TRUE;
2746 else if (hdr->unknown != 1)
2748 SetLastError(ERROR_FILE_NOT_FOUND);
2749 ret = FALSE;
2751 else if (hdr->propID != CERT_CERT_PROP_ID &&
2752 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2753 CERT_CTL_PROP_ID)
2755 /* Have to create a blob for most types, but not
2756 * for all.. arghh.
2758 switch (hdr->propID)
2760 case CERT_AUTO_ENROLL_PROP_ID:
2761 case CERT_CTL_USAGE_PROP_ID:
2762 case CERT_DESCRIPTION_PROP_ID:
2763 case CERT_FRIENDLY_NAME_PROP_ID:
2764 case CERT_HASH_PROP_ID:
2765 case CERT_KEY_IDENTIFIER_PROP_ID:
2766 case CERT_MD5_HASH_PROP_ID:
2767 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2768 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2769 case CERT_PVK_FILE_PROP_ID:
2770 case CERT_SIGNATURE_HASH_PROP_ID:
2771 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2772 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2773 case CERT_ENROLLMENT_PROP_ID:
2774 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2775 case CERT_RENEWAL_PROP_ID:
2777 CRYPT_DATA_BLOB blob = { hdr->cb,
2778 (LPBYTE)pbElement };
2780 ret = contextInterface->setProp(context,
2781 hdr->propID, 0, &blob);
2782 break;
2784 case CERT_DATE_STAMP_PROP_ID:
2785 ret = contextInterface->setProp(context,
2786 hdr->propID, 0, pbElement);
2787 break;
2788 default:
2789 FIXME("prop ID %ld: stub\n", hdr->propID);
2792 pbElement += hdr->cb;
2793 cbElement -= hdr->cb;
2794 if (!cbElement)
2795 noMoreProps = TRUE;
2798 if (ret)
2800 if (pdwContentType)
2801 *pdwContentType = type;
2803 else
2805 contextInterface->free(context);
2806 context = NULL;
2810 __EXCEPT(page_fault)
2812 SetLastError(STATUS_ACCESS_VIOLATION);
2813 context = NULL;
2815 __ENDTRY
2816 return context;
2819 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2820 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2821 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2823 const void *context;
2824 DWORD type;
2825 BOOL ret;
2827 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2828 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2829 pdwContentType, ppvContext);
2831 /* Call the internal function, then delete the hashes. Tests show this
2832 * function uses real hash values, not whatever's stored in the hash
2833 * property.
2835 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2836 dwContextTypeFlags, &type);
2837 if (context)
2839 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2841 switch (type)
2843 case CERT_STORE_CERTIFICATE_CONTEXT:
2844 contextInterface = &gCertInterface;
2845 break;
2846 case CERT_STORE_CRL_CONTEXT:
2847 contextInterface = &gCRLInterface;
2848 break;
2849 case CERT_STORE_CTL_CONTEXT:
2850 contextInterface = &gCTLInterface;
2851 break;
2852 default:
2853 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2855 if (contextInterface)
2857 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2858 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2859 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2860 NULL);
2861 if (pdwContentType)
2862 *pdwContentType = type;
2863 ret = contextInterface->addContextToStore(hCertStore, context,
2864 dwAddDisposition, ppvContext);
2865 contextInterface->free(context);
2867 else
2868 ret = FALSE;
2870 else
2871 ret = FALSE;
2872 return ret;
2875 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2877 TRACE("(%p)\n", pCertContext);
2879 if (pCertContext)
2881 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2882 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2884 if (InterlockedDecrement(&ref->context->ref) == 0)
2886 TRACE("freeing %p\n", ref->context);
2887 CRYPT_FreeCert(ref->context);
2889 else
2890 TRACE("%p's ref count is %ld\n", ref->context,
2891 ref->context->ref);
2892 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2893 store->freeCert)
2894 store->freeCert(ref);
2895 HeapFree(GetProcessHeap(), 0, ref);
2897 return TRUE;
2900 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2901 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2902 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2904 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2905 dwFlags, dwType, pvPara, pPrevCertContext);
2906 SetLastError(CRYPT_E_NOT_FOUND);
2907 return NULL;
2910 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2911 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2913 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2914 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2915 PWINE_STORE_LIST_ENTRY entry;
2916 BOOL ret;
2918 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2919 dwUpdateFlags, dwPriority);
2921 if (!collection || !sibling)
2922 return TRUE;
2923 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2925 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2926 return FALSE;
2928 if (collection->hdr.type != StoreTypeCollection)
2930 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2931 return FALSE;
2933 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2935 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2936 return FALSE;
2939 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
2940 if (entry)
2942 InterlockedIncrement(&sibling->ref);
2943 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2944 entry->store = sibling;
2945 entry->dwUpdateFlags = dwUpdateFlags;
2946 entry->dwPriority = dwPriority;
2947 list_init(&entry->entry);
2948 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2949 EnterCriticalSection(&collection->cs);
2950 if (dwPriority)
2952 PWINE_STORE_LIST_ENTRY cursor;
2953 BOOL added = FALSE;
2955 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2956 WINE_STORE_LIST_ENTRY, entry)
2958 if (cursor->dwPriority < dwPriority)
2960 list_add_before(&cursor->entry, &entry->entry);
2961 added = TRUE;
2962 break;
2965 if (!added)
2966 list_add_tail(&collection->stores, &entry->entry);
2968 else
2969 list_add_tail(&collection->stores, &entry->entry);
2970 LeaveCriticalSection(&collection->cs);
2971 ret = TRUE;
2973 else
2974 ret = FALSE;
2975 return ret;
2978 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2979 HCERTSTORE hSiblingStore)
2981 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2982 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2983 PWINE_STORE_LIST_ENTRY store, next;
2985 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2987 if (!collection || !sibling)
2988 return;
2989 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2991 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2992 return;
2994 if (collection->hdr.type != StoreTypeCollection)
2995 return;
2996 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2998 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2999 return;
3001 EnterCriticalSection(&collection->cs);
3002 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3003 WINE_STORE_LIST_ENTRY, entry)
3005 if (store->store == sibling)
3007 list_remove(&store->entry);
3008 CertCloseStore(store->store, 0);
3009 HeapFree(GetProcessHeap(), 0, store);
3010 break;
3013 LeaveCriticalSection(&collection->cs);
3016 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3017 CRYPT_ATTRIBUTE rgAttr[])
3019 PCRYPT_ATTRIBUTE ret = NULL;
3020 DWORD i;
3022 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3024 if (!cAttr)
3025 return NULL;
3026 if (!pszObjId)
3028 SetLastError(ERROR_INVALID_PARAMETER);
3029 return NULL;
3032 for (i = 0; !ret && i < cAttr; i++)
3033 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3034 ret = &rgAttr[i];
3035 return ret;
3038 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3039 CERT_EXTENSION rgExtensions[])
3041 PCERT_EXTENSION ret = NULL;
3042 DWORD i;
3044 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3046 if (!cExtensions)
3047 return NULL;
3048 if (!pszObjId)
3050 SetLastError(ERROR_INVALID_PARAMETER);
3051 return NULL;
3054 for (i = 0; !ret && i < cExtensions; i++)
3055 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3056 rgExtensions[i].pszObjId))
3057 ret = &rgExtensions[i];
3058 return ret;
3061 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3063 PCERT_RDN_ATTR ret = NULL;
3064 DWORD i, j;
3066 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3068 if (!pszObjId)
3070 SetLastError(ERROR_INVALID_PARAMETER);
3071 return NULL;
3074 for (i = 0; !ret && i < pName->cRDN; i++)
3075 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3076 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3077 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3078 ret = &pName->rgRDN[i].rgRDNAttr[j];
3079 return ret;
3082 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3083 PCERT_INFO pCertInfo)
3085 FILETIME fileTime;
3086 LONG ret;
3088 if (!pTimeToVerify)
3090 SYSTEMTIME sysTime;
3092 GetSystemTime(&sysTime);
3093 SystemTimeToFileTime(&sysTime, &fileTime);
3094 pTimeToVerify = &fileTime;
3096 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3098 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3099 if (ret < 0)
3100 ret = 0;
3102 return ret;
3105 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3106 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3107 DWORD *pcbComputedHash)
3109 BOOL ret = TRUE;
3110 HCRYPTHASH hHash = 0;
3112 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3113 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3115 if (!hCryptProv)
3116 hCryptProv = CRYPT_GetDefaultProvider();
3117 if (!Algid)
3118 Algid = CALG_SHA1;
3119 if (ret)
3121 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3122 if (ret)
3124 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3125 if (ret)
3126 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3127 pcbComputedHash, 0);
3128 CryptDestroyHash(hHash);
3131 return ret;