When decoding a signed cert, make sure it's really a cert.
[wine/multimedia.git] / dlls / crypt32 / cert.c
blobabec7f5d132b7fa6d20913ac4834084c2cff848e
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 break;
529 ret = TRUE;
530 LeaveCriticalSection(&store->cs);
531 return ret;
534 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
536 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
537 PWINE_CERT_LIST_ENTRY cert, next;
539 TRACE("(%p, %08lx)\n", store, dwFlags);
540 if (dwFlags)
541 FIXME("Unimplemented flags: %08lx\n", dwFlags);
543 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
544 * pointer if its ref-count reaches zero. That's okay here because there
545 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
546 * of the CertListEntry.
548 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
549 entry)
551 TRACE("removing %p\n", cert);
552 list_remove(&cert->entry);
553 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
555 DeleteCriticalSection(&store->cs);
556 HeapFree(GetProcessHeap(), 0, store);
559 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
560 DWORD dwFlags, const void *pvPara)
562 PWINE_MEMSTORE store;
564 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
566 if (dwFlags & CERT_STORE_DELETE_FLAG)
568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
569 store = NULL;
571 else
573 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
574 sizeof(WINE_MEMSTORE));
575 if (store)
577 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
578 store->hdr.closeStore = CRYPT_MemCloseStore;
579 store->hdr.addCert = CRYPT_MemAddCert;
580 store->hdr.createCertRef = CRYPT_CreateCertRef;
581 store->hdr.enumCert = CRYPT_MemEnumCert;
582 store->hdr.deleteCert = CRYPT_MemDeleteCert;
583 store->hdr.freeCert = NULL;
584 InitializeCriticalSection(&store->cs);
585 list_init(&store->certs);
588 return (PWINECRYPT_CERTSTORE)store;
591 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
592 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
594 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
595 PWINE_STORE_LIST_ENTRY entry, next;
596 BOOL ret;
598 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
600 ret = FALSE;
601 EnterCriticalSection(&cs->cs);
602 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
603 entry)
605 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
607 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
608 break;
611 LeaveCriticalSection(&cs->cs);
612 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
613 return ret;
616 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
617 PWINE_CERT_CONTEXT context, HCERTSTORE store)
619 PWINE_COLLECTION_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
620 sizeof(WINE_COLLECTION_CERT_CONTEXT));
622 if (ret)
624 /* Initialize to empty for now, just make sure the size is right */
625 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
626 ret->entry = NULL;
627 ret->childContext = NULL;
629 return (PWINE_CERT_CONTEXT_REF)ret;
632 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
634 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
635 PWINE_STORE_LIST_ENTRY entry, next;
637 TRACE("(%p, %08lx)\n", store, dwFlags);
639 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
640 entry)
642 TRACE("closing %p\n", entry);
643 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
644 HeapFree(GetProcessHeap(), 0, entry);
646 DeleteCriticalSection(&cs->cs);
647 HeapFree(GetProcessHeap(), 0, cs);
650 /* Advances a collection enumeration by one cert, if possible, where advancing
651 * means:
652 * - calling the current store's enumeration function once, and returning
653 * the enumerated cert if one is returned
654 * - moving to the next store if the current store has no more items, and
655 * recursively calling itself to get the next item.
656 * Returns NULL if the collection contains no more items or on error.
657 * Assumes the collection store's lock is held.
659 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
660 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
661 PWINE_COLLECTION_CERT_CONTEXT pPrev)
663 PWINE_COLLECTION_CERT_CONTEXT ret;
664 PWINE_CERT_CONTEXT_REF child;
666 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
668 if (pPrev)
670 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
671 pPrev->childContext);
672 if (child)
674 ret = pPrev;
675 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
676 ret->cert.cert.hCertStore = (HCERTSTORE)store;
677 InterlockedIncrement(&ret->cert.context->ref);
678 ret->childContext = child;
680 else
682 struct list *storeNext = list_next(&store->stores,
683 &storeEntry->entry);
685 pPrev->childContext = NULL;
686 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
687 if (storeNext)
689 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
690 entry);
691 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
693 else
695 SetLastError(CRYPT_E_NOT_FOUND);
696 ret = NULL;
700 else
702 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
703 NULL);
704 if (child)
706 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
707 child->context, store);
708 if (ret)
710 ret->entry = storeEntry;
711 ret->childContext = child;
713 else
714 CertFreeCertificateContext((PCCERT_CONTEXT)child);
716 else
718 struct list *storeNext = list_next(&store->stores,
719 &storeEntry->entry);
721 if (storeNext)
723 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
724 entry);
725 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
727 else
729 SetLastError(CRYPT_E_NOT_FOUND);
730 ret = NULL;
734 TRACE("returning %p\n", ret);
735 return ret;
738 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
739 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
741 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
742 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
743 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
745 TRACE("(%p, %p)\n", store, pPrev);
747 if (prevEntry)
749 EnterCriticalSection(&cs->cs);
750 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
751 LeaveCriticalSection(&cs->cs);
753 else
755 EnterCriticalSection(&cs->cs);
756 if (!list_empty(&cs->stores))
758 PWINE_STORE_LIST_ENTRY storeEntry;
760 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
761 entry);
762 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
764 else
766 SetLastError(CRYPT_E_NOT_FOUND);
767 ret = NULL;
769 LeaveCriticalSection(&cs->cs);
771 TRACE("returning %p\n", ret);
772 return (PWINE_CERT_CONTEXT_REF)ret;
775 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
776 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
778 PWINE_COLLECTION_CERT_CONTEXT context =
779 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
780 BOOL ret;
782 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
784 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
785 if (ret)
786 context->childContext = NULL;
787 return ret;
790 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
792 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
794 TRACE("(%p)\n", ref);
796 if (context->childContext)
797 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
800 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
801 DWORD dwFlags, const void *pvPara)
803 PWINE_COLLECTIONSTORE store;
805 if (dwFlags & CERT_STORE_DELETE_FLAG)
807 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
808 store = NULL;
810 else
812 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
813 sizeof(WINE_COLLECTIONSTORE));
814 if (store)
816 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
817 StoreTypeCollection);
818 store->hdr.closeStore = CRYPT_CollectionCloseStore;
819 store->hdr.addCert = CRYPT_CollectionAddCert;
820 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
821 store->hdr.enumCert = CRYPT_CollectionEnumCert;
822 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
823 store->hdr.freeCert = CRYPT_CollectionFreeCert;
824 InitializeCriticalSection(&store->cs);
825 list_init(&store->stores);
828 return (PWINECRYPT_CERTSTORE)store;
831 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
833 static const WCHAR fmt[] = { '%','0','2','X',0 };
834 DWORD i;
836 assert(hash);
837 assert(asciiHash);
839 for (i = 0; i < 20; i++)
840 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
843 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
844 0 };
845 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
846 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
847 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
849 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
850 DWORD contextType)
852 LONG rc;
853 DWORD index = 0;
854 WCHAR subKeyName[MAX_PATH];
856 do {
857 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
859 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
860 NULL);
861 if (!rc)
863 HKEY subKey;
865 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
866 if (!rc)
868 LPBYTE buf = NULL;
870 size = 0;
871 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
872 if (!rc)
873 buf = HeapAlloc(GetProcessHeap(), 0, size);
874 if (buf)
876 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
877 &size);
878 if (!rc)
880 const void *context;
881 DWORD addedType;
883 TRACE("Adding cert with hash %s\n",
884 debugstr_w(subKeyName));
885 context = CRYPT_ReadSerializedElement(buf, size,
886 contextType, &addedType);
887 if (context)
889 const WINE_CONTEXT_INTERFACE *contextInterface;
890 BYTE hash[20];
892 switch (addedType)
894 case CERT_STORE_CERTIFICATE_CONTEXT:
895 contextInterface = &gCertInterface;
896 break;
897 case CERT_STORE_CRL_CONTEXT:
898 contextInterface = &gCRLInterface;
899 break;
900 case CERT_STORE_CTL_CONTEXT:
901 contextInterface = &gCTLInterface;
902 break;
903 default:
904 contextInterface = NULL;
906 if (contextInterface)
908 size = sizeof(hash);
909 if (contextInterface->getProp(context,
910 CERT_HASH_PROP_ID, hash, &size))
912 WCHAR asciiHash[20 * 2 + 1];
914 CRYPT_HashToStr(hash, asciiHash);
915 TRACE("comparing %s\n",
916 debugstr_w(asciiHash));
917 TRACE("with %s\n", debugstr_w(subKeyName));
918 if (!lstrcmpW(asciiHash, subKeyName))
920 TRACE("hash matches, adding\n");
921 contextInterface->addContextToStore(
922 store, context,
923 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
925 else
927 TRACE("hash doesn't match, ignoring\n");
928 contextInterface->free(context);
934 HeapFree(GetProcessHeap(), 0, buf);
936 RegCloseKey(subKey);
938 /* Ignore intermediate errors, continue enumerating */
939 rc = ERROR_SUCCESS;
941 } while (!rc);
944 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
946 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
947 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
948 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
949 DWORD i;
951 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
953 HKEY key;
954 LONG rc;
956 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
957 &key, NULL);
958 if (!rc)
960 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
961 RegCloseKey(key);
966 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
967 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
968 DWORD len)
970 WCHAR asciiHash[20 * 2 + 1];
971 LONG rc;
972 HKEY subKey;
973 BOOL ret;
975 CRYPT_HashToStr(hash, asciiHash);
976 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
977 &subKey, NULL);
978 if (!rc)
980 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
981 RegCloseKey(subKey);
983 if (!rc)
984 ret = TRUE;
985 else
987 SetLastError(rc);
988 ret = FALSE;
990 return ret;
993 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
994 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
996 const void *context = NULL;
997 BOOL ret;
999 do {
1000 context = contextInterface->enumContextsInStore(memStore, context);
1001 if (context)
1003 BYTE hash[20];
1004 DWORD hashSize = sizeof(hash);
1006 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1007 &hashSize);
1008 if (ret)
1010 DWORD size = 0;
1011 LPBYTE buf = NULL;
1013 ret = contextInterface->serialize(context, 0, NULL, &size);
1014 if (size)
1015 buf = HeapAlloc(GetProcessHeap(), 0, size);
1016 if (buf)
1018 ret = contextInterface->serialize(context, 0, buf, &size);
1019 if (ret)
1020 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1022 HeapFree(GetProcessHeap(), 0, buf);
1025 else
1026 ret = TRUE;
1027 } while (ret && context != NULL);
1028 if (context)
1029 contextInterface->free(context);
1030 return ret;
1033 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1035 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1036 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1037 &gCRLInterface, &gCTLInterface };
1038 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1039 BOOL ret = TRUE;
1040 DWORD i;
1042 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1044 HKEY key;
1045 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1046 KEY_ALL_ACCESS, NULL, &key, NULL);
1048 if (!rc)
1050 if (listToDelete[i])
1052 PWINE_HASH_TO_DELETE toDelete, next;
1053 WCHAR asciiHash[20 * 2 + 1];
1055 EnterCriticalSection(&store->cs);
1056 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1057 WINE_HASH_TO_DELETE, entry)
1059 LONG rc;
1061 CRYPT_HashToStr(toDelete->hash, asciiHash);
1062 TRACE("Removing %s\n", debugstr_w(asciiHash));
1063 rc = RegDeleteKeyW(key, asciiHash);
1064 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1066 SetLastError(rc);
1067 ret = FALSE;
1069 list_remove(&toDelete->entry);
1070 HeapFree(GetProcessHeap(), 0, toDelete);
1072 LeaveCriticalSection(&store->cs);
1074 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1075 store->memStore);
1076 RegCloseKey(key);
1078 else
1080 SetLastError(rc);
1081 ret = FALSE;
1084 return ret;
1087 /* If force is true or the registry store is dirty, writes the contents of the
1088 * store to the registry.
1090 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1092 BOOL ret;
1094 if (store->dirty || force)
1095 ret = CRYPT_RegWriteToReg(store);
1096 else
1097 ret = TRUE;
1098 return ret;
1101 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1103 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1105 TRACE("(%p, %08lx)\n", store, dwFlags);
1106 if (dwFlags)
1107 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1109 CRYPT_RegFlushStore(store, FALSE);
1110 /* certsToDelete should already be cleared by this point */
1111 store->memStore->closeStore(store->memStore, 0);
1112 RegCloseKey(store->key);
1113 DeleteCriticalSection(&store->cs);
1114 HeapFree(GetProcessHeap(), 0, store);
1117 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1118 DWORD dwAddDisposition)
1120 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1121 BOOL ret;
1123 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1125 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1127 SetLastError(ERROR_ACCESS_DENIED);
1128 ret = FALSE;
1130 else
1132 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1133 if (ret)
1134 store->dirty = TRUE;
1136 return ret;
1139 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1140 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1142 PWINE_REG_CERT_CONTEXT ret = HeapAlloc(GetProcessHeap(), 0,
1143 sizeof(WINE_REG_CERT_CONTEXT));
1145 if (ret)
1147 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1148 ret->childContext = NULL;
1150 return (PWINE_CERT_CONTEXT_REF)ret;
1153 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1154 PWINE_CERT_CONTEXT_REF pPrev)
1156 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1157 PWINE_CERT_CONTEXT_REF child;
1158 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1160 TRACE("(%p, %p)\n", store, pPrev);
1162 if (pPrev)
1164 child = rs->memStore->enumCert(rs->memStore, prev->childContext);
1165 if (child)
1167 ret = (PWINE_REG_CERT_CONTEXT)pPrev;
1168 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1169 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1170 ret->childContext = child;
1173 else
1175 child = rs->memStore->enumCert(rs->memStore, NULL);
1176 if (child)
1178 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_REG_CERT_CONTEXT));
1180 if (ret)
1182 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1183 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1184 ret->childContext = child;
1186 else
1187 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1190 return (PWINE_CERT_CONTEXT_REF)ret;
1193 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1194 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1196 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1197 BOOL ret;
1199 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1201 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1203 SetLastError(ERROR_ACCESS_DENIED);
1204 ret = FALSE;
1206 else
1208 PWINE_HASH_TO_DELETE toDelete =
1209 HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HASH_TO_DELETE));
1211 if (toDelete)
1213 DWORD size = sizeof(toDelete->hash);
1215 ret = CertGetCertificateContextProperty(pCertContext,
1216 CERT_HASH_PROP_ID, toDelete->hash, &size);
1217 if (ret)
1219 list_init(&toDelete->entry);
1220 EnterCriticalSection(&store->cs);
1221 list_add_tail(&store->certsToDelete, &toDelete->entry);
1222 LeaveCriticalSection(&store->cs);
1223 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1224 dwFlags);
1226 else
1227 HeapFree(GetProcessHeap(), 0, toDelete);
1229 else
1230 ret = FALSE;
1231 if (ret)
1232 store->dirty = TRUE;
1234 return ret;
1237 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1239 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1241 TRACE("(%p)\n", ref);
1243 if (context->childContext)
1244 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1247 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1248 DWORD dwCtrlType, void const *pvCtrlPara)
1250 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1251 BOOL ret;
1253 switch (dwCtrlType)
1255 case CERT_STORE_CTRL_RESYNC:
1256 CRYPT_RegFlushStore(store, FALSE);
1257 store->memStore->closeStore(store->memStore, 0);
1258 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1259 store->hdr.dwOpenFlags, NULL);
1260 if (store->memStore)
1262 CRYPT_RegReadFromReg(store);
1263 ret = TRUE;
1265 else
1266 ret = FALSE;
1267 break;
1268 case CERT_STORE_CTRL_COMMIT:
1269 ret = CRYPT_RegFlushStore(store,
1270 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1271 break;
1272 default:
1273 FIXME("%ld: stub\n", dwCtrlType);
1274 ret = FALSE;
1276 return ret;
1279 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1280 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1282 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1283 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1284 HKEY hSubKey = 0;
1286 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1288 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1289 if (!dwRet)
1291 /* Find how many subkeys there are */
1292 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1293 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1294 if (!dwRet)
1296 dwMaxSubkeyLen++;
1297 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1299 /* Name too big: alloc a buffer for it */
1300 lpszName = HeapAlloc(GetProcessHeap(), 0,
1301 dwMaxSubkeyLen*sizeof(WCHAR));
1304 if (!lpszName)
1305 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1306 else
1308 /* Recursively delete all the subkeys */
1309 for (i = 0; i < dwKeyCount && !dwRet; i++)
1311 dwSize = dwMaxSubkeyLen;
1312 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1313 NULL, NULL, NULL);
1314 if (!dwRet)
1315 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1318 if (lpszName != szNameBuf)
1320 /* Free buffer if allocated */
1321 HeapFree(GetProcessHeap(), 0, lpszName);
1326 RegCloseKey(hSubKey);
1327 if (!dwRet)
1328 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1330 return dwRet;
1333 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1334 DWORD dwFlags, const void *pvPara)
1336 PWINE_REGSTORE store = NULL;
1338 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1340 if (dwFlags & CERT_STORE_DELETE_FLAG)
1342 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1344 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1345 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1346 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1347 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1348 if (rc == ERROR_NO_MORE_ITEMS)
1349 rc = ERROR_SUCCESS;
1350 SetLastError(rc);
1352 else
1354 HKEY key;
1356 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1357 GetCurrentProcess(), (LPHANDLE)&key,
1358 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1359 TRUE, 0))
1361 PWINECRYPT_CERTSTORE memStore;
1363 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1364 if (memStore)
1366 store = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1367 sizeof(WINE_REGSTORE));
1368 if (store)
1370 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1371 StoreTypeReg);
1372 store->hdr.closeStore = CRYPT_RegCloseStore;
1373 store->hdr.addCert = CRYPT_RegAddCert;
1374 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1375 store->hdr.enumCert = CRYPT_RegEnumCert;
1376 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1377 store->hdr.freeCert = CRYPT_RegFreeCert;
1378 store->hdr.control = CRYPT_RegControl;
1379 store->memStore = memStore;
1380 store->key = key;
1381 InitializeCriticalSection(&store->cs);
1382 list_init(&store->certsToDelete);
1383 CRYPT_RegReadFromReg(store);
1384 store->dirty = FALSE;
1389 TRACE("returning %p\n", store);
1390 return (WINECRYPT_CERTSTORE *)store;
1393 /* FIXME: this isn't complete for the Root store, in which the top-level
1394 * self-signed CA certs reside. Adding a cert to the Root store should present
1395 * the user with a dialog indicating the consequences of doing so, and asking
1396 * the user to confirm whether the cert should be added.
1398 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1399 DWORD dwFlags, const void *pvPara)
1401 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1402 LPCWSTR storeName = (LPCWSTR)pvPara;
1403 LPWSTR storePath;
1404 PWINECRYPT_CERTSTORE store = NULL;
1405 HKEY root;
1406 LPCWSTR base;
1407 BOOL ret;
1409 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1410 debugstr_w((LPCWSTR)pvPara));
1412 if (!pvPara)
1414 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1415 return NULL;
1418 ret = TRUE;
1419 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1421 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1422 root = HKEY_LOCAL_MACHINE;
1423 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1424 break;
1425 case CERT_SYSTEM_STORE_CURRENT_USER:
1426 root = HKEY_CURRENT_USER;
1427 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1428 break;
1429 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1430 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1431 * SystemCertificates
1433 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1434 debugstr_w(storeName));
1435 return NULL;
1436 case CERT_SYSTEM_STORE_SERVICES:
1437 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1438 * SystemCertificates
1440 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1441 debugstr_w(storeName));
1442 return NULL;
1443 case CERT_SYSTEM_STORE_USERS:
1444 /* hku\user sid\Software\Microsoft\SystemCertificates */
1445 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1446 debugstr_w(storeName));
1447 return NULL;
1448 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1449 root = HKEY_CURRENT_USER;
1450 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1451 break;
1452 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1453 root = HKEY_LOCAL_MACHINE;
1454 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1455 break;
1456 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1457 /* hklm\Software\Microsoft\EnterpriseCertificates */
1458 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1459 debugstr_w(storeName));
1460 return NULL;
1461 default:
1462 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1463 return NULL;
1466 storePath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(base) +
1467 lstrlenW(storeName) + 2) * sizeof(WCHAR));
1468 if (storePath)
1470 LONG rc;
1471 HKEY key;
1472 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1473 KEY_ALL_ACCESS;
1475 wsprintfW(storePath, fmt, base, storeName);
1476 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1477 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1478 else
1480 DWORD disp;
1482 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1483 &key, &disp);
1484 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1485 disp == REG_OPENED_EXISTING_KEY)
1487 RegCloseKey(key);
1488 rc = ERROR_FILE_EXISTS;
1491 if (!rc)
1493 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1494 RegCloseKey(key);
1496 else
1497 SetLastError(rc);
1498 HeapFree(GetProcessHeap(), 0, storePath);
1500 return store;
1503 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1504 DWORD dwFlags, const void *pvPara)
1506 int len;
1507 PWINECRYPT_CERTSTORE ret = NULL;
1509 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1510 debugstr_a((LPCSTR)pvPara));
1512 if (!pvPara)
1514 SetLastError(ERROR_FILE_NOT_FOUND);
1515 return NULL;
1517 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1518 if (len)
1520 LPWSTR storeName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1522 if (storeName)
1524 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1525 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1526 HeapFree(GetProcessHeap(), 0, storeName);
1529 return ret;
1532 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1533 DWORD dwFlags, const void *pvPara)
1535 HCERTSTORE store = 0;
1536 BOOL ret;
1538 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1539 debugstr_w((LPCWSTR)pvPara));
1541 if (!pvPara)
1543 SetLastError(ERROR_FILE_NOT_FOUND);
1544 return NULL;
1546 /* This returns a different error than system registry stores if the
1547 * location is invalid.
1549 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1551 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1552 case CERT_SYSTEM_STORE_CURRENT_USER:
1553 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1554 case CERT_SYSTEM_STORE_SERVICES:
1555 case CERT_SYSTEM_STORE_USERS:
1556 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1557 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1558 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1559 ret = TRUE;
1560 break;
1561 default:
1562 SetLastError(ERROR_FILE_NOT_FOUND);
1563 ret = FALSE;
1565 if (ret)
1567 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1568 0, hCryptProv, dwFlags, pvPara);
1570 if (regStore)
1572 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1573 CERT_STORE_CREATE_NEW_FLAG, NULL);
1574 if (store)
1576 CertAddStoreToCollection(store, regStore,
1577 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1578 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1579 CertCloseStore(regStore, 0);
1583 return (PWINECRYPT_CERTSTORE)store;
1586 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1587 DWORD dwFlags, const void *pvPara)
1589 int len;
1590 PWINECRYPT_CERTSTORE ret = NULL;
1592 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1593 debugstr_a((LPCSTR)pvPara));
1595 if (!pvPara)
1597 SetLastError(ERROR_FILE_NOT_FOUND);
1598 return NULL;
1600 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1601 if (len)
1603 LPWSTR storeName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1605 if (storeName)
1607 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1608 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1609 HeapFree(GetProcessHeap(), 0, storeName);
1612 return ret;
1615 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1616 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1617 const void* pvPara)
1619 WINECRYPT_CERTSTORE *hcs;
1620 StoreOpenFunc openFunc = NULL;
1622 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1623 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1625 if (!HIWORD(lpszStoreProvider))
1627 switch (LOWORD(lpszStoreProvider))
1629 case (int)CERT_STORE_PROV_MEMORY:
1630 openFunc = CRYPT_MemOpenStore;
1631 break;
1632 case (int)CERT_STORE_PROV_REG:
1633 openFunc = CRYPT_RegOpenStore;
1634 break;
1635 case (int)CERT_STORE_PROV_COLLECTION:
1636 openFunc = CRYPT_CollectionOpenStore;
1637 break;
1638 case (int)CERT_STORE_PROV_SYSTEM_A:
1639 openFunc = CRYPT_SysOpenStoreA;
1640 break;
1641 case (int)CERT_STORE_PROV_SYSTEM_W:
1642 openFunc = CRYPT_SysOpenStoreW;
1643 break;
1644 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1645 openFunc = CRYPT_SysRegOpenStoreA;
1646 break;
1647 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1648 openFunc = CRYPT_SysRegOpenStoreW;
1649 break;
1650 default:
1651 if (LOWORD(lpszStoreProvider))
1652 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1655 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1656 openFunc = CRYPT_MemOpenStore;
1657 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1658 openFunc = CRYPT_SysOpenStoreW;
1659 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1660 openFunc = CRYPT_CollectionOpenStore;
1661 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1662 openFunc = CRYPT_SysRegOpenStoreW;
1663 else
1665 FIXME("unimplemented type %s\n", lpszStoreProvider);
1666 openFunc = NULL;
1669 if (!openFunc)
1671 /* FIXME: need to look for an installed provider for this type */
1672 SetLastError(ERROR_FILE_NOT_FOUND);
1673 hcs = NULL;
1675 else
1676 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1677 return (HCERTSTORE)hcs;
1680 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1681 LPCSTR szSubSystemProtocol)
1683 HCERTSTORE ret = 0;
1685 if (szSubSystemProtocol)
1687 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1689 LPWSTR param = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1691 if (param)
1693 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1694 ret = CertOpenSystemStoreW(hProv, param);
1695 HeapFree(GetProcessHeap(), 0, param);
1698 else
1699 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1700 return ret;
1703 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1704 LPCWSTR szSubSystemProtocol)
1706 HCERTSTORE ret;
1708 if (!szSubSystemProtocol)
1710 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1711 return 0;
1714 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1715 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1716 * it fails.
1718 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1719 CERT_STORE_CREATE_NEW_FLAG, NULL);
1720 if (ret)
1722 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1723 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1725 if (store)
1727 CertAddStoreToCollection(ret, store,
1728 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1729 CertCloseStore(store, 0);
1731 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1732 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1733 if (store)
1735 CertAddStoreToCollection(ret, store,
1736 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1737 CertCloseStore(store, 0);
1740 return ret;
1743 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1744 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1746 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1747 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1748 return TRUE;
1751 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1752 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1754 PCRL_CONTEXT pcrl;
1755 BYTE* data;
1757 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1759 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1760 pcrl = HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT) );
1761 if( !pcrl )
1762 return NULL;
1764 data = HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded );
1765 if( !data )
1767 HeapFree( GetProcessHeap(), 0, pcrl );
1768 return NULL;
1771 pcrl->dwCertEncodingType = dwCertEncodingType;
1772 pcrl->pbCrlEncoded = data;
1773 pcrl->cbCrlEncoded = cbCrlEncoded;
1774 pcrl->pCrlInfo = NULL;
1775 pcrl->hCertStore = 0;
1777 return pcrl;
1780 /* Decodes the encoded certificate and creates the certificate context for it.
1781 * The reference count is initially zero, so you must create a reference to it
1782 * to avoid leaking memory.
1784 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1785 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1787 PWINE_CERT_CONTEXT cert = NULL;
1788 BOOL ret;
1789 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1790 PCERT_INFO certInfo = NULL;
1791 DWORD size = 0;
1793 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1794 cbCertEncoded);
1796 /* First try to decode it as a signed cert. */
1797 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1798 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1799 (BYTE *)&signedCert, &size);
1800 if (ret)
1802 size = 0;
1803 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1804 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1805 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1806 (BYTE *)&certInfo, &size);
1807 LocalFree(signedCert);
1809 /* Failing that, try it as an unsigned cert */
1810 if (!ret)
1812 size = 0;
1813 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1814 pbCertEncoded, cbCertEncoded,
1815 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1816 (BYTE *)&certInfo, &size);
1818 if (ret)
1820 BYTE *data = NULL;
1822 cert = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT));
1823 if (!cert)
1824 goto end;
1825 data = HeapAlloc(GetProcessHeap(), 0, cbCertEncoded);
1826 if (!data)
1828 HeapFree(GetProcessHeap(), 0, cert);
1829 cert = NULL;
1830 goto end;
1832 memcpy(data, pbCertEncoded, cbCertEncoded);
1833 cert->cert.dwCertEncodingType = dwCertEncodingType;
1834 cert->cert.pbCertEncoded = data;
1835 cert->cert.cbCertEncoded = cbCertEncoded;
1836 cert->cert.pCertInfo = certInfo;
1837 cert->cert.hCertStore = 0;
1838 cert->ref = 0;
1839 InitializeCriticalSection(&cert->cs);
1840 list_init(&cert->extendedProperties);
1843 end:
1844 return cert;
1847 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1849 PWINE_CERT_PROPERTY prop, next;
1851 HeapFree(GetProcessHeap(), 0, context->cert.pbCertEncoded);
1852 LocalFree(context->cert.pCertInfo);
1853 DeleteCriticalSection(&context->cs);
1854 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1855 WINE_CERT_PROPERTY, entry)
1857 list_remove(&prop->entry);
1858 HeapFree(GetProcessHeap(), 0, prop->pbData);
1859 HeapFree(GetProcessHeap(), 0, prop);
1861 HeapFree(GetProcessHeap(), 0, context);
1864 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1865 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1867 PWINE_CERT_CONTEXT cert;
1868 PWINE_CERT_CONTEXT_REF ret = NULL;
1870 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1871 cbCertEncoded);
1873 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1874 cbCertEncoded);
1875 if (cert)
1876 ret = CRYPT_CreateCertRef(cert, 0);
1877 return (PCCERT_CONTEXT)ret;
1880 /* Since the properties are stored in a list, this is a tad inefficient
1881 * (O(n^2)) since I have to find the previous position every time.
1883 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1884 DWORD dwPropId)
1886 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1887 DWORD ret;
1889 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1891 EnterCriticalSection(&ref->context->cs);
1892 if (dwPropId)
1894 PWINE_CERT_PROPERTY cursor = NULL;
1896 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1897 WINE_CERT_PROPERTY, entry)
1899 if (cursor->hdr.propID == dwPropId)
1900 break;
1902 if (cursor)
1904 if (cursor->entry.next != &ref->context->extendedProperties)
1905 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1906 entry)->hdr.propID;
1907 else
1908 ret = 0;
1910 else
1911 ret = 0;
1913 else if (!list_empty(&ref->context->extendedProperties))
1914 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1915 WINE_CERT_PROPERTY, entry)->hdr.propID;
1916 else
1917 ret = 0;
1918 LeaveCriticalSection(&ref->context->cs);
1919 return ret;
1922 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1923 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1925 PWINE_CERT_PROPERTY prop;
1926 BOOL ret, found;
1928 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1930 EnterCriticalSection(&context->cs);
1931 ret = FALSE;
1932 found = FALSE;
1933 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1934 WINE_CERT_PROPERTY, entry)
1936 if (prop->hdr.propID == dwPropId)
1938 if (!pvData)
1940 *pcbData = prop->hdr.cb;
1941 ret = TRUE;
1943 else if (*pcbData < prop->hdr.cb)
1945 SetLastError(ERROR_MORE_DATA);
1946 *pcbData = prop->hdr.cb;
1948 else
1950 memcpy(pvData, prop->pbData, prop->hdr.cb);
1951 *pcbData = prop->hdr.cb;
1952 ret = TRUE;
1954 found = TRUE;
1956 break;
1958 if (!found)
1960 /* Implicit properties */
1961 switch (dwPropId)
1963 case CERT_SHA1_HASH_PROP_ID:
1964 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1965 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1966 pcbData);
1967 if (ret)
1969 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1971 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1972 0, &blob);
1974 break;
1975 case CERT_KEY_PROV_INFO_PROP_ID:
1976 case CERT_MD5_HASH_PROP_ID:
1977 case CERT_SIGNATURE_HASH_PROP_ID:
1978 case CERT_KEY_IDENTIFIER_PROP_ID:
1979 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1980 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1981 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1982 FIXME("implicit property %ld\n", dwPropId);
1983 break;
1986 LeaveCriticalSection(&context->cs);
1987 TRACE("returning %d\n", ret);
1988 return ret;
1991 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1992 DWORD dwPropId, void *pvData, DWORD *pcbData)
1994 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1995 BOOL ret;
1997 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1999 /* Special cases for invalid/special prop IDs.
2001 switch (dwPropId)
2003 case 0:
2004 case CERT_CERT_PROP_ID:
2005 case CERT_CRL_PROP_ID:
2006 case CERT_CTL_PROP_ID:
2007 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2008 return FALSE;
2009 case CERT_ACCESS_STATE_PROP_ID:
2010 if (!pvData)
2012 *pcbData = sizeof(DWORD);
2013 return TRUE;
2015 else if (*pcbData < sizeof(DWORD))
2017 SetLastError(ERROR_MORE_DATA);
2018 *pcbData = sizeof(DWORD);
2019 return FALSE;
2021 else
2023 DWORD state = 0;
2025 if (pCertContext->hCertStore)
2027 PWINECRYPT_CERTSTORE store =
2028 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2030 /* Take advantage of knowledge of the stores to answer the
2031 * access state question
2033 if (store->type != StoreTypeReg ||
2034 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2035 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2037 *(DWORD *)pvData = state;
2038 return TRUE;
2042 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2043 pvData, pcbData);
2044 TRACE("returning %d\n", ret);
2045 return ret;
2048 /* Copies cbData bytes from pbData to the context's property with ID
2049 * dwPropId.
2051 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2052 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2054 BOOL ret = FALSE;
2055 LPBYTE data;
2057 if (cbData)
2059 data = HeapAlloc(GetProcessHeap(), 0, cbData);
2060 if (data)
2061 memcpy(data, pbData, cbData);
2063 else
2064 data = NULL;
2065 if (!cbData || data)
2067 PWINE_CERT_PROPERTY prop;
2069 EnterCriticalSection(&context->cs);
2070 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2071 WINE_CERT_PROPERTY, entry)
2073 if (prop->hdr.propID == dwPropId)
2074 break;
2076 if (prop && prop->entry.next != &context->extendedProperties)
2078 HeapFree(GetProcessHeap(), 0, prop->pbData);
2079 prop->hdr.cb = cbData;
2080 prop->pbData = cbData ? data : NULL;
2081 ret = TRUE;
2083 else
2085 prop = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY));
2086 if (prop)
2088 prop->hdr.propID = dwPropId;
2089 prop->hdr.unknown = 1;
2090 prop->hdr.cb = cbData;
2091 list_init(&prop->entry);
2092 prop->pbData = cbData ? data : NULL;
2093 list_add_tail(&context->extendedProperties, &prop->entry);
2094 ret = TRUE;
2096 else
2097 HeapFree(GetProcessHeap(), 0, data);
2099 LeaveCriticalSection(&context->cs);
2101 return ret;
2104 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2105 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2107 BOOL ret = FALSE;
2109 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2111 if (!pvData)
2113 PWINE_CERT_PROPERTY prop, next;
2115 EnterCriticalSection(&context->cs);
2116 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2117 WINE_CERT_PROPERTY, entry)
2119 if (prop->hdr.propID == dwPropId)
2121 list_remove(&prop->entry);
2122 HeapFree(GetProcessHeap(), 0, prop->pbData);
2123 HeapFree(GetProcessHeap(), 0, prop);
2126 LeaveCriticalSection(&context->cs);
2127 ret = TRUE;
2129 else
2131 switch (dwPropId)
2133 case CERT_AUTO_ENROLL_PROP_ID:
2134 case CERT_CTL_USAGE_PROP_ID:
2135 case CERT_DESCRIPTION_PROP_ID:
2136 case CERT_FRIENDLY_NAME_PROP_ID:
2137 case CERT_HASH_PROP_ID:
2138 case CERT_KEY_IDENTIFIER_PROP_ID:
2139 case CERT_MD5_HASH_PROP_ID:
2140 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2141 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2142 case CERT_PVK_FILE_PROP_ID:
2143 case CERT_SIGNATURE_HASH_PROP_ID:
2144 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2145 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2146 case CERT_ENROLLMENT_PROP_ID:
2147 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2148 case CERT_RENEWAL_PROP_ID:
2150 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2152 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2153 blob->pbData, blob->cbData);
2154 break;
2156 case CERT_DATE_STAMP_PROP_ID:
2157 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2158 pvData, sizeof(FILETIME));
2159 break;
2160 default:
2161 FIXME("%ld: stub\n", dwPropId);
2164 TRACE("returning %d\n", ret);
2165 return ret;
2168 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2169 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2171 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2172 BOOL ret;
2174 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2176 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2177 * crashes on most of these, I'll be safer.
2179 switch (dwPropId)
2181 case 0:
2182 case CERT_ACCESS_STATE_PROP_ID:
2183 case CERT_CERT_PROP_ID:
2184 case CERT_CRL_PROP_ID:
2185 case CERT_CTL_PROP_ID:
2186 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2187 return FALSE;
2189 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2190 dwFlags, pvData);
2191 TRACE("returning %d\n", ret);
2192 return ret;
2195 /* Only the reference portion of the context is duplicated. The returned
2196 * context has the cert store set to 0, to prevent the store's certificate free
2197 * function from getting called on partial data.
2198 * FIXME: is this okay? Needs a test.
2200 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2201 PCCERT_CONTEXT pCertContext)
2203 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2205 TRACE("(%p)\n", pCertContext);
2206 if (ref)
2208 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF));
2209 if (ret)
2211 memcpy(ret, ref, sizeof(*ret));
2212 ret->cert.hCertStore = 0;
2213 InterlockedIncrement(&ret->context->ref);
2216 else
2217 ret = NULL;
2218 return (PCCERT_CONTEXT)ret;
2221 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2222 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2223 PCCERT_CONTEXT *ppStoreContext)
2225 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2226 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2227 PWINE_CERT_CONTEXT cert;
2228 BOOL ret;
2230 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2231 dwAddDisposition, ppStoreContext);
2233 /* FIXME: some tests needed to verify return codes */
2234 if (!store)
2236 SetLastError(ERROR_INVALID_PARAMETER);
2237 return FALSE;
2239 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2241 SetLastError(ERROR_INVALID_PARAMETER);
2242 return FALSE;
2245 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2246 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2247 if (cert)
2249 PWINE_CERT_PROPERTY prop;
2251 ret = TRUE;
2252 EnterCriticalSection(&ref->context->cs);
2253 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2254 WINE_CERT_PROPERTY, entry)
2256 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2257 prop->pbData, prop->hdr.cb);
2258 if (!ret)
2259 break;
2261 LeaveCriticalSection(&ref->context->cs);
2262 if (ret)
2264 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2265 if (ret && ppStoreContext)
2266 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2267 hCertStore);
2269 if (!ret)
2270 CRYPT_FreeCert(cert);
2272 else
2273 ret = FALSE;
2274 return ret;
2277 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2278 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2279 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2281 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2282 BOOL ret;
2284 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2285 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2287 if (!hcs)
2288 ret = FALSE;
2289 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2290 ret = FALSE;
2291 else
2293 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2294 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2296 if (cert)
2298 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2299 if (ret && ppCertContext)
2300 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2301 hCertStore);
2302 if (!ret)
2303 CRYPT_FreeCert(cert);
2305 else
2306 ret = FALSE;
2308 return ret;
2311 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2312 PCCERT_CONTEXT pPrev)
2314 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2315 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2316 PCCERT_CONTEXT ret;
2318 TRACE("(%p, %p)\n", hCertStore, pPrev);
2319 if (!hCertStore)
2320 ret = NULL;
2321 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2322 ret = NULL;
2323 else
2324 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2325 return ret;
2328 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2330 BOOL ret;
2332 TRACE("(%p)\n", pCertContext);
2334 if (!pCertContext)
2335 ret = TRUE;
2336 else if (!pCertContext->hCertStore)
2338 ret = TRUE;
2339 CertFreeCertificateContext(pCertContext);
2341 else
2343 PWINECRYPT_CERTSTORE hcs =
2344 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2346 if (!hcs)
2347 ret = TRUE;
2348 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2349 ret = FALSE;
2350 else
2352 ret = hcs->deleteCert(hcs, pCertContext, 0);
2353 CertFreeCertificateContext(pCertContext);
2356 return ret;
2359 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2360 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2361 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2363 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2364 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2365 ppCrlContext);
2366 return FALSE;
2369 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2370 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2371 PCCRL_CONTEXT* ppStoreContext )
2373 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2374 dwAddDisposition, ppStoreContext);
2375 return TRUE;
2378 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2380 FIXME("%p\n", pCrlContext );
2382 return TRUE;
2385 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2387 FIXME("(%p): stub\n", pCrlContext);
2388 return TRUE;
2391 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2392 PCCRL_CONTEXT pPrev)
2394 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2395 return NULL;
2398 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2399 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2401 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2402 cbCtlEncoded);
2403 return NULL;
2406 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2407 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2408 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2410 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2411 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2412 ppCtlContext);
2413 return FALSE;
2416 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2417 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2418 PCCTL_CONTEXT* ppStoreContext)
2420 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2421 dwAddDisposition, ppStoreContext);
2422 return TRUE;
2425 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2427 FIXME("(%p): stub\n", pCtlContext );
2428 return TRUE;
2431 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2433 FIXME("(%p): stub\n", pCtlContext);
2434 return TRUE;
2437 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2438 PCCTL_CONTEXT pPrev)
2440 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2441 return NULL;
2445 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2447 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2449 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2451 if( ! hCertStore )
2452 return TRUE;
2454 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2455 return FALSE;
2457 if (InterlockedDecrement(&hcs->ref) == 0)
2459 TRACE("%p's ref count is 0, freeing\n", hcs);
2460 hcs->dwMagic = 0;
2461 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2462 CryptReleaseContext(hcs->cryptProv, 0);
2463 hcs->closeStore(hcs, dwFlags);
2465 else
2466 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2467 return TRUE;
2470 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2471 DWORD dwCtrlType, void const *pvCtrlPara)
2473 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2474 BOOL ret;
2476 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2477 pvCtrlPara);
2479 if (!hcs)
2480 ret = FALSE;
2481 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2482 ret = FALSE;
2483 else
2485 if (hcs->control)
2486 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2487 else
2488 ret = TRUE;
2490 return ret;
2493 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2494 DWORD dwPropId, void *pvData, DWORD *pcbData)
2496 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2497 return FALSE;
2500 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2501 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2503 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2504 pvData);
2505 return FALSE;
2508 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2509 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2511 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2512 pcbElement);
2513 return FALSE;
2516 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2517 DWORD dwPropId, void *pvData, DWORD *pcbData)
2519 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2520 return FALSE;
2523 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2524 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2526 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2527 pvData);
2528 return FALSE;
2531 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2532 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2534 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2535 pcbElement);
2536 return FALSE;
2539 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2540 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2542 BOOL ret;
2544 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2545 pcbElement);
2547 if (pCertContext)
2549 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2550 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2551 pCertContext->cbCertEncoded;
2552 PWINE_CERT_PROPERTY prop;
2554 EnterCriticalSection(&ref->context->cs);
2555 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2556 WINE_CERT_PROPERTY, entry)
2557 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2558 if (!pbElement)
2560 *pcbElement = bytesNeeded;
2561 ret = TRUE;
2563 else if (*pcbElement < bytesNeeded)
2565 *pcbElement = bytesNeeded;
2566 SetLastError(ERROR_MORE_DATA);
2567 ret = FALSE;
2569 else
2571 PWINE_CERT_PROP_HEADER hdr;
2573 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2574 WINE_CERT_PROPERTY, entry)
2576 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2577 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2578 if (prop->hdr.cb)
2580 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2581 pbElement += prop->hdr.cb;
2584 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2585 hdr->propID = CERT_CERT_PROP_ID;
2586 hdr->unknown = 1;
2587 hdr->cb = pCertContext->cbCertEncoded;
2588 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2589 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2590 ret = TRUE;
2592 LeaveCriticalSection(&ref->context->cs);
2594 else
2595 ret = FALSE;
2596 return ret;
2599 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2600 * to its header if a valid header is found, NULL if not. Valid means the
2601 * length of thte property won't overrun buf, and the unknown field is 1.
2603 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2604 DWORD size, DWORD propID)
2606 const WINE_CERT_PROP_HEADER *ret = NULL;
2607 BOOL done = FALSE;
2609 while (size && !ret && !done)
2611 if (size < sizeof(WINE_CERT_PROP_HEADER))
2613 SetLastError(CRYPT_E_FILE_ERROR);
2614 done = TRUE;
2616 else
2618 const WINE_CERT_PROP_HEADER *hdr =
2619 (const WINE_CERT_PROP_HEADER *)buf;
2621 size -= sizeof(WINE_CERT_PROP_HEADER);
2622 buf += sizeof(WINE_CERT_PROP_HEADER);
2623 if (size < hdr->cb)
2625 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2626 done = TRUE;
2628 else if (!hdr->propID)
2630 /* assume a zero prop ID means the data are uninitialized, so
2631 * stop looking.
2633 done = TRUE;
2635 else if (hdr->unknown != 1)
2637 SetLastError(ERROR_FILE_NOT_FOUND);
2638 done = TRUE;
2640 else if (hdr->propID == propID)
2641 ret = hdr;
2642 else
2644 buf += hdr->cb;
2645 size -= hdr->cb;
2649 return ret;
2652 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2653 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2655 const void *context;
2657 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2658 pdwContentType);
2660 if (!cbElement)
2662 SetLastError(ERROR_END_OF_MEDIA);
2663 return NULL;
2666 __TRY
2668 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2669 const WINE_CERT_PROP_HEADER *hdr = NULL;
2670 DWORD type = 0;
2671 BOOL ret;
2673 ret = TRUE;
2674 context = NULL;
2675 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2677 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2678 if (hdr)
2679 type = CERT_STORE_CERTIFICATE_CONTEXT;
2680 else
2682 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2683 if (hdr)
2684 type = CERT_STORE_CRL_CONTEXT;
2685 else
2687 hdr = CRYPT_findPropID(pbElement, cbElement,
2688 CERT_CTL_PROP_ID);
2689 if (hdr)
2690 type = CERT_STORE_CTL_CONTEXT;
2694 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2696 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2697 type = CERT_STORE_CERTIFICATE_CONTEXT;
2699 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2701 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2702 type = CERT_STORE_CRL_CONTEXT;
2704 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2706 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2707 type = CERT_STORE_CTL_CONTEXT;
2710 switch (type)
2712 case CERT_STORE_CERTIFICATE_CONTEXT:
2713 contextInterface = &gCertInterface;
2714 break;
2715 case CERT_STORE_CRL_CONTEXT:
2716 contextInterface = &gCRLInterface;
2717 break;
2718 case CERT_STORE_CTL_CONTEXT:
2719 contextInterface = &gCTLInterface;
2720 break;
2721 default:
2722 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2723 ret = FALSE;
2725 if (!hdr)
2726 ret = FALSE;
2728 if (ret)
2729 context = contextInterface->create(X509_ASN_ENCODING,
2730 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2731 if (ret && context)
2733 BOOL noMoreProps = FALSE;
2735 while (!noMoreProps && ret)
2737 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2738 ret = FALSE;
2739 else
2741 const WINE_CERT_PROP_HEADER *hdr =
2742 (const WINE_CERT_PROP_HEADER *)pbElement;
2744 TRACE("prop is %ld\n", hdr->propID);
2745 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2746 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2747 if (cbElement < hdr->cb)
2749 SetLastError(HRESULT_FROM_WIN32(
2750 ERROR_INVALID_PARAMETER));
2751 ret = FALSE;
2753 else if (!hdr->propID)
2755 /* Like in CRYPT_findPropID, stop if the propID is zero
2757 noMoreProps = TRUE;
2759 else if (hdr->unknown != 1)
2761 SetLastError(ERROR_FILE_NOT_FOUND);
2762 ret = FALSE;
2764 else if (hdr->propID != CERT_CERT_PROP_ID &&
2765 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2766 CERT_CTL_PROP_ID)
2768 /* Have to create a blob for most types, but not
2769 * for all.. arghh.
2771 switch (hdr->propID)
2773 case CERT_AUTO_ENROLL_PROP_ID:
2774 case CERT_CTL_USAGE_PROP_ID:
2775 case CERT_DESCRIPTION_PROP_ID:
2776 case CERT_FRIENDLY_NAME_PROP_ID:
2777 case CERT_HASH_PROP_ID:
2778 case CERT_KEY_IDENTIFIER_PROP_ID:
2779 case CERT_MD5_HASH_PROP_ID:
2780 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2781 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2782 case CERT_PVK_FILE_PROP_ID:
2783 case CERT_SIGNATURE_HASH_PROP_ID:
2784 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2785 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2786 case CERT_ENROLLMENT_PROP_ID:
2787 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2788 case CERT_RENEWAL_PROP_ID:
2790 CRYPT_DATA_BLOB blob = { hdr->cb,
2791 (LPBYTE)pbElement };
2793 ret = contextInterface->setProp(context,
2794 hdr->propID, 0, &blob);
2795 break;
2797 case CERT_DATE_STAMP_PROP_ID:
2798 ret = contextInterface->setProp(context,
2799 hdr->propID, 0, pbElement);
2800 break;
2801 default:
2802 FIXME("prop ID %ld: stub\n", hdr->propID);
2805 pbElement += hdr->cb;
2806 cbElement -= hdr->cb;
2807 if (!cbElement)
2808 noMoreProps = TRUE;
2811 if (ret)
2813 if (pdwContentType)
2814 *pdwContentType = type;
2816 else
2818 contextInterface->free(context);
2819 context = NULL;
2823 __EXCEPT(page_fault)
2825 SetLastError(STATUS_ACCESS_VIOLATION);
2826 context = NULL;
2828 __ENDTRY
2829 return context;
2832 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2833 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2834 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2836 const void *context;
2837 DWORD type;
2838 BOOL ret;
2840 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2841 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2842 pdwContentType, ppvContext);
2844 /* Call the internal function, then delete the hashes. Tests show this
2845 * function uses real hash values, not whatever's stored in the hash
2846 * property.
2848 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2849 dwContextTypeFlags, &type);
2850 if (context)
2852 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2854 switch (type)
2856 case CERT_STORE_CERTIFICATE_CONTEXT:
2857 contextInterface = &gCertInterface;
2858 break;
2859 case CERT_STORE_CRL_CONTEXT:
2860 contextInterface = &gCRLInterface;
2861 break;
2862 case CERT_STORE_CTL_CONTEXT:
2863 contextInterface = &gCTLInterface;
2864 break;
2865 default:
2866 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2868 if (contextInterface)
2870 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2871 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2872 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2873 NULL);
2874 if (pdwContentType)
2875 *pdwContentType = type;
2876 ret = contextInterface->addContextToStore(hCertStore, context,
2877 dwAddDisposition, ppvContext);
2878 contextInterface->free(context);
2880 else
2881 ret = FALSE;
2883 else
2884 ret = FALSE;
2885 return ret;
2888 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2890 TRACE("(%p)\n", pCertContext);
2892 if (pCertContext)
2894 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2895 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2897 if (InterlockedDecrement(&ref->context->ref) == 0)
2899 TRACE("%p's ref count is 0, freeing\n", ref->context);
2900 CRYPT_FreeCert(ref->context);
2902 else
2903 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2904 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2905 store->freeCert)
2906 store->freeCert(ref);
2907 HeapFree(GetProcessHeap(), 0, ref);
2909 return TRUE;
2912 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2913 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2914 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2916 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2917 dwFlags, dwType, pvPara, pPrevCertContext);
2918 SetLastError(CRYPT_E_NOT_FOUND);
2919 return NULL;
2922 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2923 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2925 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2926 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2927 PWINE_STORE_LIST_ENTRY entry;
2928 BOOL ret;
2930 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2931 dwUpdateFlags, dwPriority);
2933 if (!collection || !sibling)
2934 return TRUE;
2935 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2937 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2938 return FALSE;
2940 if (collection->hdr.type != StoreTypeCollection)
2942 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2943 return FALSE;
2945 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2947 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2948 return FALSE;
2951 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY));
2952 if (entry)
2954 InterlockedIncrement(&sibling->ref);
2955 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2956 entry->store = sibling;
2957 entry->dwUpdateFlags = dwUpdateFlags;
2958 entry->dwPriority = dwPriority;
2959 list_init(&entry->entry);
2960 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2961 EnterCriticalSection(&collection->cs);
2962 if (dwPriority)
2964 PWINE_STORE_LIST_ENTRY cursor;
2965 BOOL added = FALSE;
2967 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2968 WINE_STORE_LIST_ENTRY, entry)
2970 if (cursor->dwPriority < dwPriority)
2972 list_add_before(&cursor->entry, &entry->entry);
2973 added = TRUE;
2974 break;
2977 if (!added)
2978 list_add_tail(&collection->stores, &entry->entry);
2980 else
2981 list_add_tail(&collection->stores, &entry->entry);
2982 LeaveCriticalSection(&collection->cs);
2983 ret = TRUE;
2985 else
2986 ret = FALSE;
2987 return ret;
2990 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2991 HCERTSTORE hSiblingStore)
2993 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2994 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2995 PWINE_STORE_LIST_ENTRY store, next;
2997 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2999 if (!collection || !sibling)
3000 return;
3001 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3003 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3004 return;
3006 if (collection->hdr.type != StoreTypeCollection)
3007 return;
3008 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3010 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3011 return;
3013 EnterCriticalSection(&collection->cs);
3014 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3015 WINE_STORE_LIST_ENTRY, entry)
3017 if (store->store == sibling)
3019 list_remove(&store->entry);
3020 CertCloseStore(store->store, 0);
3021 HeapFree(GetProcessHeap(), 0, store);
3022 break;
3025 LeaveCriticalSection(&collection->cs);
3028 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3029 CRYPT_ATTRIBUTE rgAttr[])
3031 PCRYPT_ATTRIBUTE ret = NULL;
3032 DWORD i;
3034 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3036 if (!cAttr)
3037 return NULL;
3038 if (!pszObjId)
3040 SetLastError(ERROR_INVALID_PARAMETER);
3041 return NULL;
3044 for (i = 0; !ret && i < cAttr; i++)
3045 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3046 ret = &rgAttr[i];
3047 return ret;
3050 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3051 CERT_EXTENSION rgExtensions[])
3053 PCERT_EXTENSION ret = NULL;
3054 DWORD i;
3056 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3058 if (!cExtensions)
3059 return NULL;
3060 if (!pszObjId)
3062 SetLastError(ERROR_INVALID_PARAMETER);
3063 return NULL;
3066 for (i = 0; !ret && i < cExtensions; i++)
3067 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3068 rgExtensions[i].pszObjId))
3069 ret = &rgExtensions[i];
3070 return ret;
3073 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3075 PCERT_RDN_ATTR ret = NULL;
3076 DWORD i, j;
3078 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3080 if (!pszObjId)
3082 SetLastError(ERROR_INVALID_PARAMETER);
3083 return NULL;
3086 for (i = 0; !ret && i < pName->cRDN; i++)
3087 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3088 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3089 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3090 ret = &pName->rgRDN[i].rgRDNAttr[j];
3091 return ret;
3094 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3095 PCERT_INFO pCertInfo)
3097 FILETIME fileTime;
3098 LONG ret;
3100 if (!pTimeToVerify)
3102 SYSTEMTIME sysTime;
3104 GetSystemTime(&sysTime);
3105 SystemTimeToFileTime(&sysTime, &fileTime);
3106 pTimeToVerify = &fileTime;
3108 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3110 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3111 if (ret < 0)
3112 ret = 0;
3114 return ret;
3117 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3118 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3119 DWORD *pcbComputedHash)
3121 BOOL ret = TRUE;
3122 HCRYPTHASH hHash = 0;
3124 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3125 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3127 if (!hCryptProv)
3128 hCryptProv = CRYPT_GetDefaultProvider();
3129 if (!Algid)
3130 Algid = CALG_SHA1;
3131 if (ret)
3133 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3134 if (ret)
3136 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3137 if (ret)
3138 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3139 pcbComputedHash, 0);
3140 CryptDestroyHash(hHash);
3143 return ret;