2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2004,2005 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * - As you can see in the stubs below, support for CRLs and CTLs is missing.
21 * Mostly this should be copy-paste work, and some code (e.g. extended
22 * properties) could be shared between them.
23 * - Opening a cert store provider should be morphed to support loading
25 * - The concept of physical stores and locations isn't implemented. (This
26 * doesn't mean registry stores et al aren't implemented. See the PSDK for
27 * registering and enumerating physical stores and locations.)
28 * - Many flags, options and whatnot are unimplemented.
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 #include "wine/exception.h"
42 #include "crypt32_private.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
46 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
47 /* The following aren't defined in wincrypt.h, as they're "reserved" */
48 #define CERT_CERT_PROP_ID 32
49 #define CERT_CRL_PROP_ID 33
50 #define CERT_CTL_PROP_ID 34
52 /* Some typedefs that make it easier to abstract which type of context we're
55 typedef const void *(WINAPI
*CreateContextFunc
)(DWORD dwCertEncodingType
,
56 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
);
57 typedef BOOL (WINAPI
*AddContextToStoreFunc
)(HCERTSTORE hCertStore
,
58 const void *context
, DWORD dwAddDisposition
, const void **ppStoreContext
);
59 typedef BOOL (WINAPI
*AddEncodedContextToStoreFunc
)(HCERTSTORE hCertStore
,
60 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
61 DWORD dwAddDisposition
, const void **ppContext
);
62 typedef const void *(WINAPI
*EnumContextsInStoreFunc
)(HCERTSTORE hCertStore
,
63 const void *pPrevContext
);
64 typedef BOOL (WINAPI
*GetContextPropertyFunc
)(const void *context
,
65 DWORD dwPropID
, void *pvData
, DWORD
*pcbData
);
66 typedef BOOL (WINAPI
*SetContextPropertyFunc
)(const void *context
,
67 DWORD dwPropID
, DWORD dwFlags
, const void *pvData
);
68 typedef BOOL (WINAPI
*SerializeElementFunc
)(const void *context
, DWORD dwFlags
,
69 BYTE
*pbElement
, DWORD
*pcbElement
);
70 typedef BOOL (WINAPI
*FreeContextFunc
)(const void *context
);
71 typedef BOOL (WINAPI
*DeleteContextFunc
)(const void *context
);
73 /* An abstract context (certificate, CRL, or CTL) interface */
74 typedef struct _WINE_CONTEXT_INTERFACE
76 CreateContextFunc create
;
77 AddContextToStoreFunc addContextToStore
;
78 AddEncodedContextToStoreFunc addEncodedToStore
;
79 EnumContextsInStoreFunc enumContextsInStore
;
80 GetContextPropertyFunc getProp
;
81 SetContextPropertyFunc setProp
;
82 SerializeElementFunc serialize
;
84 DeleteContextFunc deleteFromStore
;
85 } WINE_CONTEXT_INTERFACE
, *PWINE_CONTEXT_INTERFACE
;
87 static const WINE_CONTEXT_INTERFACE gCertInterface
= {
88 (CreateContextFunc
)CertCreateCertificateContext
,
89 (AddContextToStoreFunc
)CertAddCertificateContextToStore
,
90 (AddEncodedContextToStoreFunc
)CertAddEncodedCertificateToStore
,
91 (EnumContextsInStoreFunc
)CertEnumCertificatesInStore
,
92 (GetContextPropertyFunc
)CertGetCertificateContextProperty
,
93 (SetContextPropertyFunc
)CertSetCertificateContextProperty
,
94 (SerializeElementFunc
)CertSerializeCertificateStoreElement
,
95 (FreeContextFunc
)CertFreeCertificateContext
,
96 (DeleteContextFunc
)CertDeleteCertificateFromStore
,
99 static const WINE_CONTEXT_INTERFACE gCRLInterface
= {
100 (CreateContextFunc
)CertCreateCRLContext
,
101 (AddContextToStoreFunc
)CertAddCRLContextToStore
,
102 (AddEncodedContextToStoreFunc
)CertAddEncodedCRLToStore
,
103 (EnumContextsInStoreFunc
)CertEnumCRLsInStore
,
104 (GetContextPropertyFunc
)CertGetCRLContextProperty
,
105 (SetContextPropertyFunc
)CertSetCRLContextProperty
,
106 (SerializeElementFunc
)CertSerializeCRLStoreElement
,
107 (FreeContextFunc
)CertFreeCRLContext
,
108 (DeleteContextFunc
)CertDeleteCRLFromStore
,
111 static const WINE_CONTEXT_INTERFACE gCTLInterface
= {
112 (CreateContextFunc
)CertCreateCTLContext
,
113 (AddContextToStoreFunc
)CertAddCTLContextToStore
,
114 (AddEncodedContextToStoreFunc
)CertAddEncodedCTLToStore
,
115 (EnumContextsInStoreFunc
)CertEnumCTLsInStore
,
116 (GetContextPropertyFunc
)CertGetCTLContextProperty
,
117 (SetContextPropertyFunc
)CertSetCTLContextProperty
,
118 (SerializeElementFunc
)CertSerializeCTLStoreElement
,
119 (FreeContextFunc
)CertFreeCTLContext
,
120 (DeleteContextFunc
)CertDeleteCTLFromStore
,
123 struct WINE_CRYPTCERTSTORE
;
125 typedef struct WINE_CRYPTCERTSTORE
* (*StoreOpenFunc
)(HCRYPTPROV hCryptProv
,
126 DWORD dwFlags
, const void *pvPara
);
128 struct _WINE_CERT_CONTEXT_REF
;
130 /* Called to enumerate the next certificate in a store. The returned pointer
131 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
134 typedef struct _WINE_CERT_CONTEXT_REF
* (*EnumCertFunc
)
135 (struct WINE_CRYPTCERTSTORE
*store
, struct _WINE_CERT_CONTEXT_REF
*pPrev
);
137 struct _WINE_CERT_CONTEXT
;
139 /* Called to create a new reference to an existing cert context. Should call
140 * CRYPT_InitCertRef to make sure the reference count is properly updated.
141 * If the store does not provide any additional allocated data (that is, does
142 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
145 typedef struct _WINE_CERT_CONTEXT_REF
* (*CreateRefFunc
)
146 (struct _WINE_CERT_CONTEXT
*context
, HCERTSTORE store
);
148 /* Optional, called when a cert context reference is being freed. Don't free
149 * the ref pointer itself, CertFreeCertificateContext does that.
151 typedef void (*FreeCertFunc
)(struct _WINE_CERT_CONTEXT_REF
*ref
);
153 typedef enum _CertStoreType
{
160 /* A cert store is polymorphic through the use of function pointers. A type
161 * is still needed to distinguish collection stores from other types.
162 * On the function pointers:
163 * - closeStore is called when the store's ref count becomes 0
164 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
165 * - control is optional, but should be implemented by any store that supports
168 typedef struct WINE_CRYPTCERTSTORE
173 HCRYPTPROV cryptProv
;
175 PFN_CERT_STORE_PROV_CLOSE closeStore
;
176 PFN_CERT_STORE_PROV_WRITE_CERT addCert
;
177 CreateRefFunc createCertRef
;
178 EnumCertFunc enumCert
;
179 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert
;
180 FreeCertFunc freeCert
; /* optional */
181 PFN_CERT_STORE_PROV_CONTROL control
; /* optional */
182 } WINECRYPT_CERTSTORE
, *PWINECRYPT_CERTSTORE
;
184 /* A certificate context has pointers to data that are owned by this module,
185 * so rather than duplicate the data every time a certificate context is
186 * copied, I keep a reference count to the data. Thus I have two data
187 * structures, the "true" certificate context (that has the reference count)
188 * and a reference certificate context, that has a pointer to the true context.
189 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
190 * with the reference version.
192 typedef struct _WINE_CERT_CONTEXT
197 struct list extendedProperties
;
198 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
200 typedef struct _WINE_CERT_CONTEXT_REF
203 WINE_CERT_CONTEXT
*context
;
204 } WINE_CERT_CONTEXT_REF
, *PWINE_CERT_CONTEXT_REF
;
206 /* An extended certificate property in serialized form is prefixed by this
209 typedef struct _WINE_CERT_PROP_HEADER
212 DWORD unknown
; /* always 1 */
214 } WINE_CERT_PROP_HEADER
, *PWINE_CERT_PROP_HEADER
;
216 /* Stores an extended property in a cert. */
217 typedef struct _WINE_CERT_PROPERTY
219 WINE_CERT_PROP_HEADER hdr
;
222 } WINE_CERT_PROPERTY
, *PWINE_CERT_PROPERTY
;
224 /* A mem store has a list of these. They're also returned by the mem store
225 * during enumeration.
227 typedef struct _WINE_CERT_LIST_ENTRY
229 WINE_CERT_CONTEXT_REF cert
;
231 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
233 typedef struct _WINE_MEMSTORE
235 WINECRYPT_CERTSTORE hdr
;
238 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
240 typedef struct _WINE_HASH_TO_DELETE
244 } WINE_HASH_TO_DELETE
, *PWINE_HASH_TO_DELETE
;
246 /* Returned by a reg store during enumeration. */
247 typedef struct _WINE_REG_CERT_CONTEXT
249 WINE_CERT_CONTEXT_REF cert
;
250 PWINE_CERT_CONTEXT_REF childContext
;
251 } WINE_REG_CERT_CONTEXT
, *PWINE_REG_CERT_CONTEXT
;
253 typedef struct _WINE_REGSTORE
255 WINECRYPT_CERTSTORE hdr
;
256 PWINECRYPT_CERTSTORE memStore
;
260 struct list certsToDelete
;
261 } WINE_REGSTORE
, *PWINE_REGSTORE
;
263 typedef struct _WINE_STORE_LIST_ENTRY
265 PWINECRYPT_CERTSTORE store
;
269 } WINE_STORE_LIST_ENTRY
, *PWINE_STORE_LIST_ENTRY
;
271 /* Returned by a collection store during enumeration.
272 * Note: relies on the list entry being valid after use, which a number of
273 * conditions might make untrue (reentrancy, closing a collection store before
274 * continuing an enumeration on it, ...). The tests seem to indicate this
275 * sort of unsafety is okay, since Windows isn't well-behaved in these
278 typedef struct _WINE_COLLECTION_CERT_CONTEXT
280 WINE_CERT_CONTEXT_REF cert
;
281 PWINE_STORE_LIST_ENTRY entry
;
282 PWINE_CERT_CONTEXT_REF childContext
;
283 } WINE_COLLECTION_CERT_CONTEXT
, *PWINE_COLLECTION_CERT_CONTEXT
;
285 typedef struct _WINE_COLLECTIONSTORE
287 WINECRYPT_CERTSTORE hdr
;
290 } WINE_COLLECTIONSTORE
, *PWINE_COLLECTIONSTORE
;
292 /* Like CertGetCertificateContextProperty, but operates directly on the
293 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
294 * are handled by CertGetCertificateContextProperty, and are particular to the
295 * store in which the property exists (which is separate from the context.)
297 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
298 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
);
300 /* Like CertSetCertificateContextProperty, but operates directly on the
301 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
302 * CertSetCertificateContextProperty anyway.
304 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
305 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
);
307 /* Helper function for store reading functions and
308 * CertAddSerializedElementToStore. Returns a context of the appropriate type
309 * if it can, or NULL otherwise. Doesn't validate any of the properties in
310 * the serialized context (for example, bad hashes are retained.)
311 * *pdwContentType is set to the type of the returned context.
313 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
314 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
);
316 /* filter for page-fault exceptions */
317 static WINE_EXCEPTION_FILTER(page_fault
)
319 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
320 return EXCEPTION_EXECUTE_HANDLER
;
321 return EXCEPTION_CONTINUE_SEARCH
;
324 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
325 DWORD dwFlags
, CertStoreType type
)
328 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
332 hCryptProv
= CRYPT_GetDefaultProvider();
333 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
335 store
->cryptProv
= hCryptProv
;
336 store
->dwOpenFlags
= dwFlags
;
339 /* Initializes the reference ref to point to pCertContext, which is assumed to
340 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
341 * Also sets the hCertStore member of the reference to store.
343 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref
,
344 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
346 TRACE("(%p, %p)\n", ref
, context
);
347 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
348 ref
->context
= context
;
349 InterlockedIncrement(&context
->ref
);
350 TRACE("%p's ref count is %ld\n", context
, context
->ref
);
351 ref
->cert
.hCertStore
= store
;
354 static PWINE_CERT_CONTEXT_REF
CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context
,
357 PWINE_CERT_CONTEXT_REF pCertRef
= CryptMemAlloc(
358 sizeof(WINE_CERT_CONTEXT_REF
));
360 TRACE("(%p, %p)\n", context
, store
);
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
);
466 TRACE("returning %d\n", ret
);
470 static PWINE_CERT_CONTEXT_REF
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
471 PWINE_CERT_CONTEXT_REF pPrev
)
473 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
474 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
, ret
;
475 struct list
*listNext
;
477 TRACE("(%p, %p)\n", store
, pPrev
);
478 EnterCriticalSection(&ms
->cs
);
481 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
482 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
485 listNext
= list_next(&ms
->certs
, &ms
->certs
);
488 ret
= CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY
));
491 memcpy(ret
, LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
),
492 sizeof(WINE_CERT_LIST_ENTRY
));
493 InterlockedIncrement(&ret
->cert
.context
->ref
);
498 SetLastError(CRYPT_E_NOT_FOUND
);
501 LeaveCriticalSection(&ms
->cs
);
503 TRACE("returning %p\n", ret
);
504 return (PWINE_CERT_CONTEXT_REF
)ret
;
507 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref
);
509 static BOOL WINAPI
CRYPT_MemDeleteCert(HCERTSTORE hCertStore
,
510 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
512 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
513 WINE_CERT_CONTEXT_REF
*ref
= (WINE_CERT_CONTEXT_REF
*)pCertContext
;
514 PWINE_CERT_LIST_ENTRY cert
, next
;
517 /* Find the entry associated with the passed-in context, since the
518 * passed-in context may not be a list entry itself (e.g. if it came from
519 * CertDuplicateCertificateContext.) Pointing to the same context is
520 * a sufficient test of equality.
522 EnterCriticalSection(&store
->cs
);
523 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
526 if (cert
->cert
.context
== ref
->context
)
528 TRACE("removing %p\n", cert
);
529 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
532 list_remove(&cert
->entry
);
533 /* FIXME: generally I should do the following, otherwise there is
534 * a memory leak. But doing so when called by
535 * CertDeleteCertificateFromStore results in a double free, so
536 * leaving commented for now.
537 ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
539 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
543 LeaveCriticalSection(&store
->cs
);
547 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
549 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
550 PWINE_CERT_LIST_ENTRY cert
, next
;
552 TRACE("(%p, %08lx)\n", store
, dwFlags
);
554 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
556 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
557 * pointer if its ref-count reaches zero. That's okay here because there
558 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
559 * of the CertListEntry.
561 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
564 TRACE("removing %p\n", cert
);
565 list_remove(&cert
->entry
);
566 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
568 DeleteCriticalSection(&store
->cs
);
572 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
573 DWORD dwFlags
, const void *pvPara
)
575 PWINE_MEMSTORE store
;
577 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
579 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
581 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
586 store
= CryptMemAlloc(sizeof(WINE_MEMSTORE
));
589 memset(store
, 0, sizeof(WINE_MEMSTORE
));
590 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
591 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
592 store
->hdr
.addCert
= CRYPT_MemAddCert
;
593 store
->hdr
.createCertRef
= CRYPT_CreateCertRef
;
594 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
595 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
596 store
->hdr
.freeCert
= NULL
;
597 InitializeCriticalSection(&store
->cs
);
598 list_init(&store
->certs
);
601 return (PWINECRYPT_CERTSTORE
)store
;
604 static BOOL WINAPI
CRYPT_CollectionAddCert(HCERTSTORE store
,
605 PCCERT_CONTEXT pCert
, DWORD dwAddDisposition
)
607 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
608 PWINE_STORE_LIST_ENTRY entry
, next
;
611 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
614 EnterCriticalSection(&cs
->cs
);
615 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
618 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
620 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
624 LeaveCriticalSection(&cs
->cs
);
625 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
629 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionCreateCertRef(
630 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
632 PWINE_COLLECTION_CERT_CONTEXT ret
= CryptMemAlloc(
633 sizeof(WINE_COLLECTION_CERT_CONTEXT
));
637 /* Initialize to empty for now, just make sure the size is right */
638 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
640 ret
->childContext
= NULL
;
642 return (PWINE_CERT_CONTEXT_REF
)ret
;
645 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
647 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
648 PWINE_STORE_LIST_ENTRY entry
, next
;
650 TRACE("(%p, %08lx)\n", store
, dwFlags
);
652 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
655 TRACE("closing %p\n", entry
);
656 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
659 DeleteCriticalSection(&cs
->cs
);
663 /* Advances a collection enumeration by one cert, if possible, where advancing
665 * - calling the current store's enumeration function once, and returning
666 * the enumerated cert if one is returned
667 * - moving to the next store if the current store has no more items, and
668 * recursively calling itself to get the next item.
669 * Returns NULL if the collection contains no more items or on error.
670 * Assumes the collection store's lock is held.
672 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
673 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
674 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
676 PWINE_COLLECTION_CERT_CONTEXT ret
;
677 PWINE_CERT_CONTEXT_REF child
;
678 struct list
*storeNext
= list_next(&store
->stores
, &storeEntry
->entry
);
680 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
682 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
683 pPrev
? pPrev
->childContext
: NULL
);
686 pPrev
->childContext
= NULL
;
687 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
692 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
693 child
->context
, store
);
696 ret
->entry
= storeEntry
;
697 ret
->childContext
= child
;
700 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
706 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
707 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
711 SetLastError(CRYPT_E_NOT_FOUND
);
715 TRACE("returning %p\n", ret
);
719 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionEnumCert(
720 PWINECRYPT_CERTSTORE store
, PWINE_CERT_CONTEXT_REF pPrev
)
722 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
723 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
724 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
726 TRACE("(%p, %p)\n", store
, pPrev
);
730 EnterCriticalSection(&cs
->cs
);
731 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
732 LeaveCriticalSection(&cs
->cs
);
736 EnterCriticalSection(&cs
->cs
);
737 if (!list_empty(&cs
->stores
))
739 PWINE_STORE_LIST_ENTRY storeEntry
;
741 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
743 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
747 SetLastError(CRYPT_E_NOT_FOUND
);
750 LeaveCriticalSection(&cs
->cs
);
752 TRACE("returning %p\n", ret
);
753 return (PWINE_CERT_CONTEXT_REF
)ret
;
756 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
757 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
759 PWINE_COLLECTION_CERT_CONTEXT context
=
760 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
763 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
765 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
767 context
->childContext
= NULL
;
771 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref
)
773 PWINE_COLLECTION_CERT_CONTEXT context
= (PWINE_COLLECTION_CERT_CONTEXT
)ref
;
775 TRACE("(%p)\n", ref
);
777 if (context
->childContext
)
778 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
781 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
782 DWORD dwFlags
, const void *pvPara
)
784 PWINE_COLLECTIONSTORE store
;
786 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
793 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
796 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
797 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
798 StoreTypeCollection
);
799 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
800 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
801 store
->hdr
.createCertRef
= CRYPT_CollectionCreateCertRef
;
802 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
803 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
804 store
->hdr
.freeCert
= CRYPT_CollectionFreeCert
;
805 InitializeCriticalSection(&store
->cs
);
806 list_init(&store
->stores
);
809 return (PWINECRYPT_CERTSTORE
)store
;
812 static void CRYPT_HashToStr(LPBYTE hash
, LPWSTR asciiHash
)
814 static const WCHAR fmt
[] = { '%','0','2','X',0 };
820 for (i
= 0; i
< 20; i
++)
821 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
824 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
826 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
827 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
828 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
830 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store
, HKEY key
,
835 WCHAR subKeyName
[MAX_PATH
];
838 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
840 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
846 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
852 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
854 buf
= CryptMemAlloc(size
);
857 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
864 TRACE("Adding cert with hash %s\n",
865 debugstr_w(subKeyName
));
866 context
= CRYPT_ReadSerializedElement(buf
, size
,
867 contextType
, &addedType
);
870 const WINE_CONTEXT_INTERFACE
*contextInterface
;
875 case CERT_STORE_CERTIFICATE_CONTEXT
:
876 contextInterface
= &gCertInterface
;
878 case CERT_STORE_CRL_CONTEXT
:
879 contextInterface
= &gCRLInterface
;
881 case CERT_STORE_CTL_CONTEXT
:
882 contextInterface
= &gCTLInterface
;
885 contextInterface
= NULL
;
887 if (contextInterface
)
890 if (contextInterface
->getProp(context
,
891 CERT_HASH_PROP_ID
, hash
, &size
))
893 WCHAR asciiHash
[20 * 2 + 1];
895 CRYPT_HashToStr(hash
, asciiHash
);
896 TRACE("comparing %s\n",
897 debugstr_w(asciiHash
));
898 TRACE("with %s\n", debugstr_w(subKeyName
));
899 if (!lstrcmpW(asciiHash
, subKeyName
))
901 TRACE("hash matches, adding\n");
902 contextInterface
->addContextToStore(
904 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
907 TRACE("hash doesn't match, ignoring\n");
909 contextInterface
->free(context
);
917 /* Ignore intermediate errors, continue enumerating */
923 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store
)
925 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
926 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
927 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
930 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
935 rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
939 CRYPT_RegReadSerializedFromReg(store
, key
, contextFlags
[i
]);
945 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
946 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, LPBYTE hash
, LPBYTE buf
,
949 WCHAR asciiHash
[20 * 2 + 1];
954 CRYPT_HashToStr(hash
, asciiHash
);
955 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
959 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
972 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
973 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
975 const void *context
= NULL
;
979 context
= contextInterface
->enumContextsInStore(memStore
, context
);
983 DWORD hashSize
= sizeof(hash
);
985 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
992 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
994 buf
= CryptMemAlloc(size
);
997 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
999 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
1006 } while (ret
&& context
!= NULL
);
1008 contextInterface
->free(context
);
1012 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTORE store
)
1014 static const WCHAR
*subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
1015 static const WINE_CONTEXT_INTERFACE
*interfaces
[] = { &gCertInterface
,
1016 &gCRLInterface
, &gCTLInterface
};
1017 struct list
*listToDelete
[] = { &store
->certsToDelete
, NULL
, NULL
};
1021 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
1024 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
1025 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1029 if (listToDelete
[i
])
1031 PWINE_HASH_TO_DELETE toDelete
, next
;
1032 WCHAR asciiHash
[20 * 2 + 1];
1034 EnterCriticalSection(&store
->cs
);
1035 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
1036 WINE_HASH_TO_DELETE
, entry
)
1040 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
1041 TRACE("Removing %s\n", debugstr_w(asciiHash
));
1042 rc
= RegDeleteKeyW(key
, asciiHash
);
1043 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
1048 list_remove(&toDelete
->entry
);
1049 CryptMemFree(toDelete
);
1051 LeaveCriticalSection(&store
->cs
);
1053 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
1066 /* If force is true or the registry store is dirty, writes the contents of the
1067 * store to the registry.
1069 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTORE store
, BOOL force
)
1073 if (store
->dirty
|| force
)
1074 ret
= CRYPT_RegWriteToReg(store
);
1080 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1082 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1084 TRACE("(%p, %08lx)\n", store
, dwFlags
);
1086 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
1088 CRYPT_RegFlushStore(store
, FALSE
);
1089 /* certsToDelete should already be cleared by this point */
1090 store
->memStore
->closeStore(store
->memStore
, 0);
1091 RegCloseKey(store
->key
);
1092 DeleteCriticalSection(&store
->cs
);
1093 CryptMemFree(store
);
1096 static BOOL WINAPI
CRYPT_RegAddCert(HCERTSTORE hCertStore
, PCCERT_CONTEXT cert
,
1097 DWORD dwAddDisposition
)
1099 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1102 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwAddDisposition
);
1104 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1106 SetLastError(ERROR_ACCESS_DENIED
);
1111 ret
= store
->memStore
->addCert(store
->memStore
, cert
, dwAddDisposition
);
1113 store
->dirty
= TRUE
;
1118 static PWINE_CERT_CONTEXT_REF
CRYPT_RegCreateCertRef(
1119 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
1121 PWINE_REG_CERT_CONTEXT ret
= CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT
));
1125 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
1126 ret
->childContext
= NULL
;
1128 return (PWINE_CERT_CONTEXT_REF
)ret
;
1131 static PWINE_CERT_CONTEXT_REF
CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store
,
1132 PWINE_CERT_CONTEXT_REF pPrev
)
1134 PWINE_REGSTORE rs
= (PWINE_REGSTORE
)store
;
1135 PWINE_CERT_CONTEXT_REF child
;
1136 PWINE_REG_CERT_CONTEXT prev
= (PWINE_REG_CERT_CONTEXT
)pPrev
, ret
= NULL
;
1138 TRACE("(%p, %p)\n", store
, pPrev
);
1140 child
= rs
->memStore
->enumCert(rs
->memStore
, prev
? prev
->childContext
1144 prev
->childContext
= NULL
;
1145 CertFreeCertificateContext((PCCERT_CONTEXT
)prev
);
1150 ret
= (PWINE_REG_CERT_CONTEXT
)CRYPT_RegCreateCertRef(child
->context
,
1153 ret
->childContext
= child
;
1155 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
1157 return (PWINE_CERT_CONTEXT_REF
)ret
;
1160 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
1161 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
1163 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1166 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
1168 if (store
->hdr
.dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
1170 SetLastError(ERROR_ACCESS_DENIED
);
1175 PWINE_HASH_TO_DELETE toDelete
=
1176 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
1180 DWORD size
= sizeof(toDelete
->hash
);
1182 ret
= CertGetCertificateContextProperty(pCertContext
,
1183 CERT_HASH_PROP_ID
, toDelete
->hash
, &size
);
1186 list_init(&toDelete
->entry
);
1187 EnterCriticalSection(&store
->cs
);
1188 list_add_tail(&store
->certsToDelete
, &toDelete
->entry
);
1189 LeaveCriticalSection(&store
->cs
);
1190 ret
= store
->memStore
->deleteCert(store
->memStore
, pCertContext
,
1194 CryptMemFree(toDelete
);
1199 store
->dirty
= TRUE
;
1204 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref
)
1206 PWINE_REG_CERT_CONTEXT context
= (PWINE_REG_CERT_CONTEXT
)ref
;
1208 TRACE("(%p)\n", ref
);
1210 if (context
->childContext
)
1211 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
1214 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
1215 DWORD dwCtrlType
, void const *pvCtrlPara
)
1217 PWINE_REGSTORE store
= (PWINE_REGSTORE
)hCertStore
;
1222 case CERT_STORE_CTRL_RESYNC
:
1223 CRYPT_RegFlushStore(store
, FALSE
);
1224 store
->memStore
->closeStore(store
->memStore
, 0);
1225 store
->memStore
= CRYPT_MemOpenStore(store
->hdr
.cryptProv
,
1226 store
->hdr
.dwOpenFlags
, NULL
);
1227 if (store
->memStore
)
1229 CRYPT_RegReadFromReg(store
);
1235 case CERT_STORE_CTRL_COMMIT
:
1236 ret
= CRYPT_RegFlushStore(store
,
1237 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
1240 FIXME("%ld: stub\n", dwCtrlType
);
1246 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1247 static DWORD
CRYPT_RecurseDeleteKey(HKEY hKey
, LPCWSTR lpszSubKey
)
1249 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
1250 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
1253 TRACE("(hkey=%p,%s)\n", hKey
, debugstr_w(lpszSubKey
));
1255 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
1258 /* Find how many subkeys there are */
1259 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
1260 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1264 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
1266 /* Name too big: alloc a buffer for it */
1267 lpszName
= CryptMemAlloc(dwMaxSubkeyLen
*sizeof(WCHAR
));
1271 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
1274 /* Recursively delete all the subkeys */
1275 for (i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
1277 dwSize
= dwMaxSubkeyLen
;
1278 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
,
1281 dwRet
= CRYPT_RecurseDeleteKey(hSubKey
, lpszName
);
1284 if (lpszName
!= szNameBuf
)
1286 /* Free buffer if allocated */
1287 CryptMemFree(lpszName
);
1292 RegCloseKey(hSubKey
);
1294 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
1299 static WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
,
1300 DWORD dwFlags
, const void *pvPara
)
1302 PWINE_REGSTORE store
= NULL
;
1304 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
1306 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
1308 DWORD rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CertsW
);
1310 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1311 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CRLsW
);
1312 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
1313 rc
= CRYPT_RecurseDeleteKey((HKEY
)pvPara
, CTLsW
);
1314 if (rc
== ERROR_NO_MORE_ITEMS
)
1322 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
1323 GetCurrentProcess(), (LPHANDLE
)&key
,
1324 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
1327 PWINECRYPT_CERTSTORE memStore
;
1329 memStore
= CRYPT_MemOpenStore(hCryptProv
, dwFlags
, NULL
);
1332 store
= CryptMemAlloc(sizeof(WINE_REGSTORE
));
1335 memset(store
, 0, sizeof(WINE_REGSTORE
));
1336 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
1338 store
->hdr
.closeStore
= CRYPT_RegCloseStore
;
1339 store
->hdr
.addCert
= CRYPT_RegAddCert
;
1340 store
->hdr
.createCertRef
= CRYPT_RegCreateCertRef
;
1341 store
->hdr
.enumCert
= CRYPT_RegEnumCert
;
1342 store
->hdr
.deleteCert
= CRYPT_RegDeleteCert
;
1343 store
->hdr
.freeCert
= CRYPT_RegFreeCert
;
1344 store
->hdr
.control
= CRYPT_RegControl
;
1345 store
->memStore
= memStore
;
1347 InitializeCriticalSection(&store
->cs
);
1348 list_init(&store
->certsToDelete
);
1349 CRYPT_RegReadFromReg(store
);
1350 store
->dirty
= FALSE
;
1355 TRACE("returning %p\n", store
);
1356 return (WINECRYPT_CERTSTORE
*)store
;
1359 /* FIXME: this isn't complete for the Root store, in which the top-level
1360 * self-signed CA certs reside. Adding a cert to the Root store should present
1361 * the user with a dialog indicating the consequences of doing so, and asking
1362 * the user to confirm whether the cert should be added.
1364 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv
,
1365 DWORD dwFlags
, const void *pvPara
)
1367 static const WCHAR fmt
[] = { '%','s','\\','%','s',0 };
1368 LPCWSTR storeName
= (LPCWSTR
)pvPara
;
1370 PWINECRYPT_CERTSTORE store
= NULL
;
1375 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1376 debugstr_w((LPCWSTR
)pvPara
));
1380 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1385 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1387 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1388 root
= HKEY_LOCAL_MACHINE
;
1389 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1391 case CERT_SYSTEM_STORE_CURRENT_USER
:
1392 root
= HKEY_CURRENT_USER
;
1393 base
= CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH
;
1395 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1396 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1397 * SystemCertificates
1399 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1400 debugstr_w(storeName
));
1402 case CERT_SYSTEM_STORE_SERVICES
:
1403 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1404 * SystemCertificates
1406 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1407 debugstr_w(storeName
));
1409 case CERT_SYSTEM_STORE_USERS
:
1410 /* hku\user sid\Software\Microsoft\SystemCertificates */
1411 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1412 debugstr_w(storeName
));
1414 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1415 root
= HKEY_CURRENT_USER
;
1416 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1418 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1419 root
= HKEY_LOCAL_MACHINE
;
1420 base
= CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH
;
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1423 /* hklm\Software\Microsoft\EnterpriseCertificates */
1424 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1425 debugstr_w(storeName
));
1428 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1432 storePath
= CryptMemAlloc((lstrlenW(base
) + lstrlenW(storeName
) + 2) *
1438 REGSAM sam
= dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
:
1441 wsprintfW(storePath
, fmt
, base
, storeName
);
1442 if (dwFlags
& CERT_STORE_OPEN_EXISTING_FLAG
)
1443 rc
= RegOpenKeyExW(root
, storePath
, 0, sam
, &key
);
1448 rc
= RegCreateKeyExW(root
, storePath
, 0, NULL
, 0, sam
, NULL
,
1450 if (!rc
&& dwFlags
& CERT_STORE_CREATE_NEW_FLAG
&&
1451 disp
== REG_OPENED_EXISTING_KEY
)
1454 rc
= ERROR_FILE_EXISTS
;
1459 store
= CRYPT_RegOpenStore(hCryptProv
, dwFlags
, key
);
1464 CryptMemFree(storePath
);
1469 static PWINECRYPT_CERTSTORE
CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv
,
1470 DWORD dwFlags
, const void *pvPara
)
1473 PWINECRYPT_CERTSTORE ret
= NULL
;
1475 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1476 debugstr_a((LPCSTR
)pvPara
));
1480 SetLastError(ERROR_FILE_NOT_FOUND
);
1483 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1486 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1490 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1491 ret
= CRYPT_SysRegOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1492 CryptMemFree(storeName
);
1498 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv
,
1499 DWORD dwFlags
, const void *pvPara
)
1501 HCERTSTORE store
= 0;
1504 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1505 debugstr_w((LPCWSTR
)pvPara
));
1509 SetLastError(ERROR_FILE_NOT_FOUND
);
1512 /* This returns a different error than system registry stores if the
1513 * location is invalid.
1515 switch (dwFlags
& CERT_SYSTEM_STORE_LOCATION_MASK
)
1517 case CERT_SYSTEM_STORE_LOCAL_MACHINE
:
1518 case CERT_SYSTEM_STORE_CURRENT_USER
:
1519 case CERT_SYSTEM_STORE_CURRENT_SERVICE
:
1520 case CERT_SYSTEM_STORE_SERVICES
:
1521 case CERT_SYSTEM_STORE_USERS
:
1522 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
:
1523 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
:
1524 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
:
1528 SetLastError(ERROR_FILE_NOT_FOUND
);
1533 HCERTSTORE regStore
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1534 0, hCryptProv
, dwFlags
, pvPara
);
1538 store
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
1539 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1542 CertAddStoreToCollection(store
, regStore
,
1543 dwFlags
& CERT_STORE_READONLY_FLAG
? 0 :
1544 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1545 CertCloseStore(regStore
, 0);
1549 return (PWINECRYPT_CERTSTORE
)store
;
1552 static PWINECRYPT_CERTSTORE
CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv
,
1553 DWORD dwFlags
, const void *pvPara
)
1556 PWINECRYPT_CERTSTORE ret
= NULL
;
1558 TRACE("(%ld, %08lx, %s)\n", hCryptProv
, dwFlags
,
1559 debugstr_a((LPCSTR
)pvPara
));
1563 SetLastError(ERROR_FILE_NOT_FOUND
);
1566 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, NULL
, 0);
1569 LPWSTR storeName
= CryptMemAlloc(len
* sizeof(WCHAR
));
1573 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pvPara
, -1, storeName
, len
);
1574 ret
= CRYPT_SysOpenStoreW(hCryptProv
, dwFlags
, storeName
);
1575 CryptMemFree(storeName
);
1581 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
1582 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
1585 WINECRYPT_CERTSTORE
*hcs
;
1586 StoreOpenFunc openFunc
= NULL
;
1588 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
1589 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
1591 if (!HIWORD(lpszStoreProvider
))
1593 switch (LOWORD(lpszStoreProvider
))
1595 case (int)CERT_STORE_PROV_MEMORY
:
1596 openFunc
= CRYPT_MemOpenStore
;
1598 case (int)CERT_STORE_PROV_REG
:
1599 openFunc
= CRYPT_RegOpenStore
;
1601 case (int)CERT_STORE_PROV_COLLECTION
:
1602 openFunc
= CRYPT_CollectionOpenStore
;
1604 case (int)CERT_STORE_PROV_SYSTEM_A
:
1605 openFunc
= CRYPT_SysOpenStoreA
;
1607 case (int)CERT_STORE_PROV_SYSTEM_W
:
1608 openFunc
= CRYPT_SysOpenStoreW
;
1610 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A
:
1611 openFunc
= CRYPT_SysRegOpenStoreA
;
1613 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W
:
1614 openFunc
= CRYPT_SysRegOpenStoreW
;
1617 if (LOWORD(lpszStoreProvider
))
1618 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
1621 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
1622 openFunc
= CRYPT_MemOpenStore
;
1623 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
1624 openFunc
= CRYPT_SysOpenStoreW
;
1625 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
1626 openFunc
= CRYPT_CollectionOpenStore
;
1627 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM_REGISTRY
))
1628 openFunc
= CRYPT_SysRegOpenStoreW
;
1631 FIXME("unimplemented type %s\n", lpszStoreProvider
);
1637 /* FIXME: need to look for an installed provider for this type */
1638 SetLastError(ERROR_FILE_NOT_FOUND
);
1642 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
1643 return (HCERTSTORE
)hcs
;
1646 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
1647 LPCSTR szSubSystemProtocol
)
1651 if (szSubSystemProtocol
)
1653 int len
= MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, NULL
,
1655 LPWSTR param
= CryptMemAlloc(len
* sizeof(WCHAR
));
1659 MultiByteToWideChar(CP_ACP
, 0, szSubSystemProtocol
, -1, param
, len
);
1660 ret
= CertOpenSystemStoreW(hProv
, param
);
1661 CryptMemFree(param
);
1665 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1669 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
1670 LPCWSTR szSubSystemProtocol
)
1674 if (!szSubSystemProtocol
)
1676 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1680 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1681 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1684 ret
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, hProv
,
1685 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
1688 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1689 0, hProv
, CERT_SYSTEM_STORE_LOCAL_MACHINE
, szSubSystemProtocol
);
1693 CertAddStoreToCollection(ret
, store
,
1694 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1695 CertCloseStore(store
, 0);
1697 store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W
,
1698 0, hProv
, CERT_SYSTEM_STORE_CURRENT_USER
, szSubSystemProtocol
);
1701 CertAddStoreToCollection(ret
, store
,
1702 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
, 0);
1703 CertCloseStore(store
, 0);
1709 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
1710 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
1712 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
1713 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
1717 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
1718 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
1723 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
1725 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1726 pcrl
= CryptMemAlloc( sizeof (CRL_CONTEXT
) );
1730 data
= CryptMemAlloc( cbCrlEncoded
);
1733 CryptMemFree( pcrl
);
1737 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
1738 pcrl
->pbCrlEncoded
= data
;
1739 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
1740 pcrl
->pCrlInfo
= NULL
;
1741 pcrl
->hCertStore
= 0;
1746 /* Decodes the encoded certificate and creates the certificate context for it.
1747 * The reference count is initially zero, so you must create a reference to it
1748 * to avoid leaking memory.
1750 static PWINE_CERT_CONTEXT
CRYPT_CreateCertificateContext(
1751 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1753 PWINE_CERT_CONTEXT cert
= NULL
;
1755 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1756 PCERT_INFO certInfo
= NULL
;
1759 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1762 /* First try to decode it as a signed cert. */
1763 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT
, pbCertEncoded
,
1764 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1765 (BYTE
*)&signedCert
, &size
);
1769 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1770 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
1771 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1772 (BYTE
*)&certInfo
, &size
);
1773 LocalFree(signedCert
);
1775 /* Failing that, try it as an unsigned cert */
1779 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1780 pbCertEncoded
, cbCertEncoded
,
1781 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1782 (BYTE
*)&certInfo
, &size
);
1788 cert
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT
));
1791 data
= CryptMemAlloc(cbCertEncoded
);
1798 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
1799 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
1800 cert
->cert
.pbCertEncoded
= data
;
1801 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
1802 cert
->cert
.pCertInfo
= certInfo
;
1803 cert
->cert
.hCertStore
= 0;
1805 InitializeCriticalSection(&cert
->cs
);
1806 list_init(&cert
->extendedProperties
);
1813 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context
)
1815 PWINE_CERT_PROPERTY prop
, next
;
1817 CryptMemFree(context
->cert
.pbCertEncoded
);
1818 LocalFree(context
->cert
.pCertInfo
);
1819 DeleteCriticalSection(&context
->cs
);
1820 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
1821 WINE_CERT_PROPERTY
, entry
)
1823 list_remove(&prop
->entry
);
1824 CryptMemFree(prop
->pbData
);
1827 CryptMemFree(context
);
1830 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
1831 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
1833 PWINE_CERT_CONTEXT cert
;
1834 PWINE_CERT_CONTEXT_REF ret
= NULL
;
1836 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
1839 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
1842 ret
= CRYPT_CreateCertRef(cert
, 0);
1843 return (PCCERT_CONTEXT
)ret
;
1846 /* Since the properties are stored in a list, this is a tad inefficient
1847 * (O(n^2)) since I have to find the previous position every time.
1849 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
1852 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1855 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
1857 EnterCriticalSection(&ref
->context
->cs
);
1860 PWINE_CERT_PROPERTY cursor
= NULL
;
1862 LIST_FOR_EACH_ENTRY(cursor
, &ref
->context
->extendedProperties
,
1863 WINE_CERT_PROPERTY
, entry
)
1865 if (cursor
->hdr
.propID
== dwPropId
)
1870 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
1871 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
1879 else if (!list_empty(&ref
->context
->extendedProperties
))
1880 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
1881 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
1884 LeaveCriticalSection(&ref
->context
->cs
);
1888 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1889 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1891 PWINE_CERT_PROPERTY prop
;
1894 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1896 EnterCriticalSection(&context
->cs
);
1899 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1900 WINE_CERT_PROPERTY
, entry
)
1902 if (prop
->hdr
.propID
== dwPropId
)
1906 *pcbData
= prop
->hdr
.cb
;
1909 else if (*pcbData
< prop
->hdr
.cb
)
1911 SetLastError(ERROR_MORE_DATA
);
1912 *pcbData
= prop
->hdr
.cb
;
1916 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1917 *pcbData
= prop
->hdr
.cb
;
1926 /* Implicit properties */
1929 case CERT_SHA1_HASH_PROP_ID
:
1930 ret
= CryptHashCertificate(0, CALG_SHA1
, 0,
1931 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1935 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1937 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
1941 case CERT_KEY_PROV_INFO_PROP_ID
:
1942 case CERT_MD5_HASH_PROP_ID
:
1943 case CERT_SIGNATURE_HASH_PROP_ID
:
1944 case CERT_KEY_IDENTIFIER_PROP_ID
:
1945 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1946 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1947 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1948 FIXME("implicit property %ld\n", dwPropId
);
1952 LeaveCriticalSection(&context
->cs
);
1953 TRACE("returning %d\n", ret
);
1957 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1958 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1960 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1963 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1965 /* Special cases for invalid/special prop IDs.
1970 case CERT_CERT_PROP_ID
:
1971 case CERT_CRL_PROP_ID
:
1972 case CERT_CTL_PROP_ID
:
1973 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1975 case CERT_ACCESS_STATE_PROP_ID
:
1978 *pcbData
= sizeof(DWORD
);
1981 else if (*pcbData
< sizeof(DWORD
))
1983 SetLastError(ERROR_MORE_DATA
);
1984 *pcbData
= sizeof(DWORD
);
1991 if (pCertContext
->hCertStore
)
1993 PWINECRYPT_CERTSTORE store
=
1994 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
1996 /* Take advantage of knowledge of the stores to answer the
1997 * access state question
1999 if (store
->type
!= StoreTypeReg
||
2000 !(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
2001 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
2003 *(DWORD
*)pvData
= state
;
2008 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
2010 TRACE("returning %d\n", ret
);
2014 /* Copies cbData bytes from pbData to the context's property with ID
2017 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
2018 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
2025 data
= CryptMemAlloc(cbData
);
2027 memcpy(data
, pbData
, cbData
);
2031 if (!cbData
|| data
)
2033 PWINE_CERT_PROPERTY prop
;
2035 EnterCriticalSection(&context
->cs
);
2036 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
2037 WINE_CERT_PROPERTY
, entry
)
2039 if (prop
->hdr
.propID
== dwPropId
)
2042 if (prop
&& prop
->entry
.next
!= &context
->extendedProperties
)
2044 CryptMemFree(prop
->pbData
);
2045 prop
->hdr
.cb
= cbData
;
2046 prop
->pbData
= cbData
? data
: NULL
;
2051 prop
= CryptMemAlloc(sizeof(WINE_CERT_PROPERTY
));
2054 prop
->hdr
.propID
= dwPropId
;
2055 prop
->hdr
.unknown
= 1;
2056 prop
->hdr
.cb
= cbData
;
2057 list_init(&prop
->entry
);
2058 prop
->pbData
= cbData
? data
: NULL
;
2059 list_add_tail(&context
->extendedProperties
, &prop
->entry
);
2065 LeaveCriticalSection(&context
->cs
);
2070 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
2071 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2075 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
2079 PWINE_CERT_PROPERTY prop
, next
;
2081 EnterCriticalSection(&context
->cs
);
2082 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
2083 WINE_CERT_PROPERTY
, entry
)
2085 if (prop
->hdr
.propID
== dwPropId
)
2087 list_remove(&prop
->entry
);
2088 CryptMemFree(prop
->pbData
);
2092 LeaveCriticalSection(&context
->cs
);
2099 case CERT_AUTO_ENROLL_PROP_ID
:
2100 case CERT_CTL_USAGE_PROP_ID
:
2101 case CERT_DESCRIPTION_PROP_ID
:
2102 case CERT_FRIENDLY_NAME_PROP_ID
:
2103 case CERT_HASH_PROP_ID
:
2104 case CERT_KEY_IDENTIFIER_PROP_ID
:
2105 case CERT_MD5_HASH_PROP_ID
:
2106 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2107 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2108 case CERT_PVK_FILE_PROP_ID
:
2109 case CERT_SIGNATURE_HASH_PROP_ID
:
2110 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2111 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2112 case CERT_ENROLLMENT_PROP_ID
:
2113 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2114 case CERT_RENEWAL_PROP_ID
:
2116 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
2118 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2119 blob
->pbData
, blob
->cbData
);
2122 case CERT_DATE_STAMP_PROP_ID
:
2123 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
2124 pvData
, sizeof(FILETIME
));
2127 FIXME("%ld: stub\n", dwPropId
);
2130 TRACE("returning %d\n", ret
);
2134 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
2135 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2137 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2140 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
2142 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2143 * crashes on most of these, I'll be safer.
2148 case CERT_ACCESS_STATE_PROP_ID
:
2149 case CERT_CERT_PROP_ID
:
2150 case CERT_CRL_PROP_ID
:
2151 case CERT_CTL_PROP_ID
:
2152 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2155 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
2157 TRACE("returning %d\n", ret
);
2161 /* Only the reference portion of the context is duplicated. The returned
2162 * context has the cert store set to 0, to prevent the store's certificate free
2163 * function from getting called on partial data.
2164 * FIXME: is this okay? Needs a test.
2166 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
2167 PCCERT_CONTEXT pCertContext
)
2169 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
, ret
;
2171 TRACE("(%p)\n", pCertContext
);
2174 ret
= CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF
));
2177 memcpy(ret
, ref
, sizeof(*ret
));
2178 ret
->cert
.hCertStore
= 0;
2179 InterlockedIncrement(&ret
->context
->ref
);
2184 return (PCCERT_CONTEXT
)ret
;
2187 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
2188 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
2189 PCCERT_CONTEXT
*ppStoreContext
)
2191 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
2192 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2193 PWINE_CERT_CONTEXT cert
;
2196 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
2197 dwAddDisposition
, ppStoreContext
);
2199 /* FIXME: some tests needed to verify return codes */
2202 SetLastError(ERROR_INVALID_PARAMETER
);
2205 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2207 SetLastError(ERROR_INVALID_PARAMETER
);
2211 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
2212 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
2215 PWINE_CERT_PROPERTY prop
;
2218 EnterCriticalSection(&ref
->context
->cs
);
2219 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2220 WINE_CERT_PROPERTY
, entry
)
2222 ret
= CRYPT_SaveCertificateContextProperty(cert
, prop
->hdr
.propID
,
2223 prop
->pbData
, prop
->hdr
.cb
);
2227 LeaveCriticalSection(&ref
->context
->cs
);
2230 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2231 if (ret
&& ppStoreContext
)
2232 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
2236 CRYPT_FreeCert(cert
);
2243 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
2244 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
2245 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
2247 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2250 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
2251 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
2255 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2259 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
2260 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
2264 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
2265 if (ret
&& ppCertContext
)
2266 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
2269 CRYPT_FreeCert(cert
);
2277 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
2278 PCCERT_CONTEXT pPrev
)
2280 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2281 PWINE_CERT_CONTEXT_REF prev
= (PWINE_CERT_CONTEXT_REF
)pPrev
;
2284 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
2287 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2290 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
2294 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
2298 TRACE("(%p)\n", pCertContext
);
2302 else if (!pCertContext
->hCertStore
)
2305 CertFreeCertificateContext(pCertContext
);
2309 PWINECRYPT_CERTSTORE hcs
=
2310 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
2314 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2318 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
2320 CertFreeCertificateContext(pCertContext
);
2326 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
2327 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
2328 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
2330 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2331 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
2336 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
2337 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
2338 PCCRL_CONTEXT
* ppStoreContext
)
2340 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
2341 dwAddDisposition
, ppStoreContext
);
2345 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
2347 FIXME("%p\n", pCrlContext
);
2352 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
2354 FIXME("(%p): stub\n", pCrlContext
);
2358 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
2359 PCCRL_CONTEXT pPrev
)
2361 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2365 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
2366 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
2368 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
2373 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
2374 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
2375 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
2377 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
2378 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
2383 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
2384 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
2385 PCCTL_CONTEXT
* ppStoreContext
)
2387 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
2388 dwAddDisposition
, ppStoreContext
);
2392 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
2394 FIXME("(%p): stub\n", pCtlContext
);
2398 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
2400 FIXME("(%p): stub\n", pCtlContext
);
2404 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
2405 PCCTL_CONTEXT pPrev
)
2407 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
2412 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
2414 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
2416 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
2421 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2424 if (InterlockedDecrement(&hcs
->ref
) == 0)
2426 TRACE("%p's ref count is 0, freeing\n", hcs
);
2428 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
2429 CryptReleaseContext(hcs
->cryptProv
, 0);
2430 hcs
->closeStore(hcs
, dwFlags
);
2433 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
2437 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
2438 DWORD dwCtrlType
, void const *pvCtrlPara
)
2440 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
2443 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
2448 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2453 ret
= hcs
->control(hCertStore
, dwFlags
, dwCtrlType
, pvCtrlPara
);
2460 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2461 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2463 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
2467 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
2468 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2470 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
2475 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
2476 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2478 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext
, dwFlags
, pbElement
,
2483 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2484 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
2486 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
2490 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
2491 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
2493 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
2498 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
2499 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2501 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext
, dwFlags
, pbElement
,
2506 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
2507 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
2511 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
2516 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2517 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) +
2518 pCertContext
->cbCertEncoded
;
2519 PWINE_CERT_PROPERTY prop
;
2521 EnterCriticalSection(&ref
->context
->cs
);
2522 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2523 WINE_CERT_PROPERTY
, entry
)
2524 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + prop
->hdr
.cb
;
2527 *pcbElement
= bytesNeeded
;
2530 else if (*pcbElement
< bytesNeeded
)
2532 *pcbElement
= bytesNeeded
;
2533 SetLastError(ERROR_MORE_DATA
);
2538 PWINE_CERT_PROP_HEADER hdr
;
2540 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
2541 WINE_CERT_PROPERTY
, entry
)
2543 memcpy(pbElement
, &prop
->hdr
, sizeof(WINE_CERT_PROP_HEADER
));
2544 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2547 memcpy(pbElement
, prop
->pbData
, prop
->hdr
.cb
);
2548 pbElement
+= prop
->hdr
.cb
;
2551 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
2552 hdr
->propID
= CERT_CERT_PROP_ID
;
2554 hdr
->cb
= pCertContext
->cbCertEncoded
;
2555 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
2556 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
2559 LeaveCriticalSection(&ref
->context
->cs
);
2566 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2567 * to its header if a valid header is found, NULL if not. Valid means the
2568 * length of thte property won't overrun buf, and the unknown field is 1.
2570 static const WINE_CERT_PROP_HEADER
*CRYPT_findPropID(const BYTE
*buf
,
2571 DWORD size
, DWORD propID
)
2573 const WINE_CERT_PROP_HEADER
*ret
= NULL
;
2576 while (size
&& !ret
&& !done
)
2578 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
2580 SetLastError(CRYPT_E_FILE_ERROR
);
2585 const WINE_CERT_PROP_HEADER
*hdr
=
2586 (const WINE_CERT_PROP_HEADER
*)buf
;
2588 size
-= sizeof(WINE_CERT_PROP_HEADER
);
2589 buf
+= sizeof(WINE_CERT_PROP_HEADER
);
2592 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2595 else if (!hdr
->propID
)
2597 /* assume a zero prop ID means the data are uninitialized, so
2602 else if (hdr
->unknown
!= 1)
2604 SetLastError(ERROR_FILE_NOT_FOUND
);
2607 else if (hdr
->propID
== propID
)
2619 static const void * WINAPI
CRYPT_ReadSerializedElement(const BYTE
*pbElement
,
2620 DWORD cbElement
, DWORD dwContextTypeFlags
, DWORD
*pdwContentType
)
2622 const void *context
;
2624 TRACE("(%p, %ld, %08lx, %p)\n", pbElement
, cbElement
, dwContextTypeFlags
,
2629 SetLastError(ERROR_END_OF_MEDIA
);
2635 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2636 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
2642 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
2644 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2646 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2649 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2651 type
= CERT_STORE_CRL_CONTEXT
;
2654 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
2657 type
= CERT_STORE_CTL_CONTEXT
;
2661 else if (dwContextTypeFlags
& CERT_STORE_CERTIFICATE_CONTEXT_FLAG
)
2663 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
2664 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
2666 else if (dwContextTypeFlags
& CERT_STORE_CRL_CONTEXT_FLAG
)
2668 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
2669 type
= CERT_STORE_CRL_CONTEXT
;
2671 else if (dwContextTypeFlags
& CERT_STORE_CTL_CONTEXT_FLAG
)
2673 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CTL_PROP_ID
);
2674 type
= CERT_STORE_CTL_CONTEXT
;
2679 case CERT_STORE_CERTIFICATE_CONTEXT
:
2680 contextInterface
= &gCertInterface
;
2682 case CERT_STORE_CRL_CONTEXT
:
2683 contextInterface
= &gCRLInterface
;
2685 case CERT_STORE_CTL_CONTEXT
:
2686 contextInterface
= &gCTLInterface
;
2689 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2696 context
= contextInterface
->create(X509_ASN_ENCODING
,
2697 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
2700 BOOL noMoreProps
= FALSE
;
2702 while (!noMoreProps
&& ret
)
2704 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
2708 const WINE_CERT_PROP_HEADER
*hdr
=
2709 (const WINE_CERT_PROP_HEADER
*)pbElement
;
2711 TRACE("prop is %ld\n", hdr
->propID
);
2712 cbElement
-= sizeof(WINE_CERT_PROP_HEADER
);
2713 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
2714 if (cbElement
< hdr
->cb
)
2716 SetLastError(HRESULT_FROM_WIN32(
2717 ERROR_INVALID_PARAMETER
));
2720 else if (!hdr
->propID
)
2722 /* Like in CRYPT_findPropID, stop if the propID is zero
2726 else if (hdr
->unknown
!= 1)
2728 SetLastError(ERROR_FILE_NOT_FOUND
);
2731 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
2732 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!=
2735 /* Have to create a blob for most types, but not
2738 switch (hdr
->propID
)
2740 case CERT_AUTO_ENROLL_PROP_ID
:
2741 case CERT_CTL_USAGE_PROP_ID
:
2742 case CERT_DESCRIPTION_PROP_ID
:
2743 case CERT_FRIENDLY_NAME_PROP_ID
:
2744 case CERT_HASH_PROP_ID
:
2745 case CERT_KEY_IDENTIFIER_PROP_ID
:
2746 case CERT_MD5_HASH_PROP_ID
:
2747 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
2748 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
2749 case CERT_PVK_FILE_PROP_ID
:
2750 case CERT_SIGNATURE_HASH_PROP_ID
:
2751 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2752 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
2753 case CERT_ENROLLMENT_PROP_ID
:
2754 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
2755 case CERT_RENEWAL_PROP_ID
:
2757 CRYPT_DATA_BLOB blob
= { hdr
->cb
,
2758 (LPBYTE
)pbElement
};
2760 ret
= contextInterface
->setProp(context
,
2761 hdr
->propID
, 0, &blob
);
2764 case CERT_DATE_STAMP_PROP_ID
:
2765 ret
= contextInterface
->setProp(context
,
2766 hdr
->propID
, 0, pbElement
);
2769 FIXME("prop ID %ld: stub\n", hdr
->propID
);
2772 pbElement
+= hdr
->cb
;
2773 cbElement
-= hdr
->cb
;
2781 *pdwContentType
= type
;
2785 contextInterface
->free(context
);
2790 __EXCEPT(page_fault
)
2792 SetLastError(STATUS_ACCESS_VIOLATION
);
2799 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
2800 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
2801 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
2803 const void *context
;
2807 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore
,
2808 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
2809 pdwContentType
, ppvContext
);
2811 /* Call the internal function, then delete the hashes. Tests show this
2812 * function uses real hash values, not whatever's stored in the hash
2815 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
2816 dwContextTypeFlags
, &type
);
2819 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
2823 case CERT_STORE_CERTIFICATE_CONTEXT
:
2824 contextInterface
= &gCertInterface
;
2826 case CERT_STORE_CRL_CONTEXT
:
2827 contextInterface
= &gCRLInterface
;
2829 case CERT_STORE_CTL_CONTEXT
:
2830 contextInterface
= &gCTLInterface
;
2833 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2835 if (contextInterface
)
2837 contextInterface
->setProp(context
, CERT_HASH_PROP_ID
, 0, NULL
);
2838 contextInterface
->setProp(context
, CERT_MD5_HASH_PROP_ID
, 0, NULL
);
2839 contextInterface
->setProp(context
, CERT_SIGNATURE_HASH_PROP_ID
, 0,
2842 *pdwContentType
= type
;
2843 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
2844 dwAddDisposition
, ppvContext
);
2845 contextInterface
->free(context
);
2855 static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref
)
2857 if (InterlockedDecrement(&ref
->context
->ref
) == 0)
2859 TRACE("%p's ref count is 0, freeing\n", ref
->context
);
2860 CRYPT_FreeCert(ref
->context
);
2863 TRACE("%p's ref count is %ld\n", ref
->context
, ref
->context
->ref
);
2866 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
2868 TRACE("(%p)\n", pCertContext
);
2872 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
2873 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)ref
->cert
.hCertStore
;
2875 CRYPT_UnrefCertificateContext(ref
);
2876 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
2878 store
->freeCert(ref
);
2879 TRACE("freeing %p\n", ref
);
2885 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
2886 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
,
2887 const void *pvPara
, PCCERT_CONTEXT pPrevCertContext
)
2889 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore
, dwCertEncodingType
,
2890 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
2891 SetLastError(CRYPT_E_NOT_FOUND
);
2895 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
2896 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
2898 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2899 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2900 PWINE_STORE_LIST_ENTRY entry
;
2903 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
2904 dwUpdateFlags
, dwPriority
);
2906 if (!collection
|| !sibling
)
2908 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2910 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2913 if (collection
->hdr
.type
!= StoreTypeCollection
)
2915 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2918 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2920 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2924 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
2927 InterlockedIncrement(&sibling
->ref
);
2928 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
2929 entry
->store
= sibling
;
2930 entry
->dwUpdateFlags
= dwUpdateFlags
;
2931 entry
->dwPriority
= dwPriority
;
2932 list_init(&entry
->entry
);
2933 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
2934 EnterCriticalSection(&collection
->cs
);
2937 PWINE_STORE_LIST_ENTRY cursor
;
2940 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
2941 WINE_STORE_LIST_ENTRY
, entry
)
2943 if (cursor
->dwPriority
< dwPriority
)
2945 list_add_before(&cursor
->entry
, &entry
->entry
);
2951 list_add_tail(&collection
->stores
, &entry
->entry
);
2954 list_add_tail(&collection
->stores
, &entry
->entry
);
2955 LeaveCriticalSection(&collection
->cs
);
2963 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
2964 HCERTSTORE hSiblingStore
)
2966 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
2967 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
2968 PWINE_STORE_LIST_ENTRY store
, next
;
2970 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
2972 if (!collection
|| !sibling
)
2974 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2976 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2979 if (collection
->hdr
.type
!= StoreTypeCollection
)
2981 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
2983 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
2986 EnterCriticalSection(&collection
->cs
);
2987 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
2988 WINE_STORE_LIST_ENTRY
, entry
)
2990 if (store
->store
== sibling
)
2992 list_remove(&store
->entry
);
2993 CertCloseStore(store
->store
, 0);
2994 CryptMemFree(store
);
2998 LeaveCriticalSection(&collection
->cs
);
3001 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
3002 CRYPT_ATTRIBUTE rgAttr
[])
3004 PCRYPT_ATTRIBUTE ret
= NULL
;
3007 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
3013 SetLastError(ERROR_INVALID_PARAMETER
);
3017 for (i
= 0; !ret
&& i
< cAttr
; i
++)
3018 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
3023 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
3024 CERT_EXTENSION rgExtensions
[])
3026 PCERT_EXTENSION ret
= NULL
;
3029 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
3035 SetLastError(ERROR_INVALID_PARAMETER
);
3039 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
3040 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
3041 rgExtensions
[i
].pszObjId
))
3042 ret
= &rgExtensions
[i
];
3046 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
3048 PCERT_RDN_ATTR ret
= NULL
;
3051 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
3055 SetLastError(ERROR_INVALID_PARAMETER
);
3059 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
3060 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
3061 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
3062 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
3063 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
3067 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
3068 PCERT_INFO pCertInfo
)
3077 GetSystemTime(&sysTime
);
3078 SystemTimeToFileTime(&sysTime
, &fileTime
);
3079 pTimeToVerify
= &fileTime
;
3081 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
3083 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
3090 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
3091 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
3092 DWORD
*pcbComputedHash
)
3095 HCRYPTHASH hHash
= 0;
3097 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
3098 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
3101 hCryptProv
= CRYPT_GetDefaultProvider();
3106 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
3109 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
3111 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
3112 pcbComputedHash
, 0);
3113 CryptDestroyHash(hHash
);
3119 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV hCryptProv
, DWORD dwKeySpec
,
3120 DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
3121 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
3122 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
3128 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv
,
3129 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
3130 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
3132 algID
= CertOIDToAlgId(pSignatureAlgorithm
->pszObjId
);
3135 SetLastError(NTE_BAD_ALGID
);
3140 SetLastError(ERROR_INVALID_PARAMETER
);
3144 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hHash
);
3147 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
, cbEncodedToBeSigned
, 0);
3149 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
3151 CryptDestroyHash(hHash
);
3156 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv
,
3157 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
3158 PCERT_PUBLIC_KEY_INFO pPublicKey
)
3160 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
3161 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, (void *)pbEncoded
,
3162 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
3165 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv
,
3166 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
3167 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
3170 CRYPT_DATA_BLOB subjectBlob
;
3172 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv
,
3173 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
3174 dwFlags
, pvReserved
);
3176 switch (dwSubjectType
)
3178 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
3180 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvSubject
;
3182 subjectBlob
.pbData
= blob
->pbData
;
3183 subjectBlob
.cbData
= blob
->cbData
;
3186 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
3188 PCERT_CONTEXT context
= (PCERT_CONTEXT
)pvSubject
;
3190 subjectBlob
.pbData
= context
->pbCertEncoded
;
3191 subjectBlob
.cbData
= context
->cbCertEncoded
;
3194 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
3196 PCRL_CONTEXT context
= (PCRL_CONTEXT
)pvSubject
;
3198 subjectBlob
.pbData
= context
->pbCrlEncoded
;
3199 subjectBlob
.cbData
= context
->cbCrlEncoded
;
3203 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3209 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
3212 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
3213 subjectBlob
.pbData
, subjectBlob
.cbData
,
3214 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
3215 (BYTE
*)&signedCert
, &size
);
3218 switch (dwIssuerType
)
3220 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
3222 PCERT_PUBLIC_KEY_INFO pubKeyInfo
=
3223 (PCERT_PUBLIC_KEY_INFO
)pvIssuer
;
3224 ALG_ID algID
= CertOIDToAlgId(pubKeyInfo
->Algorithm
.pszObjId
);
3230 ret
= CryptImportPublicKeyInfoEx(hCryptProv
,
3231 dwCertEncodingType
, pubKeyInfo
, algID
, 0, NULL
, &key
);
3236 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hash
);
3239 ret
= CryptHashData(hash
,
3240 signedCert
->ToBeSigned
.pbData
,
3241 signedCert
->ToBeSigned
.cbData
, 0);
3244 ret
= CryptVerifySignatureW(hash
,
3245 signedCert
->Signature
.pbData
,
3246 signedCert
->Signature
.cbData
, key
, NULL
, 0);
3248 CryptDestroyHash(hash
);
3250 CryptDestroyKey(key
);
3255 SetLastError(NTE_BAD_ALGID
);
3260 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
3261 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
3262 FIXME("issuer type %ld: stub\n", dwIssuerType
);
3265 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
3268 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3273 FIXME("unimplemented for NULL signer\n");
3274 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3279 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
3282 LocalFree(signedCert
);
3288 BOOL WINAPI
CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara
,
3289 DWORD dwSignerIndex
, const BYTE
* pbSignedBlob
, DWORD cbSignedBlob
,
3290 BYTE
* pbDecoded
, DWORD
* pcbDecoded
, PCCERT_CONTEXT
* ppSignerCert
)
3292 FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n",
3293 pVerifyPara
, dwSignerIndex
, pbSignedBlob
, cbSignedBlob
,
3294 pbDecoded
, pcbDecoded
, ppSignerCert
);