3 Mike McCormack for CodeWeavers
4 * Copyright 2004,2005 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * - As you can see in the stubs below, support for CRLs and CTLs is missing.
22 * Mostly this should be copy-paste work, and some code (e.g. extended
23 * properties) could be shared between them.
24 * - Opening a cert store provider should be morphed to support loading
26 * - The concept of physical stores and locations isn't implemented. (This
27 * doesn't mean registry stores et al aren't implemented. See the PSDK for
28 * registering and enumerating physical stores and locations.)
29 * - Many flags, options and whatnot are unimplemented.
34 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
36 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
37 /* The following aren't defined in wincrypt.h, as they're "reserved" */
38 #define CERT_CERT_PROP_ID 32
39 #define CERT_CRL_PROP_ID 33
40 #define CERT_CTL_PROP_ID 34
42 /* Some typedefs that make it easier to abstract which type of context we're
45 typedef const void *(WINAPI
*CreateContextFunc
)(DWORD dwCertEncodingType
,
46 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
);
47 typedef BOOL (WINAPI
*AddContextToStoreFunc
)(HCERTSTORE hCertStore
,
48 const void *context
, DWORD dwAddDisposition
, const void **ppStoreContext
);
49 typedef BOOL (WINAPI
*AddEncodedContextToStoreFunc
)(HCERTSTORE hCertStore
,
50 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
51 DWORD dwAddDisposition
, const void **ppContext
);
52 typedef const void *(WINAPI
*EnumContextsInStoreFunc
)(HCERTSTORE hCertStore
,
53 const void *pPrevContext
);
54 typedef BOOL (WINAPI
*GetContextPropertyFunc
)(const void *context
,
55 DWORD dwPropID
, void *pvData
, DWORD
*pcbData
);
56 typedef BOOL (WINAPI
*SetContextPropertyFunc
)(const void *context
,
57 DWORD dwPropID
, DWORD dwFlags
, const void *pvData
);
58 typedef BOOL (WINAPI
*SerializeElementFunc
)(const void *context
, DWORD dwFlags
,
59 BYTE
*pbElement
, DWORD
*pcbElement
);
60 typedef BOOL (WINAPI
*FreeContextFunc
)(const void *context
);
61 typedef BOOL (WINAPI
*DeleteContextFunc
)(const void *context
);
63 /* An abstract context (certificate, CRL, or CTL) interface */
64 typedef struct _WINE_CONTEXT_INTERFACE
66 CreateContextFunc create
;
67 AddContextToStoreFunc addContextToStore
;
68 AddEncodedContextToStoreFunc addEncodedToStore
;
69 EnumContextsInStoreFunc enumContextsInStore
;
70 GetContextPropertyFunc getProp
;
71 SetContextPropertyFunc setProp
;
72 SerializeElementFunc serialize
;
74 DeleteContextFunc deleteFromStore
;
75 } WINE_CONTEXT_INTERFACE
, *PWINE_CONTEXT_INTERFACE
;
77 static const WINE_CONTEXT_INTERFACE gCertInterface
= {
78 (CreateContextFunc
)CertCreateCertificateContext
,
79 (AddContextToStoreFunc
)CertAddCertificateContextToStore
,
80 (AddEncodedContextToStoreFunc
)CertAddEncodedCertificateToStore
,
81 (EnumContextsInStoreFunc
)CertEnumCertificatesInStore
,
82 (GetContextPropertyFunc
)CertGetCertificateContextProperty
,
83 (SetContextPropertyFunc
)CertSetCertificateContextProperty
,
84 (SerializeElementFunc
)CertSerializeCertificateStoreElement
,
85 (FreeContextFunc
)CertFreeCertificateContext
,
86 (DeleteContextFunc
)CertDeleteCertificateFromStore
,
89 static const WINE_CONTEXT_INTERFACE gCRLInterface
= {
90 (CreateContextFunc
)CertCreateCRLContext
,
91 (AddContextToStoreFunc
)CertAddCRLContextToStore
,
92 (AddEncodedContextToStoreFunc
)CertAddEncodedCRLToStore
,
93 (EnumContextsInStoreFunc
)CertEnumCRLsInStore
,
94 (GetContextPropertyFunc
)CertGetCRLContextProperty
,
95 (SetContextPropertyFunc
)CertSetCRLContextProperty
,
96 (SerializeElementFunc
)CertSerializeCRLStoreElement
,
97 (FreeContextFunc
)CertFreeCRLContext
,
98 (DeleteContextFunc
)CertDeleteCRLFromStore
,
101 static const WINE_CONTEXT_INTERFACE gCTLInterface
= {
102 (CreateContextFunc
)CertCreateCTLContext
,
103 (AddContextToStoreFunc
)CertAddCTLContextToStore
,
104 (AddEncodedContextToStoreFunc
)CertAddEncodedCTLToStore
,
105 (EnumContextsInStoreFunc
)CertEnumCTLsInStore
,
106 (GetContextPropertyFunc
)CertGetCTLContextProperty
,
107 (SetContextPropertyFunc
)CertSetCTLContextProperty
,
108 (SerializeElementFunc
)CertSerializeCTLStoreElement
,
109 (FreeContextFunc
)CertFreeCTLContext
,
110 (DeleteContextFunc
)CertDeleteCTLFromStore
,
113 struct WINE_CRYPTCERTSTORE
;
115 typedef struct WINE_CRYPTCERTSTORE
* (*StoreOpenFunc
)(HCRYPTPROV hCryptProv
,
116 DWORD dwFlags
, const void *pvPara
);
118 struct _WINE_CERT_CONTEXT_REF
;
120 /* Called to enumerate the next certificate in a store. The returned pointer
121 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
124 typedef struct _WINE_CERT_CONTEXT_REF
* (*EnumCertFunc
)
125 (struct WINE_CRYPTCERTSTORE
*store
, struct _WINE_CERT_CONTEXT_REF
*pPrev
);
127 struct _WINE_CERT_CONTEXT
;
129 /* Called to create a new reference to an existing cert context. Should call
130 * CRYPT_InitCertRef to make sure the reference count is properly updated.
131 * If the store does not provide any additional allocated data (that is, does
132 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
135 typedef struct _WINE_CERT_CONTEXT_REF
* (*CreateRefFunc
)
136 (struct _WINE_CERT_CONTEXT
*context
, HCERTSTORE store
);
138 /* Optional, called when a cert context reference is being freed. Don't free
139 * the ref pointer itself, CertFreeCertificateContext does that.
141 typedef void (*FreeCertFunc
)(struct _WINE_CERT_CONTEXT_REF
*ref
);
143 typedef enum _CertStoreType
{
150 /* A cert store is polymorphic through the use of function pointers. A type
151 * is still needed to distinguish collection stores from other types.
152 * On the function pointers:
153 * - closeStore is called when the store's ref count becomes 0
154 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
155 * - control is optional, but should be implemented by any store that supports
158 typedef struct WINE_CRYPTCERTSTORE
163 HCRYPTPROV cryptProv
;
165 PFN_CERT_STORE_PROV_CLOSE closeStore
;
166 PFN_CERT_STORE_PROV_WRITE_CERT addCert
;
167 CreateRefFunc createCertRef
;
168 EnumCertFunc enumCert
;
169 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert
;
170 FreeCertFunc freeCert
; /* optional */
171 PFN_CERT_STORE_PROV_CONTROL control
; /* optional */
172 } WINECRYPT_CERTSTORE
, *PWINECRYPT_CERTSTORE
;
174 /* A certificate context has pointers to data that are owned by this module,
175 * so rather than duplicate the data every time a certificate context is
176 * copied, I keep a reference count to the data. Thus I have two data
177 * structures, the "true" certificate context (that has the reference count)
178 * and a reference certificate context, that has a pointer to the true context.
179 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
180 * with the reference version.
182 typedef struct _WINE_CERT_CONTEXT
187 struct list extendedProperties
;
188 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
190 typedef struct _WINE_CERT_CONTEXT_REF
193 WINE_CERT_CONTEXT
*context
;
194 } WINE_CERT_CONTEXT_REF
, *PWINE_CERT_CONTEXT_REF
;
196 /* An extended certificate property in serialized form is prefixed by this
199 typedef struct _WINE_CERT_PROP_HEADER
202 DWORD unknown
; /* always 1 */
204 } WINE_CERT_PROP_HEADER
, *PWINE_CERT_PROP_HEADER
;
206 /* Stores an extended property in a cert. */
207 typedef struct _WINE_CERT_PROPERTY
209 WINE_CERT_PROP_HEADER hdr
;
212 } WINE_CERT_PROPERTY
, *PWINE_CERT_PROPERTY
;
214 /* A mem store has a list of these. They're also returned by the mem store
215 * during enumeration.
217 typedef struct _WINE_CERT_LIST_ENTRY
219 WINE_CERT_CONTEXT_REF cert
;
221 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
223 typedef struct _WINE_MEMSTORE
225 WINECRYPT_CERTSTORE hdr
;
228 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
230 typedef struct _WINE_HASH_TO_DELETE
234 } WINE_HASH_TO_DELETE
, *PWINE_HASH_TO_DELETE
;
236 /* Returned by a reg store during enumeration. */
237 typedef struct _WINE_REG_CERT_CONTEXT
239 WINE_CERT_CONTEXT_REF cert
;
240 PWINE_CERT_CONTEXT_REF childContext
;
241 } WINE_REG_CERT_CONTEXT
, *PWINE_REG_CERT_CONTEXT
;
243 typedef struct _WINE_REGSTORE
245 WINECRYPT_CERTSTORE hdr
;
246 PWINECRYPT_CERTSTORE memStore
;
250 struct list certsToDelete
;
251 } WINE_REGSTORE
, *PWINE_REGSTORE
;
253 typedef struct _WINE_STORE_LIST_ENTRY
255 PWINECRYPT_CERTSTORE store
;
259 } WINE_STORE_LIST_ENTRY
, *PWINE_STORE_LIST_ENTRY
;
261 /* Returned by a collection store during enumeration.
262 * Note: relies on the list entry being valid after use, which a number of
263 * conditions might make untrue (reentrancy, closing a collection store before
264 * continuing an enumeration on it, ...). The tests seem to indicate this
265 * sort of unsafety is okay, since Windows isn't well-behaved in these
268 typedef struct _WINE_COLLECTION_CERT_CONTEXT
270 WINE_CERT_CONTEXT_REF cert
;
271 PWINE_STORE_LIST_ENTRY entry
;
272 PWINE_CERT_CONTEXT_REF childContext
;
273 } WINE_COLLECTION_CERT_CONTEXT
, *PWINE_COLLECTION_CERT_CONTEXT
;
275 typedef struct _WINE_COLLECTIONSTORE
277 WINECRYPT_CERTSTORE hdr
;
280 } WINE_COLLECTIONSTORE
, *PWINE_COLLECTIONSTORE
;
282 /* Like CertGetCertificateContextProperty, but operates directly on the
283 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
284 * are handled by CertGetCertificateContextProperty, and are particular to the
285 * store in which the property exists (which is separate from the context.)
287 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
288 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
);
290 /* Like CertSetCertificateContextProperty, but operates directly on the
291 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
292 * CertSetCertificateContextProperty anyway.
294 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
295 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
);
297 /* Helper function for store reading functions and
298 * CertAddSerializedElementToStore. Returns a context of the appropriate type
299 * if it can, or NULL otherwise. Doesn't validate any of the properties in
300 * the serialized context (for example, bad hashes are retained.)
301 * *pdwContentType is set to the type of the returned context.
303 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
304 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
);
306 /* filter for page-fault exceptions */
307 static WINE_EXCEPTION_FILTER(page_fault
)
309 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
310 return EXCEPTION_EXECUTE_HANDLER
;
311 return EXCEPTION_CONTINUE_SEARCH
;
314 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
315 DWORD dwFlags
, CertStoreType type
)
318 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
322 hCryptProv
= CRYPT_GetDefaultProvider();
323 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
325 store
->cryptProv
= hCryptProv
;
326 store
->dwOpenFlags
= dwFlags
;
329 /* Initializes the reference ref to point to pCertContext, which is assumed to
330 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
331 * Also sets the hCertStore member of the reference to store.
333 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref
,
334 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
336 TRACE("(%p, %p)\n", ref
, context
);
337 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
338 ref
->context
= context
;
339 InterlockedIncrement(&context
->ref
);
340 ref
->cert
.hCertStore
= store
;
343 static PWINE_CERT_CONTEXT_REF
CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context
,
346 PWINE_CERT_CONTEXT_REF pCertRef
= CryptMemAlloc(
347 sizeof(WINE_CERT_CONTEXT_REF
));
350 CRYPT_InitCertRef(pCertRef
, context
, store
);
354 static BOOL WINAPI
CRYPT_MemAddCert(HCERTSTORE store
, PCCERT_CONTEXT pCert
,
355 DWORD dwAddDisposition
)
357 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
358 BOOL add
= FALSE
, ret
;
360 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
362 switch (dwAddDisposition
)
364 case CERT_STORE_ADD_ALWAYS
:
367 case CERT_STORE_ADD_NEW
:
369 BYTE hashToAdd
[20], hash
[20];
370 DWORD size
= sizeof(hashToAdd
);
372 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
373 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
376 PWINE_CERT_LIST_ENTRY cursor
;
378 /* Add if no cert with the same hash is found. */
380 EnterCriticalSection(&ms
->cs
);
381 LIST_FOR_EACH_ENTRY(cursor
, &ms
->certs
, WINE_CERT_LIST_ENTRY
, entry
)
384 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
385 CERT_HASH_PROP_ID
, hash
, &size
);
386 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
388 TRACE("found matching certificate, not adding\n");
389 SetLastError(CRYPT_E_EXISTS
);
394 LeaveCriticalSection(&ms
->cs
);
398 case CERT_STORE_ADD_REPLACE_EXISTING
:
400 BYTE hashToAdd
[20], hash
[20];
401 DWORD size
= sizeof(hashToAdd
);
404 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
405 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
408 PWINE_CERT_LIST_ENTRY cursor
, next
;
410 /* Look for existing cert to delete */
411 EnterCriticalSection(&ms
->cs
);
412 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &ms
->certs
,
413 WINE_CERT_LIST_ENTRY
, entry
)
416 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
417 CERT_HASH_PROP_ID
, hash
, &size
);
418 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
420 TRACE("found matching certificate, replacing\n");
421 list_remove(&cursor
->entry
);
422 CertFreeCertificateContext((PCCERT_CONTEXT
)cursor
);
426 LeaveCriticalSection(&ms
->cs
);
431 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
436 PWINE_CERT_LIST_ENTRY entry
= CryptMemAlloc(
437 sizeof(WINE_CERT_LIST_ENTRY
));
441 TRACE("adding %p\n", entry
);
442 CRYPT_InitCertRef(&entry
->cert
, (PWINE_CERT_CONTEXT
)pCert
, store
);
443 list_init(&entry
->entry
);
444 EnterCriticalSection(&ms
->cs
);
445 list_add_tail(&ms
->certs
, &entry
->entry
);
446 LeaveCriticalSection(&ms
->cs
);
457 static PWINE_CERT_CONTEXT_REF
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
458 PWINE_CERT_CONTEXT_REF pPrev
)
460 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
461 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
, ret
;
462 struct list
*listNext
;
464 TRACE("(%p, %p)\n", store
, pPrev
);
465 EnterCriticalSection(&ms
->cs
);
468 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
469 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
472 listNext
= list_next(&ms
->certs
, &ms
->certs
);
475 ret
= CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY
));
476 memcpy(ret
, LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
),
477 sizeof(WINE_CERT_LIST_ENTRY
));
478 InterlockedIncrement(&ret
->cert
.context
->ref
);
482 SetLastError(CRYPT_E_NOT_FOUND
);
485 LeaveCriticalSection(&ms
->cs
);
487 TRACE("returning %p\n", ret
);
488 return (PWINE_CERT_CONTEXT_REF
)ret
;
491 static BOOL WINAPI
CRYPT_MemDeleteCert(HCERTSTORE hCertStore
,
492 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
494 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
495 WINE_CERT_CONTEXT_REF
*ref
= (WINE_CERT_CONTEXT_REF
*)pCertContext
;
496 PWINE_CERT_LIST_ENTRY cert
, next
;
499 /* Find the entry associated with the passed-in context, since the
500 * passed-in context may not be a list entry itself (e.g. if it came from
501 * CertDuplicateCertificateContext.) Pointing to the same context is
502 * a sufficient test of equality.
504 EnterCriticalSection(&store
->cs
);
505 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
508 if (cert
->cert
.context
== ref
->context
)
510 TRACE("removing %p\n", cert
);
511 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
514 list_remove(&cert
->entry
);
515 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
520 LeaveCriticalSection(&store
->cs
);
524 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
526 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
527 PWINE_CERT_LIST_ENTRY cert
, next
;
529 TRACE("(%p, %08lx)\n", store
, dwFlags
);
531 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
533 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
534 * pointer if its ref-count reaches zero. That's okay here because there
535 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
536 * of the CertListEntry.
538 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
541 TRACE("removing %p\n", cert
);
542 list_remove(&cert
->entry
);
543 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
545 DeleteCriticalSection(&store
->cs
);
549 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
550 DWORD dwFlags
, const void *pvPara
)
552 PWINE_MEMSTORE store
;
554 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
556 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
558 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
563 store
= CryptMemAlloc(sizeof(WINE_MEMSTORE
));
566 memset(store
, 0, sizeof(WINE_MEMSTORE
));
567 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
568 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
569 store
->hdr
.addCert
= CRYPT_MemAddCert
;
570 store
->hdr
.createCertRef
= CRYPT_CreateCertRef
;
571 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
572 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
573 store
->hdr
.freeCert
= NULL
;
574 InitializeCriticalSection(&store
->cs
);
575 list_init(&store
->certs
);
578 return (PWINECRYPT_CERTSTORE
)store
;
581 static BOOL WINAPI
CRYPT_CollectionAddCert(HCERTSTORE store
,
582 PCCERT_CONTEXT pCert
, DWORD dwAddDisposition
)
584 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
585 PWINE_STORE_LIST_ENTRY entry
, next
;
588 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
591 EnterCriticalSection(&cs
->cs
);
592 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
595 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
597 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
601 LeaveCriticalSection(&cs
->cs
);
602 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
606 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionCreateCertRef(
607 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
609 PWINE_COLLECTION_CERT_CONTEXT ret
= CryptMemAlloc(
610 sizeof(WINE_COLLECTION_CERT_CONTEXT
));
614 /* Initialize to empty for now, just make sure the size is right */
615 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
617 ret
->childContext
= NULL
;
619 return (PWINE_CERT_CONTEXT_REF
)ret
;
622 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
624 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
625 PWINE_STORE_LIST_ENTRY entry
, next
;
627 TRACE("(%p, %08lx)\n", store
, dwFlags
);
629 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
632 TRACE("closing %p\n", entry
);
633 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
636 DeleteCriticalSection(&cs
->cs
);
640 /* Advances a collection enumeration by one cert, if possible, where advancing
642 * - calling the current store's enumeration function once, and returning
643 * the enumerated cert if one is returned
644 * - moving to the next store if the current store has no more items, and
645 * recursively calling itself to get the next item.
646 * Returns NULL if the collection contains no more items or on error.
647 * Assumes the collection store's lock is held.
649 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
650 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
651 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
653 PWINE_COLLECTION_CERT_CONTEXT ret
;
654 PWINE_CERT_CONTEXT_REF child
;
656 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
660 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
661 pPrev
->childContext
);
665 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
666 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
667 InterlockedIncrement(&ret
->cert
.context
->ref
);
668 ret
->childContext
= child
;
672 struct list
*storeNext
= list_next(&store
->stores
,
675 pPrev
->childContext
= NULL
;
676 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
679 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
681 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
685 SetLastError(CRYPT_E_NOT_FOUND
);
692 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
696 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
697 child
->context
, store
);
700 ret
->entry
= storeEntry
;
701 ret
->childContext
= child
;
704 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
708 struct list
*storeNext
= list_next(&store
->stores
,
713 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
715 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
719 SetLastError(CRYPT_E_NOT_FOUND
);
724 TRACE("returning %p\n", ret
);
728 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionEnumCert(
729 PWINECRYPT_CERTSTORE store
, PWINE_CERT_CONTEXT_REF pPrev
)
731 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
732 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
733 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
735 TRACE("(%p, %p)\n", store
, pPrev
);
739 EnterCriticalSection(&cs
->cs
);
740 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
741 LeaveCriticalSection(&cs
->cs
);
745 EnterCriticalSection(&cs
->cs
);
746 if (!list_empty(&cs
->stores
))
748 PWINE_STORE_LIST_ENTRY storeEntry
;
750 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
752 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
756 SetLastError(CRYPT_E_NOT_FOUND
);
759 LeaveCriticalSection(&cs
->cs
);
761 TRACE("returning %p\n", ret
);
762 return (PWINE_CERT_CONTEXT_REF
)ret
;
765 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
766 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
768 PWINE_COLLECTION_CERT_CONTEXT context
=
769 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
772 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
774 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
776 context
->childContext
= NULL
;
780 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref
)
782 PWINE_COLLECTION_CERT_CONTEXT context
= (PWINE_COLLECTION_CERT_CONTEXT
)ref
;
784 TRACE("(%p)\n", ref
);
786 if (context
->childContext
)
787 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
790 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
791 DWORD dwFlags
, const void *pvPara
)
793 PWINE_COLLECTIONSTORE store
;
795 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
797 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
802 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
805 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
806 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
807 StoreTypeCollection
);
808 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
809 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
810 store
->hdr
.createCertRef
= CRYPT_CollectionCreateCertRef
;
811 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
812 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
813 store
->hdr
.freeCert
= CRYPT_CollectionFreeCert
;
814 InitializeCriticalSection(&store
->cs
);
815 list_init(&store
->stores
);
818 return (PWINECRYPT_CERTSTORE
)store
;
821 static void CRYPT_HashToStr(LPBYTE hash
, LPWSTR asciiHash
)
823 static const WCHAR fmt
[] = { '%','0','2','X',0 };
829 for (i
= 0; i
< 20; i
++)
830 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
833 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
835 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
836 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
837 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
839 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store
, HKEY key
,
844 WCHAR subKeyName
[MAX_PATH
];
847 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
849 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
855 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
861 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
863 buf
= CryptMemAlloc(size
);
866 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
873 TRACE("Adding cert with hash %s\n",
874 debugstr_w(subKeyName
));
875 context
= CRYPT_ReadSerializedElement(buf
, size
,
876 contextType
, &addedType
);
879 const WINE_CONTEXT_INTERFACE
*contextInterface
;
884 case CERT_STORE_CERTIFICATE_CONTEXT
:
885 contextInterface
= &gCertInterface
;
887 case CERT_STORE_CRL_CONTEXT
:
888 contextInterface
= &gCRLInterface
;
890 case CERT_STORE_CTL_CONTEXT
:
891 contextInterface
= &gCTLInterface
;
894 contextInterface
= NULL
;
896 if (contextInterface
)
899 if (contextInterface
->getProp(context
,
900 CERT_HASH_PROP_ID
, hash
, &size
))
902 WCHAR asciiHash
[20 * 2 + 1];
904 CRYPT_HashToStr(hash
, asciiHash
);
905 TRACE("comparing %s\n",
906 debugstr_w(asciiHash
));
907 TRACE("with %s\n", debugstr_w(subKeyName
));
908 if (!lstrcmpW(asciiHash
, subKeyName
))
910 TRACE("hash matches, adding\n");
911 contextInterface
->addContextToStore(
913 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
917 TRACE("hash doesn't match, ignoring\n");
918 contextInterface
->free(context
);
928 /* Ignore intermediate errors, continue enumerating */
934 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store
)
936 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
937 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
938 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
941 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
946 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
950 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
956 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
957 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, LPBYTE hash
, LPBYTE buf
,
960 WCHAR asciiHash
[20 * 2 + 1];
965 CRYPT_HashToStr(hash
, asciiHash
);
966 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
970 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
983 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
984 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
986 const void *context
= NULL
;
990 context
= contextInterface
->enumContextsInStore(memStore
, context
);
994 DWORD hashSize
= sizeof(hash
);
996 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
1003 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
1005 buf
= CryptMemAlloc(size
);
1008 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
1010 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
1017 } while (ret
&& context
!= NULL
);
1019 contextInterface
->free(context
);
1023 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTORE store
)
1025 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
1026 static const WINE_CONTEXT_INTERFACE
*interfaces
[] = { &gCertInterface
,
1027 &gCRLInterface
, &gCTLInterface
};
1028 struct list
*listToDelete
[] = { &store
->certsToDelete
, NULL
, NULL
};
1032 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1035 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1036 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1040 if (listToDelete
[i
])
1042 PWINE_HASH_TO_DELETE toDelete
, next
;
1043 WCHAR asciiHash
[20 * 2 + 1];
1045 EnterCriticalSection(&store
->cs
);
1046 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
1047 WINE_HASH_TO_DELETE
, entry
)
1051 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
1052 TRACE("Removing %s\n", debugstr_w(asciiHash
));
1053 rc
= RegDeleteKeyW(key
, asciiHash
);
1054 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
1059 list_remove(&toDelete
->entry
);
1060 CryptMemFree(toDelete
);
1062 LeaveCriticalSection(&store
->cs
);
1064 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
1077 /* If force is true or the registry store is dirty, writes the contents of the
1078 * store to the registry.
1080 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTORE store
, BOOL force
)
1084 if (store
->dirty
|| force
)
1085 ret
= CRYPT_RegWriteToReg(store
);
1091 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1093 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1095 TRACE("(%p, %08lx)\n", store
, dwFlags
);
1097 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
1099 CRYPT_RegFlushStore(store
, FALSE
);
1100 /* certsToDelete should already be cleared by this point */
1101 store
->memStore
->closeStore(store
->memStore
, 0);
1102 RegCloseKey(store
->key
);
1103 DeleteCriticalSection(&store
->cs
);
1104 CryptMemFree(store
);
1107 static BOOL WINAPI
CRYPT_RegAddCert(HCERTSTORE hCertStore
, PCCERT_CONTEXT cert
,
1108 DWORD dwAddDisposition
)
1110 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1113 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwAddDisposition
);
1115 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1117 SetLastError(ERROR_ACCESS_DENIED
);
1122 ret
= store
->memStore
->addCert(store
->memStore
, cert
, dwAddDisposition
);
1124 store
->dirty
= TRUE
;
1129 static PWINE_CERT_CONTEXT_REF
CRYPT_RegCreateCertRef(
1130 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
1132 PWINE_REG_CERT_CONTEXT ret
= CryptMemAlloc(
1133 sizeof(WINE_REG_CERT_CONTEXT
));
1137 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
1138 ret
->childContext
= NULL
;
1140 return (PWINE_CERT_CONTEXT_REF
)ret
;
1143 static PWINE_CERT_CONTEXT_REF
CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store
,
1144 PWINE_CERT_CONTEXT_REF pPrev
)
1146 PWINE_REGSTORE rs
= (PWINE_REGSTORE
)store
;
1147 PWINE_CERT_CONTEXT_REF child
;
1148 PWINE_REG_CERT_CONTEXT prev
= (PWINE_REG_CERT_CONTEXT
)pPrev
, ret
= NULL
;
1150 TRACE("(%p, %p)\n", store
, pPrev
);
1154 child
= rs
->memStore
->enumCert(rs
->memStore
, prev
->childContext
);
1157 ret
= (PWINE_REG_CERT_CONTEXT
)pPrev
;
1158 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
1159 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
1160 ret
->childContext
= child
;
1165 child
= rs
->memStore
->enumCert(rs
->memStore
, NULL
);
1168 ret
= CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT
));
1172 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
1173 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
1174 ret
->childContext
= child
;
1177 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
1180 return (PWINE_CERT_CONTEXT_REF
)ret
;
1183 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
1184 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
1186 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1189 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1191 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1193 SetLastError(ERROR_ACCESS_DENIED
);
1198 PWINE_HASH_TO_DELETE toDelete
=
1199 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
1203 DWORD size
= sizeof(toDelete
->hash
);
1205 ret
= CertGetCertificateContextProperty(pCertContext
,
1206 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
1209 list_init(&toDelete
->entry
);
1210 EnterCriticalSection(&store
->cs
);
1211 list_add_tail(&store
->certsToDelete
, &toDelete
->entry
);
1212 LeaveCriticalSection(&store
->cs
);
1213 ret
= store
->memStore
->deleteCert(store
->memStore
, pCertContext
,
1217 CryptMemFree(toDelete
);
1222 store
->dirty
= TRUE
;
1227 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref
)
1229 PWINE_REG_CERT_CONTEXT context
= (PWINE_REG_CERT_CONTEXT
)ref
;
1231 TRACE("(%p)\n", ref
);
1233 if (context
->childContext
)
1234 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
1237 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
1238 DWORD dwCtrlType
, void const *pvCtrlPara
)
1240 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1245 case CERT_STORE_CTRL_RESYNC
:
1246 CRYPT_RegFlushStore(store
, FALSE
);
1247 store
->memStore
->closeStore(store
->memStore
, 0);
1248 store
->memStore
= CRYPT_MemOpenStore(store
->hdr
.cryptProv
,
1249 store
->hdr
.dwOpenFlags
, NULL
);
1250 if (store
->memStore
)
1252 CRYPT_RegReadFromReg(store
);
1258 case CERT_STORE_CTRL_COMMIT
:
1259 ret
= CRYPT_RegFlushStore(store
,
1260 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1263 FIXME("%ld: stub\n", dwCtrlType
);
1269 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1270 static DWORD
CRYPT_RecurseDeleteKey(HKEY hKey
, LPCWSTR lpszSubKey
)
1272 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1273 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1276 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1278 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1281 /* Find how many subkeys there are */
1282 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1283 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1287 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1289 /* Name too big: alloc a buffer for it */
1290 lpszName
= CryptMemAlloc(dwMaxSubkeyLen
*sizeof(WCHAR
));
1294 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1297 /* Recursively delete all the subkeys */
1298 for (i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1300 dwSize
= dwMaxSubkeyLen
;
1301 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
,
1304 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1307 if (lpszName
!= szNameBuf
)
1309 /* Free buffer if allocated */
1310 CryptMemFree(lpszName
);
1315 RegCloseKey(hSubKey
);
1317 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1322 static WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
,
1323 DWORD dwFlags
, const void *pvPara
)
1325 PWINE_REGSTORE store
= NULL
;
1327 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
1329 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
1331 DWORD rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CertsW
);
1333 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1334 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CRLsW
);
1335 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1336 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CTLsW
);
1337 if (rc
== ERROR_NO_MORE_ITEMS
)
1345 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1346 GetCurrentProcess(), (LPHANDLE
)&key
,
1347 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1350 PWINECRYPT_CERTSTORE memStore
;
1352 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1355 store
= CryptMemAlloc(sizeof(WINE_REGSTORE
));
1358 memset(store
, 0, sizeof(WINE_REGSTORE
));
1359 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
1361 store
->hdr
.closeStore
= CRYPT_RegCloseStore
;
1362 store
->hdr
.addCert
= CRYPT_RegAddCert
;
1363 store
->hdr
.createCertRef
= CRYPT_RegCreateCertRef
;
1364 store
->hdr
.enumCert
= CRYPT_RegEnumCert
;
1365 store
->hdr
.deleteCert
= CRYPT_RegDeleteCert
;
1366 store
->hdr
.freeCert
= CRYPT_RegFreeCert
;
1367 store
->hdr
.control
= CRYPT_RegControl
;
1368 store
->memStore
= memStore
;
1370 InitializeCriticalSection(&store
->cs
);
1371 list_init(&store
->certsToDelete
);
1372 CRYPT_RegReadFromReg(store
);
1373 store
->dirty
= FALSE
;
1378 TRACE("returning %p\n", store
);
1379 return (WINECRYPT_CERTSTORE
*)store
;
1382 /* FIXME: this isn't complete for the Root store, in which the top-level
1383 * self-signed CA certs reside. Adding a cert to the Root store should present
1384 * the user with a dialog indicating the consequences of doing so, and asking
1385 * the user to confirm whether the cert should be added.
1387 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv
,
1388 DWORD dwFlags
, const void *pvPara
)
1390 static const WCHAR fmt
[] = { '%','s','\\','%','s',0 };
1391 LPCWSTR storeName
= (LPCWSTR
)pvPara
;
1393 PWINECRYPT_CERTSTORE store
= NULL
;
1398 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1399 debugstr_w((LPCWSTR
)pvPara
));
1403 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1408 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1410 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1411 root
= HKEY_LOCAL_MACHINE
;
1412 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1414 case CERT_SYSTEM_STORE_CURRENT_USER
:
1415 root
= HKEY_CURRENT_USER
;
1416 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1418 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1419 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1420 * SystemCertificates
1422 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1423 debugstr_w(storeName
));
1425 case CERT_SYSTEM_STORE_SERVICES
:
1426 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1427 * SystemCertificates
1429 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1430 debugstr_w(storeName
));
1432 case CERT_SYSTEM_STORE_USERS
:
1433 /* hku\user sid\Software\Microsoft\SystemCertificates */
1434 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1435 debugstr_w(storeName
));
1437 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1438 root
= HKEY_CURRENT_USER
;
1439 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1441 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1442 root
= HKEY_LOCAL_MACHINE
;
1443 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1445 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1446 /* hklm\Software\Microsoft\EnterpriseCertificates */
1447 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1448 debugstr_w(storeName
));
1451 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1455 storePath
= CryptMemAlloc((lstrlenW(base
) + lstrlenW(storeName
) + 2) *
1461 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1464 wsprintfW(storePath
, fmt
, base
, storeName
);
1465 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1466 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1471 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1473 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1474 disp
== REG_OPENED_EXISTING_KEY
)
1477 rc
= ERROR_FILE_EXISTS
;
1482 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1487 CryptMemFree(storePath
);
1492 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1493 DWORD dwFlags
, const void *pvPara
)
1496 PWINECRYPT_CERTSTORE ret
= NULL
;
1498 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1499 debugstr_a((LPCSTR
)pvPara
));
1503 SetLastError(ERROR_FILE_NOT_FOUND
);
1506 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1509 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1513 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1514 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1515 CryptMemFree(storeName
);
1521 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1522 DWORD dwFlags
, const void *pvPara
)
1524 HCERTSTORE store
= 0;
1527 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1528 debugstr_w((LPCWSTR
)pvPara
));
1532 SetLastError(ERROR_FILE_NOT_FOUND
);
1535 /* This returns a different error than system registry stores if the
1536 * location is invalid.
1538 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1540 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1541 case CERT_SYSTEM_STORE_CURRENT_USER
:
1542 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1543 case CERT_SYSTEM_STORE_SERVICES
:
1544 case CERT_SYSTEM_STORE_USERS
:
1545 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1546 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1547 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1551 SetLastError(ERROR_FILE_NOT_FOUND
);
1556 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1557 0, hCryptProv
, dwFlags
, pvPara
);
1561 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1562 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1565 CertAddStoreToCollection(store
, regStore
,
1566 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1567 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1568 CertCloseStore(regStore
, 0);
1572 return (PWINECRYPT_CERTSTORE
)store
;
1575 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv
,
1576 DWORD dwFlags
, const void *pvPara
)
1579 PWINECRYPT_CERTSTORE ret
= NULL
;
1581 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1582 debugstr_a((LPCSTR
)pvPara
));
1586 SetLastError(ERROR_FILE_NOT_FOUND
);
1589 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1592 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1596 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1597 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1598 CryptMemFree(storeName
);
1604 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1605 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
1608 WINECRYPT_CERTSTORE
*hcs
;
1609 StoreOpenFunc openFunc
= NULL
;
1611 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
1612 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
1614 if (!HIWORD(lpszStoreProvider
))
1616 switch (LOWORD(lpszStoreProvider
))
1618 case (int)CERT_STORE_PROV_MEMORY
:
1619 openFunc
= CRYPT_MemOpenStore
;
1621 case (int)CERT_STORE_PROV_REG
:
1622 openFunc
= CRYPT_RegOpenStore
;
1624 case (int)CERT_STORE_PROV_COLLECTION
:
1625 openFunc
= CRYPT_CollectionOpenStore
;
1627 case (int)CERT_STORE_PROV_SYSTEM_A
:
1628 openFunc
= CRYPT_SysOpenStoreA
;
1630 case (int)CERT_STORE_PROV_SYSTEM_W
:
1631 openFunc
= CRYPT_SysOpenStoreW
;
1633 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1634 openFunc
= CRYPT_SysRegOpenStoreA
;
1636 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1637 openFunc
= CRYPT_SysRegOpenStoreW
;
1640 if (LOWORD(lpszStoreProvider
))
1641 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
1644 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
1645 openFunc
= CRYPT_MemOpenStore
;
1646 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
1647 openFunc
= CRYPT_SysOpenStoreW
;
1648 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
1649 openFunc
= CRYPT_CollectionOpenStore
;
1650 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM_REGISTRY
))
1651 openFunc
= CRYPT_SysRegOpenStoreW
;
1654 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1660 /* FIXME: need to look for an installed provider for this type */
1661 SetLastError(ERROR_FILE_NOT_FOUND
);
1665 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1666 return (HCERTSTORE
)hcs
;
1669 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1670 LPCSTR szSubSystemProtocol
)
1674 if (szSubSystemProtocol
)
1676 int len
= MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, NULL
,
1678 LPWSTR param
= CryptMemAlloc(len
* sizeof(WCHAR
));
1682 MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, param
, len
);
1683 ret
= CertOpenSystemStoreW(hProv
, param
);
1684 CryptMemFree(param
);
1688 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1692 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1693 LPCWSTR szSubSystemProtocol
)
1697 if (!szSubSystemProtocol
)
1699 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1703 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1704 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1707 ret
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, hProv
,
1708 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1711 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1712 0, hProv
, CERT_SYSTEM_STORE_LOCAL_MACHINE
, szSubSystemProtocol
);
1716 CertAddStoreToCollection(ret
, store
,
1717 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1718 CertCloseStore(store
, 0);
1720 store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1721 0, hProv
, CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1724 CertAddStoreToCollection(ret
, store
,
1725 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1726 CertCloseStore(store
, 0);
1732 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
1733 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
1735 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
1736 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
1740 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1741 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
1746 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
1748 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1749 pcrl
= CryptMemAlloc( sizeof (CRL_CONTEXT
) );
1753 data
= CryptMemAlloc( cbCrlEncoded
);
1756 CryptMemFree( pcrl
);
1760 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1761 pcrl
->pbCrlEncoded
= data
;
1762 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1763 pcrl
->pCrlInfo
= NULL
;
1764 pcrl
->hCertStore
= 0;
1769 /* Decodes the encoded certificate and creates the certificate context for it.
1770 * The reference count is initially zero, so you must create a reference to it
1771 * to avoid leaking memory.
1773 static PWINE_CERT_CONTEXT
CRYPT_CreateCertificateContext(
1774 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1776 PWINE_CERT_CONTEXT cert
= NULL
;
1778 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1779 PCERT_INFO certInfo
= NULL
;
1782 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1785 /* First try to decode it as a signed cert. */
1786 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT
, pbCertEncoded
,
1787 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1788 (BYTE
*)&signedCert
, &size
);
1792 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1793 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
1794 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1795 (BYTE
*)&certInfo
, &size
);
1796 LocalFree(signedCert
);
1798 /* Failing that, try it as an unsigned cert */
1802 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1803 pbCertEncoded
, cbCertEncoded
,
1804 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1805 (BYTE
*)&certInfo
, &size
);
1811 cert
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT
));
1814 data
= CryptMemAlloc(cbCertEncoded
);
1821 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
1822 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
1823 cert
->cert
.pbCertEncoded
= data
;
1824 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
1825 cert
->cert
.pCertInfo
= certInfo
;
1826 cert
->cert
.hCertStore
= 0;
1828 InitializeCriticalSection(&cert
->cs
);
1829 list_init(&cert
->extendedProperties
);
1836 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context
)
1838 PWINE_CERT_PROPERTY prop
, next
;
1840 CryptMemFree(context
->cert
.pbCertEncoded
);
1841 LocalFree(context
->cert
.pCertInfo
);
1842 DeleteCriticalSection(&context
->cs
);
1843 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
1844 WINE_CERT_PROPERTY
, entry
)
1846 list_remove(&prop
->entry
);
1847 CryptMemFree(prop
->pbData
);
1850 CryptMemFree(context
);
1853 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
1854 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1856 PWINE_CERT_CONTEXT cert
;
1857 PWINE_CERT_CONTEXT_REF ret
= NULL
;
1859 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1862 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
1865 ret
= CRYPT_CreateCertRef(cert
, 0);
1866 return (PCCERT_CONTEXT
)ret
;
1869 /* Since the properties are stored in a list, this is a tad inefficient
1870 * (O(n^2)) since I have to find the previous position every time.
1872 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
1875 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1878 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1880 EnterCriticalSection(&ref
->context
->cs
);
1883 PWINE_CERT_PROPERTY cursor
= NULL
;
1885 LIST_FOR_EACH_ENTRY(cursor
, &ref
->context
->extendedProperties
,
1886 WINE_CERT_PROPERTY
, entry
)
1888 if (cursor
->hdr
.propID
== dwPropId
)
1893 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
1894 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
1902 else if (!list_empty(&ref
->context
->extendedProperties
))
1903 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
1904 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
1907 LeaveCriticalSection(&ref
->context
->cs
);
1911 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1912 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1914 PWINE_CERT_PROPERTY prop
;
1917 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1919 EnterCriticalSection(&context
->cs
);
1922 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1923 WINE_CERT_PROPERTY
, entry
)
1925 if (prop
->hdr
.propID
== dwPropId
)
1929 *pcbData
= prop
->hdr
.cb
;
1932 else if (*pcbData
< prop
->hdr
.cb
)
1934 SetLastError(ERROR_MORE_DATA
);
1935 *pcbData
= prop
->hdr
.cb
;
1939 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1940 *pcbData
= prop
->hdr
.cb
;
1949 /* Implicit properties */
1952 case CERT_SHA1_HASH_PROP_ID
:
1953 ret
= CryptHashCertificate(0, CALG_SHA1
, 0,
1954 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1958 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1960 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
1964 case CERT_KEY_PROV_INFO_PROP_ID
:
1965 case CERT_MD5_HASH_PROP_ID
:
1966 case CERT_SIGNATURE_HASH_PROP_ID
:
1967 case CERT_KEY_IDENTIFIER_PROP_ID
:
1968 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1969 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1970 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1971 FIXME("implicit property %ld\n", dwPropId
);
1975 LeaveCriticalSection(&context
->cs
);
1976 TRACE("returning %d\n", ret
);
1980 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1981 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1983 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1986 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1988 /* Special cases for invalid/special prop IDs.
1993 case CERT_CERT_PROP_ID
:
1994 case CERT_CRL_PROP_ID
:
1995 case CERT_CTL_PROP_ID
:
1996 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1998 case CERT_ACCESS_STATE_PROP_ID
:
2001 *pcbData
= sizeof(DWORD
);
2004 else if (*pcbData
< sizeof(DWORD
))
2006 SetLastError(ERROR_MORE_DATA
);
2007 *pcbData
= sizeof(DWORD
);
2014 if (pCertContext
->hCertStore
)
2016 PWINECRYPT_CERTSTORE store
=
2017 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2019 /* Take advantage of knowledge of the stores to answer the
2020 * access state question
2022 if (store
->type
!= StoreTypeReg
||
2023 !(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
2024 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
2026 *(DWORD
*)pvData
= state
;
2031 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
2033 TRACE("returning %d\n", ret
);
2037 /* Copies cbData bytes from pbData to the context's property with ID
2040 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
2041 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
2048 data
= CryptMemAlloc(cbData
);
2050 memcpy(data
, pbData
, cbData
);
2054 if (!cbData
|| data
)
2056 PWINE_CERT_PROPERTY prop
;
2058 EnterCriticalSection(&context
->cs
);
2059 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
2060 WINE_CERT_PROPERTY
, entry
)
2062 if (prop
->hdr
.propID
== dwPropId
)
2065 if (prop
&& prop
->entry
.next
!= &context
->extendedProperties
)
2067 CryptMemFree(prop
->pbData
);
2068 prop
->hdr
.cb
= cbData
;
2069 prop
->pbData
= cbData
? data
: NULL
;
2074 prop
= CryptMemAlloc(sizeof(WINE_CERT_PROPERTY
));
2077 prop
->hdr
.propID
= dwPropId
;
2078 prop
->hdr
.unknown
= 1;
2079 prop
->hdr
.cb
= cbData
;
2080 list_init(&prop
->entry
);
2081 prop
->pbData
= cbData
? data
: NULL
;
2082 list_add_tail(&context
->extendedProperties
, &prop
->entry
);
2088 LeaveCriticalSection(&context
->cs
);
2093 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
2094 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2098 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
2102 PWINE_CERT_PROPERTY prop
, next
;
2104 EnterCriticalSection(&context
->cs
);
2105 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
2106 WINE_CERT_PROPERTY
, entry
)
2108 if (prop
->hdr
.propID
== dwPropId
)
2110 list_remove(&prop
->entry
);
2111 CryptMemFree(prop
->pbData
);
2115 LeaveCriticalSection(&context
->cs
);
2122 case CERT_AUTO_ENROLL_PROP_ID
:
2123 case CERT_CTL_USAGE_PROP_ID
:
2124 case CERT_DESCRIPTION_PROP_ID
:
2125 case CERT_FRIENDLY_NAME_PROP_ID
:
2126 case CERT_HASH_PROP_ID
:
2127 case CERT_KEY_IDENTIFIER_PROP_ID
:
2128 case CERT_MD5_HASH_PROP_ID
:
2129 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2130 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2131 case CERT_PVK_FILE_PROP_ID
:
2132 case CERT_SIGNATURE_HASH_PROP_ID
:
2133 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2134 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2135 case CERT_ENROLLMENT_PROP_ID
:
2136 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2137 case CERT_RENEWAL_PROP_ID
:
2139 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
2141 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2142 blob
->pbData
, blob
->cbData
);
2145 case CERT_DATE_STAMP_PROP_ID
:
2146 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2147 pvData
, sizeof(FILETIME
));
2150 FIXME("%ld: stub\n", dwPropId
);
2153 TRACE("returning %d\n", ret
);
2157 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
2158 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2160 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2163 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
2165 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2166 * crashes on most of these, I'll be safer.
2171 case CERT_ACCESS_STATE_PROP_ID
:
2172 case CERT_CERT_PROP_ID
:
2173 case CERT_CRL_PROP_ID
:
2174 case CERT_CTL_PROP_ID
:
2175 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2178 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
2180 TRACE("returning %d\n", ret
);
2184 /* Only the reference portion of the context is duplicated. The returned
2185 * context has the cert store set to 0, to prevent the store's certificate free
2186 * function from getting called on partial data.
2187 * FIXME: is this okay? Needs a test.
2189 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
2190 PCCERT_CONTEXT pCertContext
)
2192 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
, ret
;
2194 TRACE("(%p)\n", pCertContext
);
2197 ret
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF
));
2200 memcpy(ret
, ref
, sizeof(*ret
));
2201 ret
->cert
.hCertStore
= 0;
2202 InterlockedIncrement(&ret
->context
->ref
);
2207 return (PCCERT_CONTEXT
)ret
;
2210 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
2211 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
2212 PCCERT_CONTEXT
*ppStoreContext
)
2214 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
2215 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2216 PWINE_CERT_CONTEXT cert
;
2219 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2220 dwAddDisposition
, ppStoreContext
);
2222 /* FIXME: some tests needed to verify return codes */
2225 SetLastError(ERROR_INVALID_PARAMETER
);
2228 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2230 SetLastError(ERROR_INVALID_PARAMETER
);
2234 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
2235 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
2238 PWINE_CERT_PROPERTY prop
;
2241 EnterCriticalSection(&ref
->context
->cs
);
2242 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2243 WINE_CERT_PROPERTY
, entry
)
2245 ret
= CRYPT_SaveCertificateContextProperty(cert
, prop
->hdr
.propID
,
2246 prop
->pbData
, prop
->hdr
.cb
);
2250 LeaveCriticalSection(&ref
->context
->cs
);
2253 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2254 if (ret
&& ppStoreContext
)
2255 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
2259 CRYPT_FreeCert(cert
);
2266 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
2267 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
2268 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
2270 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2273 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2274 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2278 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2282 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
2283 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2287 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2288 if (ret
&& ppCertContext
)
2289 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
2292 CRYPT_FreeCert(cert
);
2300 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
2301 PCCERT_CONTEXT pPrev
)
2303 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2304 PWINE_CERT_CONTEXT_REF prev
= (PWINE_CERT_CONTEXT_REF
)pPrev
;
2307 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2310 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2313 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
2317 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2321 TRACE("(%p)\n", pCertContext
);
2325 else if (!pCertContext
->hCertStore
)
2328 CertFreeCertificateContext(pCertContext
);
2332 PWINECRYPT_CERTSTORE hcs
=
2333 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2337 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2341 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2342 CertFreeCertificateContext(pCertContext
);
2348 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
2349 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
2350 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
2352 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2353 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
2358 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
2359 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
2360 PCCRL_CONTEXT
* ppStoreContext
)
2362 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
2363 dwAddDisposition
, ppStoreContext
);
2367 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2369 FIXME("%p\n", pCrlContext
);
2374 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2376 FIXME("(%p): stub\n", pCrlContext
);
2380 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2381 PCCRL_CONTEXT pPrev
)
2383 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2387 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2388 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2390 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
2395 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
2396 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
2397 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
2399 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2400 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
2405 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
2406 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
2407 PCCTL_CONTEXT
* ppStoreContext
)
2409 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
2410 dwAddDisposition
, ppStoreContext
);
2414 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2416 FIXME("(%p): stub\n", pCtlContext
);
2420 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2422 FIXME("(%p): stub\n", pCtlContext
);
2426 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2427 PCCTL_CONTEXT pPrev
)
2429 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2434 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2436 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2438 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2443 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2446 if (InterlockedDecrement(&hcs
->ref
) == 0)
2448 TRACE("%p's ref count is 0, freeing\n", hcs
);
2450 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2451 CryptReleaseContext(hcs
->cryptProv
, 0);
2452 hcs
->closeStore(hcs
, dwFlags
);
2455 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2459 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2460 DWORD dwCtrlType
, void const *pvCtrlPara
)
2462 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2465 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2470 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2475 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
2482 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2483 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2485 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
2489 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2490 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2492 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
2497 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
2498 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2500 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext
, dwFlags
, pbElement
,
2505 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2506 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2508 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
2512 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2513 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2515 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
2520 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
2521 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2523 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext
, dwFlags
, pbElement
,
2528 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
2529 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2533 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
2538 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2539 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) +
2540 pCertContext
->cbCertEncoded
;
2541 PWINE_CERT_PROPERTY prop
;
2543 EnterCriticalSection(&ref
->context
->cs
);
2544 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2545 WINE_CERT_PROPERTY
, entry
)
2546 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + prop
->hdr
.cb
;
2549 *pcbElement
= bytesNeeded
;
2552 else if (*pcbElement
< bytesNeeded
)
2554 *pcbElement
= bytesNeeded
;
2555 SetLastError(ERROR_MORE_DATA
);
2560 PWINE_CERT_PROP_HEADER hdr
;
2562 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2563 WINE_CERT_PROPERTY
, entry
)
2565 memcpy(pbElement
, &prop
->hdr
, sizeof(WINE_CERT_PROP_HEADER
));
2566 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2569 memcpy(pbElement
, prop
->pbData
, prop
->hdr
.cb
);
2570 pbElement
+= prop
->hdr
.cb
;
2573 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
2574 hdr
->propID
= CERT_CERT_PROP_ID
;
2576 hdr
->cb
= pCertContext
->cbCertEncoded
;
2577 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
2578 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
2581 LeaveCriticalSection(&ref
->context
->cs
);
2588 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2589 * to its header if a valid header is found, NULL if not. Valid means the
2590 * length of thte property won't overrun buf, and the unknown field is 1.
2592 static const WINE_CERT_PROP_HEADER
*CRYPT_findPropID(const BYTE
*buf
,
2593 DWORD size
, DWORD propID
)
2595 const WINE_CERT_PROP_HEADER
*ret
= NULL
;
2598 while (size
&& !ret
&& !done
)
2600 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
2602 SetLastError(CRYPT_E_FILE_ERROR
);
2607 const WINE_CERT_PROP_HEADER
*hdr
=
2608 (const WINE_CERT_PROP_HEADER
*)buf
;
2610 size
-= sizeof(WINE_CERT_PROP_HEADER
);
2611 buf
+= sizeof(WINE_CERT_PROP_HEADER
);
2614 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2617 else if (!hdr
->propID
)
2619 /* assume a zero prop ID means the data are uninitialized, so
2624 else if (hdr
->unknown
!= 1)
2626 SetLastError(ERROR_FILE_NOT_FOUND
);
2629 else if (hdr
->propID
== propID
)
2641 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
2642 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
)
2644 const void *context
;
2646 TRACE("(%p, %ld, %08lx, %p)\n", pbElement
, cbElement
, dwContextTypeFlags
,
2651 SetLastError(ERROR_END_OF_MEDIA
);
2657 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2658 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
2664 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
2666 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2668 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2671 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2673 type
= CERT_STORE_CRL_CONTEXT
;
2676 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
2679 type
= CERT_STORE_CTL_CONTEXT
;
2683 else if (dwContextTypeFlags
& CERT_STORE_CERTIFICATE_CONTEXT_FLAG
)
2685 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2686 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2688 else if (dwContextTypeFlags
& CERT_STORE_CRL_CONTEXT_FLAG
)
2690 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2691 type
= CERT_STORE_CRL_CONTEXT
;
2693 else if (dwContextTypeFlags
& CERT_STORE_CTL_CONTEXT_FLAG
)
2695 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CTL_PROP_ID
);
2696 type
= CERT_STORE_CTL_CONTEXT
;
2701 case CERT_STORE_CERTIFICATE_CONTEXT
:
2702 contextInterface
= &gCertInterface
;
2704 case CERT_STORE_CRL_CONTEXT
:
2705 contextInterface
= &gCRLInterface
;
2707 case CERT_STORE_CTL_CONTEXT
:
2708 contextInterface
= &gCTLInterface
;
2711 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2718 context
= contextInterface
->create(X509_ASN_ENCODING
,
2719 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
2722 BOOL noMoreProps
= FALSE
;
2724 while (!noMoreProps
&& ret
)
2726 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
2730 const WINE_CERT_PROP_HEADER
*hdr
=
2731 (const WINE_CERT_PROP_HEADER
*)pbElement
;
2733 TRACE("prop is %ld\n", hdr
->propID
);
2734 cbElement
-= sizeof(WINE_CERT_PROP_HEADER
);
2735 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2736 if (cbElement
< hdr
->cb
)
2738 SetLastError(HRESULT_FROM_WIN32(
2739 ERROR_INVALID_PARAMETER
));
2742 else if (!hdr
->propID
)
2744 /* Like in CRYPT_findPropID, stop if the propID is zero
2748 else if (hdr
->unknown
!= 1)
2750 SetLastError(ERROR_FILE_NOT_FOUND
);
2753 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
2754 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!=
2757 /* Have to create a blob for most types, but not
2760 switch (hdr
->propID
)
2762 case CERT_AUTO_ENROLL_PROP_ID
:
2763 case CERT_CTL_USAGE_PROP_ID
:
2764 case CERT_DESCRIPTION_PROP_ID
:
2765 case CERT_FRIENDLY_NAME_PROP_ID
:
2766 case CERT_HASH_PROP_ID
:
2767 case CERT_KEY_IDENTIFIER_PROP_ID
:
2768 case CERT_MD5_HASH_PROP_ID
:
2769 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2770 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2771 case CERT_PVK_FILE_PROP_ID
:
2772 case CERT_SIGNATURE_HASH_PROP_ID
:
2773 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2774 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2775 case CERT_ENROLLMENT_PROP_ID
:
2776 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2777 case CERT_RENEWAL_PROP_ID
:
2779 CRYPT_DATA_BLOB blob
= { hdr
->cb
,
2780 (LPBYTE
)pbElement
};
2782 ret
= contextInterface
->setProp(context
,
2783 hdr
->propID
, 0, &blob
);
2786 case CERT_DATE_STAMP_PROP_ID
:
2787 ret
= contextInterface
->setProp(context
,
2788 hdr
->propID
, 0, pbElement
);
2791 FIXME("prop ID %ld: stub\n", hdr
->propID
);
2794 pbElement
+= hdr
->cb
;
2795 cbElement
-= hdr
->cb
;
2803 *pdwContentType
= type
;
2807 contextInterface
->free(context
);
2812 _SEH_EXCEPT(page_fault
)
2814 SetLastError(STATUS_ACCESS_VIOLATION
);
2821 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
2822 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
2823 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
2825 const void *context
;
2829 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore
,
2830 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
2831 pdwContentType
, ppvContext
);
2833 /* Call the internal function, then delete the hashes. Tests show this
2834 * function uses real hash values, not whatever's stored in the hash
2837 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
2838 dwContextTypeFlags
, &type
);
2841 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2845 case CERT_STORE_CERTIFICATE_CONTEXT
:
2846 contextInterface
= &gCertInterface
;
2848 case CERT_STORE_CRL_CONTEXT
:
2849 contextInterface
= &gCRLInterface
;
2851 case CERT_STORE_CTL_CONTEXT
:
2852 contextInterface
= &gCTLInterface
;
2855 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2857 if (contextInterface
)
2859 contextInterface
->setProp(context
, CERT_HASH_PROP_ID
, 0, NULL
);
2860 contextInterface
->setProp(context
, CERT_MD5_HASH_PROP_ID
, 0, NULL
);
2861 contextInterface
->setProp(context
, CERT_SIGNATURE_HASH_PROP_ID
, 0,
2864 *pdwContentType
= type
;
2865 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
2866 dwAddDisposition
, ppvContext
);
2867 contextInterface
->free(context
);
2877 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2879 TRACE("(%p)\n", pCertContext
);
2883 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2884 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)ref
->cert
.hCertStore
;
2886 if (InterlockedDecrement(&ref
->context
->ref
) == 0)
2888 TRACE("%p's ref count is 0, freeing\n", ref
->context
);
2889 CRYPT_FreeCert(ref
->context
);
2892 TRACE("%p's ref count is %ld\n", ref
->context
, ref
->context
->ref
);
2893 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
2895 store
->freeCert(ref
);
2901 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
2902 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
,
2903 const void *pvPara
, PCCERT_CONTEXT pPrevCertContext
)
2905 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore
, dwCertEncodingType
,
2906 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
2907 SetLastError(CRYPT_E_NOT_FOUND
);
2911 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
2912 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
2914 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2915 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2916 PWINE_STORE_LIST_ENTRY entry
;
2919 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2920 dwUpdateFlags
, dwPriority
);
2922 if (!collection
|| !sibling
)
2924 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2926 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2929 if (collection
->hdr
.type
!= StoreTypeCollection
)
2931 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2934 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2936 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2940 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
2943 InterlockedIncrement(&sibling
->ref
);
2944 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
2945 entry
->store
= sibling
;
2946 entry
->dwUpdateFlags
= dwUpdateFlags
;
2947 entry
->dwPriority
= dwPriority
;
2948 list_init(&entry
->entry
);
2949 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
2950 EnterCriticalSection(&collection
->cs
);
2953 PWINE_STORE_LIST_ENTRY cursor
;
2956 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
2957 WINE_STORE_LIST_ENTRY
, entry
)
2959 if (cursor
->dwPriority
< dwPriority
)
2961 list_add_before(&cursor
->entry
, &entry
->entry
);
2967 list_add_tail(&collection
->stores
, &entry
->entry
);
2970 list_add_tail(&collection
->stores
, &entry
->entry
);
2971 LeaveCriticalSection(&collection
->cs
);
2979 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
2980 HCERTSTORE hSiblingStore
)
2982 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2983 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2984 PWINE_STORE_LIST_ENTRY store
, next
;
2986 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
2988 if (!collection
|| !sibling
)
2990 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2992 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2995 if (collection
->hdr
.type
!= StoreTypeCollection
)
2997 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2999 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3002 EnterCriticalSection(&collection
->cs
);
3003 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
3004 WINE_STORE_LIST_ENTRY
, entry
)
3006 if (store
->store
== sibling
)
3008 list_remove(&store
->entry
);
3009 CertCloseStore(store
->store
, 0);
3010 CryptMemFree(store
);
3014 LeaveCriticalSection(&collection
->cs
);
3017 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
3018 CRYPT_ATTRIBUTE rgAttr
[])
3020 PCRYPT_ATTRIBUTE ret
= NULL
;
3023 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
3029 SetLastError(ERROR_INVALID_PARAMETER
);
3033 for (i
= 0; !ret
&& i
< cAttr
; i
++)
3034 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
3039 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
3040 CERT_EXTENSION rgExtensions
[])
3042 PCERT_EXTENSION ret
= NULL
;
3045 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
3051 SetLastError(ERROR_INVALID_PARAMETER
);
3055 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
3056 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
3057 rgExtensions
[i
].pszObjId
))
3058 ret
= &rgExtensions
[i
];
3062 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
3064 PCERT_RDN_ATTR ret
= NULL
;
3067 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
3071 SetLastError(ERROR_INVALID_PARAMETER
);
3075 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
3076 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
3077 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
3078 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
3079 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
3083 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
3084 PCERT_INFO pCertInfo
)
3093 GetSystemTime(&sysTime
);
3094 SystemTimeToFileTime(&sysTime
, &fileTime
);
3095 pTimeToVerify
= &fileTime
;
3097 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
3099 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
3106 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
3107 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
3108 DWORD
*pcbComputedHash
)
3111 HCRYPTHASH hHash
= 0;
3113 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
3114 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
3117 hCryptProv
= CRYPT_GetDefaultProvider();
3122 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
3125 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
3127 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
3128 pcbComputedHash
, 0);
3129 CryptDestroyHash(hHash
);
3135 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV hCryptProv
, DWORD dwKeySpec
,
3136 DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
3137 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
3138 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
3144 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv
,
3145 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
3146 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
3148 algID
= CertOIDToAlgId(pSignatureAlgorithm
->pszObjId
);
3151 SetLastError(NTE_BAD_ALGID
);
3156 SetLastError(ERROR_INVALID_PARAMETER
);
3160 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hHash
);
3163 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
, cbEncodedToBeSigned
, 0);
3165 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
3167 CryptDestroyHash(hHash
);
3172 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv
,
3173 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
3174 PCERT_PUBLIC_KEY_INFO pPublicKey
)
3176 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
3177 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, (void *)pbEncoded
,
3178 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
3181 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv
,
3182 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
3183 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
3186 CRYPT_DATA_BLOB subjectBlob
;
3188 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv
,
3189 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
3190 dwFlags
, pvReserved
);
3192 switch (dwSubjectType
)
3194 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
3196 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvSubject
;
3198 subjectBlob
.pbData
= blob
->pbData
;
3199 subjectBlob
.cbData
= blob
->cbData
;
3202 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
3204 PCERT_CONTEXT context
= (PCERT_CONTEXT
)pvSubject
;
3206 subjectBlob
.pbData
= context
->pbCertEncoded
;
3207 subjectBlob
.cbData
= context
->cbCertEncoded
;
3210 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
3212 PCRL_CONTEXT context
= (PCRL_CONTEXT
)pvSubject
;
3214 subjectBlob
.pbData
= context
->pbCrlEncoded
;
3215 subjectBlob
.cbData
= context
->cbCrlEncoded
;
3219 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3225 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
3228 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
3229 subjectBlob
.pbData
, subjectBlob
.cbData
,
3230 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
3231 (BYTE
*)&signedCert
, &size
);
3234 switch (dwIssuerType
)
3236 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
3238 PCERT_PUBLIC_KEY_INFO pubKeyInfo
=
3239 (PCERT_PUBLIC_KEY_INFO
)pvIssuer
;
3240 ALG_ID algID
= CertOIDToAlgId(pubKeyInfo
->Algorithm
.pszObjId
);
3246 ret
= CryptImportPublicKeyInfoEx(hCryptProv
,
3247 dwCertEncodingType
, pubKeyInfo
, algID
, 0, NULL
, &key
);
3252 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hash
);
3255 ret
= CryptHashData(hash
,
3256 signedCert
->ToBeSigned
.pbData
,
3257 signedCert
->ToBeSigned
.cbData
, 0);
3260 ret
= CryptVerifySignatureW(hash
,
3261 signedCert
->Signature
.pbData
,
3262 signedCert
->Signature
.cbData
, key
, NULL
, 0);
3264 CryptDestroyHash(hash
);
3266 CryptDestroyKey(key
);
3271 SetLastError(NTE_BAD_ALGID
);
3276 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
3277 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
3278 FIXME("issuer type %ld: stub\n", dwIssuerType
);
3281 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
3284 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3289 FIXME("unimplemented for NULL signer\n");
3290 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3295 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3298 LocalFree(signedCert
);
3304 HCRYPTOIDFUNCSET WINAPI
CryptInitOIDFunctionSet(LPCSTR pszFuncName
, DWORD dwFlags
)
3306 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName
), dwFlags
);
3310 BOOL WINAPI
CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType
,
3311 LPCSTR pszFuncName
, LPCWSTR pwszDll
)
3313 FIXME("stub: %lx %s %s\n", dwEncodingType
, debugstr_a(pszFuncName
), debugstr_w(pwszDll
));