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 #define NONAMELESSUNION
36 static _SEH_FILTER(page_fault
)
38 if (_SEH_GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
39 return _SEH_EXECUTE_HANDLER
;
40 return _SEH_CONTINUE_SEARCH
;
43 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
45 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
46 /* The following aren't defined in wincrypt.h, as they're "reserved" */
47 #define CERT_CERT_PROP_ID 32
48 #define CERT_CRL_PROP_ID 33
49 #define CERT_CTL_PROP_ID 34
51 /* Some typedefs that make it easier to abstract which type of context we're
54 typedef const void *(WINAPI
*CreateContextFunc
)(DWORD dwCertEncodingType
,
55 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
);
56 typedef BOOL (WINAPI
*AddContextToStoreFunc
)(HCERTSTORE hCertStore
,
57 const void *context
, DWORD dwAddDisposition
, const void **ppStoreContext
);
58 typedef BOOL (WINAPI
*AddEncodedContextToStoreFunc
)(HCERTSTORE hCertStore
,
59 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
60 DWORD dwAddDisposition
, const void **ppContext
);
61 typedef const void *(WINAPI
*EnumContextsInStoreFunc
)(HCERTSTORE hCertStore
,
62 const void *pPrevContext
);
63 typedef BOOL (WINAPI
*GetContextPropertyFunc
)(const void *context
,
64 DWORD dwPropID
, void *pvData
, DWORD
*pcbData
);
65 typedef BOOL (WINAPI
*SetContextPropertyFunc
)(const void *context
,
66 DWORD dwPropID
, DWORD dwFlags
, const void *pvData
);
67 typedef BOOL (WINAPI
*SerializeElementFunc
)(const void *context
, DWORD dwFlags
,
68 BYTE
*pbElement
, DWORD
*pcbElement
);
69 typedef BOOL (WINAPI
*FreeContextFunc
)(const void *context
);
70 typedef BOOL (WINAPI
*DeleteContextFunc
)(const void *context
);
72 /* An abstract context (certificate, CRL, or CTL) interface */
73 typedef struct _WINE_CONTEXT_INTERFACE
75 CreateContextFunc create
;
76 AddContextToStoreFunc addContextToStore
;
77 AddEncodedContextToStoreFunc addEncodedToStore
;
78 EnumContextsInStoreFunc enumContextsInStore
;
79 GetContextPropertyFunc getProp
;
80 SetContextPropertyFunc setProp
;
81 SerializeElementFunc serialize
;
83 DeleteContextFunc deleteFromStore
;
84 } WINE_CONTEXT_INTERFACE
, *PWINE_CONTEXT_INTERFACE
;
86 static const WINE_CONTEXT_INTERFACE gCertInterface
= {
87 (CreateContextFunc
)CertCreateCertificateContext
,
88 (AddContextToStoreFunc
)CertAddCertificateContextToStore
,
89 (AddEncodedContextToStoreFunc
)CertAddEncodedCertificateToStore
,
90 (EnumContextsInStoreFunc
)CertEnumCertificatesInStore
,
91 (GetContextPropertyFunc
)CertGetCertificateContextProperty
,
92 (SetContextPropertyFunc
)CertSetCertificateContextProperty
,
93 (SerializeElementFunc
)CertSerializeCertificateStoreElement
,
94 (FreeContextFunc
)CertFreeCertificateContext
,
95 (DeleteContextFunc
)CertDeleteCertificateFromStore
,
98 static const WINE_CONTEXT_INTERFACE gCRLInterface
= {
99 (CreateContextFunc
)CertCreateCRLContext
,
100 (AddContextToStoreFunc
)CertAddCRLContextToStore
,
101 (AddEncodedContextToStoreFunc
)CertAddEncodedCRLToStore
,
102 (EnumContextsInStoreFunc
)CertEnumCRLsInStore
,
103 (GetContextPropertyFunc
)CertGetCRLContextProperty
,
104 (SetContextPropertyFunc
)CertSetCRLContextProperty
,
105 (SerializeElementFunc
)CertSerializeCRLStoreElement
,
106 (FreeContextFunc
)CertFreeCRLContext
,
107 (DeleteContextFunc
)CertDeleteCRLFromStore
,
110 static const WINE_CONTEXT_INTERFACE gCTLInterface
= {
111 (CreateContextFunc
)CertCreateCTLContext
,
112 (AddContextToStoreFunc
)CertAddCTLContextToStore
,
113 (AddEncodedContextToStoreFunc
)CertAddEncodedCTLToStore
,
114 (EnumContextsInStoreFunc
)CertEnumCTLsInStore
,
115 (GetContextPropertyFunc
)CertGetCTLContextProperty
,
116 (SetContextPropertyFunc
)CertSetCTLContextProperty
,
117 (SerializeElementFunc
)CertSerializeCTLStoreElement
,
118 (FreeContextFunc
)CertFreeCTLContext
,
119 (DeleteContextFunc
)CertDeleteCTLFromStore
,
122 struct WINE_CRYPTCERTSTORE
;
124 typedef struct WINE_CRYPTCERTSTORE
* (*StoreOpenFunc
)(HCRYPTPROV hCryptProv
,
125 DWORD dwFlags
, const void *pvPara
);
127 struct _WINE_CERT_CONTEXT_REF
;
129 /* Called to enumerate the next certificate in a store. The returned pointer
130 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
133 typedef struct _WINE_CERT_CONTEXT_REF
* (*EnumCertFunc
)
134 (struct WINE_CRYPTCERTSTORE
*store
, struct _WINE_CERT_CONTEXT_REF
*pPrev
);
136 struct _WINE_CERT_CONTEXT
;
138 /* Called to create a new reference to an existing cert context. Should call
139 * CRYPT_InitCertRef to make sure the reference count is properly updated.
140 * If the store does not provide any additional allocated data (that is, does
141 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
144 typedef struct _WINE_CERT_CONTEXT_REF
* (*CreateRefFunc
)
145 (struct _WINE_CERT_CONTEXT
*context
, HCERTSTORE store
);
147 /* Optional, called when a cert context reference is being freed. Don't free
148 * the ref pointer itself, CertFreeCertificateContext does that.
150 typedef void (*FreeCertFunc
)(struct _WINE_CERT_CONTEXT_REF
*ref
);
152 typedef enum _CertStoreType
{
159 /* A cert store is polymorphic through the use of function pointers. A type
160 * is still needed to distinguish collection stores from other types.
161 * On the function pointers:
162 * - closeStore is called when the store's ref count becomes 0
163 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
164 * - control is optional, but should be implemented by any store that supports
167 typedef struct WINE_CRYPTCERTSTORE
172 HCRYPTPROV cryptProv
;
174 PFN_CERT_STORE_PROV_CLOSE closeStore
;
175 PFN_CERT_STORE_PROV_WRITE_CERT addCert
;
176 CreateRefFunc createCertRef
;
177 EnumCertFunc enumCert
;
178 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert
;
179 FreeCertFunc freeCert
; /* optional */
180 PFN_CERT_STORE_PROV_CONTROL control
; /* optional */
181 } WINECRYPT_CERTSTORE
, *PWINECRYPT_CERTSTORE
;
183 /* A certificate context has pointers to data that are owned by this module,
184 * so rather than duplicate the data every time a certificate context is
185 * copied, I keep a reference count to the data. Thus I have two data
186 * structures, the "true" certificate context (that has the reference count)
187 * and a reference certificate context, that has a pointer to the true context.
188 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
189 * with the reference version.
191 typedef struct _WINE_CERT_CONTEXT
196 struct list extendedProperties
;
197 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
199 typedef struct _WINE_CERT_CONTEXT_REF
202 WINE_CERT_CONTEXT
*context
;
203 } WINE_CERT_CONTEXT_REF
, *PWINE_CERT_CONTEXT_REF
;
205 /* An extended certificate property in serialized form is prefixed by this
208 typedef struct _WINE_CERT_PROP_HEADER
211 DWORD unknown
; /* always 1 */
213 } WINE_CERT_PROP_HEADER
, *PWINE_CERT_PROP_HEADER
;
215 /* Stores an extended property in a cert. */
216 typedef struct _WINE_CERT_PROPERTY
218 WINE_CERT_PROP_HEADER hdr
;
221 } WINE_CERT_PROPERTY
, *PWINE_CERT_PROPERTY
;
223 /* A mem store has a list of these. They're also returned by the mem store
224 * during enumeration.
226 typedef struct _WINE_CERT_LIST_ENTRY
228 WINE_CERT_CONTEXT_REF cert
;
230 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
232 typedef struct _WINE_MEMSTORE
234 WINECRYPT_CERTSTORE hdr
;
237 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
239 typedef struct _WINE_HASH_TO_DELETE
243 } WINE_HASH_TO_DELETE
, *PWINE_HASH_TO_DELETE
;
245 /* Returned by a reg store during enumeration. */
246 typedef struct _WINE_REG_CERT_CONTEXT
248 WINE_CERT_CONTEXT_REF cert
;
249 PWINE_CERT_CONTEXT_REF childContext
;
250 } WINE_REG_CERT_CONTEXT
, *PWINE_REG_CERT_CONTEXT
;
252 typedef struct _WINE_REGSTORE
254 WINECRYPT_CERTSTORE hdr
;
255 PWINECRYPT_CERTSTORE memStore
;
259 struct list certsToDelete
;
260 } WINE_REGSTORE
, *PWINE_REGSTORE
;
262 typedef struct _WINE_STORE_LIST_ENTRY
264 PWINECRYPT_CERTSTORE store
;
268 } WINE_STORE_LIST_ENTRY
, *PWINE_STORE_LIST_ENTRY
;
270 /* Returned by a collection store during enumeration.
271 * Note: relies on the list entry being valid after use, which a number of
272 * conditions might make untrue (reentrancy, closing a collection store before
273 * continuing an enumeration on it, ...). The tests seem to indicate this
274 * sort of unsafety is okay, since Windows isn't well-behaved in these
277 typedef struct _WINE_COLLECTION_CERT_CONTEXT
279 WINE_CERT_CONTEXT_REF cert
;
280 PWINE_STORE_LIST_ENTRY entry
;
281 PWINE_CERT_CONTEXT_REF childContext
;
282 } WINE_COLLECTION_CERT_CONTEXT
, *PWINE_COLLECTION_CERT_CONTEXT
;
284 typedef struct _WINE_COLLECTIONSTORE
286 WINECRYPT_CERTSTORE hdr
;
289 } WINE_COLLECTIONSTORE
, *PWINE_COLLECTIONSTORE
;
291 /* Like CertGetCertificateContextProperty, but operates directly on the
292 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
293 * are handled by CertGetCertificateContextProperty, and are particular to the
294 * store in which the property exists (which is separate from the context.)
296 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
297 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
);
299 /* Like CertSetCertificateContextProperty, but operates directly on the
300 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
301 * CertSetCertificateContextProperty anyway.
303 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
304 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
);
306 /* Helper function for store reading functions and
307 * CertAddSerializedElementToStore. Returns a context of the appropriate type
308 * if it can, or NULL otherwise. Doesn't validate any of the properties in
309 * the serialized context (for example, bad hashes are retained.)
310 * *pdwContentType is set to the type of the returned context.
312 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
313 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
);
315 /* 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;
325 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
326 DWORD dwFlags
, CertStoreType type
)
329 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
333 hCryptProv
= CRYPT_GetDefaultProvider();
334 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
336 store
->cryptProv
= hCryptProv
;
337 store
->dwOpenFlags
= dwFlags
;
340 /* Initializes the reference ref to point to pCertContext, which is assumed to
341 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
342 * Also sets the hCertStore member of the reference to store.
345 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref
,
346 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
348 TRACE("(%p, %p)\n", ref
, context
);
349 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
350 ref
->context
= context
;
351 InterlockedIncrement(&context
->ref
);
352 ref
->cert
.hCertStore
= store
;
355 static PWINE_CERT_CONTEXT_REF
CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context
,
358 PWINE_CERT_CONTEXT_REF pCertRef
= CryptMemAlloc(
359 sizeof(WINE_CERT_CONTEXT_REF
));
362 CRYPT_InitCertRef(pCertRef
, context
, store
);
366 static BOOL WINAPI
CRYPT_MemAddCert(HCERTSTORE store
, PCCERT_CONTEXT pCert
,
367 DWORD dwAddDisposition
)
369 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
370 BOOL add
= FALSE
, ret
;
372 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
374 switch (dwAddDisposition
)
376 case CERT_STORE_ADD_ALWAYS
:
379 case CERT_STORE_ADD_NEW
:
381 BYTE hashToAdd
[20], hash
[20];
382 DWORD size
= sizeof(hashToAdd
);
384 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
385 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
388 PWINE_CERT_LIST_ENTRY cursor
;
390 /* Add if no cert with the same hash is found. */
392 EnterCriticalSection(&ms
->cs
);
393 LIST_FOR_EACH_ENTRY(cursor
, &ms
->certs
, WINE_CERT_LIST_ENTRY
, entry
)
396 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
397 CERT_HASH_PROP_ID
, hash
, &size
);
398 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
400 TRACE("found matching certificate, not adding\n");
401 SetLastError(CRYPT_E_EXISTS
);
406 LeaveCriticalSection(&ms
->cs
);
410 case CERT_STORE_ADD_REPLACE_EXISTING
:
412 BYTE hashToAdd
[20], hash
[20];
413 DWORD size
= sizeof(hashToAdd
);
416 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
417 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
420 PWINE_CERT_LIST_ENTRY cursor
, next
;
422 /* Look for existing cert to delete */
423 EnterCriticalSection(&ms
->cs
);
424 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &ms
->certs
,
425 WINE_CERT_LIST_ENTRY
, entry
)
428 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
429 CERT_HASH_PROP_ID
, hash
, &size
);
430 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
432 TRACE("found matching certificate, replacing\n");
433 list_remove(&cursor
->entry
);
434 CertFreeCertificateContext((PCCERT_CONTEXT
)cursor
);
438 LeaveCriticalSection(&ms
->cs
);
443 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
448 PWINE_CERT_LIST_ENTRY entry
= CryptMemAlloc(
449 sizeof(WINE_CERT_LIST_ENTRY
));
453 TRACE("adding %p\n", entry
);
454 CRYPT_InitCertRef(&entry
->cert
, (PWINE_CERT_CONTEXT
)pCert
, store
);
455 list_init(&entry
->entry
);
456 EnterCriticalSection(&ms
->cs
);
457 list_add_tail(&ms
->certs
, &entry
->entry
);
458 LeaveCriticalSection(&ms
->cs
);
469 static PWINE_CERT_CONTEXT_REF
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
470 PWINE_CERT_CONTEXT_REF pPrev
)
472 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
473 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
, ret
;
474 struct list
*listNext
;
476 TRACE("(%p, %p)\n", store
, pPrev
);
477 EnterCriticalSection(&ms
->cs
);
480 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
481 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
484 listNext
= list_next(&ms
->certs
, &ms
->certs
);
487 ret
= CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY
));
488 memcpy(ret
, LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
),
489 sizeof(WINE_CERT_LIST_ENTRY
));
490 InterlockedIncrement(&ret
->cert
.context
->ref
);
494 SetLastError(CRYPT_E_NOT_FOUND
);
497 LeaveCriticalSection(&ms
->cs
);
499 TRACE("returning %p\n", ret
);
500 return (PWINE_CERT_CONTEXT_REF
)ret
;
503 static BOOL WINAPI
CRYPT_MemDeleteCert(HCERTSTORE hCertStore
,
504 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
506 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
507 WINE_CERT_CONTEXT_REF
*ref
= (WINE_CERT_CONTEXT_REF
*)pCertContext
;
508 PWINE_CERT_LIST_ENTRY cert
, next
;
511 /* Find the entry associated with the passed-in context, since the
512 * passed-in context may not be a list entry itself (e.g. if it came from
513 * CertDuplicateCertificateContext.) Pointing to the same context is
514 * a sufficient test of equality.
516 EnterCriticalSection(&store
->cs
);
517 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
520 if (cert
->cert
.context
== ref
->context
)
522 TRACE("removing %p\n", cert
);
523 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
526 list_remove(&cert
->entry
);
527 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
532 LeaveCriticalSection(&store
->cs
);
536 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
538 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
539 PWINE_CERT_LIST_ENTRY cert
, next
;
541 TRACE("(%p, %08lx)\n", store
, dwFlags
);
543 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
545 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
546 * pointer if its ref-count reaches zero. That's okay here because there
547 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
548 * of the CertListEntry.
550 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
553 TRACE("removing %p\n", cert
);
554 list_remove(&cert
->entry
);
555 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
557 DeleteCriticalSection(&store
->cs
);
561 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
562 DWORD dwFlags
, const void *pvPara
)
564 PWINE_MEMSTORE store
;
566 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
568 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
575 store
= CryptMemAlloc(sizeof(WINE_MEMSTORE
));
578 memset(store
, 0, sizeof(WINE_MEMSTORE
));
579 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
580 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
581 store
->hdr
.addCert
= CRYPT_MemAddCert
;
582 store
->hdr
.createCertRef
= CRYPT_CreateCertRef
;
583 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
584 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
585 store
->hdr
.freeCert
= NULL
;
586 InitializeCriticalSection(&store
->cs
);
587 list_init(&store
->certs
);
590 return (PWINECRYPT_CERTSTORE
)store
;
593 static BOOL WINAPI
CRYPT_CollectionAddCert(HCERTSTORE store
,
594 PCCERT_CONTEXT pCert
, DWORD dwAddDisposition
)
596 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
597 PWINE_STORE_LIST_ENTRY entry
, next
;
600 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
603 EnterCriticalSection(&cs
->cs
);
604 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
607 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
609 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
613 LeaveCriticalSection(&cs
->cs
);
614 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
618 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionCreateCertRef(
619 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
621 PWINE_COLLECTION_CERT_CONTEXT ret
= CryptMemAlloc(
622 sizeof(WINE_COLLECTION_CERT_CONTEXT
));
626 /* Initialize to empty for now, just make sure the size is right */
627 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
629 ret
->childContext
= NULL
;
631 return (PWINE_CERT_CONTEXT_REF
)ret
;
634 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
636 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
637 PWINE_STORE_LIST_ENTRY entry
, next
;
639 TRACE("(%p, %08lx)\n", store
, dwFlags
);
641 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
644 TRACE("closing %p\n", entry
);
645 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
648 DeleteCriticalSection(&cs
->cs
);
652 /* Advances a collection enumeration by one cert, if possible, where advancing
654 * - calling the current store's enumeration function once, and returning
655 * the enumerated cert if one is returned
656 * - moving to the next store if the current store has no more items, and
657 * recursively calling itself to get the next item.
658 * Returns NULL if the collection contains no more items or on error.
659 * Assumes the collection store's lock is held.
661 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
662 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
663 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
665 PWINE_COLLECTION_CERT_CONTEXT ret
;
666 PWINE_CERT_CONTEXT_REF child
;
668 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
672 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
673 pPrev
->childContext
);
677 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
678 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
679 InterlockedIncrement(&ret
->cert
.context
->ref
);
680 ret
->childContext
= child
;
684 struct list
*storeNext
= list_next(&store
->stores
,
687 pPrev
->childContext
= NULL
;
688 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
691 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
693 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
697 SetLastError(CRYPT_E_NOT_FOUND
);
704 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
708 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
709 child
->context
, store
);
712 ret
->entry
= storeEntry
;
713 ret
->childContext
= child
;
716 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
720 struct list
*storeNext
= list_next(&store
->stores
,
725 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
727 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
731 SetLastError(CRYPT_E_NOT_FOUND
);
736 TRACE("returning %p\n", ret
);
740 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionEnumCert(
741 PWINECRYPT_CERTSTORE store
, PWINE_CERT_CONTEXT_REF pPrev
)
743 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
744 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
745 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
747 TRACE("(%p, %p)\n", store
, pPrev
);
751 EnterCriticalSection(&cs
->cs
);
752 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
753 LeaveCriticalSection(&cs
->cs
);
757 EnterCriticalSection(&cs
->cs
);
758 if (!list_empty(&cs
->stores
))
760 PWINE_STORE_LIST_ENTRY storeEntry
;
762 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
764 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
768 SetLastError(CRYPT_E_NOT_FOUND
);
771 LeaveCriticalSection(&cs
->cs
);
773 TRACE("returning %p\n", ret
);
774 return (PWINE_CERT_CONTEXT_REF
)ret
;
777 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
778 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
780 PWINE_COLLECTION_CERT_CONTEXT context
=
781 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
784 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
786 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
788 context
->childContext
= NULL
;
792 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref
)
794 PWINE_COLLECTION_CERT_CONTEXT context
= (PWINE_COLLECTION_CERT_CONTEXT
)ref
;
796 TRACE("(%p)\n", ref
);
798 if (context
->childContext
)
799 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
802 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
803 DWORD dwFlags
, const void *pvPara
)
805 PWINE_COLLECTIONSTORE store
;
807 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
809 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
814 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
817 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
818 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
819 StoreTypeCollection
);
820 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
821 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
822 store
->hdr
.createCertRef
= CRYPT_CollectionCreateCertRef
;
823 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
824 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
825 store
->hdr
.freeCert
= CRYPT_CollectionFreeCert
;
826 InitializeCriticalSection(&store
->cs
);
827 list_init(&store
->stores
);
830 return (PWINECRYPT_CERTSTORE
)store
;
833 static void CRYPT_HashToStr(LPBYTE hash
, LPWSTR asciiHash
)
835 static const WCHAR fmt
[] = { '%','0','2','X',0 };
841 for (i
= 0; i
< 20; i
++)
842 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
845 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
847 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
848 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
849 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
851 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store
, HKEY key
,
856 WCHAR subKeyName
[MAX_PATH
];
859 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
861 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
867 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
873 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
875 buf
= CryptMemAlloc(size
);
878 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
885 TRACE("Adding cert with hash %s\n",
886 debugstr_w(subKeyName
));
887 context
= CRYPT_ReadSerializedElement(buf
, size
,
888 contextType
, &addedType
);
891 const WINE_CONTEXT_INTERFACE
*contextInterface
;
896 case CERT_STORE_CERTIFICATE_CONTEXT
:
897 contextInterface
= &gCertInterface
;
899 case CERT_STORE_CRL_CONTEXT
:
900 contextInterface
= &gCRLInterface
;
902 case CERT_STORE_CTL_CONTEXT
:
903 contextInterface
= &gCTLInterface
;
906 contextInterface
= NULL
;
908 if (contextInterface
)
911 if (contextInterface
->getProp(context
,
912 CERT_HASH_PROP_ID
, hash
, &size
))
914 WCHAR asciiHash
[20 * 2 + 1];
916 CRYPT_HashToStr(hash
, asciiHash
);
917 TRACE("comparing %s\n",
918 debugstr_w(asciiHash
));
919 TRACE("with %s\n", debugstr_w(subKeyName
));
920 if (!lstrcmpW(asciiHash
, subKeyName
))
922 TRACE("hash matches, adding\n");
923 contextInterface
->addContextToStore(
925 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
929 TRACE("hash doesn't match, ignoring\n");
930 contextInterface
->free(context
);
940 /* Ignore intermediate errors, continue enumerating */
946 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store
)
948 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
949 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
950 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
953 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
958 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
962 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
968 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
969 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, LPBYTE hash
, LPBYTE buf
,
972 WCHAR asciiHash
[20 * 2 + 1];
977 CRYPT_HashToStr(hash
, asciiHash
);
978 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
982 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
995 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
996 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
998 const void *context
= NULL
;
1002 context
= contextInterface
->enumContextsInStore(memStore
, context
);
1006 DWORD hashSize
= sizeof(hash
);
1008 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
1015 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
1017 buf
= CryptMemAlloc(size
);
1020 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
1022 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
1029 } while (ret
&& context
!= NULL
);
1031 contextInterface
->free(context
);
1035 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTORE store
)
1037 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
1038 static const WINE_CONTEXT_INTERFACE
*interfaces
[] = { &gCertInterface
,
1039 &gCRLInterface
, &gCTLInterface
};
1040 struct list
*listToDelete
[] = { &store
->certsToDelete
, NULL
, NULL
};
1044 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1047 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1048 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1052 if (listToDelete
[i
])
1054 PWINE_HASH_TO_DELETE toDelete
, next
;
1055 WCHAR asciiHash
[20 * 2 + 1];
1057 EnterCriticalSection(&store
->cs
);
1058 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
1059 WINE_HASH_TO_DELETE
, entry
)
1063 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
1064 TRACE("Removing %s\n", debugstr_w(asciiHash
));
1065 rc
= RegDeleteKeyW(key
, asciiHash
);
1066 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
1071 list_remove(&toDelete
->entry
);
1072 CryptMemFree(toDelete
);
1074 LeaveCriticalSection(&store
->cs
);
1076 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
1089 /* If force is true or the registry store is dirty, writes the contents of the
1090 * store to the registry.
1092 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTORE store
, BOOL force
)
1096 if (store
->dirty
|| force
)
1097 ret
= CRYPT_RegWriteToReg(store
);
1103 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1105 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1107 TRACE("(%p, %08lx)\n", store
, dwFlags
);
1109 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
1111 CRYPT_RegFlushStore(store
, FALSE
);
1112 /* certsToDelete should already be cleared by this point */
1113 store
->memStore
->closeStore(store
->memStore
, 0);
1114 RegCloseKey(store
->key
);
1115 DeleteCriticalSection(&store
->cs
);
1116 CryptMemFree(store
);
1119 static BOOL WINAPI
CRYPT_RegAddCert(HCERTSTORE hCertStore
, PCCERT_CONTEXT cert
,
1120 DWORD dwAddDisposition
)
1122 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1125 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwAddDisposition
);
1127 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1129 SetLastError(ERROR_ACCESS_DENIED
);
1134 ret
= store
->memStore
->addCert(store
->memStore
, cert
, dwAddDisposition
);
1136 store
->dirty
= TRUE
;
1141 static PWINE_CERT_CONTEXT_REF
CRYPT_RegCreateCertRef(
1142 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
1144 PWINE_REG_CERT_CONTEXT ret
= CryptMemAlloc(
1145 sizeof(WINE_REG_CERT_CONTEXT
));
1149 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
1150 ret
->childContext
= NULL
;
1152 return (PWINE_CERT_CONTEXT_REF
)ret
;
1155 static PWINE_CERT_CONTEXT_REF
CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store
,
1156 PWINE_CERT_CONTEXT_REF pPrev
)
1158 PWINE_REGSTORE rs
= (PWINE_REGSTORE
)store
;
1159 PWINE_CERT_CONTEXT_REF child
;
1160 PWINE_REG_CERT_CONTEXT prev
= (PWINE_REG_CERT_CONTEXT
)pPrev
, ret
= NULL
;
1162 TRACE("(%p, %p)\n", store
, pPrev
);
1166 child
= rs
->memStore
->enumCert(rs
->memStore
, prev
->childContext
);
1169 ret
= (PWINE_REG_CERT_CONTEXT
)pPrev
;
1170 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
1171 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
1172 ret
->childContext
= child
;
1177 child
= rs
->memStore
->enumCert(rs
->memStore
, NULL
);
1180 ret
= CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT
));
1184 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
1185 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
1186 ret
->childContext
= child
;
1189 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
1192 return (PWINE_CERT_CONTEXT_REF
)ret
;
1195 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
1196 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
1198 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1201 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1203 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1205 SetLastError(ERROR_ACCESS_DENIED
);
1210 PWINE_HASH_TO_DELETE toDelete
=
1211 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
1215 DWORD size
= sizeof(toDelete
->hash
);
1217 ret
= CertGetCertificateContextProperty(pCertContext
,
1218 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
1221 list_init(&toDelete
->entry
);
1222 EnterCriticalSection(&store
->cs
);
1223 list_add_tail(&store
->certsToDelete
, &toDelete
->entry
);
1224 LeaveCriticalSection(&store
->cs
);
1225 ret
= store
->memStore
->deleteCert(store
->memStore
, pCertContext
,
1229 CryptMemFree(toDelete
);
1234 store
->dirty
= TRUE
;
1239 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref
)
1241 PWINE_REG_CERT_CONTEXT context
= (PWINE_REG_CERT_CONTEXT
)ref
;
1243 TRACE("(%p)\n", ref
);
1245 if (context
->childContext
)
1246 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
1249 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
1250 DWORD dwCtrlType
, void const *pvCtrlPara
)
1252 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1257 case CERT_STORE_CTRL_RESYNC
:
1258 CRYPT_RegFlushStore(store
, FALSE
);
1259 store
->memStore
->closeStore(store
->memStore
, 0);
1260 store
->memStore
= CRYPT_MemOpenStore(store
->hdr
.cryptProv
,
1261 store
->hdr
.dwOpenFlags
, NULL
);
1262 if (store
->memStore
)
1264 CRYPT_RegReadFromReg(store
);
1270 case CERT_STORE_CTRL_COMMIT
:
1271 ret
= CRYPT_RegFlushStore(store
,
1272 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1275 FIXME("%ld: stub\n", dwCtrlType
);
1281 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1282 static DWORD
CRYPT_RecurseDeleteKey(HKEY hKey
, LPCWSTR lpszSubKey
)
1284 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1285 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1288 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1290 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1293 /* Find how many subkeys there are */
1294 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1295 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1299 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1301 /* Name too big: alloc a buffer for it */
1302 lpszName
= CryptMemAlloc(dwMaxSubkeyLen
*sizeof(WCHAR
));
1306 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1309 /* Recursively delete all the subkeys */
1310 for (i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1312 dwSize
= dwMaxSubkeyLen
;
1313 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
,
1316 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1319 if (lpszName
!= szNameBuf
)
1321 /* Free buffer if allocated */
1322 CryptMemFree(lpszName
);
1327 RegCloseKey(hSubKey
);
1329 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1334 static WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
,
1335 DWORD dwFlags
, const void *pvPara
)
1337 PWINE_REGSTORE store
= NULL
;
1339 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
1341 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
1343 DWORD rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CertsW
);
1345 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1346 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CRLsW
);
1347 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1348 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CTLsW
);
1349 if (rc
== ERROR_NO_MORE_ITEMS
)
1357 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1358 GetCurrentProcess(), (LPHANDLE
)&key
,
1359 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1362 PWINECRYPT_CERTSTORE memStore
;
1364 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1367 store
= CryptMemAlloc(sizeof(WINE_REGSTORE
));
1370 memset(store
, 0, sizeof(WINE_REGSTORE
));
1371 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
1373 store
->hdr
.closeStore
= CRYPT_RegCloseStore
;
1374 store
->hdr
.addCert
= CRYPT_RegAddCert
;
1375 store
->hdr
.createCertRef
= CRYPT_RegCreateCertRef
;
1376 store
->hdr
.enumCert
= CRYPT_RegEnumCert
;
1377 store
->hdr
.deleteCert
= CRYPT_RegDeleteCert
;
1378 store
->hdr
.freeCert
= CRYPT_RegFreeCert
;
1379 store
->hdr
.control
= CRYPT_RegControl
;
1380 store
->memStore
= memStore
;
1382 InitializeCriticalSection(&store
->cs
);
1383 list_init(&store
->certsToDelete
);
1384 CRYPT_RegReadFromReg(store
);
1385 store
->dirty
= FALSE
;
1390 TRACE("returning %p\n", store
);
1391 return (WINECRYPT_CERTSTORE
*)store
;
1394 /* FIXME: this isn't complete for the Root store, in which the top-level
1395 * self-signed CA certs reside. Adding a cert to the Root store should present
1396 * the user with a dialog indicating the consequences of doing so, and asking
1397 * the user to confirm whether the cert should be added.
1399 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv
,
1400 DWORD dwFlags
, const void *pvPara
)
1402 static const WCHAR fmt
[] = { '%','s','\\','%','s',0 };
1403 LPCWSTR storeName
= (LPCWSTR
)pvPara
;
1405 PWINECRYPT_CERTSTORE store
= NULL
;
1410 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1411 debugstr_w((LPCWSTR
)pvPara
));
1415 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1420 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1423 root
= HKEY_LOCAL_MACHINE
;
1424 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1426 case CERT_SYSTEM_STORE_CURRENT_USER
:
1427 root
= HKEY_CURRENT_USER
;
1428 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1430 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1431 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1432 * SystemCertificates
1434 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1435 debugstr_w(storeName
));
1437 case CERT_SYSTEM_STORE_SERVICES
:
1438 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1439 * SystemCertificates
1441 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1442 debugstr_w(storeName
));
1444 case CERT_SYSTEM_STORE_USERS
:
1445 /* hku\user sid\Software\Microsoft\SystemCertificates */
1446 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1447 debugstr_w(storeName
));
1449 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1450 root
= HKEY_CURRENT_USER
;
1451 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1453 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1454 root
= HKEY_LOCAL_MACHINE
;
1455 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1457 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1458 /* hklm\Software\Microsoft\EnterpriseCertificates */
1459 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1460 debugstr_w(storeName
));
1463 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1467 storePath
= CryptMemAlloc((lstrlenW(base
) + lstrlenW(storeName
) + 2) *
1473 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1476 wsprintfW(storePath
, fmt
, base
, storeName
);
1477 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1478 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1483 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1485 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1486 disp
== REG_OPENED_EXISTING_KEY
)
1489 rc
= ERROR_FILE_EXISTS
;
1494 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1499 CryptMemFree(storePath
);
1504 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1505 DWORD dwFlags
, const void *pvPara
)
1508 PWINECRYPT_CERTSTORE ret
= NULL
;
1510 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1511 debugstr_a((LPCSTR
)pvPara
));
1515 SetLastError(ERROR_FILE_NOT_FOUND
);
1518 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1521 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1525 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1526 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1527 CryptMemFree(storeName
);
1533 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1534 DWORD dwFlags
, const void *pvPara
)
1536 HCERTSTORE store
= 0;
1539 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1540 debugstr_w((LPCWSTR
)pvPara
));
1544 SetLastError(ERROR_FILE_NOT_FOUND
);
1547 /* This returns a different error than system registry stores if the
1548 * location is invalid.
1550 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1552 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1553 case CERT_SYSTEM_STORE_CURRENT_USER
:
1554 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1555 case CERT_SYSTEM_STORE_SERVICES
:
1556 case CERT_SYSTEM_STORE_USERS
:
1557 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1558 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1559 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1563 SetLastError(ERROR_FILE_NOT_FOUND
);
1568 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1569 0, hCryptProv
, dwFlags
, pvPara
);
1573 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1574 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1577 CertAddStoreToCollection(store
, regStore
,
1578 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1579 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1580 CertCloseStore(regStore
, 0);
1584 return (PWINECRYPT_CERTSTORE
)store
;
1587 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv
,
1588 DWORD dwFlags
, const void *pvPara
)
1591 PWINECRYPT_CERTSTORE ret
= NULL
;
1593 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1594 debugstr_a((LPCSTR
)pvPara
));
1598 SetLastError(ERROR_FILE_NOT_FOUND
);
1601 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1604 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1608 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1609 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1610 CryptMemFree(storeName
);
1616 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1617 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
1620 WINECRYPT_CERTSTORE
*hcs
;
1621 StoreOpenFunc openFunc
= NULL
;
1623 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
1624 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
1626 if (!HIWORD(lpszStoreProvider
))
1628 switch (LOWORD(lpszStoreProvider
))
1630 case (int)CERT_STORE_PROV_MEMORY
:
1631 openFunc
= CRYPT_MemOpenStore
;
1633 case (int)CERT_STORE_PROV_REG
:
1634 openFunc
= CRYPT_RegOpenStore
;
1636 case (int)CERT_STORE_PROV_COLLECTION
:
1637 openFunc
= CRYPT_CollectionOpenStore
;
1639 case (int)CERT_STORE_PROV_SYSTEM_A
:
1640 openFunc
= CRYPT_SysOpenStoreA
;
1642 case (int)CERT_STORE_PROV_SYSTEM_W
:
1643 openFunc
= CRYPT_SysOpenStoreW
;
1645 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1646 openFunc
= CRYPT_SysRegOpenStoreA
;
1648 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1649 openFunc
= CRYPT_SysRegOpenStoreW
;
1652 if (LOWORD(lpszStoreProvider
))
1653 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
1656 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
1657 openFunc
= CRYPT_MemOpenStore
;
1658 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
1659 openFunc
= CRYPT_SysOpenStoreW
;
1660 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
1661 openFunc
= CRYPT_CollectionOpenStore
;
1662 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM_REGISTRY
))
1663 openFunc
= CRYPT_SysRegOpenStoreW
;
1666 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1672 /* FIXME: need to look for an installed provider for this type */
1673 SetLastError(ERROR_FILE_NOT_FOUND
);
1677 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1678 return (HCERTSTORE
)hcs
;
1681 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1682 LPCSTR szSubSystemProtocol
)
1686 if (szSubSystemProtocol
)
1688 int len
= MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, NULL
,
1690 LPWSTR param
= CryptMemAlloc(len
* sizeof(WCHAR
));
1694 MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, param
, len
);
1695 ret
= CertOpenSystemStoreW(hProv
, param
);
1696 CryptMemFree(param
);
1700 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1704 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1705 LPCWSTR szSubSystemProtocol
)
1709 if (!szSubSystemProtocol
)
1711 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1715 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1716 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1719 ret
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, hProv
,
1720 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1723 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1724 0, hProv
, CERT_SYSTEM_STORE_LOCAL_MACHINE
, szSubSystemProtocol
);
1728 CertAddStoreToCollection(ret
, store
,
1729 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1730 CertCloseStore(store
, 0);
1732 store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1733 0, hProv
, CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1736 CertAddStoreToCollection(ret
, store
,
1737 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1738 CertCloseStore(store
, 0);
1744 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
1745 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
1747 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
1748 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
1752 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1753 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
1758 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
1760 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1761 pcrl
= CryptMemAlloc( sizeof (CRL_CONTEXT
) );
1765 data
= CryptMemAlloc( cbCrlEncoded
);
1768 CryptMemFree( pcrl
);
1772 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1773 pcrl
->pbCrlEncoded
= data
;
1774 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1775 pcrl
->pCrlInfo
= NULL
;
1776 pcrl
->hCertStore
= 0;
1781 /* Decodes the encoded certificate and creates the certificate context for it.
1782 * The reference count is initially zero, so you must create a reference to it
1783 * to avoid leaking memory.
1785 static PWINE_CERT_CONTEXT
CRYPT_CreateCertificateContext(
1786 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1788 PWINE_CERT_CONTEXT cert
= NULL
;
1790 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1791 PCERT_INFO certInfo
= NULL
;
1794 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1797 /* First try to decode it as a signed cert. */
1798 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT
, pbCertEncoded
,
1799 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1800 (BYTE
*)&signedCert
, &size
);
1804 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1805 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
1806 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1807 (BYTE
*)&certInfo
, &size
);
1808 LocalFree(signedCert
);
1810 /* Failing that, try it as an unsigned cert */
1814 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1815 pbCertEncoded
, cbCertEncoded
,
1816 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1817 (BYTE
*)&certInfo
, &size
);
1823 cert
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT
));
1826 data
= CryptMemAlloc(cbCertEncoded
);
1833 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
1834 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
1835 cert
->cert
.pbCertEncoded
= data
;
1836 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
1837 cert
->cert
.pCertInfo
= certInfo
;
1838 cert
->cert
.hCertStore
= 0;
1840 InitializeCriticalSection(&cert
->cs
);
1841 list_init(&cert
->extendedProperties
);
1848 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context
)
1850 PWINE_CERT_PROPERTY prop
, next
;
1852 CryptMemFree(context
->cert
.pbCertEncoded
);
1853 LocalFree(context
->cert
.pCertInfo
);
1854 DeleteCriticalSection(&context
->cs
);
1855 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
1856 WINE_CERT_PROPERTY
, entry
)
1858 list_remove(&prop
->entry
);
1859 CryptMemFree(prop
->pbData
);
1862 CryptMemFree(context
);
1865 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
1866 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1868 PWINE_CERT_CONTEXT cert
;
1869 PWINE_CERT_CONTEXT_REF ret
= NULL
;
1871 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1874 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
1877 ret
= CRYPT_CreateCertRef(cert
, 0);
1878 return (PCCERT_CONTEXT
)ret
;
1881 /* Since the properties are stored in a list, this is a tad inefficient
1882 * (O(n^2)) since I have to find the previous position every time.
1884 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
1887 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1890 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1892 EnterCriticalSection(&ref
->context
->cs
);
1895 PWINE_CERT_PROPERTY cursor
= NULL
;
1897 LIST_FOR_EACH_ENTRY(cursor
, &ref
->context
->extendedProperties
,
1898 WINE_CERT_PROPERTY
, entry
)
1900 if (cursor
->hdr
.propID
== dwPropId
)
1905 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
1906 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
1914 else if (!list_empty(&ref
->context
->extendedProperties
))
1915 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
1916 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
1919 LeaveCriticalSection(&ref
->context
->cs
);
1923 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1924 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1926 PWINE_CERT_PROPERTY prop
;
1929 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1931 EnterCriticalSection(&context
->cs
);
1934 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1935 WINE_CERT_PROPERTY
, entry
)
1937 if (prop
->hdr
.propID
== dwPropId
)
1941 *pcbData
= prop
->hdr
.cb
;
1944 else if (*pcbData
< prop
->hdr
.cb
)
1946 SetLastError(ERROR_MORE_DATA
);
1947 *pcbData
= prop
->hdr
.cb
;
1951 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1952 *pcbData
= prop
->hdr
.cb
;
1961 /* Implicit properties */
1964 case CERT_SHA1_HASH_PROP_ID
:
1965 ret
= CryptHashCertificate(0, CALG_SHA1
, 0,
1966 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1970 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1972 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
1976 case CERT_KEY_PROV_INFO_PROP_ID
:
1977 case CERT_MD5_HASH_PROP_ID
:
1978 case CERT_SIGNATURE_HASH_PROP_ID
:
1979 case CERT_KEY_IDENTIFIER_PROP_ID
:
1980 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1981 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1982 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1983 FIXME("implicit property %ld\n", dwPropId
);
1987 LeaveCriticalSection(&context
->cs
);
1988 TRACE("returning %d\n", ret
);
1992 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1993 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1995 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1998 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
2000 /* Special cases for invalid/special prop IDs.
2005 case CERT_CERT_PROP_ID
:
2006 case CERT_CRL_PROP_ID
:
2007 case CERT_CTL_PROP_ID
:
2008 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2010 case CERT_ACCESS_STATE_PROP_ID
:
2013 *pcbData
= sizeof(DWORD
);
2016 else if (*pcbData
< sizeof(DWORD
))
2018 SetLastError(ERROR_MORE_DATA
);
2019 *pcbData
= sizeof(DWORD
);
2026 if (pCertContext
->hCertStore
)
2028 PWINECRYPT_CERTSTORE store
=
2029 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2031 /* Take advantage of knowledge of the stores to answer the
2032 * access state question
2034 if (store
->type
!= StoreTypeReg
||
2035 !(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
2036 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
2038 *(DWORD
*)pvData
= state
;
2043 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
2045 TRACE("returning %d\n", ret
);
2049 /* Copies cbData bytes from pbData to the context's property with ID
2052 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
2053 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
2060 data
= CryptMemAlloc(cbData
);
2062 memcpy(data
, pbData
, cbData
);
2066 if (!cbData
|| data
)
2068 PWINE_CERT_PROPERTY prop
;
2070 EnterCriticalSection(&context
->cs
);
2071 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
2072 WINE_CERT_PROPERTY
, entry
)
2074 if (prop
->hdr
.propID
== dwPropId
)
2077 if (prop
&& prop
->entry
.next
!= &context
->extendedProperties
)
2079 CryptMemFree(prop
->pbData
);
2080 prop
->hdr
.cb
= cbData
;
2081 prop
->pbData
= cbData
? data
: NULL
;
2086 prop
= CryptMemAlloc(sizeof(WINE_CERT_PROPERTY
));
2089 prop
->hdr
.propID
= dwPropId
;
2090 prop
->hdr
.unknown
= 1;
2091 prop
->hdr
.cb
= cbData
;
2092 list_init(&prop
->entry
);
2093 prop
->pbData
= cbData
? data
: NULL
;
2094 list_add_tail(&context
->extendedProperties
, &prop
->entry
);
2100 LeaveCriticalSection(&context
->cs
);
2105 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
2106 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2110 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
2114 PWINE_CERT_PROPERTY prop
, next
;
2116 EnterCriticalSection(&context
->cs
);
2117 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
2118 WINE_CERT_PROPERTY
, entry
)
2120 if (prop
->hdr
.propID
== dwPropId
)
2122 list_remove(&prop
->entry
);
2123 CryptMemFree(prop
->pbData
);
2127 LeaveCriticalSection(&context
->cs
);
2134 case CERT_AUTO_ENROLL_PROP_ID
:
2135 case CERT_CTL_USAGE_PROP_ID
:
2136 case CERT_DESCRIPTION_PROP_ID
:
2137 case CERT_FRIENDLY_NAME_PROP_ID
:
2138 case CERT_HASH_PROP_ID
:
2139 case CERT_KEY_IDENTIFIER_PROP_ID
:
2140 case CERT_MD5_HASH_PROP_ID
:
2141 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2142 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2143 case CERT_PVK_FILE_PROP_ID
:
2144 case CERT_SIGNATURE_HASH_PROP_ID
:
2145 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2146 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2147 case CERT_ENROLLMENT_PROP_ID
:
2148 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2149 case CERT_RENEWAL_PROP_ID
:
2151 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
2153 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2154 blob
->pbData
, blob
->cbData
);
2157 case CERT_DATE_STAMP_PROP_ID
:
2158 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2159 pvData
, sizeof(FILETIME
));
2162 FIXME("%ld: stub\n", dwPropId
);
2165 TRACE("returning %d\n", ret
);
2169 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
2170 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2172 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2175 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
2177 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2178 * crashes on most of these, I'll be safer.
2183 case CERT_ACCESS_STATE_PROP_ID
:
2184 case CERT_CERT_PROP_ID
:
2185 case CERT_CRL_PROP_ID
:
2186 case CERT_CTL_PROP_ID
:
2187 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2190 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
2192 TRACE("returning %d\n", ret
);
2196 /* Only the reference portion of the context is duplicated. The returned
2197 * context has the cert store set to 0, to prevent the store's certificate free
2198 * function from getting called on partial data.
2199 * FIXME: is this okay? Needs a test.
2201 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
2202 PCCERT_CONTEXT pCertContext
)
2204 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
, ret
;
2206 TRACE("(%p)\n", pCertContext
);
2209 ret
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF
));
2212 memcpy(ret
, ref
, sizeof(*ret
));
2213 ret
->cert
.hCertStore
= 0;
2214 InterlockedIncrement(&ret
->context
->ref
);
2219 return (PCCERT_CONTEXT
)ret
;
2222 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
2223 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
2224 PCCERT_CONTEXT
*ppStoreContext
)
2226 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
2227 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2228 PWINE_CERT_CONTEXT cert
;
2231 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2232 dwAddDisposition
, ppStoreContext
);
2234 /* FIXME: some tests needed to verify return codes */
2237 SetLastError(ERROR_INVALID_PARAMETER
);
2240 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2242 SetLastError(ERROR_INVALID_PARAMETER
);
2246 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
2247 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
2250 PWINE_CERT_PROPERTY prop
;
2253 EnterCriticalSection(&ref
->context
->cs
);
2254 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2255 WINE_CERT_PROPERTY
, entry
)
2257 ret
= CRYPT_SaveCertificateContextProperty(cert
, prop
->hdr
.propID
,
2258 prop
->pbData
, prop
->hdr
.cb
);
2262 LeaveCriticalSection(&ref
->context
->cs
);
2265 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2266 if (ret
&& ppStoreContext
)
2267 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
2271 CRYPT_FreeCert(cert
);
2278 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
2279 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
2280 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
2282 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2285 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2286 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2290 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2294 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
2295 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2299 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2300 if (ret
&& ppCertContext
)
2301 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
2304 CRYPT_FreeCert(cert
);
2312 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
2313 PCCERT_CONTEXT pPrev
)
2315 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2316 PWINE_CERT_CONTEXT_REF prev
= (PWINE_CERT_CONTEXT_REF
)pPrev
;
2319 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2322 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2325 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
2329 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2333 TRACE("(%p)\n", pCertContext
);
2337 else if (!pCertContext
->hCertStore
)
2340 CertFreeCertificateContext(pCertContext
);
2344 PWINECRYPT_CERTSTORE hcs
=
2345 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2349 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2353 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2354 CertFreeCertificateContext(pCertContext
);
2360 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
2361 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
2362 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
2364 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2365 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
2370 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
2371 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
2372 PCCRL_CONTEXT
* ppStoreContext
)
2374 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
2375 dwAddDisposition
, ppStoreContext
);
2379 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2381 FIXME("%p\n", pCrlContext
);
2386 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2388 FIXME("(%p): stub\n", pCrlContext
);
2392 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2393 PCCRL_CONTEXT pPrev
)
2395 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2399 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2400 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2402 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
2407 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
2408 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
2409 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
2411 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2412 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
2417 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
2418 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
2419 PCCTL_CONTEXT
* ppStoreContext
)
2421 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
2422 dwAddDisposition
, ppStoreContext
);
2426 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2428 FIXME("(%p): stub\n", pCtlContext
);
2432 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2434 FIXME("(%p): stub\n", pCtlContext
);
2438 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2439 PCCTL_CONTEXT pPrev
)
2441 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2446 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2448 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2450 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2455 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2458 if (InterlockedDecrement(&hcs
->ref
) == 0)
2460 TRACE("%p's ref count is 0, freeing\n", hcs
);
2462 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2463 CryptReleaseContext(hcs
->cryptProv
, 0);
2464 hcs
->closeStore(hcs
, dwFlags
);
2467 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2471 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2472 DWORD dwCtrlType
, void const *pvCtrlPara
)
2474 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2477 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2482 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2487 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
2494 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2495 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2497 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
2501 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2502 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2504 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
2509 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
2510 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2512 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext
, dwFlags
, pbElement
,
2517 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2518 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2520 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
2524 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2525 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2527 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
2532 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
2533 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2535 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext
, dwFlags
, pbElement
,
2540 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
2541 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2545 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
2550 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2551 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) +
2552 pCertContext
->cbCertEncoded
;
2553 PWINE_CERT_PROPERTY prop
;
2555 EnterCriticalSection(&ref
->context
->cs
);
2556 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2557 WINE_CERT_PROPERTY
, entry
)
2558 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + prop
->hdr
.cb
;
2561 *pcbElement
= bytesNeeded
;
2564 else if (*pcbElement
< bytesNeeded
)
2566 *pcbElement
= bytesNeeded
;
2567 SetLastError(ERROR_MORE_DATA
);
2572 PWINE_CERT_PROP_HEADER hdr
;
2574 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2575 WINE_CERT_PROPERTY
, entry
)
2577 memcpy(pbElement
, &prop
->hdr
, sizeof(WINE_CERT_PROP_HEADER
));
2578 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2581 memcpy(pbElement
, prop
->pbData
, prop
->hdr
.cb
);
2582 pbElement
+= prop
->hdr
.cb
;
2585 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
2586 hdr
->propID
= CERT_CERT_PROP_ID
;
2588 hdr
->cb
= pCertContext
->cbCertEncoded
;
2589 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
2590 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
2593 LeaveCriticalSection(&ref
->context
->cs
);
2600 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2601 * to its header if a valid header is found, NULL if not. Valid means the
2602 * length of thte property won't overrun buf, and the unknown field is 1.
2604 static const WINE_CERT_PROP_HEADER
*CRYPT_findPropID(const BYTE
*buf
,
2605 DWORD size
, DWORD propID
)
2607 const WINE_CERT_PROP_HEADER
*ret
= NULL
;
2610 while (size
&& !ret
&& !done
)
2612 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
2614 SetLastError(CRYPT_E_FILE_ERROR
);
2619 const WINE_CERT_PROP_HEADER
*hdr
=
2620 (const WINE_CERT_PROP_HEADER
*)buf
;
2622 size
-= sizeof(WINE_CERT_PROP_HEADER
);
2623 buf
+= sizeof(WINE_CERT_PROP_HEADER
);
2626 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2629 else if (!hdr
->propID
)
2631 /* assume a zero prop ID means the data are uninitialized, so
2636 else if (hdr
->unknown
!= 1)
2638 SetLastError(ERROR_FILE_NOT_FOUND
);
2641 else if (hdr
->propID
== propID
)
2653 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
2654 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
)
2656 const void *context
;
2658 TRACE("(%p, %ld, %08lx, %p)\n", pbElement
, cbElement
, dwContextTypeFlags
,
2663 SetLastError(ERROR_END_OF_MEDIA
);
2669 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2670 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
2676 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
2678 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2680 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2683 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2685 type
= CERT_STORE_CRL_CONTEXT
;
2688 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
2691 type
= CERT_STORE_CTL_CONTEXT
;
2695 else if (dwContextTypeFlags
& CERT_STORE_CERTIFICATE_CONTEXT_FLAG
)
2697 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2698 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2700 else if (dwContextTypeFlags
& CERT_STORE_CRL_CONTEXT_FLAG
)
2702 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2703 type
= CERT_STORE_CRL_CONTEXT
;
2705 else if (dwContextTypeFlags
& CERT_STORE_CTL_CONTEXT_FLAG
)
2707 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CTL_PROP_ID
);
2708 type
= CERT_STORE_CTL_CONTEXT
;
2713 case CERT_STORE_CERTIFICATE_CONTEXT
:
2714 contextInterface
= &gCertInterface
;
2716 case CERT_STORE_CRL_CONTEXT
:
2717 contextInterface
= &gCRLInterface
;
2719 case CERT_STORE_CTL_CONTEXT
:
2720 contextInterface
= &gCTLInterface
;
2723 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2730 context
= contextInterface
->create(X509_ASN_ENCODING
,
2731 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
2734 BOOL noMoreProps
= FALSE
;
2736 while (!noMoreProps
&& ret
)
2738 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
2742 const WINE_CERT_PROP_HEADER
*hdr
=
2743 (const WINE_CERT_PROP_HEADER
*)pbElement
;
2745 TRACE("prop is %ld\n", hdr
->propID
);
2746 cbElement
-= sizeof(WINE_CERT_PROP_HEADER
);
2747 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2748 if (cbElement
< hdr
->cb
)
2750 SetLastError(HRESULT_FROM_WIN32(
2751 ERROR_INVALID_PARAMETER
));
2754 else if (!hdr
->propID
)
2756 /* Like in CRYPT_findPropID, stop if the propID is zero
2760 else if (hdr
->unknown
!= 1)
2762 SetLastError(ERROR_FILE_NOT_FOUND
);
2765 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
2766 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!=
2769 /* Have to create a blob for most types, but not
2772 switch (hdr
->propID
)
2774 case CERT_AUTO_ENROLL_PROP_ID
:
2775 case CERT_CTL_USAGE_PROP_ID
:
2776 case CERT_DESCRIPTION_PROP_ID
:
2777 case CERT_FRIENDLY_NAME_PROP_ID
:
2778 case CERT_HASH_PROP_ID
:
2779 case CERT_KEY_IDENTIFIER_PROP_ID
:
2780 case CERT_MD5_HASH_PROP_ID
:
2781 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2782 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2783 case CERT_PVK_FILE_PROP_ID
:
2784 case CERT_SIGNATURE_HASH_PROP_ID
:
2785 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2786 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2787 case CERT_ENROLLMENT_PROP_ID
:
2788 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2789 case CERT_RENEWAL_PROP_ID
:
2791 CRYPT_DATA_BLOB blob
= { hdr
->cb
,
2792 (LPBYTE
)pbElement
};
2794 ret
= contextInterface
->setProp(context
,
2795 hdr
->propID
, 0, &blob
);
2798 case CERT_DATE_STAMP_PROP_ID
:
2799 ret
= contextInterface
->setProp(context
,
2800 hdr
->propID
, 0, pbElement
);
2803 FIXME("prop ID %ld: stub\n", hdr
->propID
);
2806 pbElement
+= hdr
->cb
;
2807 cbElement
-= hdr
->cb
;
2815 *pdwContentType
= type
;
2819 contextInterface
->free(context
);
2824 _SEH_EXCEPT(page_fault
)
2826 SetLastError(STATUS_ACCESS_VIOLATION
);
2833 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
2834 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
2835 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
2837 const void *context
;
2841 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore
,
2842 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
2843 pdwContentType
, ppvContext
);
2845 /* Call the internal function, then delete the hashes. Tests show this
2846 * function uses real hash values, not whatever's stored in the hash
2849 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
2850 dwContextTypeFlags
, &type
);
2853 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2857 case CERT_STORE_CERTIFICATE_CONTEXT
:
2858 contextInterface
= &gCertInterface
;
2860 case CERT_STORE_CRL_CONTEXT
:
2861 contextInterface
= &gCRLInterface
;
2863 case CERT_STORE_CTL_CONTEXT
:
2864 contextInterface
= &gCTLInterface
;
2867 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2869 if (contextInterface
)
2871 contextInterface
->setProp(context
, CERT_HASH_PROP_ID
, 0, NULL
);
2872 contextInterface
->setProp(context
, CERT_MD5_HASH_PROP_ID
, 0, NULL
);
2873 contextInterface
->setProp(context
, CERT_SIGNATURE_HASH_PROP_ID
, 0,
2876 *pdwContentType
= type
;
2877 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
2878 dwAddDisposition
, ppvContext
);
2879 contextInterface
->free(context
);
2889 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2891 TRACE("(%p)\n", pCertContext
);
2895 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2896 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)ref
->cert
.hCertStore
;
2898 if (InterlockedDecrement(&ref
->context
->ref
) == 0)
2900 TRACE("%p's ref count is 0, freeing\n", ref
->context
);
2901 CRYPT_FreeCert(ref
->context
);
2904 TRACE("%p's ref count is %ld\n", ref
->context
, ref
->context
->ref
);
2905 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
2907 store
->freeCert(ref
);
2913 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
2914 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
,
2915 const void *pvPara
, PCCERT_CONTEXT pPrevCertContext
)
2917 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore
, dwCertEncodingType
,
2918 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
2919 SetLastError(CRYPT_E_NOT_FOUND
);
2923 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
2924 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
2926 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2927 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2928 PWINE_STORE_LIST_ENTRY entry
;
2931 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2932 dwUpdateFlags
, dwPriority
);
2934 if (!collection
|| !sibling
)
2936 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2938 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2941 if (collection
->hdr
.type
!= StoreTypeCollection
)
2943 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2946 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2948 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2952 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
2955 InterlockedIncrement(&sibling
->ref
);
2956 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
2957 entry
->store
= sibling
;
2958 entry
->dwUpdateFlags
= dwUpdateFlags
;
2959 entry
->dwPriority
= dwPriority
;
2960 list_init(&entry
->entry
);
2961 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
2962 EnterCriticalSection(&collection
->cs
);
2965 PWINE_STORE_LIST_ENTRY cursor
;
2968 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
2969 WINE_STORE_LIST_ENTRY
, entry
)
2971 if (cursor
->dwPriority
< dwPriority
)
2973 list_add_before(&cursor
->entry
, &entry
->entry
);
2979 list_add_tail(&collection
->stores
, &entry
->entry
);
2982 list_add_tail(&collection
->stores
, &entry
->entry
);
2983 LeaveCriticalSection(&collection
->cs
);
2991 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
2992 HCERTSTORE hSiblingStore
)
2994 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2995 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2996 PWINE_STORE_LIST_ENTRY store
, next
;
2998 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
3000 if (!collection
|| !sibling
)
3002 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
3004 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3007 if (collection
->hdr
.type
!= StoreTypeCollection
)
3009 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
3011 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3014 EnterCriticalSection(&collection
->cs
);
3015 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
3016 WINE_STORE_LIST_ENTRY
, entry
)
3018 if (store
->store
== sibling
)
3020 list_remove(&store
->entry
);
3021 CertCloseStore(store
->store
, 0);
3022 CryptMemFree(store
);
3026 LeaveCriticalSection(&collection
->cs
);
3029 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
3030 CRYPT_ATTRIBUTE rgAttr
[])
3032 PCRYPT_ATTRIBUTE ret
= NULL
;
3035 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
3041 SetLastError(ERROR_INVALID_PARAMETER
);
3045 for (i
= 0; !ret
&& i
< cAttr
; i
++)
3046 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
3051 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
3052 CERT_EXTENSION rgExtensions
[])
3054 PCERT_EXTENSION ret
= NULL
;
3057 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
3063 SetLastError(ERROR_INVALID_PARAMETER
);
3067 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
3068 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
3069 rgExtensions
[i
].pszObjId
))
3070 ret
= &rgExtensions
[i
];
3074 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
3076 PCERT_RDN_ATTR ret
= NULL
;
3079 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
3083 SetLastError(ERROR_INVALID_PARAMETER
);
3087 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
3088 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
3089 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
3090 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
3091 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
3095 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
3096 PCERT_INFO pCertInfo
)
3105 GetSystemTime(&sysTime
);
3106 SystemTimeToFileTime(&sysTime
, &fileTime
);
3107 pTimeToVerify
= &fileTime
;
3109 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
3111 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
3118 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
3119 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
3120 DWORD
*pcbComputedHash
)
3123 HCRYPTHASH hHash
= 0;
3125 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
3126 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
3129 hCryptProv
= CRYPT_GetDefaultProvider();
3134 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
3137 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
3139 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
3140 pcbComputedHash
, 0);
3141 CryptDestroyHash(hHash
);
3147 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV hCryptProv
, DWORD dwKeySpec
,
3148 DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
3149 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
3150 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
3156 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv
,
3157 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
3158 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
3160 algID
= CertOIDToAlgId(pSignatureAlgorithm
->pszObjId
);
3163 SetLastError(NTE_BAD_ALGID
);
3168 SetLastError(ERROR_INVALID_PARAMETER
);
3172 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hHash
);
3175 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
, cbEncodedToBeSigned
, 0);
3177 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
3179 CryptDestroyHash(hHash
);
3184 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv
,
3185 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
3186 PCERT_PUBLIC_KEY_INFO pPublicKey
)
3188 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
3189 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, (void *)pbEncoded
,
3190 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
3193 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv
,
3194 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
3195 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
3198 CRYPT_DATA_BLOB subjectBlob
;
3200 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv
,
3201 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
3202 dwFlags
, pvReserved
);
3204 switch (dwSubjectType
)
3206 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
3208 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvSubject
;
3210 subjectBlob
.pbData
= blob
->pbData
;
3211 subjectBlob
.cbData
= blob
->cbData
;
3214 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
3216 PCERT_CONTEXT context
= (PCERT_CONTEXT
)pvSubject
;
3218 subjectBlob
.pbData
= context
->pbCertEncoded
;
3219 subjectBlob
.cbData
= context
->cbCertEncoded
;
3222 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
3224 PCRL_CONTEXT context
= (PCRL_CONTEXT
)pvSubject
;
3226 subjectBlob
.pbData
= context
->pbCrlEncoded
;
3227 subjectBlob
.cbData
= context
->cbCrlEncoded
;
3231 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3237 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
3240 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
3241 subjectBlob
.pbData
, subjectBlob
.cbData
,
3242 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
3243 (BYTE
*)&signedCert
, &size
);
3246 switch (dwIssuerType
)
3248 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
3250 PCERT_PUBLIC_KEY_INFO pubKeyInfo
=
3251 (PCERT_PUBLIC_KEY_INFO
)pvIssuer
;
3252 ALG_ID algID
= CertOIDToAlgId(pubKeyInfo
->Algorithm
.pszObjId
);
3258 ret
= CryptImportPublicKeyInfoEx(hCryptProv
,
3259 dwCertEncodingType
, pubKeyInfo
, algID
, 0, NULL
, &key
);
3264 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hash
);
3267 ret
= CryptHashData(hash
,
3268 signedCert
->ToBeSigned
.pbData
,
3269 signedCert
->ToBeSigned
.cbData
, 0);
3272 ret
= CryptVerifySignatureW(hash
,
3273 signedCert
->Signature
.pbData
,
3274 signedCert
->Signature
.cbData
, key
, NULL
, 0);
3276 CryptDestroyHash(hash
);
3278 CryptDestroyKey(key
);
3283 SetLastError(NTE_BAD_ALGID
);
3288 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
3289 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
3290 FIXME("issuer type %ld: stub\n", dwIssuerType
);
3293 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
3296 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3301 FIXME("unimplemented for NULL signer\n");
3302 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3307 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3310 LocalFree(signedCert
);
3316 BOOL WINAPI
CryptEncryptMessage( PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptMessagePara
,
3317 DWORD dwCert
, PCCERT_CONTEXT pccertCert
[],
3318 const BYTE
* pbEncrypted
, DWORD dwEncrypted
,
3319 BYTE
* pbBlob
, DWORD
* dwEncryptedBlob
)
3325 HCRYPTOIDFUNCSET WINAPI
CryptInitOIDFunctionSet(LPCSTR pszFuncName
, DWORD dwFlags
)
3327 FIXME("stub: %s %lx\n", debugstr_a(pszFuncName
), dwFlags
);
3331 BOOL WINAPI
CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType
,
3332 LPCSTR pszFuncName
, LPCWSTR pwszDll
)
3334 FIXME("stub: %lx %s %s\n", dwEncodingType
, debugstr_a(pszFuncName
), debugstr_w(pwszDll
));
3338 DWORD WINAPI
CertGetNameStringW(PCCERT_CONTEXT pCertContext
,
3339 DWORD dwType
, DWORD dwFlags
,
3340 LPVOID pvType
, LPWSTR pszName
,
3344 return ERROR_CALL_NOT_IMPLEMENTED
;
3347 DWORD WINAPI
CertGetNameStringA(PCCERT_CONTEXT pCertContext
,
3348 DWORD dwType
, DWORD dwFlags
,
3349 LPVOID pvType
, LPSTR pszName
,
3353 return ERROR_CALL_NOT_IMPLEMENTED
;
3357 DWORD WINAPI
CertNameToStrA(DWORD dwCertEncoding
,
3358 PCERT_NAME_BLOB pCertName
,
3359 DWORD dwType
, LPSTR psz
,
3363 return ERROR_CALL_NOT_IMPLEMENTED
;
3366 DWORD WINAPI
CertNameToStrW(DWORD dwCertEncoding
,
3367 PCERT_NAME_BLOB pCertName
,
3368 DWORD dwType
, LPWSTR psz
,
3372 return ERROR_CALL_NOT_IMPLEMENTED
;