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
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
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.
38 #include "wine/debug.h"
39 #include "wine/list.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
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
;
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 CryptMemAlloc): CertFreeCertificateContext
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
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
{
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
168 typedef struct WINE_CRYPTCERTSTORE
173 HCRYPTPROV cryptProv
;
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
197 struct list extendedProperties
;
198 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
200 typedef struct _WINE_CERT_CONTEXT_REF
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
209 typedef struct _WINE_CERT_PROP_HEADER
212 DWORD unknown
; /* always 1 */
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
;
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
;
231 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
233 typedef struct _WINE_MEMSTORE
235 WINECRYPT_CERTSTORE hdr
;
238 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
240 typedef struct _WINE_HASH_TO_DELETE
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
;
260 struct list certsToDelete
;
261 } WINE_REGSTORE
, *PWINE_REGSTORE
;
263 typedef struct _WINE_STORE_LIST_ENTRY
265 PWINECRYPT_CERTSTORE store
;
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
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
;
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 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
317 DWORD dwFlags
, CertStoreType type
)
320 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
324 hCryptProv
= CRYPT_GetDefaultProvider();
325 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
327 store
->cryptProv
= hCryptProv
;
328 store
->dwOpenFlags
= dwFlags
;
331 /* Initializes the reference ref to point to pCertContext, which is assumed to
332 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
333 * Also sets the hCertStore member of the reference to store.
335 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref
,
336 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
338 TRACE("(%p, %p)\n", ref
, context
);
339 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
340 ref
->context
= context
;
341 InterlockedIncrement(&context
->ref
);
342 TRACE("%p's ref count is %ld\n", context
, context
->ref
);
343 ref
->cert
.hCertStore
= store
;
346 static PWINE_CERT_CONTEXT_REF
CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context
,
349 PWINE_CERT_CONTEXT_REF pCertRef
= CryptMemAlloc(
350 sizeof(WINE_CERT_CONTEXT_REF
));
352 TRACE("(%p, %p)\n", context
, store
);
354 CRYPT_InitCertRef(pCertRef
, context
, store
);
358 static BOOL WINAPI
CRYPT_MemAddCert(HCERTSTORE store
, PCCERT_CONTEXT pCert
,
359 DWORD dwAddDisposition
)
361 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
362 BOOL add
= FALSE
, ret
;
364 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
366 switch (dwAddDisposition
)
368 case CERT_STORE_ADD_ALWAYS
:
371 case CERT_STORE_ADD_NEW
:
373 BYTE hashToAdd
[20], hash
[20];
374 DWORD size
= sizeof(hashToAdd
);
376 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
377 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
380 PWINE_CERT_LIST_ENTRY cursor
;
382 /* Add if no cert with the same hash is found. */
384 EnterCriticalSection(&ms
->cs
);
385 LIST_FOR_EACH_ENTRY(cursor
, &ms
->certs
, WINE_CERT_LIST_ENTRY
, entry
)
388 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
389 CERT_HASH_PROP_ID
, hash
, &size
);
390 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
392 TRACE("found matching certificate, not adding\n");
393 SetLastError(CRYPT_E_EXISTS
);
398 LeaveCriticalSection(&ms
->cs
);
402 case CERT_STORE_ADD_REPLACE_EXISTING
:
404 BYTE hashToAdd
[20], hash
[20];
405 DWORD size
= sizeof(hashToAdd
);
408 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
409 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
412 PWINE_CERT_LIST_ENTRY cursor
, next
;
414 /* Look for existing cert to delete */
415 EnterCriticalSection(&ms
->cs
);
416 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &ms
->certs
,
417 WINE_CERT_LIST_ENTRY
, entry
)
420 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
421 CERT_HASH_PROP_ID
, hash
, &size
);
422 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
424 TRACE("found matching certificate, replacing\n");
425 list_remove(&cursor
->entry
);
426 CertFreeCertificateContext((PCCERT_CONTEXT
)cursor
);
430 LeaveCriticalSection(&ms
->cs
);
435 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
440 PWINE_CERT_LIST_ENTRY entry
= CryptMemAlloc(
441 sizeof(WINE_CERT_LIST_ENTRY
));
445 TRACE("adding %p\n", entry
);
446 CRYPT_InitCertRef(&entry
->cert
, (PWINE_CERT_CONTEXT
)pCert
, store
);
447 list_init(&entry
->entry
);
448 EnterCriticalSection(&ms
->cs
);
449 list_add_tail(&ms
->certs
, &entry
->entry
);
450 LeaveCriticalSection(&ms
->cs
);
458 TRACE("returning %d\n", ret
);
462 static PWINE_CERT_CONTEXT_REF
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
463 PWINE_CERT_CONTEXT_REF pPrev
)
465 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
466 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
, ret
;
467 struct list
*listNext
;
469 TRACE("(%p, %p)\n", store
, pPrev
);
470 EnterCriticalSection(&ms
->cs
);
473 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
474 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
477 listNext
= list_next(&ms
->certs
, &ms
->certs
);
480 ret
= CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY
));
483 memcpy(ret
, LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
),
484 sizeof(WINE_CERT_LIST_ENTRY
));
485 InterlockedIncrement(&ret
->cert
.context
->ref
);
490 SetLastError(CRYPT_E_NOT_FOUND
);
493 LeaveCriticalSection(&ms
->cs
);
495 TRACE("returning %p\n", ret
);
496 return (PWINE_CERT_CONTEXT_REF
)ret
;
499 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref
);
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
;
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
,
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
524 list_remove(&cert
->entry
);
525 /* FIXME: generally I should do the following, otherwise there is
526 * a memory leak. But doing so when called by
527 * CertDeleteCertificateFromStore results in a double free, so
528 * leaving commented for now.
529 ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
531 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
535 LeaveCriticalSection(&store
->cs
);
539 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
541 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
542 PWINE_CERT_LIST_ENTRY cert
, next
;
544 TRACE("(%p, %08lx)\n", store
, dwFlags
);
546 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
548 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
549 * pointer if its ref-count reaches zero. That's okay here because there
550 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
551 * of the CertListEntry.
553 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
556 TRACE("removing %p\n", cert
);
557 list_remove(&cert
->entry
);
558 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
560 DeleteCriticalSection(&store
->cs
);
564 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
565 DWORD dwFlags
, const void *pvPara
)
567 PWINE_MEMSTORE store
;
569 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
571 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
573 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
578 store
= CryptMemAlloc(sizeof(WINE_MEMSTORE
));
581 memset(store
, 0, sizeof(WINE_MEMSTORE
));
582 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
583 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
584 store
->hdr
.addCert
= CRYPT_MemAddCert
;
585 store
->hdr
.createCertRef
= CRYPT_CreateCertRef
;
586 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
587 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
588 store
->hdr
.freeCert
= NULL
;
589 InitializeCriticalSection(&store
->cs
);
590 list_init(&store
->certs
);
593 return (PWINECRYPT_CERTSTORE
)store
;
596 static BOOL WINAPI
CRYPT_CollectionAddCert(HCERTSTORE store
,
597 PCCERT_CONTEXT pCert
, DWORD dwAddDisposition
)
599 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
600 PWINE_STORE_LIST_ENTRY entry
, next
;
603 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
606 EnterCriticalSection(&cs
->cs
);
607 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
610 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
612 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
616 LeaveCriticalSection(&cs
->cs
);
617 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
621 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionCreateCertRef(
622 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
624 PWINE_COLLECTION_CERT_CONTEXT ret
= CryptMemAlloc(
625 sizeof(WINE_COLLECTION_CERT_CONTEXT
));
629 /* Initialize to empty for now, just make sure the size is right */
630 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
632 ret
->childContext
= NULL
;
634 return (PWINE_CERT_CONTEXT_REF
)ret
;
637 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
639 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
640 PWINE_STORE_LIST_ENTRY entry
, next
;
642 TRACE("(%p, %08lx)\n", store
, dwFlags
);
644 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
647 TRACE("closing %p\n", entry
);
648 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
651 DeleteCriticalSection(&cs
->cs
);
655 /* Advances a collection enumeration by one cert, if possible, where advancing
657 * - calling the current store's enumeration function once, and returning
658 * the enumerated cert if one is returned
659 * - moving to the next store if the current store has no more items, and
660 * recursively calling itself to get the next item.
661 * Returns NULL if the collection contains no more items or on error.
662 * Assumes the collection store's lock is held.
664 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
665 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
666 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
668 PWINE_COLLECTION_CERT_CONTEXT ret
;
669 PWINE_CERT_CONTEXT_REF child
;
670 struct list
*storeNext
= list_next(&store
->stores
, &storeEntry
->entry
);
672 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
674 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
675 pPrev
? pPrev
->childContext
: NULL
);
678 pPrev
->childContext
= NULL
;
679 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
684 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
685 child
->context
, store
);
688 ret
->entry
= storeEntry
;
689 ret
->childContext
= child
;
692 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
698 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
699 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
703 SetLastError(CRYPT_E_NOT_FOUND
);
707 TRACE("returning %p\n", ret
);
711 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionEnumCert(
712 PWINECRYPT_CERTSTORE store
, PWINE_CERT_CONTEXT_REF pPrev
)
714 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
715 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
716 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
718 TRACE("(%p, %p)\n", store
, pPrev
);
722 EnterCriticalSection(&cs
->cs
);
723 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
724 LeaveCriticalSection(&cs
->cs
);
728 EnterCriticalSection(&cs
->cs
);
729 if (!list_empty(&cs
->stores
))
731 PWINE_STORE_LIST_ENTRY storeEntry
;
733 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
735 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
739 SetLastError(CRYPT_E_NOT_FOUND
);
742 LeaveCriticalSection(&cs
->cs
);
744 TRACE("returning %p\n", ret
);
745 return (PWINE_CERT_CONTEXT_REF
)ret
;
748 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
749 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
751 PWINE_COLLECTION_CERT_CONTEXT context
=
752 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
755 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
757 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
759 context
->childContext
= NULL
;
763 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref
)
765 PWINE_COLLECTION_CERT_CONTEXT context
= (PWINE_COLLECTION_CERT_CONTEXT
)ref
;
767 TRACE("(%p)\n", ref
);
769 if (context
->childContext
)
770 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
773 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
774 DWORD dwFlags
, const void *pvPara
)
776 PWINE_COLLECTIONSTORE store
;
778 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
780 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
785 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
788 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
789 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
790 StoreTypeCollection
);
791 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
792 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
793 store
->hdr
.createCertRef
= CRYPT_CollectionCreateCertRef
;
794 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
795 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
796 store
->hdr
.freeCert
= CRYPT_CollectionFreeCert
;
797 InitializeCriticalSection(&store
->cs
);
798 list_init(&store
->stores
);
801 return (PWINECRYPT_CERTSTORE
)store
;
804 static void CRYPT_HashToStr(LPBYTE hash
, LPWSTR asciiHash
)
806 static const WCHAR fmt
[] = { '%','0','2','X',0 };
812 for (i
= 0; i
< 20; i
++)
813 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
816 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
818 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
819 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
820 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
822 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store
, HKEY key
,
827 WCHAR subKeyName
[MAX_PATH
];
830 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
832 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
838 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
844 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
846 buf
= CryptMemAlloc(size
);
849 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
856 TRACE("Adding cert with hash %s\n",
857 debugstr_w(subKeyName
));
858 context
= CRYPT_ReadSerializedElement(buf
, size
,
859 contextType
, &addedType
);
862 const WINE_CONTEXT_INTERFACE
*contextInterface
;
867 case CERT_STORE_CERTIFICATE_CONTEXT
:
868 contextInterface
= &gCertInterface
;
870 case CERT_STORE_CRL_CONTEXT
:
871 contextInterface
= &gCRLInterface
;
873 case CERT_STORE_CTL_CONTEXT
:
874 contextInterface
= &gCTLInterface
;
877 contextInterface
= NULL
;
879 if (contextInterface
)
882 if (contextInterface
->getProp(context
,
883 CERT_HASH_PROP_ID
, hash
, &size
))
885 WCHAR asciiHash
[20 * 2 + 1];
887 CRYPT_HashToStr(hash
, asciiHash
);
888 TRACE("comparing %s\n",
889 debugstr_w(asciiHash
));
890 TRACE("with %s\n", debugstr_w(subKeyName
));
891 if (!lstrcmpW(asciiHash
, subKeyName
))
893 TRACE("hash matches, adding\n");
894 contextInterface
->addContextToStore(
896 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
899 TRACE("hash doesn't match, ignoring\n");
901 contextInterface
->free(context
);
909 /* Ignore intermediate errors, continue enumerating */
915 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store
)
917 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
918 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
919 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
922 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
927 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
931 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
937 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
938 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, LPBYTE hash
, LPBYTE buf
,
941 WCHAR asciiHash
[20 * 2 + 1];
946 CRYPT_HashToStr(hash
, asciiHash
);
947 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
951 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
964 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
965 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
967 const void *context
= NULL
;
971 context
= contextInterface
->enumContextsInStore(memStore
, context
);
975 DWORD hashSize
= sizeof(hash
);
977 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
984 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
986 buf
= CryptMemAlloc(size
);
989 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
991 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
998 } while (ret
&& context
!= NULL
);
1000 contextInterface
->free(context
);
1004 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTORE store
)
1006 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
1007 static const WINE_CONTEXT_INTERFACE
*interfaces
[] = { &gCertInterface
,
1008 &gCRLInterface
, &gCTLInterface
};
1009 struct list
*listToDelete
[] = { &store
->certsToDelete
, NULL
, NULL
};
1013 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1016 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1017 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1021 if (listToDelete
[i
])
1023 PWINE_HASH_TO_DELETE toDelete
, next
;
1024 WCHAR asciiHash
[20 * 2 + 1];
1026 EnterCriticalSection(&store
->cs
);
1027 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
1028 WINE_HASH_TO_DELETE
, entry
)
1032 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
1033 TRACE("Removing %s\n", debugstr_w(asciiHash
));
1034 rc
= RegDeleteKeyW(key
, asciiHash
);
1035 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
1040 list_remove(&toDelete
->entry
);
1041 CryptMemFree(toDelete
);
1043 LeaveCriticalSection(&store
->cs
);
1045 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
1058 /* If force is true or the registry store is dirty, writes the contents of the
1059 * store to the registry.
1061 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTORE store
, BOOL force
)
1065 if (store
->dirty
|| force
)
1066 ret
= CRYPT_RegWriteToReg(store
);
1072 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1074 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1076 TRACE("(%p, %08lx)\n", store
, dwFlags
);
1078 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
1080 CRYPT_RegFlushStore(store
, FALSE
);
1081 /* certsToDelete should already be cleared by this point */
1082 store
->memStore
->closeStore(store
->memStore
, 0);
1083 RegCloseKey(store
->key
);
1084 DeleteCriticalSection(&store
->cs
);
1085 CryptMemFree(store
);
1088 static BOOL WINAPI
CRYPT_RegAddCert(HCERTSTORE hCertStore
, PCCERT_CONTEXT cert
,
1089 DWORD dwAddDisposition
)
1091 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1094 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwAddDisposition
);
1096 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1098 SetLastError(ERROR_ACCESS_DENIED
);
1103 ret
= store
->memStore
->addCert(store
->memStore
, cert
, dwAddDisposition
);
1105 store
->dirty
= TRUE
;
1110 static PWINE_CERT_CONTEXT_REF
CRYPT_RegCreateCertRef(
1111 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
1113 PWINE_REG_CERT_CONTEXT ret
= CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT
));
1117 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
1118 ret
->childContext
= NULL
;
1120 return (PWINE_CERT_CONTEXT_REF
)ret
;
1123 static PWINE_CERT_CONTEXT_REF
CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store
,
1124 PWINE_CERT_CONTEXT_REF pPrev
)
1126 PWINE_REGSTORE rs
= (PWINE_REGSTORE
)store
;
1127 PWINE_CERT_CONTEXT_REF child
;
1128 PWINE_REG_CERT_CONTEXT prev
= (PWINE_REG_CERT_CONTEXT
)pPrev
, ret
= NULL
;
1130 TRACE("(%p, %p)\n", store
, pPrev
);
1132 child
= rs
->memStore
->enumCert(rs
->memStore
, prev
? prev
->childContext
1136 prev
->childContext
= NULL
;
1137 CertFreeCertificateContext((PCCERT_CONTEXT
)prev
);
1142 ret
= (PWINE_REG_CERT_CONTEXT
)CRYPT_RegCreateCertRef(child
->context
,
1145 ret
->childContext
= child
;
1147 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
1149 return (PWINE_CERT_CONTEXT_REF
)ret
;
1152 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
1153 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
1155 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1158 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1160 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1162 SetLastError(ERROR_ACCESS_DENIED
);
1167 PWINE_HASH_TO_DELETE toDelete
=
1168 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
1172 DWORD size
= sizeof(toDelete
->hash
);
1174 ret
= CertGetCertificateContextProperty(pCertContext
,
1175 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
1178 list_init(&toDelete
->entry
);
1179 EnterCriticalSection(&store
->cs
);
1180 list_add_tail(&store
->certsToDelete
, &toDelete
->entry
);
1181 LeaveCriticalSection(&store
->cs
);
1182 ret
= store
->memStore
->deleteCert(store
->memStore
, pCertContext
,
1186 CryptMemFree(toDelete
);
1191 store
->dirty
= TRUE
;
1196 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref
)
1198 PWINE_REG_CERT_CONTEXT context
= (PWINE_REG_CERT_CONTEXT
)ref
;
1200 TRACE("(%p)\n", ref
);
1202 if (context
->childContext
)
1203 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
1206 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
1207 DWORD dwCtrlType
, void const *pvCtrlPara
)
1209 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1214 case CERT_STORE_CTRL_RESYNC
:
1215 CRYPT_RegFlushStore(store
, FALSE
);
1216 store
->memStore
->closeStore(store
->memStore
, 0);
1217 store
->memStore
= CRYPT_MemOpenStore(store
->hdr
.cryptProv
,
1218 store
->hdr
.dwOpenFlags
, NULL
);
1219 if (store
->memStore
)
1221 CRYPT_RegReadFromReg(store
);
1227 case CERT_STORE_CTRL_COMMIT
:
1228 ret
= CRYPT_RegFlushStore(store
,
1229 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1232 FIXME("%ld: stub\n", dwCtrlType
);
1238 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1239 static DWORD
CRYPT_RecurseDeleteKey(HKEY hKey
, LPCWSTR lpszSubKey
)
1241 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1242 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1245 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1247 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1250 /* Find how many subkeys there are */
1251 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1252 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1256 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1258 /* Name too big: alloc a buffer for it */
1259 lpszName
= CryptMemAlloc(dwMaxSubkeyLen
*sizeof(WCHAR
));
1263 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1266 /* Recursively delete all the subkeys */
1267 for (i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1269 dwSize
= dwMaxSubkeyLen
;
1270 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
,
1273 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1276 if (lpszName
!= szNameBuf
)
1278 /* Free buffer if allocated */
1279 CryptMemFree(lpszName
);
1284 RegCloseKey(hSubKey
);
1286 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1291 static WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
,
1292 DWORD dwFlags
, const void *pvPara
)
1294 PWINE_REGSTORE store
= NULL
;
1296 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
1298 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
1300 DWORD rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CertsW
);
1302 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1303 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CRLsW
);
1304 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1305 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CTLsW
);
1306 if (rc
== ERROR_NO_MORE_ITEMS
)
1314 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1315 GetCurrentProcess(), (LPHANDLE
)&key
,
1316 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1319 PWINECRYPT_CERTSTORE memStore
;
1321 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1324 store
= CryptMemAlloc(sizeof(WINE_REGSTORE
));
1327 memset(store
, 0, sizeof(WINE_REGSTORE
));
1328 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
1330 store
->hdr
.closeStore
= CRYPT_RegCloseStore
;
1331 store
->hdr
.addCert
= CRYPT_RegAddCert
;
1332 store
->hdr
.createCertRef
= CRYPT_RegCreateCertRef
;
1333 store
->hdr
.enumCert
= CRYPT_RegEnumCert
;
1334 store
->hdr
.deleteCert
= CRYPT_RegDeleteCert
;
1335 store
->hdr
.freeCert
= CRYPT_RegFreeCert
;
1336 store
->hdr
.control
= CRYPT_RegControl
;
1337 store
->memStore
= memStore
;
1339 InitializeCriticalSection(&store
->cs
);
1340 list_init(&store
->certsToDelete
);
1341 CRYPT_RegReadFromReg(store
);
1342 store
->dirty
= FALSE
;
1347 TRACE("returning %p\n", store
);
1348 return (WINECRYPT_CERTSTORE
*)store
;
1351 /* FIXME: this isn't complete for the Root store, in which the top-level
1352 * self-signed CA certs reside. Adding a cert to the Root store should present
1353 * the user with a dialog indicating the consequences of doing so, and asking
1354 * the user to confirm whether the cert should be added.
1356 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv
,
1357 DWORD dwFlags
, const void *pvPara
)
1359 static const WCHAR fmt
[] = { '%','s','\\','%','s',0 };
1360 LPCWSTR storeName
= (LPCWSTR
)pvPara
;
1362 PWINECRYPT_CERTSTORE store
= NULL
;
1367 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1368 debugstr_w((LPCWSTR
)pvPara
));
1372 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1377 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1379 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1380 root
= HKEY_LOCAL_MACHINE
;
1381 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1383 case CERT_SYSTEM_STORE_CURRENT_USER
:
1384 root
= HKEY_CURRENT_USER
;
1385 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1387 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1388 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1389 * SystemCertificates
1391 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1392 debugstr_w(storeName
));
1394 case CERT_SYSTEM_STORE_SERVICES
:
1395 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1396 * SystemCertificates
1398 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1399 debugstr_w(storeName
));
1401 case CERT_SYSTEM_STORE_USERS
:
1402 /* hku\user sid\Software\Microsoft\SystemCertificates */
1403 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1404 debugstr_w(storeName
));
1406 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1407 root
= HKEY_CURRENT_USER
;
1408 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1410 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1411 root
= HKEY_LOCAL_MACHINE
;
1412 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1414 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1415 /* hklm\Software\Microsoft\EnterpriseCertificates */
1416 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1417 debugstr_w(storeName
));
1420 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1424 storePath
= CryptMemAlloc((lstrlenW(base
) + lstrlenW(storeName
) + 2) *
1430 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1433 wsprintfW(storePath
, fmt
, base
, storeName
);
1434 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1435 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1440 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1442 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1443 disp
== REG_OPENED_EXISTING_KEY
)
1446 rc
= ERROR_FILE_EXISTS
;
1451 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1456 CryptMemFree(storePath
);
1461 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1462 DWORD dwFlags
, const void *pvPara
)
1465 PWINECRYPT_CERTSTORE ret
= NULL
;
1467 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1468 debugstr_a((LPCSTR
)pvPara
));
1472 SetLastError(ERROR_FILE_NOT_FOUND
);
1475 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1478 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1482 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1483 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1484 CryptMemFree(storeName
);
1490 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1491 DWORD dwFlags
, const void *pvPara
)
1493 HCERTSTORE store
= 0;
1496 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1497 debugstr_w((LPCWSTR
)pvPara
));
1501 SetLastError(ERROR_FILE_NOT_FOUND
);
1504 /* This returns a different error than system registry stores if the
1505 * location is invalid.
1507 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1509 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1510 case CERT_SYSTEM_STORE_CURRENT_USER
:
1511 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1512 case CERT_SYSTEM_STORE_SERVICES
:
1513 case CERT_SYSTEM_STORE_USERS
:
1514 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1515 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1516 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1520 SetLastError(ERROR_FILE_NOT_FOUND
);
1525 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1526 0, hCryptProv
, dwFlags
, pvPara
);
1530 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1531 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1534 CertAddStoreToCollection(store
, regStore
,
1535 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1536 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1537 CertCloseStore(regStore
, 0);
1541 return (PWINECRYPT_CERTSTORE
)store
;
1544 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv
,
1545 DWORD dwFlags
, const void *pvPara
)
1548 PWINECRYPT_CERTSTORE ret
= NULL
;
1550 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1551 debugstr_a((LPCSTR
)pvPara
));
1555 SetLastError(ERROR_FILE_NOT_FOUND
);
1558 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1561 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1565 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1566 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1567 CryptMemFree(storeName
);
1573 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1574 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
1577 WINECRYPT_CERTSTORE
*hcs
;
1578 StoreOpenFunc openFunc
= NULL
;
1580 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
1581 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
1583 if (!HIWORD(lpszStoreProvider
))
1585 switch (LOWORD(lpszStoreProvider
))
1587 case (int)CERT_STORE_PROV_MEMORY
:
1588 openFunc
= CRYPT_MemOpenStore
;
1590 case (int)CERT_STORE_PROV_REG
:
1591 openFunc
= CRYPT_RegOpenStore
;
1593 case (int)CERT_STORE_PROV_COLLECTION
:
1594 openFunc
= CRYPT_CollectionOpenStore
;
1596 case (int)CERT_STORE_PROV_SYSTEM_A
:
1597 openFunc
= CRYPT_SysOpenStoreA
;
1599 case (int)CERT_STORE_PROV_SYSTEM_W
:
1600 openFunc
= CRYPT_SysOpenStoreW
;
1602 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1603 openFunc
= CRYPT_SysRegOpenStoreA
;
1605 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1606 openFunc
= CRYPT_SysRegOpenStoreW
;
1609 if (LOWORD(lpszStoreProvider
))
1610 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
1613 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
1614 openFunc
= CRYPT_MemOpenStore
;
1615 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
1616 openFunc
= CRYPT_SysOpenStoreW
;
1617 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
1618 openFunc
= CRYPT_CollectionOpenStore
;
1619 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM_REGISTRY
))
1620 openFunc
= CRYPT_SysRegOpenStoreW
;
1623 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1629 /* FIXME: need to look for an installed provider for this type */
1630 SetLastError(ERROR_FILE_NOT_FOUND
);
1634 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1635 return (HCERTSTORE
)hcs
;
1638 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1639 LPCSTR szSubSystemProtocol
)
1643 if (szSubSystemProtocol
)
1645 int len
= MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, NULL
,
1647 LPWSTR param
= CryptMemAlloc(len
* sizeof(WCHAR
));
1651 MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, param
, len
);
1652 ret
= CertOpenSystemStoreW(hProv
, param
);
1653 CryptMemFree(param
);
1657 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1661 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1662 LPCWSTR szSubSystemProtocol
)
1666 if (!szSubSystemProtocol
)
1668 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1672 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1673 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1676 ret
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, hProv
,
1677 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1680 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1681 0, hProv
, CERT_SYSTEM_STORE_LOCAL_MACHINE
, szSubSystemProtocol
);
1685 CertAddStoreToCollection(ret
, store
,
1686 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1687 CertCloseStore(store
, 0);
1689 store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1690 0, hProv
, CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1693 CertAddStoreToCollection(ret
, store
,
1694 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1695 CertCloseStore(store
, 0);
1701 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
1702 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
1704 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
1705 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
1709 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1710 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
1715 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
1717 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1718 pcrl
= CryptMemAlloc( sizeof (CRL_CONTEXT
) );
1722 data
= CryptMemAlloc( cbCrlEncoded
);
1725 CryptMemFree( pcrl
);
1729 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1730 pcrl
->pbCrlEncoded
= data
;
1731 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1732 pcrl
->pCrlInfo
= NULL
;
1733 pcrl
->hCertStore
= 0;
1738 /* Decodes the encoded certificate and creates the certificate context for it.
1739 * The reference count is initially zero, so you must create a reference to it
1740 * to avoid leaking memory.
1742 static PWINE_CERT_CONTEXT
CRYPT_CreateCertificateContext(
1743 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1745 PWINE_CERT_CONTEXT cert
= NULL
;
1747 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1748 PCERT_INFO certInfo
= NULL
;
1751 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1754 /* First try to decode it as a signed cert. */
1755 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT
, pbCertEncoded
,
1756 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1757 (BYTE
*)&signedCert
, &size
);
1761 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1762 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
1763 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1764 (BYTE
*)&certInfo
, &size
);
1765 LocalFree(signedCert
);
1767 /* Failing that, try it as an unsigned cert */
1771 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1772 pbCertEncoded
, cbCertEncoded
,
1773 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1774 (BYTE
*)&certInfo
, &size
);
1780 cert
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT
));
1783 data
= CryptMemAlloc(cbCertEncoded
);
1790 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
1791 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
1792 cert
->cert
.pbCertEncoded
= data
;
1793 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
1794 cert
->cert
.pCertInfo
= certInfo
;
1795 cert
->cert
.hCertStore
= 0;
1797 InitializeCriticalSection(&cert
->cs
);
1798 list_init(&cert
->extendedProperties
);
1805 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context
)
1807 PWINE_CERT_PROPERTY prop
, next
;
1809 CryptMemFree(context
->cert
.pbCertEncoded
);
1810 LocalFree(context
->cert
.pCertInfo
);
1811 DeleteCriticalSection(&context
->cs
);
1812 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
1813 WINE_CERT_PROPERTY
, entry
)
1815 list_remove(&prop
->entry
);
1816 CryptMemFree(prop
->pbData
);
1819 CryptMemFree(context
);
1822 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
1823 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1825 PWINE_CERT_CONTEXT cert
;
1826 PWINE_CERT_CONTEXT_REF ret
= NULL
;
1828 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1831 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
1834 ret
= CRYPT_CreateCertRef(cert
, 0);
1835 return (PCCERT_CONTEXT
)ret
;
1838 /* Since the properties are stored in a list, this is a tad inefficient
1839 * (O(n^2)) since I have to find the previous position every time.
1841 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
1844 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1847 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1849 EnterCriticalSection(&ref
->context
->cs
);
1852 PWINE_CERT_PROPERTY cursor
= NULL
;
1854 LIST_FOR_EACH_ENTRY(cursor
, &ref
->context
->extendedProperties
,
1855 WINE_CERT_PROPERTY
, entry
)
1857 if (cursor
->hdr
.propID
== dwPropId
)
1862 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
1863 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
1871 else if (!list_empty(&ref
->context
->extendedProperties
))
1872 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
1873 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
1876 LeaveCriticalSection(&ref
->context
->cs
);
1880 static BOOL
CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context
, DWORD dwPropId
,
1881 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
1884 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
1888 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1890 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
1896 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1897 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1899 PWINE_CERT_PROPERTY prop
;
1902 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1904 EnterCriticalSection(&context
->cs
);
1907 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1908 WINE_CERT_PROPERTY
, entry
)
1910 if (prop
->hdr
.propID
== dwPropId
)
1914 *pcbData
= prop
->hdr
.cb
;
1917 else if (*pcbData
< prop
->hdr
.cb
)
1919 SetLastError(ERROR_MORE_DATA
);
1920 *pcbData
= prop
->hdr
.cb
;
1924 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1925 *pcbData
= prop
->hdr
.cb
;
1934 /* Implicit properties */
1937 case CERT_SHA1_HASH_PROP_ID
:
1938 ret
= CRYPT_GetCertHashProp(context
, dwPropId
, CALG_SHA1
,
1939 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1942 case CERT_MD5_HASH_PROP_ID
:
1943 ret
= CRYPT_GetCertHashProp(context
, dwPropId
, CALG_MD5
,
1944 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1947 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1948 ret
= CRYPT_GetCertHashProp(context
, dwPropId
, CALG_MD5
,
1949 context
->cert
.pCertInfo
->Subject
.pbData
,
1950 context
->cert
.pCertInfo
->Subject
.cbData
,
1953 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1954 ret
= CRYPT_GetCertHashProp(context
, dwPropId
, CALG_MD5
,
1955 context
->cert
.pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
1956 context
->cert
.pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
,
1959 case CERT_SIGNATURE_HASH_PROP_ID
:
1960 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1961 FIXME("implicit property %ld\n", dwPropId
);
1962 SetLastError(CRYPT_E_NOT_FOUND
);
1965 SetLastError(CRYPT_E_NOT_FOUND
);
1968 LeaveCriticalSection(&context
->cs
);
1969 TRACE("returning %d\n", ret
);
1973 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1974 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1976 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1979 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1981 /* Special cases for invalid/special prop IDs.
1986 case CERT_CERT_PROP_ID
:
1987 case CERT_CRL_PROP_ID
:
1988 case CERT_CTL_PROP_ID
:
1989 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1991 case CERT_ACCESS_STATE_PROP_ID
:
1994 *pcbData
= sizeof(DWORD
);
1997 else if (*pcbData
< sizeof(DWORD
))
1999 SetLastError(ERROR_MORE_DATA
);
2000 *pcbData
= sizeof(DWORD
);
2007 if (pCertContext
->hCertStore
)
2009 PWINECRYPT_CERTSTORE store
=
2010 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2012 /* Take advantage of knowledge of the stores to answer the
2013 * access state question
2015 if (store
->type
!= StoreTypeReg
||
2016 !(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
2017 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
2019 *(DWORD
*)pvData
= state
;
2024 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
2026 TRACE("returning %d\n", ret
);
2030 /* Copies cbData bytes from pbData to the context's property with ID
2033 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
2034 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
2041 data
= CryptMemAlloc(cbData
);
2043 memcpy(data
, pbData
, cbData
);
2047 if (!cbData
|| data
)
2049 PWINE_CERT_PROPERTY prop
;
2051 EnterCriticalSection(&context
->cs
);
2052 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
2053 WINE_CERT_PROPERTY
, entry
)
2055 if (prop
->hdr
.propID
== dwPropId
)
2058 if (prop
&& prop
->entry
.next
!= &context
->extendedProperties
)
2060 CryptMemFree(prop
->pbData
);
2061 prop
->hdr
.cb
= cbData
;
2062 prop
->pbData
= cbData
? data
: NULL
;
2067 prop
= CryptMemAlloc(sizeof(WINE_CERT_PROPERTY
));
2070 prop
->hdr
.propID
= dwPropId
;
2071 prop
->hdr
.unknown
= 1;
2072 prop
->hdr
.cb
= cbData
;
2073 list_init(&prop
->entry
);
2074 prop
->pbData
= cbData
? data
: NULL
;
2075 list_add_tail(&context
->extendedProperties
, &prop
->entry
);
2081 LeaveCriticalSection(&context
->cs
);
2086 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
2087 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2091 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
2095 PWINE_CERT_PROPERTY prop
, next
;
2097 EnterCriticalSection(&context
->cs
);
2098 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
2099 WINE_CERT_PROPERTY
, entry
)
2101 if (prop
->hdr
.propID
== dwPropId
)
2103 list_remove(&prop
->entry
);
2104 CryptMemFree(prop
->pbData
);
2108 LeaveCriticalSection(&context
->cs
);
2115 case CERT_AUTO_ENROLL_PROP_ID
:
2116 case CERT_CTL_USAGE_PROP_ID
:
2117 case CERT_DESCRIPTION_PROP_ID
:
2118 case CERT_FRIENDLY_NAME_PROP_ID
:
2119 case CERT_HASH_PROP_ID
:
2120 case CERT_KEY_IDENTIFIER_PROP_ID
:
2121 case CERT_MD5_HASH_PROP_ID
:
2122 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2123 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2124 case CERT_PVK_FILE_PROP_ID
:
2125 case CERT_SIGNATURE_HASH_PROP_ID
:
2126 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2127 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
2128 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2129 case CERT_ENROLLMENT_PROP_ID
:
2130 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2131 case CERT_RENEWAL_PROP_ID
:
2133 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
2135 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2136 blob
->pbData
, blob
->cbData
);
2139 case CERT_DATE_STAMP_PROP_ID
:
2140 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2141 pvData
, sizeof(FILETIME
));
2144 FIXME("%ld: stub\n", dwPropId
);
2147 TRACE("returning %d\n", ret
);
2151 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
2152 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2154 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2157 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
2159 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2160 * crashes on most of these, I'll be safer.
2165 case CERT_ACCESS_STATE_PROP_ID
:
2166 case CERT_CERT_PROP_ID
:
2167 case CERT_CRL_PROP_ID
:
2168 case CERT_CTL_PROP_ID
:
2169 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2172 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
2174 TRACE("returning %d\n", ret
);
2178 /* Only the reference portion of the context is duplicated. The returned
2179 * context has the cert store set to 0, to prevent the store's certificate free
2180 * function from getting called on partial data.
2181 * FIXME: is this okay? Needs a test.
2183 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
2184 PCCERT_CONTEXT pCertContext
)
2186 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
, ret
;
2188 TRACE("(%p)\n", pCertContext
);
2191 ret
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF
));
2194 memcpy(ret
, ref
, sizeof(*ret
));
2195 ret
->cert
.hCertStore
= 0;
2196 InterlockedIncrement(&ret
->context
->ref
);
2201 return (PCCERT_CONTEXT
)ret
;
2204 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
2205 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
2206 PCCERT_CONTEXT
*ppStoreContext
)
2208 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
2209 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2210 PWINE_CERT_CONTEXT cert
;
2213 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2214 dwAddDisposition
, ppStoreContext
);
2216 /* FIXME: some tests needed to verify return codes */
2219 SetLastError(ERROR_INVALID_PARAMETER
);
2222 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2224 SetLastError(ERROR_INVALID_PARAMETER
);
2228 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
2229 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
2232 PWINE_CERT_PROPERTY prop
;
2235 EnterCriticalSection(&ref
->context
->cs
);
2236 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2237 WINE_CERT_PROPERTY
, entry
)
2239 ret
= CRYPT_SaveCertificateContextProperty(cert
, prop
->hdr
.propID
,
2240 prop
->pbData
, prop
->hdr
.cb
);
2244 LeaveCriticalSection(&ref
->context
->cs
);
2247 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2248 if (ret
&& ppStoreContext
)
2249 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
2253 CRYPT_FreeCert(cert
);
2260 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
2261 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
2262 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
2264 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2267 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2268 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2272 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2276 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
2277 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2281 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2282 if (ret
&& ppCertContext
)
2283 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
2286 CRYPT_FreeCert(cert
);
2294 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
2295 PCCERT_CONTEXT pPrev
)
2297 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2298 PWINE_CERT_CONTEXT_REF prev
= (PWINE_CERT_CONTEXT_REF
)pPrev
;
2301 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2304 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2307 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
2311 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2315 TRACE("(%p)\n", pCertContext
);
2319 else if (!pCertContext
->hCertStore
)
2322 CertFreeCertificateContext(pCertContext
);
2326 PWINECRYPT_CERTSTORE hcs
=
2327 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2331 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2335 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2337 CertFreeCertificateContext(pCertContext
);
2343 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
2344 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
2345 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
2347 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2348 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
2353 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
2354 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
2355 PCCRL_CONTEXT
* ppStoreContext
)
2357 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
2358 dwAddDisposition
, ppStoreContext
);
2362 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2364 FIXME("%p\n", pCrlContext
);
2369 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2371 FIXME("(%p): stub\n", pCrlContext
);
2375 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2376 PCCRL_CONTEXT pPrev
)
2378 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2382 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2383 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2385 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
2390 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
2391 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
2392 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
2394 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2395 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
2400 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
2401 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
2402 PCCTL_CONTEXT
* ppStoreContext
)
2404 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
2405 dwAddDisposition
, ppStoreContext
);
2409 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2411 FIXME("(%p): stub\n", pCtlContext
);
2415 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2417 FIXME("(%p): stub\n", pCtlContext
);
2421 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2422 PCCTL_CONTEXT pPrev
)
2424 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2429 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2431 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2433 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2438 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2441 if (InterlockedDecrement(&hcs
->ref
) == 0)
2443 TRACE("%p's ref count is 0, freeing\n", hcs
);
2445 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2446 CryptReleaseContext(hcs
->cryptProv
, 0);
2447 hcs
->closeStore(hcs
, dwFlags
);
2450 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2454 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2455 DWORD dwCtrlType
, void const *pvCtrlPara
)
2457 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2460 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2465 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2470 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
2477 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2478 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2480 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
2484 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2485 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2487 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
2492 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
2493 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2495 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext
, dwFlags
, pbElement
,
2500 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2501 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2503 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
2507 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2508 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2510 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
2515 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
2516 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2518 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext
, dwFlags
, pbElement
,
2523 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
2524 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2528 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
2533 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2534 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) +
2535 pCertContext
->cbCertEncoded
;
2536 PWINE_CERT_PROPERTY prop
;
2538 EnterCriticalSection(&ref
->context
->cs
);
2539 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2540 WINE_CERT_PROPERTY
, entry
)
2541 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + prop
->hdr
.cb
;
2544 *pcbElement
= bytesNeeded
;
2547 else if (*pcbElement
< bytesNeeded
)
2549 *pcbElement
= bytesNeeded
;
2550 SetLastError(ERROR_MORE_DATA
);
2555 PWINE_CERT_PROP_HEADER hdr
;
2557 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2558 WINE_CERT_PROPERTY
, entry
)
2560 memcpy(pbElement
, &prop
->hdr
, sizeof(WINE_CERT_PROP_HEADER
));
2561 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2564 memcpy(pbElement
, prop
->pbData
, prop
->hdr
.cb
);
2565 pbElement
+= prop
->hdr
.cb
;
2568 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
2569 hdr
->propID
= CERT_CERT_PROP_ID
;
2571 hdr
->cb
= pCertContext
->cbCertEncoded
;
2572 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
2573 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
2576 LeaveCriticalSection(&ref
->context
->cs
);
2583 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2584 * to its header if a valid header is found, NULL if not. Valid means the
2585 * length of thte property won't overrun buf, and the unknown field is 1.
2587 static const WINE_CERT_PROP_HEADER
*CRYPT_findPropID(const BYTE
*buf
,
2588 DWORD size
, DWORD propID
)
2590 const WINE_CERT_PROP_HEADER
*ret
= NULL
;
2593 while (size
&& !ret
&& !done
)
2595 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
2597 SetLastError(CRYPT_E_FILE_ERROR
);
2602 const WINE_CERT_PROP_HEADER
*hdr
=
2603 (const WINE_CERT_PROP_HEADER
*)buf
;
2605 size
-= sizeof(WINE_CERT_PROP_HEADER
);
2606 buf
+= sizeof(WINE_CERT_PROP_HEADER
);
2609 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2612 else if (!hdr
->propID
)
2614 /* assume a zero prop ID means the data are uninitialized, so
2619 else if (hdr
->unknown
!= 1)
2621 SetLastError(ERROR_FILE_NOT_FOUND
);
2624 else if (hdr
->propID
== propID
)
2636 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
2637 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
)
2639 const void *context
;
2641 TRACE("(%p, %ld, %08lx, %p)\n", pbElement
, cbElement
, dwContextTypeFlags
,
2646 SetLastError(ERROR_END_OF_MEDIA
);
2652 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2653 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
2659 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
2661 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2663 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2666 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2668 type
= CERT_STORE_CRL_CONTEXT
;
2671 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
2674 type
= CERT_STORE_CTL_CONTEXT
;
2678 else if (dwContextTypeFlags
& CERT_STORE_CERTIFICATE_CONTEXT_FLAG
)
2680 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2681 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2683 else if (dwContextTypeFlags
& CERT_STORE_CRL_CONTEXT_FLAG
)
2685 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2686 type
= CERT_STORE_CRL_CONTEXT
;
2688 else if (dwContextTypeFlags
& CERT_STORE_CTL_CONTEXT_FLAG
)
2690 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CTL_PROP_ID
);
2691 type
= CERT_STORE_CTL_CONTEXT
;
2696 case CERT_STORE_CERTIFICATE_CONTEXT
:
2697 contextInterface
= &gCertInterface
;
2699 case CERT_STORE_CRL_CONTEXT
:
2700 contextInterface
= &gCRLInterface
;
2702 case CERT_STORE_CTL_CONTEXT
:
2703 contextInterface
= &gCTLInterface
;
2706 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2713 context
= contextInterface
->create(X509_ASN_ENCODING
,
2714 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
2717 BOOL noMoreProps
= FALSE
;
2719 while (!noMoreProps
&& ret
)
2721 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
2725 const WINE_CERT_PROP_HEADER
*hdr
=
2726 (const WINE_CERT_PROP_HEADER
*)pbElement
;
2728 TRACE("prop is %ld\n", hdr
->propID
);
2729 cbElement
-= sizeof(WINE_CERT_PROP_HEADER
);
2730 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2731 if (cbElement
< hdr
->cb
)
2733 SetLastError(HRESULT_FROM_WIN32(
2734 ERROR_INVALID_PARAMETER
));
2737 else if (!hdr
->propID
)
2739 /* Like in CRYPT_findPropID, stop if the propID is zero
2743 else if (hdr
->unknown
!= 1)
2745 SetLastError(ERROR_FILE_NOT_FOUND
);
2748 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
2749 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!=
2752 /* Have to create a blob for most types, but not
2755 switch (hdr
->propID
)
2757 case CERT_AUTO_ENROLL_PROP_ID
:
2758 case CERT_CTL_USAGE_PROP_ID
:
2759 case CERT_DESCRIPTION_PROP_ID
:
2760 case CERT_FRIENDLY_NAME_PROP_ID
:
2761 case CERT_HASH_PROP_ID
:
2762 case CERT_KEY_IDENTIFIER_PROP_ID
:
2763 case CERT_MD5_HASH_PROP_ID
:
2764 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2765 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2766 case CERT_PVK_FILE_PROP_ID
:
2767 case CERT_SIGNATURE_HASH_PROP_ID
:
2768 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2769 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2770 case CERT_ENROLLMENT_PROP_ID
:
2771 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2772 case CERT_RENEWAL_PROP_ID
:
2774 CRYPT_DATA_BLOB blob
= { hdr
->cb
,
2775 (LPBYTE
)pbElement
};
2777 ret
= contextInterface
->setProp(context
,
2778 hdr
->propID
, 0, &blob
);
2781 case CERT_DATE_STAMP_PROP_ID
:
2782 ret
= contextInterface
->setProp(context
,
2783 hdr
->propID
, 0, pbElement
);
2786 FIXME("prop ID %ld: stub\n", hdr
->propID
);
2789 pbElement
+= hdr
->cb
;
2790 cbElement
-= hdr
->cb
;
2798 *pdwContentType
= type
;
2802 contextInterface
->free(context
);
2809 SetLastError(STATUS_ACCESS_VIOLATION
);
2816 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
2817 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
2818 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
2820 const void *context
;
2824 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore
,
2825 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
2826 pdwContentType
, ppvContext
);
2828 /* Call the internal function, then delete the hashes. Tests show this
2829 * function uses real hash values, not whatever's stored in the hash
2832 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
2833 dwContextTypeFlags
, &type
);
2836 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2840 case CERT_STORE_CERTIFICATE_CONTEXT
:
2841 contextInterface
= &gCertInterface
;
2843 case CERT_STORE_CRL_CONTEXT
:
2844 contextInterface
= &gCRLInterface
;
2846 case CERT_STORE_CTL_CONTEXT
:
2847 contextInterface
= &gCTLInterface
;
2850 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2852 if (contextInterface
)
2854 contextInterface
->setProp(context
, CERT_HASH_PROP_ID
, 0, NULL
);
2855 contextInterface
->setProp(context
, CERT_MD5_HASH_PROP_ID
, 0, NULL
);
2856 contextInterface
->setProp(context
, CERT_SIGNATURE_HASH_PROP_ID
, 0,
2859 *pdwContentType
= type
;
2860 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
2861 dwAddDisposition
, ppvContext
);
2862 contextInterface
->free(context
);
2872 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref
)
2874 if (InterlockedDecrement(&ref
->context
->ref
) == 0)
2876 TRACE("%p's ref count is 0, freeing\n", ref
->context
);
2877 CRYPT_FreeCert(ref
->context
);
2880 TRACE("%p's ref count is %ld\n", ref
->context
, ref
->context
->ref
);
2883 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2885 TRACE("(%p)\n", pCertContext
);
2889 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2890 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)ref
->cert
.hCertStore
;
2892 CRYPT_UnrefCertificateContext(ref
);
2893 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
2895 store
->freeCert(ref
);
2896 TRACE("freeing %p\n", ref
);
2902 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
2903 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
,
2904 const void *pvPara
, PCCERT_CONTEXT pPrevCertContext
)
2906 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore
, dwCertEncodingType
,
2907 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
2908 SetLastError(CRYPT_E_NOT_FOUND
);
2912 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
2913 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
2915 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2916 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2917 PWINE_STORE_LIST_ENTRY entry
;
2920 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2921 dwUpdateFlags
, dwPriority
);
2923 if (!collection
|| !sibling
)
2925 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2927 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2930 if (collection
->hdr
.type
!= StoreTypeCollection
)
2932 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2935 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2937 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2941 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
2944 InterlockedIncrement(&sibling
->ref
);
2945 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
2946 entry
->store
= sibling
;
2947 entry
->dwUpdateFlags
= dwUpdateFlags
;
2948 entry
->dwPriority
= dwPriority
;
2949 list_init(&entry
->entry
);
2950 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
2951 EnterCriticalSection(&collection
->cs
);
2954 PWINE_STORE_LIST_ENTRY cursor
;
2957 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
2958 WINE_STORE_LIST_ENTRY
, entry
)
2960 if (cursor
->dwPriority
< dwPriority
)
2962 list_add_before(&cursor
->entry
, &entry
->entry
);
2968 list_add_tail(&collection
->stores
, &entry
->entry
);
2971 list_add_tail(&collection
->stores
, &entry
->entry
);
2972 LeaveCriticalSection(&collection
->cs
);
2980 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
2981 HCERTSTORE hSiblingStore
)
2983 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2984 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2985 PWINE_STORE_LIST_ENTRY store
, next
;
2987 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
2989 if (!collection
|| !sibling
)
2991 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2993 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2996 if (collection
->hdr
.type
!= StoreTypeCollection
)
2998 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
3000 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3003 EnterCriticalSection(&collection
->cs
);
3004 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
3005 WINE_STORE_LIST_ENTRY
, entry
)
3007 if (store
->store
== sibling
)
3009 list_remove(&store
->entry
);
3010 CertCloseStore(store
->store
, 0);
3011 CryptMemFree(store
);
3015 LeaveCriticalSection(&collection
->cs
);
3018 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
3019 CRYPT_ATTRIBUTE rgAttr
[])
3021 PCRYPT_ATTRIBUTE ret
= NULL
;
3024 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
3030 SetLastError(ERROR_INVALID_PARAMETER
);
3034 for (i
= 0; !ret
&& i
< cAttr
; i
++)
3035 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
3040 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
3041 CERT_EXTENSION rgExtensions
[])
3043 PCERT_EXTENSION ret
= NULL
;
3046 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
3052 SetLastError(ERROR_INVALID_PARAMETER
);
3056 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
3057 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
3058 rgExtensions
[i
].pszObjId
))
3059 ret
= &rgExtensions
[i
];
3063 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
3065 PCERT_RDN_ATTR ret
= NULL
;
3068 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
3072 SetLastError(ERROR_INVALID_PARAMETER
);
3076 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
3077 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
3078 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
3079 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
3080 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
3084 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
3085 PCERT_INFO pCertInfo
)
3094 GetSystemTime(&sysTime
);
3095 SystemTimeToFileTime(&sysTime
, &fileTime
);
3096 pTimeToVerify
= &fileTime
;
3098 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
3100 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
3107 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
3108 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
3109 DWORD
*pcbComputedHash
)
3112 HCRYPTHASH hHash
= 0;
3114 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
3115 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
3118 hCryptProv
= CRYPT_GetDefaultProvider();
3123 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
3126 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
3128 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
3129 pcbComputedHash
, 0);
3130 CryptDestroyHash(hHash
);
3136 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV hCryptProv
, DWORD dwKeySpec
,
3137 DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
3138 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
3139 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
3145 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv
,
3146 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
3147 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
3149 algID
= CertOIDToAlgId(pSignatureAlgorithm
->pszObjId
);
3152 SetLastError(NTE_BAD_ALGID
);
3157 SetLastError(ERROR_INVALID_PARAMETER
);
3161 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hHash
);
3164 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
, cbEncodedToBeSigned
, 0);
3166 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
3168 CryptDestroyHash(hHash
);
3173 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv
,
3174 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
3175 PCERT_PUBLIC_KEY_INFO pPublicKey
)
3177 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
3178 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, (void *)pbEncoded
,
3179 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
3182 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv
,
3183 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
3184 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
3187 CRYPT_DATA_BLOB subjectBlob
;
3189 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv
,
3190 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
3191 dwFlags
, pvReserved
);
3193 switch (dwSubjectType
)
3195 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
3197 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvSubject
;
3199 subjectBlob
.pbData
= blob
->pbData
;
3200 subjectBlob
.cbData
= blob
->cbData
;
3203 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
3205 PCERT_CONTEXT context
= (PCERT_CONTEXT
)pvSubject
;
3207 subjectBlob
.pbData
= context
->pbCertEncoded
;
3208 subjectBlob
.cbData
= context
->cbCertEncoded
;
3211 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
3213 PCRL_CONTEXT context
= (PCRL_CONTEXT
)pvSubject
;
3215 subjectBlob
.pbData
= context
->pbCrlEncoded
;
3216 subjectBlob
.cbData
= context
->cbCrlEncoded
;
3220 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3226 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
3229 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
3230 subjectBlob
.pbData
, subjectBlob
.cbData
,
3231 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
3232 (BYTE
*)&signedCert
, &size
);
3235 switch (dwIssuerType
)
3237 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
3239 PCERT_PUBLIC_KEY_INFO pubKeyInfo
=
3240 (PCERT_PUBLIC_KEY_INFO
)pvIssuer
;
3241 ALG_ID algID
= CertOIDToAlgId(pubKeyInfo
->Algorithm
.pszObjId
);
3247 ret
= CryptImportPublicKeyInfoEx(hCryptProv
,
3248 dwCertEncodingType
, pubKeyInfo
, algID
, 0, NULL
, &key
);
3253 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hash
);
3256 ret
= CryptHashData(hash
,
3257 signedCert
->ToBeSigned
.pbData
,
3258 signedCert
->ToBeSigned
.cbData
, 0);
3261 ret
= CryptVerifySignatureW(hash
,
3262 signedCert
->Signature
.pbData
,
3263 signedCert
->Signature
.cbData
, key
, NULL
, 0);
3265 CryptDestroyHash(hash
);
3267 CryptDestroyKey(key
);
3272 SetLastError(NTE_BAD_ALGID
);
3277 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
3278 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
3279 FIXME("issuer type %ld: stub\n", dwIssuerType
);
3282 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
3285 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3290 FIXME("unimplemented for NULL signer\n");
3291 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3296 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3299 LocalFree(signedCert
);
3305 BOOL WINAPI
CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara
,
3306 DWORD dwSignerIndex
, const BYTE
* pbSignedBlob
, DWORD cbSignedBlob
,
3307 BYTE
* pbDecoded
, DWORD
* pcbDecoded
, PCCERT_CONTEXT
* ppSignerCert
)
3309 FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n",
3310 pVerifyPara
, dwSignerIndex
, pbSignedBlob
, cbSignedBlob
,
3311 pbDecoded
, pcbDecoded
, ppSignerCert
);