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.
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "crypt32_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
41 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
42 /* The following aren't defined in wincrypt.h, as they're "reserved" */
43 #define CERT_CERT_PROP_ID 32
44 #define CERT_CRL_PROP_ID 33
45 #define CERT_CTL_PROP_ID 34
47 struct WINE_CRYPTCERTSTORE
;
49 typedef struct WINE_CRYPTCERTSTORE
* (*StoreOpenFunc
)(HCRYPTPROV hCryptProv
,
50 DWORD dwFlags
, const void *pvPara
);
52 struct _WINE_CERT_CONTEXT_REF
;
54 /* Called to enumerate the next certificate in a store. The returned pointer
55 * must be newly allocated (via HeapAlloc): CertFreeCertificateContext frees
58 typedef struct _WINE_CERT_CONTEXT_REF
* (*EnumCertFunc
)
59 (struct WINE_CRYPTCERTSTORE
*store
, struct _WINE_CERT_CONTEXT_REF
*pPrev
);
61 struct _WINE_CERT_CONTEXT
;
63 /* Called to create a new reference to an existing cert context. Should call
64 * CRYPT_InitCertRef to make sure the reference count is properly updated.
65 * If the store does not provide any additional allocated data (that is, does
66 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
69 typedef struct _WINE_CERT_CONTEXT_REF
* (*CreateRefFunc
)
70 (struct _WINE_CERT_CONTEXT
*context
, HCERTSTORE store
);
72 /* Optional, called when a cert context reference is being freed. Don't free
73 * the ref pointer itself, CertFreeCertificateContext does that.
75 typedef void (*FreeCertFunc
)(struct _WINE_CERT_CONTEXT_REF
*ref
);
77 typedef enum _CertStoreType
{
84 /* A cert store is polymorphic through the use of function pointers. A type
85 * is still needed to distinguish collection stores from other types.
86 * On the function pointers:
87 * - closeStore is called when the store's ref count becomes 0
88 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
89 * - control is optional, but should be implemented by any store that supports
92 typedef struct WINE_CRYPTCERTSTORE
99 PFN_CERT_STORE_PROV_CLOSE closeStore
;
100 PFN_CERT_STORE_PROV_WRITE_CERT addCert
;
101 CreateRefFunc createCertRef
;
102 EnumCertFunc enumCert
;
103 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert
;
104 FreeCertFunc freeCert
; /* optional */
105 PFN_CERT_STORE_PROV_CONTROL control
; /* optional */
106 } WINECRYPT_CERTSTORE
, *PWINECRYPT_CERTSTORE
;
108 /* A certificate context has pointers to data that are owned by this module,
109 * so rather than duplicate the data every time a certificate context is
110 * copied, I keep a reference count to the data. Thus I have two data
111 * structures, the "true" certificate context (that has the reference count)
112 * and a reference certificate context, that has a pointer to the true context.
113 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
114 * with the reference version.
116 typedef struct _WINE_CERT_CONTEXT
121 struct list extendedProperties
;
122 } WINE_CERT_CONTEXT
, *PWINE_CERT_CONTEXT
;
124 typedef struct _WINE_CERT_CONTEXT_REF
127 WINE_CERT_CONTEXT
*context
;
128 } WINE_CERT_CONTEXT_REF
, *PWINE_CERT_CONTEXT_REF
;
130 /* An extended certificate property in serialized form is prefixed by this
133 typedef struct _WINE_CERT_PROP_HEADER
136 DWORD unknown
; /* always 1 */
138 } WINE_CERT_PROP_HEADER
, *PWINE_CERT_PROP_HEADER
;
140 /* Stores an extended property in a cert. */
141 typedef struct _WINE_CERT_PROPERTY
143 WINE_CERT_PROP_HEADER hdr
;
146 } WINE_CERT_PROPERTY
, *PWINE_CERT_PROPERTY
;
148 /* A mem store has a list of these. They're also returned by the mem store
149 * during enumeration.
151 typedef struct _WINE_CERT_LIST_ENTRY
153 WINE_CERT_CONTEXT_REF cert
;
155 } WINE_CERT_LIST_ENTRY
, *PWINE_CERT_LIST_ENTRY
;
157 typedef struct _WINE_MEMSTORE
159 WINECRYPT_CERTSTORE hdr
;
162 } WINE_MEMSTORE
, *PWINE_MEMSTORE
;
164 typedef struct _WINE_STORE_LIST_ENTRY
166 PWINECRYPT_CERTSTORE store
;
170 } WINE_STORE_LIST_ENTRY
, *PWINE_STORE_LIST_ENTRY
;
172 /* Returned by a collection store during enumeration.
173 * Note: relies on the list entry being valid after use, which a number of
174 * conditions might make untrue (reentrancy, closing a collection store before
175 * continuing an enumeration on it, ...). The tests seem to indicate this
176 * sort of unsafety is okay, since Windows isn't well-behaved in these
179 typedef struct _WINE_COLLECTION_CERT_CONTEXT
181 WINE_CERT_CONTEXT_REF cert
;
182 PWINE_STORE_LIST_ENTRY entry
;
183 PWINE_CERT_CONTEXT_REF childContext
;
184 } WINE_COLLECTION_CERT_CONTEXT
, *PWINE_COLLECTION_CERT_CONTEXT
;
186 typedef struct _WINE_COLLECTIONSTORE
188 WINECRYPT_CERTSTORE hdr
;
191 } WINE_COLLECTIONSTORE
, *PWINE_COLLECTIONSTORE
;
193 /* Like CertGetCertificateContextProperty, but operates directly on the
194 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
195 * are handled by CertGetCertificateContextProperty, and are particular to the
196 * store in which the property exists (which is separate from the context.)
198 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
199 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
);
201 /* Like CertSetCertificateContextProperty, but operates directly on the
202 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
203 * CertSetCertificateContextProperty anyway.
205 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
206 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
);
208 static void CRYPT_InitStore(WINECRYPT_CERTSTORE
*store
, HCRYPTPROV hCryptProv
,
209 DWORD dwFlags
, CertStoreType type
)
212 store
->dwMagic
= WINE_CRYPTCERTSTORE_MAGIC
;
216 hCryptProv
= CRYPT_GetDefaultProvider();
217 dwFlags
|= CERT_STORE_NO_CRYPT_RELEASE_FLAG
;
219 store
->cryptProv
= hCryptProv
;
220 store
->dwOpenFlags
= dwFlags
;
223 /* Initializes the reference ref to point to pCertContext, which is assumed to
224 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
225 * Also sets the hCertStore member of the reference to store.
227 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref
,
228 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
230 TRACE("(%p, %p)\n", ref
, context
);
231 memcpy(&ref
->cert
, context
, sizeof(ref
->cert
));
232 ref
->context
= context
;
233 InterlockedIncrement(&context
->ref
);
234 ref
->cert
.hCertStore
= store
;
237 static PWINE_CERT_CONTEXT_REF
CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context
,
240 PWINE_CERT_CONTEXT_REF pCertRef
= HeapAlloc(GetProcessHeap(), 0,
241 sizeof(WINE_CERT_CONTEXT_REF
));
244 CRYPT_InitCertRef(pCertRef
, context
, store
);
248 static BOOL WINAPI
CRYPT_MemAddCert(HCERTSTORE store
, PCCERT_CONTEXT pCert
,
249 DWORD dwAddDisposition
)
251 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
252 BOOL add
= FALSE
, ret
;
254 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
256 switch (dwAddDisposition
)
258 case CERT_STORE_ADD_ALWAYS
:
261 case CERT_STORE_ADD_NEW
:
263 BYTE hashToAdd
[20], hash
[20];
264 DWORD size
= sizeof(hashToAdd
);
266 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
267 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
270 PWINE_CERT_LIST_ENTRY cursor
;
272 /* Add if no cert with the same hash is found. */
274 EnterCriticalSection(&ms
->cs
);
275 LIST_FOR_EACH_ENTRY(cursor
, &ms
->certs
, WINE_CERT_LIST_ENTRY
, entry
)
278 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
279 CERT_HASH_PROP_ID
, hash
, &size
);
280 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
282 TRACE("found matching certificate, not adding\n");
283 SetLastError(CRYPT_E_EXISTS
);
288 LeaveCriticalSection(&ms
->cs
);
292 case CERT_STORE_ADD_REPLACE_EXISTING
:
294 BYTE hashToAdd
[20], hash
[20];
295 DWORD size
= sizeof(hashToAdd
);
298 ret
= CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT
)pCert
,
299 CERT_HASH_PROP_ID
, hashToAdd
, &size
);
302 PWINE_CERT_LIST_ENTRY cursor
, next
;
304 /* Look for existing cert to delete */
305 EnterCriticalSection(&ms
->cs
);
306 LIST_FOR_EACH_ENTRY_SAFE(cursor
, next
, &ms
->certs
,
307 WINE_CERT_LIST_ENTRY
, entry
)
310 ret
= CertGetCertificateContextProperty(&cursor
->cert
.cert
,
311 CERT_HASH_PROP_ID
, hash
, &size
);
312 if (ret
&& !memcmp(hashToAdd
, hash
, size
))
314 TRACE("found matching certificate, replacing\n");
315 list_remove(&cursor
->entry
);
316 CertFreeCertificateContext((PCCERT_CONTEXT
)cursor
);
320 LeaveCriticalSection(&ms
->cs
);
325 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition
);
330 PWINE_CERT_LIST_ENTRY entry
= HeapAlloc(GetProcessHeap(), 0,
331 sizeof(WINE_CERT_LIST_ENTRY
));
335 TRACE("adding %p\n", entry
);
336 CRYPT_InitCertRef(&entry
->cert
, (PWINE_CERT_CONTEXT
)pCert
, store
);
337 list_init(&entry
->entry
);
338 EnterCriticalSection(&ms
->cs
);
339 list_add_tail(&ms
->certs
, &entry
->entry
);
340 LeaveCriticalSection(&ms
->cs
);
351 static PWINE_CERT_CONTEXT_REF
CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store
,
352 PWINE_CERT_CONTEXT_REF pPrev
)
354 WINE_MEMSTORE
*ms
= (WINE_MEMSTORE
*)store
;
355 PWINE_CERT_LIST_ENTRY prevEntry
= (PWINE_CERT_LIST_ENTRY
)pPrev
, ret
;
356 struct list
*listNext
;
358 TRACE("(%p, %p)\n", store
, pPrev
);
359 EnterCriticalSection(&ms
->cs
);
362 listNext
= list_next(&ms
->certs
, &prevEntry
->entry
);
363 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
366 listNext
= list_next(&ms
->certs
, &ms
->certs
);
369 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_LIST_ENTRY
));
370 memcpy(ret
, LIST_ENTRY(listNext
, WINE_CERT_LIST_ENTRY
, entry
),
371 sizeof(WINE_CERT_LIST_ENTRY
));
372 InterlockedIncrement(&ret
->cert
.context
->ref
);
376 SetLastError(CRYPT_E_NOT_FOUND
);
379 LeaveCriticalSection(&ms
->cs
);
381 TRACE("returning %p\n", ret
);
382 return (PWINE_CERT_CONTEXT_REF
)ret
;
385 static BOOL WINAPI
CRYPT_MemDeleteCert(HCERTSTORE hCertStore
,
386 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
388 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
389 WINE_CERT_CONTEXT_REF
*ref
= (WINE_CERT_CONTEXT_REF
*)pCertContext
;
390 PWINE_CERT_LIST_ENTRY cert
, next
;
393 /* Find the entry associated with the passed-in context, since the
394 * passed-in context may not be a list entry itself (e.g. if it came from
395 * CertDuplicateCertificateContext.) Pointing to the same context is
396 * a sufficient test of equality.
398 EnterCriticalSection(&store
->cs
);
399 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
402 if (cert
->cert
.context
== ref
->context
)
404 TRACE("removing %p\n", cert
);
405 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
408 list_remove(&cert
->entry
);
409 cert
->entry
.prev
= cert
->entry
.next
= &store
->certs
;
410 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
415 LeaveCriticalSection(&store
->cs
);
419 static void WINAPI
CRYPT_MemCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
421 WINE_MEMSTORE
*store
= (WINE_MEMSTORE
*)hCertStore
;
422 PWINE_CERT_LIST_ENTRY cert
, next
;
424 TRACE("(%p, %08lx)\n", store
, dwFlags
);
426 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
428 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
429 * pointer if its ref-count reaches zero. That's okay here because there
430 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
431 * of the CertListEntry.
433 LIST_FOR_EACH_ENTRY_SAFE(cert
, next
, &store
->certs
, WINE_CERT_LIST_ENTRY
,
436 TRACE("removing %p\n", cert
);
437 list_remove(&cert
->entry
);
438 CertFreeCertificateContext((PCCERT_CONTEXT
)cert
);
440 DeleteCriticalSection(&store
->cs
);
441 HeapFree(GetProcessHeap(), 0, store
);
444 static WINECRYPT_CERTSTORE
*CRYPT_MemOpenStore(HCRYPTPROV hCryptProv
,
445 DWORD dwFlags
, const void *pvPara
)
447 PWINE_MEMSTORE store
;
449 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
451 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
453 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
458 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
459 sizeof(WINE_MEMSTORE
));
462 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
, StoreTypeMem
);
463 store
->hdr
.closeStore
= CRYPT_MemCloseStore
;
464 store
->hdr
.addCert
= CRYPT_MemAddCert
;
465 store
->hdr
.createCertRef
= CRYPT_CreateCertRef
;
466 store
->hdr
.enumCert
= CRYPT_MemEnumCert
;
467 store
->hdr
.deleteCert
= CRYPT_MemDeleteCert
;
468 store
->hdr
.freeCert
= NULL
;
469 InitializeCriticalSection(&store
->cs
);
470 list_init(&store
->certs
);
473 return (PWINECRYPT_CERTSTORE
)store
;
476 static BOOL WINAPI
CRYPT_CollectionAddCert(HCERTSTORE store
,
477 PCCERT_CONTEXT pCert
, DWORD dwAddDisposition
)
479 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
480 PWINE_STORE_LIST_ENTRY entry
, next
;
483 TRACE("(%p, %p, %ld)\n", store
, pCert
, dwAddDisposition
);
486 EnterCriticalSection(&cs
->cs
);
487 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
490 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
492 ret
= entry
->store
->addCert(entry
->store
, pCert
, dwAddDisposition
);
496 LeaveCriticalSection(&cs
->cs
);
497 SetLastError(ret
? ERROR_SUCCESS
: HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED
));
501 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionCreateCertRef(
502 PWINE_CERT_CONTEXT context
, HCERTSTORE store
)
504 PWINE_COLLECTION_CERT_CONTEXT ret
= HeapAlloc(GetProcessHeap(), 0,
505 sizeof(WINE_COLLECTION_CERT_CONTEXT
));
509 /* Initialize to empty for now, just make sure the size is right */
510 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF
)ret
, context
, store
);
512 ret
->childContext
= NULL
;
514 return (PWINE_CERT_CONTEXT_REF
)ret
;
517 static void WINAPI
CRYPT_CollectionCloseStore(HCERTSTORE store
, DWORD dwFlags
)
519 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
520 PWINE_STORE_LIST_ENTRY entry
, next
;
522 TRACE("(%p, %08lx)\n", store
, dwFlags
);
524 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
,
527 TRACE("closing %p\n", entry
);
528 CertCloseStore((HCERTSTORE
)entry
->store
, dwFlags
);
529 HeapFree(GetProcessHeap(), 0, entry
);
531 DeleteCriticalSection(&cs
->cs
);
532 HeapFree(GetProcessHeap(), 0, cs
);
535 /* Advances a collection enumeration by one cert, if possible, where advancing
537 * - calling the current store's enumeration function once, and returning
538 * the enumerated cert if one is returned
539 * - moving to the next store if the current store has no more items, and
540 * recursively calling itself to get the next item.
541 * Returns NULL if the collection contains no more items or on error.
542 * Assumes the collection store's lock is held.
544 static PWINE_COLLECTION_CERT_CONTEXT
CRYPT_CollectionAdvanceEnum(
545 PWINE_COLLECTIONSTORE store
, PWINE_STORE_LIST_ENTRY storeEntry
,
546 PWINE_COLLECTION_CERT_CONTEXT pPrev
)
548 PWINE_COLLECTION_CERT_CONTEXT ret
;
549 PWINE_CERT_CONTEXT_REF child
;
551 TRACE("(%p, %p, %p)\n", store
, storeEntry
, pPrev
);
555 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
556 pPrev
->childContext
);
560 memcpy(&ret
->cert
, child
, sizeof(WINE_CERT_CONTEXT_REF
));
561 ret
->cert
.cert
.hCertStore
= (HCERTSTORE
)store
;
562 InterlockedIncrement(&ret
->cert
.context
->ref
);
563 ret
->childContext
= child
;
567 struct list
*storeNext
= list_next(&store
->stores
,
570 pPrev
->childContext
= NULL
;
571 CertFreeCertificateContext((PCCERT_CONTEXT
)pPrev
);
574 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
576 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
580 SetLastError(CRYPT_E_NOT_FOUND
);
587 child
= storeEntry
->store
->enumCert((HCERTSTORE
)storeEntry
->store
,
591 ret
= (PWINE_COLLECTION_CERT_CONTEXT
)CRYPT_CollectionCreateCertRef(
592 child
->context
, store
);
595 ret
->entry
= storeEntry
;
596 ret
->childContext
= child
;
599 CertFreeCertificateContext((PCCERT_CONTEXT
)child
);
603 struct list
*storeNext
= list_next(&store
->stores
,
608 storeEntry
= LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
,
610 ret
= CRYPT_CollectionAdvanceEnum(store
, storeEntry
, NULL
);
614 SetLastError(CRYPT_E_NOT_FOUND
);
619 TRACE("returning %p\n", ret
);
623 static PWINE_CERT_CONTEXT_REF
CRYPT_CollectionEnumCert(
624 PWINECRYPT_CERTSTORE store
, PWINE_CERT_CONTEXT_REF pPrev
)
626 PWINE_COLLECTIONSTORE cs
= (PWINE_COLLECTIONSTORE
)store
;
627 PWINE_COLLECTION_CERT_CONTEXT prevEntry
=
628 (PWINE_COLLECTION_CERT_CONTEXT
)pPrev
, ret
;
630 TRACE("(%p, %p)\n", store
, pPrev
);
634 EnterCriticalSection(&cs
->cs
);
635 ret
= CRYPT_CollectionAdvanceEnum(cs
, prevEntry
->entry
, prevEntry
);
636 LeaveCriticalSection(&cs
->cs
);
640 EnterCriticalSection(&cs
->cs
);
641 if (!list_empty(&cs
->stores
))
643 PWINE_STORE_LIST_ENTRY storeEntry
;
645 storeEntry
= LIST_ENTRY(cs
->stores
.next
, WINE_STORE_LIST_ENTRY
,
647 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
, prevEntry
);
651 SetLastError(CRYPT_E_NOT_FOUND
);
654 LeaveCriticalSection(&cs
->cs
);
656 TRACE("returning %p\n", ret
);
657 return (PWINE_CERT_CONTEXT_REF
)ret
;
660 static BOOL WINAPI
CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore
,
661 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
663 PWINE_COLLECTION_CERT_CONTEXT context
=
664 (PWINE_COLLECTION_CERT_CONTEXT
)pCertContext
;
667 TRACE("(%p, %p, %08lx)\n", hCertStore
, pCertContext
, dwFlags
);
669 ret
= CertDeleteCertificateFromStore((PCCERT_CONTEXT
)context
->childContext
);
672 context
->childContext
= NULL
;
673 CertFreeCertificateContext((PCCERT_CONTEXT
)context
);
678 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref
)
680 PWINE_COLLECTION_CERT_CONTEXT context
= (PWINE_COLLECTION_CERT_CONTEXT
)ref
;
682 TRACE("(%p)\n", ref
);
684 if (context
->childContext
)
685 CertFreeCertificateContext((PCCERT_CONTEXT
)context
->childContext
);
688 static WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
689 DWORD dwFlags
, const void *pvPara
)
691 PWINE_COLLECTIONSTORE store
;
693 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
695 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
700 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
701 sizeof(WINE_COLLECTIONSTORE
));
704 CRYPT_InitStore(&store
->hdr
, hCryptProv
, dwFlags
,
705 StoreTypeCollection
);
706 store
->hdr
.closeStore
= CRYPT_CollectionCloseStore
;
707 store
->hdr
.addCert
= CRYPT_CollectionAddCert
;
708 store
->hdr
.createCertRef
= CRYPT_CollectionCreateCertRef
;
709 store
->hdr
.enumCert
= CRYPT_CollectionEnumCert
;
710 store
->hdr
.deleteCert
= CRYPT_CollectionDeleteCert
;
711 store
->hdr
.freeCert
= CRYPT_CollectionFreeCert
;
712 InitializeCriticalSection(&store
->cs
);
713 list_init(&store
->stores
);
716 return (PWINECRYPT_CERTSTORE
)store
;
719 static void WINAPI
CRYPT_DummyCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
721 HeapFree(GetProcessHeap(), 0, (PWINECRYPT_CERTSTORE
)hCertStore
);
724 static BOOL WINAPI
CRYPT_DummyAddCert(HCERTSTORE store
, PCCERT_CONTEXT pCert
,
725 DWORD dwAddDisposition
)
730 static PWINE_CERT_CONTEXT_REF
CRYPT_DummyEnumCert(PWINECRYPT_CERTSTORE store
,
731 PWINE_CERT_CONTEXT_REF pPrev
)
736 static BOOL WINAPI
CRYPT_DummyDeleteCert(HCERTSTORE hCertStore
,
737 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
742 static WINECRYPT_CERTSTORE
*CRYPT_DummyOpenStore(HCRYPTPROV hCryptProv
,
743 DWORD dwFlags
, const void *pvPara
)
745 PWINECRYPT_CERTSTORE store
;
747 TRACE("(%ld, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
749 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
751 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
756 store
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
757 sizeof(WINECRYPT_CERTSTORE
));
760 CRYPT_InitStore(store
, hCryptProv
, dwFlags
, StoreTypeDummy
);
761 store
->closeStore
= CRYPT_DummyCloseStore
;
762 store
->addCert
= CRYPT_DummyAddCert
;
763 store
->createCertRef
= CRYPT_CreateCertRef
;
764 store
->enumCert
= CRYPT_DummyEnumCert
;
765 store
->deleteCert
= CRYPT_DummyDeleteCert
;
766 store
->freeCert
= NULL
;
769 return (PWINECRYPT_CERTSTORE
)store
;
773 HCERTSTORE WINAPI
CertOpenStore(LPCSTR lpszStoreProvider
,
774 DWORD dwMsgAndCertEncodingType
, HCRYPTPROV hCryptProv
, DWORD dwFlags
,
777 WINECRYPT_CERTSTORE
*hcs
;
778 StoreOpenFunc openFunc
= NULL
;
780 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider
),
781 dwMsgAndCertEncodingType
, hCryptProv
, dwFlags
, pvPara
);
783 if (!HIWORD(lpszStoreProvider
))
785 switch (LOWORD(lpszStoreProvider
))
787 case (int)CERT_STORE_PROV_MEMORY
:
788 openFunc
= CRYPT_MemOpenStore
;
790 case (int)CERT_STORE_PROV_COLLECTION
:
791 openFunc
= CRYPT_CollectionOpenStore
;
793 case (int)CERT_STORE_PROV_REG
:
794 case (int)CERT_STORE_PROV_SYSTEM_A
:
795 case (int)CERT_STORE_PROV_SYSTEM_W
:
796 openFunc
= CRYPT_DummyOpenStore
;
799 if (LOWORD(lpszStoreProvider
))
800 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider
));
803 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_MEMORY
))
804 openFunc
= CRYPT_MemOpenStore
;
805 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_SYSTEM
))
806 openFunc
= CRYPT_DummyOpenStore
;
807 else if (!strcasecmp(lpszStoreProvider
, sz_CERT_STORE_PROV_COLLECTION
))
808 openFunc
= CRYPT_CollectionOpenStore
;
811 FIXME("unimplemented type %s\n", lpszStoreProvider
);
817 /* FIXME: need to look for an installed provider for this type */
818 SetLastError(ERROR_FILE_NOT_FOUND
);
822 hcs
= openFunc(hCryptProv
, dwFlags
, pvPara
);
823 return (HCERTSTORE
)hcs
;
826 HCERTSTORE WINAPI
CertOpenSystemStoreA(HCRYPTPROV hProv
,
827 LPCSTR szSubSystemProtocol
)
829 return CertOpenStore( CERT_STORE_PROV_SYSTEM_A
, 0, 0,
830 CERT_SYSTEM_STORE_CURRENT_USER
| CERT_SYSTEM_STORE_LOCAL_MACHINE
|
831 CERT_SYSTEM_STORE_USERS
, szSubSystemProtocol
);
834 HCERTSTORE WINAPI
CertOpenSystemStoreW(HCRYPTPROV hProv
,
835 LPCWSTR szSubSystemProtocol
)
837 return CertOpenStore( CERT_STORE_PROV_SYSTEM_W
, 0, 0,
838 CERT_SYSTEM_STORE_CURRENT_USER
| CERT_SYSTEM_STORE_LOCAL_MACHINE
|
839 CERT_SYSTEM_STORE_USERS
, szSubSystemProtocol
);
842 BOOL WINAPI
CertSaveStore(HCERTSTORE hCertStore
, DWORD dwMsgAndCertEncodingType
,
843 DWORD dwSaveAs
, DWORD dwSaveTo
, void* pvSaveToPara
, DWORD dwFlags
)
845 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore
,
846 dwMsgAndCertEncodingType
, dwSaveAs
, dwSaveTo
, pvSaveToPara
, dwFlags
);
850 PCCRL_CONTEXT WINAPI
CertCreateCRLContext( DWORD dwCertEncodingType
,
851 const BYTE
* pbCrlEncoded
, DWORD cbCrlEncoded
)
856 TRACE("%08lx %p %08lx\n", dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
);
858 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
859 pcrl
= HeapAlloc( GetProcessHeap(), 0, sizeof (CRL_CONTEXT
) );
863 data
= HeapAlloc( GetProcessHeap(), 0, cbCrlEncoded
);
866 HeapFree( GetProcessHeap(), 0, pcrl
);
870 pcrl
->dwCertEncodingType
= dwCertEncodingType
;
871 pcrl
->pbCrlEncoded
= data
;
872 pcrl
->cbCrlEncoded
= cbCrlEncoded
;
873 pcrl
->pCrlInfo
= NULL
;
874 pcrl
->hCertStore
= 0;
879 /* Decodes the encoded certificate and creates the certificate context for it.
880 * The reference count is initially zero, so you must create a reference to it
881 * to avoid leaking memory.
883 static PWINE_CERT_CONTEXT
CRYPT_CreateCertificateContext(
884 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
886 PWINE_CERT_CONTEXT cert
= NULL
;
888 PCERT_INFO certInfo
= NULL
;
891 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
894 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
895 pbCertEncoded
, cbCertEncoded
,
896 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
897 (BYTE
*)&certInfo
, &size
);
902 cert
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT
));
905 data
= HeapAlloc(GetProcessHeap(), 0, cbCertEncoded
);
908 HeapFree(GetProcessHeap(), 0, cert
);
912 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
913 cert
->cert
.dwCertEncodingType
= dwCertEncodingType
;
914 cert
->cert
.pbCertEncoded
= data
;
915 cert
->cert
.cbCertEncoded
= cbCertEncoded
;
916 cert
->cert
.pCertInfo
= certInfo
;
917 cert
->cert
.hCertStore
= 0;
919 InitializeCriticalSection(&cert
->cs
);
920 list_init(&cert
->extendedProperties
);
927 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context
)
929 PWINE_CERT_PROPERTY prop
, next
;
931 HeapFree(GetProcessHeap(), 0, context
->cert
.pbCertEncoded
);
932 LocalFree(context
->cert
.pCertInfo
);
933 HeapFree(GetProcessHeap(), 0, context
);
934 DeleteCriticalSection(&context
->cs
);
935 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
936 WINE_CERT_PROPERTY
, entry
)
938 list_remove(&prop
->entry
);
939 HeapFree(GetProcessHeap(), 0, prop
->pbData
);
940 HeapFree(GetProcessHeap(), 0, prop
);
944 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
945 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
947 PWINE_CERT_CONTEXT cert
;
948 PWINE_CERT_CONTEXT_REF ret
= NULL
;
950 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
953 cert
= CRYPT_CreateCertificateContext(dwCertEncodingType
, pbCertEncoded
,
956 ret
= CRYPT_CreateCertRef(cert
, 0);
957 return (PCCERT_CONTEXT
)ret
;
960 /* Since the properties are stored in a list, this is a tad inefficient
961 * (O(n^2)) since I have to find the previous position every time.
963 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
966 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
969 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
971 EnterCriticalSection(&ref
->context
->cs
);
974 PWINE_CERT_PROPERTY cursor
= NULL
;
976 LIST_FOR_EACH_ENTRY(cursor
, &ref
->context
->extendedProperties
,
977 WINE_CERT_PROPERTY
, entry
)
979 if (cursor
->hdr
.propID
== dwPropId
)
984 if (cursor
->entry
.next
!= &ref
->context
->extendedProperties
)
985 ret
= LIST_ENTRY(cursor
->entry
.next
, WINE_CERT_PROPERTY
,
993 else if (!list_empty(&ref
->context
->extendedProperties
))
994 ret
= LIST_ENTRY(ref
->context
->extendedProperties
.next
,
995 WINE_CERT_PROPERTY
, entry
)->hdr
.propID
;
998 LeaveCriticalSection(&ref
->context
->cs
);
1002 static BOOL WINAPI
CRYPT_GetCertificateContextProperty(
1003 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1005 PWINE_CERT_PROPERTY prop
;
1008 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
1010 EnterCriticalSection(&context
->cs
);
1013 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1014 WINE_CERT_PROPERTY
, entry
)
1016 if (prop
->hdr
.propID
== dwPropId
)
1020 *pcbData
= prop
->hdr
.cb
;
1023 else if (*pcbData
< prop
->hdr
.cb
)
1025 SetLastError(ERROR_MORE_DATA
);
1026 *pcbData
= prop
->hdr
.cb
;
1030 memcpy(pvData
, prop
->pbData
, prop
->hdr
.cb
);
1031 *pcbData
= prop
->hdr
.cb
;
1040 /* Implicit properties */
1043 case CERT_SHA1_HASH_PROP_ID
:
1044 ret
= CryptHashCertificate(0, CALG_SHA1
, 0,
1045 context
->cert
.pbCertEncoded
, context
->cert
.cbCertEncoded
, pvData
,
1049 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
1051 ret
= CRYPT_SetCertificateContextProperty(context
, dwPropId
,
1055 case CERT_KEY_PROV_INFO_PROP_ID
:
1056 case CERT_MD5_HASH_PROP_ID
:
1057 case CERT_SIGNATURE_HASH_PROP_ID
:
1058 case CERT_KEY_IDENTIFIER_PROP_ID
:
1059 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1060 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
1061 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
1062 FIXME("implicit property %ld\n", dwPropId
);
1066 LeaveCriticalSection(&context
->cs
);
1067 TRACE("returning %d\n", ret
);
1071 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1072 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1074 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1077 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
1079 /* Special cases for invalid/special prop IDs.
1084 case CERT_CERT_PROP_ID
:
1085 case CERT_CRL_PROP_ID
:
1086 case CERT_CTL_PROP_ID
:
1087 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1089 case CERT_ACCESS_STATE_PROP_ID
:
1092 *pcbData
= sizeof(DWORD
);
1095 else if (*pcbData
< sizeof(DWORD
))
1097 SetLastError(ERROR_MORE_DATA
);
1098 *pcbData
= sizeof(DWORD
);
1105 if (pCertContext
->hCertStore
)
1107 PWINECRYPT_CERTSTORE store
=
1108 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
1110 /* Take advantage of knowledge of the stores to answer the
1111 * access state question
1113 if (store
->type
!= StoreTypeReg
||
1114 !(store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
))
1115 state
|= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG
;
1117 *(DWORD
*)pvData
= state
;
1122 ret
= CRYPT_GetCertificateContextProperty(ref
->context
, dwPropId
,
1124 TRACE("returning %d\n", ret
);
1128 /* Copies cbData bytes from pbData to the context's property with ID
1131 static BOOL
CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context
,
1132 DWORD dwPropId
, const BYTE
*pbData
, size_t cbData
)
1139 data
= HeapAlloc(GetProcessHeap(), 0, cbData
);
1141 memcpy(data
, pbData
, cbData
);
1145 if (!cbData
|| data
)
1147 PWINE_CERT_PROPERTY prop
;
1149 EnterCriticalSection(&context
->cs
);
1150 LIST_FOR_EACH_ENTRY(prop
, &context
->extendedProperties
,
1151 WINE_CERT_PROPERTY
, entry
)
1153 if (prop
->hdr
.propID
== dwPropId
)
1156 if (prop
&& prop
->entry
.next
!= &context
->extendedProperties
)
1158 HeapFree(GetProcessHeap(), 0, prop
->pbData
);
1159 prop
->hdr
.cb
= cbData
;
1160 prop
->pbData
= cbData
? data
: NULL
;
1165 prop
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_PROPERTY
));
1168 prop
->hdr
.propID
= dwPropId
;
1169 prop
->hdr
.unknown
= 1;
1170 prop
->hdr
.cb
= cbData
;
1171 list_init(&prop
->entry
);
1172 prop
->pbData
= cbData
? data
: NULL
;
1173 list_add_tail(&context
->extendedProperties
, &prop
->entry
);
1177 HeapFree(GetProcessHeap(), 0, data
);
1179 LeaveCriticalSection(&context
->cs
);
1184 static BOOL WINAPI
CRYPT_SetCertificateContextProperty(
1185 PWINE_CERT_CONTEXT context
, DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
1189 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
1193 PWINE_CERT_PROPERTY prop
, next
;
1195 EnterCriticalSection(&context
->cs
);
1196 LIST_FOR_EACH_ENTRY_SAFE(prop
, next
, &context
->extendedProperties
,
1197 WINE_CERT_PROPERTY
, entry
)
1199 if (prop
->hdr
.propID
== dwPropId
)
1201 list_remove(&prop
->entry
);
1202 HeapFree(GetProcessHeap(), 0, prop
->pbData
);
1203 HeapFree(GetProcessHeap(), 0, prop
);
1206 LeaveCriticalSection(&context
->cs
);
1213 case CERT_AUTO_ENROLL_PROP_ID
:
1214 case CERT_CTL_USAGE_PROP_ID
:
1215 case CERT_DESCRIPTION_PROP_ID
:
1216 case CERT_FRIENDLY_NAME_PROP_ID
:
1217 case CERT_HASH_PROP_ID
:
1218 case CERT_KEY_IDENTIFIER_PROP_ID
:
1219 case CERT_MD5_HASH_PROP_ID
:
1220 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
1221 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
1222 case CERT_PVK_FILE_PROP_ID
:
1223 case CERT_SIGNATURE_HASH_PROP_ID
:
1224 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1225 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
1226 case CERT_ENROLLMENT_PROP_ID
:
1227 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
1228 case CERT_RENEWAL_PROP_ID
:
1230 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
1232 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
1233 blob
->pbData
, blob
->cbData
);
1236 case CERT_DATE_STAMP_PROP_ID
:
1237 ret
= CRYPT_SaveCertificateContextProperty(context
, dwPropId
,
1238 pvData
, sizeof(FILETIME
));
1241 FIXME("%ld: stub\n", dwPropId
);
1244 TRACE("returning %d\n", ret
);
1248 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
1249 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
1251 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1254 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
1256 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
1257 * crashes on most of these, I'll be safer.
1262 case CERT_ACCESS_STATE_PROP_ID
:
1263 case CERT_CERT_PROP_ID
:
1264 case CERT_CRL_PROP_ID
:
1265 case CERT_CTL_PROP_ID
:
1266 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1269 ret
= CRYPT_SetCertificateContextProperty(ref
->context
, dwPropId
,
1271 TRACE("returning %d\n", ret
);
1275 /* Only the reference portion of the context is duplicated. The returned
1276 * context has the cert store set to 0, to prevent the store's certificate free
1277 * function from getting called on partial data.
1278 * FIXME: is this okay? Needs a test.
1280 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
1281 PCCERT_CONTEXT pCertContext
)
1283 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
, ret
;
1285 TRACE("(%p)\n", pCertContext
);
1288 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CERT_CONTEXT_REF
));
1291 memcpy(ret
, ref
, sizeof(*ret
));
1292 ret
->cert
.hCertStore
= 0;
1293 InterlockedIncrement(&ret
->context
->ref
);
1298 return (PCCERT_CONTEXT
)ret
;
1301 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
1302 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
1303 PCCERT_CONTEXT
*ppStoreContext
)
1305 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
1306 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1307 PWINE_CERT_CONTEXT cert
;
1310 TRACE("(%p, %p, %08lx, %p)\n", hCertStore
, pCertContext
,
1311 dwAddDisposition
, ppStoreContext
);
1313 /* FIXME: some tests needed to verify return codes */
1316 SetLastError(ERROR_INVALID_PARAMETER
);
1319 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1321 SetLastError(ERROR_INVALID_PARAMETER
);
1325 cert
= CRYPT_CreateCertificateContext(ref
->context
->cert
.dwCertEncodingType
,
1326 ref
->context
->cert
.pbCertEncoded
, ref
->context
->cert
.cbCertEncoded
);
1329 PWINE_CERT_PROPERTY prop
;
1332 EnterCriticalSection(&ref
->context
->cs
);
1333 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
1334 WINE_CERT_PROPERTY
, entry
)
1336 ret
= CRYPT_SaveCertificateContextProperty(cert
, prop
->hdr
.propID
,
1337 prop
->pbData
, prop
->hdr
.cb
);
1341 LeaveCriticalSection(&ref
->context
->cs
);
1344 ret
= store
->addCert(store
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
1345 if (ret
&& ppStoreContext
)
1346 *ppStoreContext
= (PCCERT_CONTEXT
)store
->createCertRef(cert
,
1350 CRYPT_FreeCert(cert
);
1357 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
1358 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
1359 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
1361 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
1364 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
1365 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
1369 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1373 PWINE_CERT_CONTEXT cert
= CRYPT_CreateCertificateContext(
1374 dwCertEncodingType
, pbCertEncoded
, cbCertEncoded
);
1378 ret
= hcs
->addCert(hcs
, (PCCERT_CONTEXT
)cert
, dwAddDisposition
);
1379 if (ret
&& ppCertContext
)
1380 *ppCertContext
= (PCCERT_CONTEXT
)hcs
->createCertRef(cert
,
1383 CRYPT_FreeCert(cert
);
1391 PCCERT_CONTEXT WINAPI
CertEnumCertificatesInStore(HCERTSTORE hCertStore
,
1392 PCCERT_CONTEXT pPrev
)
1394 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
1395 PWINE_CERT_CONTEXT_REF prev
= (PWINE_CERT_CONTEXT_REF
)pPrev
;
1398 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
1401 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1404 ret
= (PCCERT_CONTEXT
)hcs
->enumCert(hcs
, prev
);
1408 BOOL WINAPI
CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext
)
1412 TRACE("(%p)\n", pCertContext
);
1416 else if (!pCertContext
->hCertStore
)
1420 PWINECRYPT_CERTSTORE hcs
=
1421 (PWINECRYPT_CERTSTORE
)pCertContext
->hCertStore
;
1425 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1428 ret
= hcs
->deleteCert(hcs
, pCertContext
, 0);
1433 BOOL WINAPI
CertAddEncodedCRLToStore(HCERTSTORE hCertStore
,
1434 DWORD dwCertEncodingType
, const BYTE
*pbCrlEncoded
, DWORD cbCrlEncoded
,
1435 DWORD dwAddDisposition
, PCCRL_CONTEXT
*ppCrlContext
)
1437 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
1438 dwCertEncodingType
, pbCrlEncoded
, cbCrlEncoded
, dwAddDisposition
,
1443 BOOL WINAPI
CertAddCRLContextToStore( HCERTSTORE hCertStore
,
1444 PCCRL_CONTEXT pCrlContext
, DWORD dwAddDisposition
,
1445 PCCRL_CONTEXT
* ppStoreContext
)
1447 FIXME("%p %p %08lx %p\n", hCertStore
, pCrlContext
,
1448 dwAddDisposition
, ppStoreContext
);
1452 BOOL WINAPI
CertFreeCRLContext( PCCRL_CONTEXT pCrlContext
)
1454 FIXME("%p\n", pCrlContext
);
1459 BOOL WINAPI
CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext
)
1461 FIXME("(%p): stub\n", pCrlContext
);
1465 PCCRL_CONTEXT WINAPI
CertEnumCRLsInStore(HCERTSTORE hCertStore
,
1466 PCCRL_CONTEXT pPrev
)
1468 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
1472 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwCertEncodingType
,
1473 const BYTE
* pbCtlEncoded
, DWORD cbCtlEncoded
)
1475 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType
, pbCtlEncoded
,
1480 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
1481 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
1482 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
1484 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore
,
1485 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
1490 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
1491 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
1492 PCCTL_CONTEXT
* ppStoreContext
)
1494 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore
, pCtlContext
,
1495 dwAddDisposition
, ppStoreContext
);
1499 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCtlContext
)
1501 FIXME("(%p): stub\n", pCtlContext
);
1505 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
1507 FIXME("(%p): stub\n", pCtlContext
);
1511 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
1512 PCCTL_CONTEXT pPrev
)
1514 FIXME("(%p, %p): stub\n", hCertStore
, pPrev
);
1519 BOOL WINAPI
CertCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
1521 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*) hCertStore
;
1523 TRACE("(%p, %08lx)\n", hCertStore
, dwFlags
);
1528 if ( hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1531 if (InterlockedDecrement(&hcs
->ref
) == 0)
1533 TRACE("freeing %p\n", hcs
);
1535 if (!(hcs
->dwOpenFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
1536 CryptReleaseContext(hcs
->cryptProv
, 0);
1537 hcs
->closeStore(hcs
, dwFlags
);
1540 TRACE("%p's ref count is %ld\n", hcs
, hcs
->ref
);
1544 BOOL WINAPI
CertControlStore(HCERTSTORE hCertStore
, DWORD dwFlags
,
1545 DWORD dwCtrlType
, void const *pvCtrlPara
)
1547 FIXME("(%p, %08lx, %ld, %p): stub\n", hCertStore
, dwFlags
, dwCtrlType
,
1552 BOOL WINAPI
CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
1553 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1555 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext
, dwPropId
, pvData
, pcbData
);
1559 BOOL WINAPI
CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext
,
1560 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
1562 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext
, dwPropId
, dwFlags
,
1567 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
1568 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
1570 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext
, dwFlags
, pbElement
,
1575 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
1576 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
1578 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
1582 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
1583 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
1585 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext
, dwPropId
, dwFlags
,
1590 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
1591 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
1593 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext
, dwFlags
, pbElement
,
1598 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
1599 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
1603 TRACE("(%p, %08lx, %p, %p)\n", pCertContext
, dwFlags
, pbElement
,
1608 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1609 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) +
1610 pCertContext
->cbCertEncoded
;
1611 PWINE_CERT_PROPERTY prop
;
1613 EnterCriticalSection(&ref
->context
->cs
);
1614 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
1615 WINE_CERT_PROPERTY
, entry
)
1616 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + prop
->hdr
.cb
;
1619 *pcbElement
= bytesNeeded
;
1622 else if (*pcbElement
< bytesNeeded
)
1624 *pcbElement
= bytesNeeded
;
1625 SetLastError(ERROR_MORE_DATA
);
1630 PWINE_CERT_PROP_HEADER hdr
;
1632 LIST_FOR_EACH_ENTRY(prop
, &ref
->context
->extendedProperties
,
1633 WINE_CERT_PROPERTY
, entry
)
1635 memcpy(pbElement
, &prop
->hdr
, sizeof(WINE_CERT_PROP_HEADER
));
1636 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
1639 memcpy(pbElement
, prop
->pbData
, prop
->hdr
.cb
);
1640 pbElement
+= prop
->hdr
.cb
;
1643 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
1644 hdr
->propID
= CERT_CERT_PROP_ID
;
1646 hdr
->cb
= pCertContext
->cbCertEncoded
;
1647 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
1648 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
);
1651 LeaveCriticalSection(&ref
->context
->cs
);
1658 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
1659 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
1660 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
1662 FIXME("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p): stub\n", hCertStore
,
1663 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
1664 pdwContentType
, ppvContext
);
1668 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
1670 TRACE("(%p)\n", pCertContext
);
1674 PWINE_CERT_CONTEXT_REF ref
= (PWINE_CERT_CONTEXT_REF
)pCertContext
;
1675 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)ref
->cert
.hCertStore
;
1677 if (InterlockedDecrement(&ref
->context
->ref
) == 0)
1679 TRACE("freeing %p\n", ref
->context
);
1680 CRYPT_FreeCert(ref
->context
);
1683 TRACE("%p's ref count is %ld\n", ref
->context
,
1685 if (store
&& store
->dwMagic
== WINE_CRYPTCERTSTORE_MAGIC
&&
1687 store
->freeCert(ref
);
1688 HeapFree(GetProcessHeap(), 0, ref
);
1693 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
1694 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
,
1695 const void *pvPara
, PCCERT_CONTEXT pPrevCertContext
)
1697 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore
, dwCertEncodingType
,
1698 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
1699 SetLastError(CRYPT_E_NOT_FOUND
);
1703 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
1704 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
1706 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
1707 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
1708 PWINE_STORE_LIST_ENTRY entry
;
1711 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
1712 dwUpdateFlags
, dwPriority
);
1714 if (!collection
|| !sibling
)
1716 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1718 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1721 if (collection
->hdr
.type
!= StoreTypeCollection
)
1723 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1726 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1728 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1732 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_STORE_LIST_ENTRY
));
1735 InterlockedIncrement(&sibling
->ref
);
1736 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
1737 entry
->store
= sibling
;
1738 entry
->dwUpdateFlags
= dwUpdateFlags
;
1739 entry
->dwPriority
= dwPriority
;
1740 list_init(&entry
->entry
);
1741 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
1742 EnterCriticalSection(&collection
->cs
);
1745 PWINE_STORE_LIST_ENTRY cursor
;
1748 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
1749 WINE_STORE_LIST_ENTRY
, entry
)
1751 if (cursor
->dwPriority
< dwPriority
)
1753 list_add_before(&cursor
->entry
, &entry
->entry
);
1759 list_add_tail(&collection
->stores
, &entry
->entry
);
1762 list_add_tail(&collection
->stores
, &entry
->entry
);
1763 LeaveCriticalSection(&collection
->cs
);
1771 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
1772 HCERTSTORE hSiblingStore
)
1774 PWINE_COLLECTIONSTORE collection
= (PWINE_COLLECTIONSTORE
)hCollectionStore
;
1775 WINECRYPT_CERTSTORE
*sibling
= (WINECRYPT_CERTSTORE
*)hSiblingStore
;
1776 PWINE_STORE_LIST_ENTRY store
, next
;
1778 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
1780 if (!collection
|| !sibling
)
1782 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1784 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1787 if (collection
->hdr
.type
!= StoreTypeCollection
)
1789 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
1791 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
1794 EnterCriticalSection(&collection
->cs
);
1795 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
1796 WINE_STORE_LIST_ENTRY
, entry
)
1798 if (store
->store
== sibling
)
1800 list_remove(&store
->entry
);
1801 CertCloseStore(store
->store
, 0);
1802 HeapFree(GetProcessHeap(), 0, store
);
1806 LeaveCriticalSection(&collection
->cs
);
1809 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
1810 CRYPT_ATTRIBUTE rgAttr
[])
1812 PCRYPT_ATTRIBUTE ret
= NULL
;
1815 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
1821 SetLastError(ERROR_INVALID_PARAMETER
);
1825 for (i
= 0; !ret
&& i
< cAttr
; i
++)
1826 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
1831 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
1832 CERT_EXTENSION rgExtensions
[])
1834 PCERT_EXTENSION ret
= NULL
;
1837 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
1843 SetLastError(ERROR_INVALID_PARAMETER
);
1847 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
1848 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
1849 rgExtensions
[i
].pszObjId
))
1850 ret
= &rgExtensions
[i
];
1854 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
1856 PCERT_RDN_ATTR ret
= NULL
;
1859 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
1863 SetLastError(ERROR_INVALID_PARAMETER
);
1867 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
1868 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
1869 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
1870 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
1871 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
1875 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
1876 PCERT_INFO pCertInfo
)
1885 GetSystemTime(&sysTime
);
1886 SystemTimeToFileTime(&sysTime
, &fileTime
);
1887 pTimeToVerify
= &fileTime
;
1889 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
1891 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
1898 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
1899 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
1900 DWORD
*pcbComputedHash
)
1903 HCRYPTHASH hHash
= 0;
1905 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
1906 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
1909 hCryptProv
= CRYPT_GetDefaultProvider();
1914 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
1917 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
1919 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
1920 pcbComputedHash
, 0);
1921 CryptDestroyHash(hHash
);