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 HeapAlloc): CertFreeCertificateContext frees
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 /* 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
)
328 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
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
,
356 PWINE_CERT_CONTEXT_REF pCertRef
= HeapAlloc(GetProcessHeap(), 0,
357 sizeof(WINE_CERT_CONTEXT_REF
));
360 CRYPT_InitCertRef(pCertRef
, context
, store
);
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
:
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
);
386 PWINE_CERT_LIST_ENTRY cursor
;
388 /* Add if no cert with the same hash is found. */
390 EnterCriticalSection(&ms
->cs
);
391 LIST_FOR_EACH_ENTRY(cursor
, &ms
->certs
, WINE_CERT_LIST_ENTRY
, entry
)
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
);
404 LeaveCriticalSection(&ms
->cs
);
408 case CERT_STORE_ADD_REPLACE_EXISTING
:
410 BYTE hashToAdd
[20], hash
[20];
411 DWORD size
= sizeof(hashToAdd
);
414 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
415 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
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
)
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
);
436 LeaveCriticalSection(&ms
->cs
);
441 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
446 PWINE_CERT_LIST_ENTRY entry
= HeapAlloc(GetProcessHeap(), 0,
447 sizeof(WINE_CERT_LIST_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
);
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
);
478 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
479 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
482 listNext
= list_next(&ms
->certs
, &ms
->certs
);
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
);
492 SetLastError(CRYPT_E_NOT_FOUND
);
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
;
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 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
530 LeaveCriticalSection(&store
->cs
);
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
);
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
,
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
);
573 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
574 sizeof(WINE_MEMSTORE
));
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
;
598 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
601 EnterCriticalSection(&cs
->cs
);
602 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
605 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
607 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
611 LeaveCriticalSection(&cs
->cs
);
612 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
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
));
624 /* Initialize to empty for now, just make sure the size is right */
625 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
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
,
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
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
);
670 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
671 pPrev
->childContext
);
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
;
682 struct list
*storeNext
= list_next(&store
->stores
,
685 pPrev
->childContext
= NULL
;
686 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
689 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
691 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
695 SetLastError(CRYPT_E_NOT_FOUND
);
702 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
706 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
707 child
->context
, store
);
710 ret
->entry
= storeEntry
;
711 ret
->childContext
= child
;
714 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
718 struct list
*storeNext
= list_next(&store
->stores
,
723 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
725 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
729 SetLastError(CRYPT_E_NOT_FOUND
);
734 TRACE("returning %p\n", 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
);
749 EnterCriticalSection(&cs
->cs
);
750 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
751 LeaveCriticalSection(&cs
->cs
);
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
,
762 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
766 SetLastError(CRYPT_E_NOT_FOUND
);
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
;
782 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
784 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
786 context
->childContext
= NULL
;
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
);
812 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
813 sizeof(WINE_COLLECTIONSTORE
));
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 };
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',
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
,
854 WCHAR subKeyName
[MAX_PATH
];
857 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
859 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
865 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
871 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
873 buf
= HeapAlloc(GetProcessHeap(), 0, size
);
876 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
883 TRACE("Adding cert with hash %s\n",
884 debugstr_w(subKeyName
));
885 context
= CRYPT_ReadSerializedElement(buf
, size
,
886 contextType
, &addedType
);
889 const WINE_CONTEXT_INTERFACE
*contextInterface
;
894 case CERT_STORE_CERTIFICATE_CONTEXT
:
895 contextInterface
= &gCertInterface
;
897 case CERT_STORE_CRL_CONTEXT
:
898 contextInterface
= &gCRLInterface
;
900 case CERT_STORE_CTL_CONTEXT
:
901 contextInterface
= &gCTLInterface
;
904 contextInterface
= NULL
;
906 if (contextInterface
)
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(
923 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
927 TRACE("hash doesn't match, ignoring\n");
928 contextInterface
->free(context
);
934 HeapFree(GetProcessHeap(), 0, buf
);
938 /* Ignore intermediate errors, continue enumerating */
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
};
951 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
956 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
960 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
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
,
970 WCHAR asciiHash
[20 * 2 + 1];
975 CRYPT_HashToStr(hash
, asciiHash
);
976 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
980 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
993 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
994 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
996 const void *context
= NULL
;
1000 context
= contextInterface
->enumContextsInStore(memStore
, context
);
1004 DWORD hashSize
= sizeof(hash
);
1006 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
1013 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
1015 buf
= HeapAlloc(GetProcessHeap(), 0, size
);
1018 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
1020 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
1022 HeapFree(GetProcessHeap(), 0, buf
);
1027 } while (ret
&& context
!= NULL
);
1029 contextInterface
->free(context
);
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
};
1042 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1045 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1046 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
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
)
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
)
1069 list_remove(&toDelete
->entry
);
1070 HeapFree(GetProcessHeap(), 0, toDelete
);
1072 LeaveCriticalSection(&store
->cs
);
1074 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
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
)
1094 if (store
->dirty
|| force
)
1095 ret
= CRYPT_RegWriteToReg(store
);
1101 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1103 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1105 TRACE("(%p, %08lx)\n", store
, 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
;
1123 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwAddDisposition
);
1125 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1127 SetLastError(ERROR_ACCESS_DENIED
);
1132 ret
= store
->memStore
->addCert(store
->memStore
, cert
, dwAddDisposition
);
1134 store
->dirty
= TRUE
;
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
));
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
);
1164 child
= rs
->memStore
->enumCert(rs
->memStore
, prev
->childContext
);
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
;
1175 child
= rs
->memStore
->enumCert(rs
->memStore
, NULL
);
1178 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_REG_CERT_CONTEXT
));
1182 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
1183 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
1184 ret
->childContext
= child
;
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
;
1199 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1201 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1203 SetLastError(ERROR_ACCESS_DENIED
);
1208 PWINE_HASH_TO_DELETE toDelete
=
1209 HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_HASH_TO_DELETE
));
1213 DWORD size
= sizeof(toDelete
->hash
);
1215 ret
= CertGetCertificateContextProperty(pCertContext
,
1216 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
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
,
1227 HeapFree(GetProcessHeap(), 0, toDelete
);
1232 store
->dirty
= TRUE
;
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
;
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
);
1268 case CERT_STORE_CTRL_COMMIT
:
1269 ret
= CRYPT_RegFlushStore(store
,
1270 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1273 FIXME("%ld: stub\n", dwCtrlType
);
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
;
1286 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1288 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1291 /* Find how many subkeys there are */
1292 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1293 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
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
));
1305 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
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
,
1315 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1318 if (lpszName
!= szNameBuf
)
1320 /* Free buffer if allocated */
1321 HeapFree(GetProcessHeap(), 0, lpszName
);
1326 RegCloseKey(hSubKey
);
1328 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
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
)
1356 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1357 GetCurrentProcess(), (LPHANDLE
)&key
,
1358 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1361 PWINECRYPT_CERTSTORE memStore
;
1363 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1366 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1367 sizeof(WINE_REGSTORE
));
1370 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
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
;
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
;
1404 PWINECRYPT_CERTSTORE store
= NULL
;
1409 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1410 debugstr_w((LPCWSTR
)pvPara
));
1414 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
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
;
1425 case CERT_SYSTEM_STORE_CURRENT_USER
:
1426 root
= HKEY_CURRENT_USER
;
1427 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
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
));
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
));
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
));
1448 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1449 root
= HKEY_CURRENT_USER
;
1450 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1452 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1453 root
= HKEY_LOCAL_MACHINE
;
1454 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
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
));
1462 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1466 storePath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(base
) +
1467 lstrlenW(storeName
) + 2) * sizeof(WCHAR
));
1472 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1475 wsprintfW(storePath
, fmt
, base
, storeName
);
1476 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1477 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1482 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1484 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1485 disp
== REG_OPENED_EXISTING_KEY
)
1488 rc
= ERROR_FILE_EXISTS
;
1493 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1498 HeapFree(GetProcessHeap(), 0, storePath
);
1503 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1504 DWORD dwFlags
, const void *pvPara
)
1507 PWINECRYPT_CERTSTORE ret
= NULL
;
1509 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1510 debugstr_a((LPCSTR
)pvPara
));
1514 SetLastError(ERROR_FILE_NOT_FOUND
);
1517 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1520 LPWSTR storeName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1524 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1525 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1526 HeapFree(GetProcessHeap(), 0, storeName
);
1532 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1533 DWORD dwFlags
, const void *pvPara
)
1535 HCERTSTORE store
= 0;
1538 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1539 debugstr_w((LPCWSTR
)pvPara
));
1543 SetLastError(ERROR_FILE_NOT_FOUND
);
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
:
1562 SetLastError(ERROR_FILE_NOT_FOUND
);
1567 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1568 0, hCryptProv
, dwFlags
, pvPara
);
1572 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1573 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
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
)
1590 PWINECRYPT_CERTSTORE ret
= NULL
;
1592 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1593 debugstr_a((LPCSTR
)pvPara
));
1597 SetLastError(ERROR_FILE_NOT_FOUND
);
1600 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1603 LPWSTR storeName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1607 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1608 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1609 HeapFree(GetProcessHeap(), 0, storeName
);
1615 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1616 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
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
;
1632 case (int)CERT_STORE_PROV_REG
:
1633 openFunc
= CRYPT_RegOpenStore
;
1635 case (int)CERT_STORE_PROV_COLLECTION
:
1636 openFunc
= CRYPT_CollectionOpenStore
;
1638 case (int)CERT_STORE_PROV_SYSTEM_A
:
1639 openFunc
= CRYPT_SysOpenStoreA
;
1641 case (int)CERT_STORE_PROV_SYSTEM_W
:
1642 openFunc
= CRYPT_SysOpenStoreW
;
1644 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1645 openFunc
= CRYPT_SysRegOpenStoreA
;
1647 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1648 openFunc
= CRYPT_SysRegOpenStoreW
;
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
;
1665 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1671 /* FIXME: need to look for an installed provider for this type */
1672 SetLastError(ERROR_FILE_NOT_FOUND
);
1676 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1677 return (HCERTSTORE
)hcs
;
1680 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1681 LPCSTR szSubSystemProtocol
)
1685 if (szSubSystemProtocol
)
1687 int len
= MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, NULL
,
1689 LPWSTR param
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1693 MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, param
, len
);
1694 ret
= CertOpenSystemStoreW(hProv
, param
);
1695 HeapFree(GetProcessHeap(), 0, param
);
1699 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1703 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1704 LPCWSTR szSubSystemProtocol
)
1708 if (!szSubSystemProtocol
)
1710 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
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,
1718 ret
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, hProv
,
1719 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1722 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1723 0, hProv
, CERT_SYSTEM_STORE_LOCAL_MACHINE
, szSubSystemProtocol
);
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
);
1735 CertAddStoreToCollection(ret
, store
,
1736 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1737 CertCloseStore(store
, 0);
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
);
1751 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1752 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
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
) );
1764 data
= HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded
);
1767 HeapFree( GetProcessHeap(), 0, pcrl
);
1771 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1772 pcrl
->pbCrlEncoded
= data
;
1773 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1774 pcrl
->pCrlInfo
= NULL
;
1775 pcrl
->hCertStore
= 0;
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
;
1789 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1790 PCERT_INFO certInfo
= NULL
;
1793 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
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
);
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 */
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
);
1822 cert
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT
));
1825 data
= HeapAlloc(GetProcessHeap(), 0, cbCertEncoded
);
1828 HeapFree(GetProcessHeap(), 0, cert
);
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;
1839 InitializeCriticalSection(&cert
->cs
);
1840 list_init(&cert
->extendedProperties
);
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
,
1873 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
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
,
1886 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1889 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1891 EnterCriticalSection(&ref
->context
->cs
);
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
)
1904 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
1905 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
1913 else if (!list_empty(&ref
->context
->extendedProperties
))
1914 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
1915 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
1918 LeaveCriticalSection(&ref
->context
->cs
);
1922 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1923 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1925 PWINE_CERT_PROPERTY prop
;
1928 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1930 EnterCriticalSection(&context
->cs
);
1933 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1934 WINE_CERT_PROPERTY
, entry
)
1936 if (prop
->hdr
.propID
== dwPropId
)
1940 *pcbData
= prop
->hdr
.cb
;
1943 else if (*pcbData
< prop
->hdr
.cb
)
1945 SetLastError(ERROR_MORE_DATA
);
1946 *pcbData
= prop
->hdr
.cb
;
1950 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1951 *pcbData
= prop
->hdr
.cb
;
1960 /* Implicit properties */
1963 case CERT_SHA1_HASH_PROP_ID
:
1964 ret
= CryptHashCertificate(0, CALG_SHA1
, 0,
1965 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1969 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1971 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
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
);
1986 LeaveCriticalSection(&context
->cs
);
1987 TRACE("returning %d\n", 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
;
1997 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1999 /* Special cases for invalid/special prop IDs.
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
));
2009 case CERT_ACCESS_STATE_PROP_ID
:
2012 *pcbData
= sizeof(DWORD
);
2015 else if (*pcbData
< sizeof(DWORD
))
2017 SetLastError(ERROR_MORE_DATA
);
2018 *pcbData
= sizeof(DWORD
);
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
;
2042 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
2044 TRACE("returning %d\n", ret
);
2048 /* Copies cbData bytes from pbData to the context's property with ID
2051 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
2052 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
2059 data
= HeapAlloc(GetProcessHeap(), 0, cbData
);
2061 memcpy(data
, pbData
, cbData
);
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
)
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
;
2085 prop
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY
));
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
);
2097 HeapFree(GetProcessHeap(), 0, data
);
2099 LeaveCriticalSection(&context
->cs
);
2104 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
2105 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2109 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, 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
);
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
);
2156 case CERT_DATE_STAMP_PROP_ID
:
2157 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2158 pvData
, sizeof(FILETIME
));
2161 FIXME("%ld: stub\n", dwPropId
);
2164 TRACE("returning %d\n", 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
;
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.
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
));
2189 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
2191 TRACE("returning %d\n", 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
);
2208 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF
));
2211 memcpy(ret
, ref
, sizeof(*ret
));
2212 ret
->cert
.hCertStore
= 0;
2213 InterlockedIncrement(&ret
->context
->ref
);
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
;
2230 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2231 dwAddDisposition
, ppStoreContext
);
2233 /* FIXME: some tests needed to verify return codes */
2236 SetLastError(ERROR_INVALID_PARAMETER
);
2239 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2241 SetLastError(ERROR_INVALID_PARAMETER
);
2245 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
2246 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
2249 PWINE_CERT_PROPERTY prop
;
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
);
2261 LeaveCriticalSection(&ref
->context
->cs
);
2264 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2265 if (ret
&& ppStoreContext
)
2266 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
2270 CRYPT_FreeCert(cert
);
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
;
2284 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2285 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2289 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2293 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
2294 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2298 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2299 if (ret
&& ppCertContext
)
2300 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
2303 CRYPT_FreeCert(cert
);
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
;
2318 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2321 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2324 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
2328 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2332 TRACE("(%p)\n", pCertContext
);
2336 else if (!pCertContext
->hCertStore
)
2339 CertFreeCertificateContext(pCertContext
);
2343 PWINECRYPT_CERTSTORE hcs
=
2344 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2348 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2352 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2353 CertFreeCertificateContext(pCertContext
);
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
,
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
);
2378 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2380 FIXME("%p\n", pCrlContext
);
2385 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2387 FIXME("(%p): stub\n", pCrlContext
);
2391 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2392 PCCRL_CONTEXT pPrev
)
2394 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2398 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2399 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2401 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
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
,
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
);
2425 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2427 FIXME("(%p): stub\n", pCtlContext
);
2431 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2433 FIXME("(%p): stub\n", pCtlContext
);
2437 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2438 PCCTL_CONTEXT pPrev
)
2440 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2445 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2447 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2449 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2454 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2457 if (InterlockedDecrement(&hcs
->ref
) == 0)
2459 TRACE("%p's ref count is 0, freeing\n", hcs
);
2461 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2462 CryptReleaseContext(hcs
->cryptProv
, 0);
2463 hcs
->closeStore(hcs
, dwFlags
);
2466 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2470 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2471 DWORD dwCtrlType
, void const *pvCtrlPara
)
2473 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2476 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2481 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2486 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
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
);
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
,
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
,
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
);
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
,
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
,
2539 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
2540 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2544 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
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
;
2560 *pcbElement
= bytesNeeded
;
2563 else if (*pcbElement
< bytesNeeded
)
2565 *pcbElement
= bytesNeeded
;
2566 SetLastError(ERROR_MORE_DATA
);
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
);
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
;
2587 hdr
->cb
= pCertContext
->cbCertEncoded
;
2588 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
2589 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
2592 LeaveCriticalSection(&ref
->context
->cs
);
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
;
2609 while (size
&& !ret
&& !done
)
2611 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
2613 SetLastError(CRYPT_E_FILE_ERROR
);
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
);
2625 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2628 else if (!hdr
->propID
)
2630 /* assume a zero prop ID means the data are uninitialized, so
2635 else if (hdr
->unknown
!= 1)
2637 SetLastError(ERROR_FILE_NOT_FOUND
);
2640 else if (hdr
->propID
== propID
)
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
,
2662 SetLastError(ERROR_END_OF_MEDIA
);
2668 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2669 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
2675 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
2677 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2679 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2682 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2684 type
= CERT_STORE_CRL_CONTEXT
;
2687 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
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
;
2712 case CERT_STORE_CERTIFICATE_CONTEXT
:
2713 contextInterface
= &gCertInterface
;
2715 case CERT_STORE_CRL_CONTEXT
:
2716 contextInterface
= &gCRLInterface
;
2718 case CERT_STORE_CTL_CONTEXT
:
2719 contextInterface
= &gCTLInterface
;
2722 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2729 context
= contextInterface
->create(X509_ASN_ENCODING
,
2730 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
2733 BOOL noMoreProps
= FALSE
;
2735 while (!noMoreProps
&& ret
)
2737 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
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
));
2753 else if (!hdr
->propID
)
2755 /* Like in CRYPT_findPropID, stop if the propID is zero
2759 else if (hdr
->unknown
!= 1)
2761 SetLastError(ERROR_FILE_NOT_FOUND
);
2764 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
2765 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!=
2768 /* Have to create a blob for most types, but not
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
);
2797 case CERT_DATE_STAMP_PROP_ID
:
2798 ret
= contextInterface
->setProp(context
,
2799 hdr
->propID
, 0, pbElement
);
2802 FIXME("prop ID %ld: stub\n", hdr
->propID
);
2805 pbElement
+= hdr
->cb
;
2806 cbElement
-= hdr
->cb
;
2814 *pdwContentType
= type
;
2818 contextInterface
->free(context
);
2823 __EXCEPT(page_fault
)
2825 SetLastError(STATUS_ACCESS_VIOLATION
);
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
;
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
2848 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
2849 dwContextTypeFlags
, &type
);
2852 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2856 case CERT_STORE_CERTIFICATE_CONTEXT
:
2857 contextInterface
= &gCertInterface
;
2859 case CERT_STORE_CRL_CONTEXT
:
2860 contextInterface
= &gCRLInterface
;
2862 case CERT_STORE_CTL_CONTEXT
:
2863 contextInterface
= &gCTLInterface
;
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,
2875 *pdwContentType
= type
;
2876 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
2877 dwAddDisposition
, ppvContext
);
2878 contextInterface
->free(context
);
2888 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2890 TRACE("(%p)\n", 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
);
2903 TRACE("%p's ref count is %ld\n", ref
->context
, ref
->context
->ref
);
2904 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
2906 store
->freeCert(ref
);
2907 HeapFree(GetProcessHeap(), 0, ref
);
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
);
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
;
2930 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2931 dwUpdateFlags
, dwPriority
);
2933 if (!collection
|| !sibling
)
2935 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2937 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2940 if (collection
->hdr
.type
!= StoreTypeCollection
)
2942 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2945 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2947 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2951 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_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
);
2964 PWINE_STORE_LIST_ENTRY cursor
;
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
);
2978 list_add_tail(&collection
->stores
, &entry
->entry
);
2981 list_add_tail(&collection
->stores
, &entry
->entry
);
2982 LeaveCriticalSection(&collection
->cs
);
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
)
3001 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
3003 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3006 if (collection
->hdr
.type
!= StoreTypeCollection
)
3008 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
3010 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
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
);
3025 LeaveCriticalSection(&collection
->cs
);
3028 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
3029 CRYPT_ATTRIBUTE rgAttr
[])
3031 PCRYPT_ATTRIBUTE ret
= NULL
;
3034 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
3040 SetLastError(ERROR_INVALID_PARAMETER
);
3044 for (i
= 0; !ret
&& i
< cAttr
; i
++)
3045 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
3050 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
3051 CERT_EXTENSION rgExtensions
[])
3053 PCERT_EXTENSION ret
= NULL
;
3056 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
3062 SetLastError(ERROR_INVALID_PARAMETER
);
3066 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
3067 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
3068 rgExtensions
[i
].pszObjId
))
3069 ret
= &rgExtensions
[i
];
3073 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
3075 PCERT_RDN_ATTR ret
= NULL
;
3078 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
3082 SetLastError(ERROR_INVALID_PARAMETER
);
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
];
3094 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
3095 PCERT_INFO pCertInfo
)
3104 GetSystemTime(&sysTime
);
3105 SystemTimeToFileTime(&sysTime
, &fileTime
);
3106 pTimeToVerify
= &fileTime
;
3108 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
3110 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
3117 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
3118 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
3119 DWORD
*pcbComputedHash
)
3122 HCRYPTHASH hHash
= 0;
3124 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
3125 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
3128 hCryptProv
= CRYPT_GetDefaultProvider();
3133 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
3136 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
3138 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
3139 pcbComputedHash
, 0);
3140 CryptDestroyHash(hHash
);
3146 HCRYPTOIDFUNCSET WINAPI
CryptInitOIDFunctionSet(LPCSTR pszFuncName
, DWORD dwFlags
)
3148 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName
), dwFlags
);
3152 BOOL WINAPI
CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType
,
3153 LPCSTR pszFuncName
, LPCWSTR pwszDll
)
3155 FIXME("stub: %lx %s %s\n", dwEncodingType
, debugstr_a(pszFuncName
), debugstr_w(pwszDll
));