got a lot of crypt32 stuff working
[reactos.git] / reactos / lib / crypt32 / cert.c
1 /*
2 * Copyright 2002
3 Mike McCormack for CodeWeavers
4 * Copyright 2004,2005 Juan Lang
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * FIXME:
21 * - As you can see in the stubs below, support for CRLs and CTLs is missing.
22 * Mostly this should be copy-paste work, and some code (e.g. extended
23 * properties) could be shared between them.
24 * - Opening a cert store provider should be morphed to support loading
25 * external DLLs.
26 * - The concept of physical stores and locations isn't implemented. (This
27 * doesn't mean registry stores et al aren't implemented. See the PSDK for
28 * registering and enumerating physical stores and locations.)
29 * - Many flags, options and whatnot are unimplemented.
30 */
31
32 #include "precomp.h"
33
34 #define NONAMELESSUNION
35
36 static _SEH_FILTER(page_fault)
37 {
38 if (_SEH_GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
39 return _SEH_EXECUTE_HANDLER;
40 return _SEH_CONTINUE_SEARCH;
41 }
42
43 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
44
45 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
46 /* The following aren't defined in wincrypt.h, as they're "reserved" */
47 #define CERT_CERT_PROP_ID 32
48 #define CERT_CRL_PROP_ID 33
49 #define CERT_CTL_PROP_ID 34
50
51 /* Some typedefs that make it easier to abstract which type of context we're
52 * working with.
53 */
54 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
55 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
56 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
57 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
58 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
59 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
60 DWORD dwAddDisposition, const void **ppContext);
61 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
62 const void *pPrevContext);
63 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
64 DWORD dwPropID, void *pvData, DWORD *pcbData);
65 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
66 DWORD dwPropID, DWORD dwFlags, const void *pvData);
67 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
68 BYTE *pbElement, DWORD *pcbElement);
69 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
70 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
71
72 /* An abstract context (certificate, CRL, or CTL) interface */
73 typedef struct _WINE_CONTEXT_INTERFACE
74 {
75 CreateContextFunc create;
76 AddContextToStoreFunc addContextToStore;
77 AddEncodedContextToStoreFunc addEncodedToStore;
78 EnumContextsInStoreFunc enumContextsInStore;
79 GetContextPropertyFunc getProp;
80 SetContextPropertyFunc setProp;
81 SerializeElementFunc serialize;
82 FreeContextFunc free;
83 DeleteContextFunc deleteFromStore;
84 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
85
86 static const WINE_CONTEXT_INTERFACE gCertInterface = {
87 (CreateContextFunc)CertCreateCertificateContext,
88 (AddContextToStoreFunc)CertAddCertificateContextToStore,
89 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
90 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
91 (GetContextPropertyFunc)CertGetCertificateContextProperty,
92 (SetContextPropertyFunc)CertSetCertificateContextProperty,
93 (SerializeElementFunc)CertSerializeCertificateStoreElement,
94 (FreeContextFunc)CertFreeCertificateContext,
95 (DeleteContextFunc)CertDeleteCertificateFromStore,
96 };
97
98 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
99 (CreateContextFunc)CertCreateCRLContext,
100 (AddContextToStoreFunc)CertAddCRLContextToStore,
101 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
102 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
103 (GetContextPropertyFunc)CertGetCRLContextProperty,
104 (SetContextPropertyFunc)CertSetCRLContextProperty,
105 (SerializeElementFunc)CertSerializeCRLStoreElement,
106 (FreeContextFunc)CertFreeCRLContext,
107 (DeleteContextFunc)CertDeleteCRLFromStore,
108 };
109
110 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
111 (CreateContextFunc)CertCreateCTLContext,
112 (AddContextToStoreFunc)CertAddCTLContextToStore,
113 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
114 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
115 (GetContextPropertyFunc)CertGetCTLContextProperty,
116 (SetContextPropertyFunc)CertSetCTLContextProperty,
117 (SerializeElementFunc)CertSerializeCTLStoreElement,
118 (FreeContextFunc)CertFreeCTLContext,
119 (DeleteContextFunc)CertDeleteCTLFromStore,
120 };
121
122 struct WINE_CRYPTCERTSTORE;
123
124 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
125 DWORD dwFlags, const void *pvPara);
126
127 struct _WINE_CERT_CONTEXT_REF;
128
129 /* Called to enumerate the next certificate in a store. The returned pointer
130 * must be newly allocated (via CryptMemAlloc): CertFreeCertificateContext
131 * frees it.
132 */
133 typedef struct _WINE_CERT_CONTEXT_REF * (*EnumCertFunc)
134 (struct WINE_CRYPTCERTSTORE *store, struct _WINE_CERT_CONTEXT_REF *pPrev);
135
136 struct _WINE_CERT_CONTEXT;
137
138 /* Called to create a new reference to an existing cert context. Should call
139 * CRYPT_InitCertRef to make sure the reference count is properly updated.
140 * If the store does not provide any additional allocated data (that is, does
141 * not need to implement a FreeCertFunc), it may use CRYPT_CreateCertRef for
142 * this.
143 */
144 typedef struct _WINE_CERT_CONTEXT_REF * (*CreateRefFunc)
145 (struct _WINE_CERT_CONTEXT *context, HCERTSTORE store);
146
147 /* Optional, called when a cert context reference is being freed. Don't free
148 * the ref pointer itself, CertFreeCertificateContext does that.
149 */
150 typedef void (*FreeCertFunc)(struct _WINE_CERT_CONTEXT_REF *ref);
151
152 typedef enum _CertStoreType {
153 StoreTypeMem,
154 StoreTypeCollection,
155 StoreTypeReg,
156 StoreTypeDummy,
157 } CertStoreType;
158
159 /* A cert store is polymorphic through the use of function pointers. A type
160 * is still needed to distinguish collection stores from other types.
161 * On the function pointers:
162 * - closeStore is called when the store's ref count becomes 0
163 * - addCert is called with a PWINE_CERT_CONTEXT as the second parameter
164 * - control is optional, but should be implemented by any store that supports
165 * persistence
166 */
167 typedef struct WINE_CRYPTCERTSTORE
168 {
169 DWORD dwMagic;
170 LONG ref;
171 DWORD dwOpenFlags;
172 HCRYPTPROV cryptProv;
173 CertStoreType type;
174 PFN_CERT_STORE_PROV_CLOSE closeStore;
175 PFN_CERT_STORE_PROV_WRITE_CERT addCert;
176 CreateRefFunc createCertRef;
177 EnumCertFunc enumCert;
178 PFN_CERT_STORE_PROV_DELETE_CERT deleteCert;
179 FreeCertFunc freeCert; /* optional */
180 PFN_CERT_STORE_PROV_CONTROL control; /* optional */
181 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
182
183 /* A certificate context has pointers to data that are owned by this module,
184 * so rather than duplicate the data every time a certificate context is
185 * copied, I keep a reference count to the data. Thus I have two data
186 * structures, the "true" certificate context (that has the reference count)
187 * and a reference certificate context, that has a pointer to the true context.
188 * Each one can be cast to a PCERT_CONTEXT, though you'll usually be dealing
189 * with the reference version.
190 */
191 typedef struct _WINE_CERT_CONTEXT
192 {
193 CERT_CONTEXT cert;
194 LONG ref;
195 CRITICAL_SECTION cs;
196 struct list extendedProperties;
197 } WINE_CERT_CONTEXT, *PWINE_CERT_CONTEXT;
198
199 typedef struct _WINE_CERT_CONTEXT_REF
200 {
201 CERT_CONTEXT cert;
202 WINE_CERT_CONTEXT *context;
203 } WINE_CERT_CONTEXT_REF, *PWINE_CERT_CONTEXT_REF;
204
205 /* An extended certificate property in serialized form is prefixed by this
206 * header.
207 */
208 typedef struct _WINE_CERT_PROP_HEADER
209 {
210 DWORD propID;
211 DWORD unknown; /* always 1 */
212 DWORD cb;
213 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
214
215 /* Stores an extended property in a cert. */
216 typedef struct _WINE_CERT_PROPERTY
217 {
218 WINE_CERT_PROP_HEADER hdr;
219 LPBYTE pbData;
220 struct list entry;
221 } WINE_CERT_PROPERTY, *PWINE_CERT_PROPERTY;
222
223 /* A mem store has a list of these. They're also returned by the mem store
224 * during enumeration.
225 */
226 typedef struct _WINE_CERT_LIST_ENTRY
227 {
228 WINE_CERT_CONTEXT_REF cert;
229 struct list entry;
230 } WINE_CERT_LIST_ENTRY, *PWINE_CERT_LIST_ENTRY;
231
232 typedef struct _WINE_MEMSTORE
233 {
234 WINECRYPT_CERTSTORE hdr;
235 CRITICAL_SECTION cs;
236 struct list certs;
237 } WINE_MEMSTORE, *PWINE_MEMSTORE;
238
239 typedef struct _WINE_HASH_TO_DELETE
240 {
241 BYTE hash[20];
242 struct list entry;
243 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
244
245 /* Returned by a reg store during enumeration. */
246 typedef struct _WINE_REG_CERT_CONTEXT
247 {
248 WINE_CERT_CONTEXT_REF cert;
249 PWINE_CERT_CONTEXT_REF childContext;
250 } WINE_REG_CERT_CONTEXT, *PWINE_REG_CERT_CONTEXT;
251
252 typedef struct _WINE_REGSTORE
253 {
254 WINECRYPT_CERTSTORE hdr;
255 PWINECRYPT_CERTSTORE memStore;
256 HKEY key;
257 BOOL dirty;
258 CRITICAL_SECTION cs;
259 struct list certsToDelete;
260 } WINE_REGSTORE, *PWINE_REGSTORE;
261
262 typedef struct _WINE_STORE_LIST_ENTRY
263 {
264 PWINECRYPT_CERTSTORE store;
265 DWORD dwUpdateFlags;
266 DWORD dwPriority;
267 struct list entry;
268 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
269
270 /* Returned by a collection store during enumeration.
271 * Note: relies on the list entry being valid after use, which a number of
272 * conditions might make untrue (reentrancy, closing a collection store before
273 * continuing an enumeration on it, ...). The tests seem to indicate this
274 * sort of unsafety is okay, since Windows isn't well-behaved in these
275 * scenarios either.
276 */
277 typedef struct _WINE_COLLECTION_CERT_CONTEXT
278 {
279 WINE_CERT_CONTEXT_REF cert;
280 PWINE_STORE_LIST_ENTRY entry;
281 PWINE_CERT_CONTEXT_REF childContext;
282 } WINE_COLLECTION_CERT_CONTEXT, *PWINE_COLLECTION_CERT_CONTEXT;
283
284 typedef struct _WINE_COLLECTIONSTORE
285 {
286 WINECRYPT_CERTSTORE hdr;
287 CRITICAL_SECTION cs;
288 struct list stores;
289 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
290
291 /* Like CertGetCertificateContextProperty, but operates directly on the
292 * WINE_CERT_CONTEXT. Doesn't support special-case properties, since they
293 * are handled by CertGetCertificateContextProperty, and are particular to the
294 * store in which the property exists (which is separate from the context.)
295 */
296 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
297 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData);
298
299 /* Like CertSetCertificateContextProperty, but operates directly on the
300 * WINE_CERT_CONTEXT. Doesn't handle special cases, since they're handled by
301 * CertSetCertificateContextProperty anyway.
302 */
303 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
304 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData);
305
306 /* Helper function for store reading functions and
307 * CertAddSerializedElementToStore. Returns a context of the appropriate type
308 * if it can, or NULL otherwise. Doesn't validate any of the properties in
309 * the serialized context (for example, bad hashes are retained.)
310 * *pdwContentType is set to the type of the returned context.
311 */
312 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
313 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
314
315 /* filter for page-fault exceptions */
316 /*
317 static WINE_EXCEPTION_FILTER(page_fault)
318 {
319 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
320 return EXCEPTION_EXECUTE_HANDLER;
321 return EXCEPTION_CONTINUE_SEARCH;
322 }
323 */
324
325 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
326 DWORD dwFlags, CertStoreType type)
327 {
328 store->ref = 1;
329 store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
330 store->type = type;
331 if (!hCryptProv)
332 {
333 hCryptProv = CRYPT_GetDefaultProvider();
334 dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
335 }
336 store->cryptProv = hCryptProv;
337 store->dwOpenFlags = dwFlags;
338 }
339
340 /* Initializes the reference ref to point to pCertContext, which is assumed to
341 * be a PWINE_CERT_CONTEXT, and increments pCertContext's reference count.
342 * Also sets the hCertStore member of the reference to store.
343 */
344
345 static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
346 PWINE_CERT_CONTEXT context, HCERTSTORE store)
347 {
348 TRACE("(%p, %p)\n", ref, context);
349 memcpy(&ref->cert, context, sizeof(ref->cert));
350 ref->context = context;
351 InterlockedIncrement(&context->ref);
352 ref->cert.hCertStore = store;
353 }
354
355 static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
356 HCERTSTORE store)
357 {
358 PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
359 sizeof(WINE_CERT_CONTEXT_REF));
360
361 if (pCertRef)
362 CRYPT_InitCertRef(pCertRef, context, store);
363 return pCertRef;
364 }
365
366 static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
367 DWORD dwAddDisposition)
368 {
369 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
370 BOOL add = FALSE, ret;
371
372 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
373
374 switch (dwAddDisposition)
375 {
376 case CERT_STORE_ADD_ALWAYS:
377 add = TRUE;
378 break;
379 case CERT_STORE_ADD_NEW:
380 {
381 BYTE hashToAdd[20], hash[20];
382 DWORD size = sizeof(hashToAdd);
383
384 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
385 CERT_HASH_PROP_ID, hashToAdd, &size);
386 if (ret)
387 {
388 PWINE_CERT_LIST_ENTRY cursor;
389
390 /* Add if no cert with the same hash is found. */
391 add = TRUE;
392 EnterCriticalSection(&ms->cs);
393 LIST_FOR_EACH_ENTRY(cursor, &ms->certs, WINE_CERT_LIST_ENTRY, entry)
394 {
395 size = sizeof(hash);
396 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
397 CERT_HASH_PROP_ID, hash, &size);
398 if (ret && !memcmp(hashToAdd, hash, size))
399 {
400 TRACE("found matching certificate, not adding\n");
401 SetLastError(CRYPT_E_EXISTS);
402 add = FALSE;
403 break;
404 }
405 }
406 LeaveCriticalSection(&ms->cs);
407 }
408 break;
409 }
410 case CERT_STORE_ADD_REPLACE_EXISTING:
411 {
412 BYTE hashToAdd[20], hash[20];
413 DWORD size = sizeof(hashToAdd);
414
415 add = TRUE;
416 ret = CRYPT_GetCertificateContextProperty((PWINE_CERT_CONTEXT)pCert,
417 CERT_HASH_PROP_ID, hashToAdd, &size);
418 if (ret)
419 {
420 PWINE_CERT_LIST_ENTRY cursor, next;
421
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)
426 {
427 size = sizeof(hash);
428 ret = CertGetCertificateContextProperty(&cursor->cert.cert,
429 CERT_HASH_PROP_ID, hash, &size);
430 if (ret && !memcmp(hashToAdd, hash, size))
431 {
432 TRACE("found matching certificate, replacing\n");
433 list_remove(&cursor->entry);
434 CertFreeCertificateContext((PCCERT_CONTEXT)cursor);
435 break;
436 }
437 }
438 LeaveCriticalSection(&ms->cs);
439 }
440 break;
441 }
442 default:
443 FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
444 add = FALSE;
445 }
446 if (add)
447 {
448 PWINE_CERT_LIST_ENTRY entry = CryptMemAlloc(
449 sizeof(WINE_CERT_LIST_ENTRY));
450
451 if (entry)
452 {
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);
459 ret = TRUE;
460 }
461 else
462 ret = FALSE;
463 }
464 else
465 ret = FALSE;
466 return ret;
467 }
468
469 static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
470 PWINE_CERT_CONTEXT_REF pPrev)
471 {
472 WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
473 PWINE_CERT_LIST_ENTRY prevEntry = (PWINE_CERT_LIST_ENTRY)pPrev, ret;
474 struct list *listNext;
475
476 TRACE("(%p, %p)\n", store, pPrev);
477 EnterCriticalSection(&ms->cs);
478 if (prevEntry)
479 {
480 listNext = list_next(&ms->certs, &prevEntry->entry);
481 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
482 }
483 else
484 listNext = list_next(&ms->certs, &ms->certs);
485 if (listNext)
486 {
487 ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
488 memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
489 sizeof(WINE_CERT_LIST_ENTRY));
490 InterlockedIncrement(&ret->cert.context->ref);
491 }
492 else
493 {
494 SetLastError(CRYPT_E_NOT_FOUND);
495 ret = NULL;
496 }
497 LeaveCriticalSection(&ms->cs);
498
499 TRACE("returning %p\n", ret);
500 return (PWINE_CERT_CONTEXT_REF)ret;
501 }
502
503 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
504 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
505 {
506 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
507 WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
508 PWINE_CERT_LIST_ENTRY cert, next;
509 BOOL ret;
510
511 /* Find the entry associated with the passed-in context, since the
512 * passed-in context may not be a list entry itself (e.g. if it came from
513 * CertDuplicateCertificateContext.) Pointing to the same context is
514 * a sufficient test of equality.
515 */
516 EnterCriticalSection(&store->cs);
517 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
518 entry)
519 {
520 if (cert->cert.context == ref->context)
521 {
522 TRACE("removing %p\n", cert);
523 /* FIXME: this isn't entirely thread-safe, the entry itself isn't
524 * protected.
525 */
526 list_remove(&cert->entry);
527 cert->entry.prev = cert->entry.next = &store->certs;
528 break;
529 }
530 }
531 ret = TRUE;
532 LeaveCriticalSection(&store->cs);
533 return ret;
534 }
535
536 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
537 {
538 WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
539 PWINE_CERT_LIST_ENTRY cert, next;
540
541 TRACE("(%p, %08lx)\n", store, dwFlags);
542 if (dwFlags)
543 FIXME("Unimplemented flags: %08lx\n", dwFlags);
544
545 /* Note that CertFreeCertificateContext calls HeapFree on the passed-in
546 * pointer if its ref-count reaches zero. That's okay here because there
547 * aren't any allocated data outside of the WINE_CERT_CONTEXT_REF portion
548 * of the CertListEntry.
549 */
550 LIST_FOR_EACH_ENTRY_SAFE(cert, next, &store->certs, WINE_CERT_LIST_ENTRY,
551 entry)
552 {
553 TRACE("removing %p\n", cert);
554 list_remove(&cert->entry);
555 CertFreeCertificateContext((PCCERT_CONTEXT)cert);
556 }
557 DeleteCriticalSection(&store->cs);
558 CryptMemFree(store);
559 }
560
561 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
562 DWORD dwFlags, const void *pvPara)
563 {
564 PWINE_MEMSTORE store;
565
566 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
567
568 if (dwFlags & CERT_STORE_DELETE_FLAG)
569 {
570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
571 store = NULL;
572 }
573 else
574 {
575 store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
576 if (store)
577 {
578 memset(store, 0, sizeof(WINE_MEMSTORE));
579 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
580 store->hdr.closeStore = CRYPT_MemCloseStore;
581 store->hdr.addCert = CRYPT_MemAddCert;
582 store->hdr.createCertRef = CRYPT_CreateCertRef;
583 store->hdr.enumCert = CRYPT_MemEnumCert;
584 store->hdr.deleteCert = CRYPT_MemDeleteCert;
585 store->hdr.freeCert = NULL;
586 InitializeCriticalSection(&store->cs);
587 list_init(&store->certs);
588 }
589 }
590 return (PWINECRYPT_CERTSTORE)store;
591 }
592
593 static BOOL WINAPI CRYPT_CollectionAddCert(HCERTSTORE store,
594 PCCERT_CONTEXT pCert, DWORD dwAddDisposition)
595 {
596 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
597 PWINE_STORE_LIST_ENTRY entry, next;
598 BOOL ret;
599
600 TRACE("(%p, %p, %ld)\n", store, pCert, dwAddDisposition);
601
602 ret = FALSE;
603 EnterCriticalSection(&cs->cs);
604 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
605 entry)
606 {
607 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
608 {
609 ret = entry->store->addCert(entry->store, pCert, dwAddDisposition);
610 break;
611 }
612 }
613 LeaveCriticalSection(&cs->cs);
614 SetLastError(ret ? ERROR_SUCCESS : HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED));
615 return ret;
616 }
617
618 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionCreateCertRef(
619 PWINE_CERT_CONTEXT context, HCERTSTORE store)
620 {
621 PWINE_COLLECTION_CERT_CONTEXT ret = CryptMemAlloc(
622 sizeof(WINE_COLLECTION_CERT_CONTEXT));
623
624 if (ret)
625 {
626 /* Initialize to empty for now, just make sure the size is right */
627 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
628 ret->entry = NULL;
629 ret->childContext = NULL;
630 }
631 return (PWINE_CERT_CONTEXT_REF)ret;
632 }
633
634 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
635 {
636 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
637 PWINE_STORE_LIST_ENTRY entry, next;
638
639 TRACE("(%p, %08lx)\n", store, dwFlags);
640
641 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
642 entry)
643 {
644 TRACE("closing %p\n", entry);
645 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
646 CryptMemFree(entry);
647 }
648 DeleteCriticalSection(&cs->cs);
649 CryptMemFree(cs);
650 }
651
652 /* Advances a collection enumeration by one cert, if possible, where advancing
653 * means:
654 * - calling the current store's enumeration function once, and returning
655 * the enumerated cert if one is returned
656 * - moving to the next store if the current store has no more items, and
657 * recursively calling itself to get the next item.
658 * Returns NULL if the collection contains no more items or on error.
659 * Assumes the collection store's lock is held.
660 */
661 static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
662 PWINE_COLLECTIONSTORE store, PWINE_STORE_LIST_ENTRY storeEntry,
663 PWINE_COLLECTION_CERT_CONTEXT pPrev)
664 {
665 PWINE_COLLECTION_CERT_CONTEXT ret;
666 PWINE_CERT_CONTEXT_REF child;
667
668 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
669
670 if (pPrev)
671 {
672 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
673 pPrev->childContext);
674 if (child)
675 {
676 ret = pPrev;
677 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
678 ret->cert.cert.hCertStore = (HCERTSTORE)store;
679 InterlockedIncrement(&ret->cert.context->ref);
680 ret->childContext = child;
681 }
682 else
683 {
684 struct list *storeNext = list_next(&store->stores,
685 &storeEntry->entry);
686
687 pPrev->childContext = NULL;
688 CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
689 if (storeNext)
690 {
691 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
692 entry);
693 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
694 }
695 else
696 {
697 SetLastError(CRYPT_E_NOT_FOUND);
698 ret = NULL;
699 }
700 }
701 }
702 else
703 {
704 child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
705 NULL);
706 if (child)
707 {
708 ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
709 child->context, store);
710 if (ret)
711 {
712 ret->entry = storeEntry;
713 ret->childContext = child;
714 }
715 else
716 CertFreeCertificateContext((PCCERT_CONTEXT)child);
717 }
718 else
719 {
720 struct list *storeNext = list_next(&store->stores,
721 &storeEntry->entry);
722
723 if (storeNext)
724 {
725 storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
726 entry);
727 ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
728 }
729 else
730 {
731 SetLastError(CRYPT_E_NOT_FOUND);
732 ret = NULL;
733 }
734 }
735 }
736 TRACE("returning %p\n", ret);
737 return ret;
738 }
739
740 static PWINE_CERT_CONTEXT_REF CRYPT_CollectionEnumCert(
741 PWINECRYPT_CERTSTORE store, PWINE_CERT_CONTEXT_REF pPrev)
742 {
743 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
744 PWINE_COLLECTION_CERT_CONTEXT prevEntry =
745 (PWINE_COLLECTION_CERT_CONTEXT)pPrev, ret;
746
747 TRACE("(%p, %p)\n", store, pPrev);
748
749 if (prevEntry)
750 {
751 EnterCriticalSection(&cs->cs);
752 ret = CRYPT_CollectionAdvanceEnum(cs, prevEntry->entry, prevEntry);
753 LeaveCriticalSection(&cs->cs);
754 }
755 else
756 {
757 EnterCriticalSection(&cs->cs);
758 if (!list_empty(&cs->stores))
759 {
760 PWINE_STORE_LIST_ENTRY storeEntry;
761
762 storeEntry = LIST_ENTRY(cs->stores.next, WINE_STORE_LIST_ENTRY,
763 entry);
764 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry, prevEntry);
765 }
766 else
767 {
768 SetLastError(CRYPT_E_NOT_FOUND);
769 ret = NULL;
770 }
771 LeaveCriticalSection(&cs->cs);
772 }
773 TRACE("returning %p\n", ret);
774 return (PWINE_CERT_CONTEXT_REF)ret;
775 }
776
777 static BOOL WINAPI CRYPT_CollectionDeleteCert(HCERTSTORE hCertStore,
778 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
779 {
780 PWINE_COLLECTION_CERT_CONTEXT context =
781 (PWINE_COLLECTION_CERT_CONTEXT)pCertContext;
782 BOOL ret;
783
784 TRACE("(%p, %p, %08lx)\n", hCertStore, pCertContext, dwFlags);
785
786 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)context->childContext);
787 if (ret)
788 context->childContext = NULL;
789 return ret;
790 }
791
792 static void CRYPT_CollectionFreeCert(PWINE_CERT_CONTEXT_REF ref)
793 {
794 PWINE_COLLECTION_CERT_CONTEXT context = (PWINE_COLLECTION_CERT_CONTEXT)ref;
795
796 TRACE("(%p)\n", ref);
797
798 if (context->childContext)
799 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
800 }
801
802 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
803 DWORD dwFlags, const void *pvPara)
804 {
805 PWINE_COLLECTIONSTORE store;
806
807 if (dwFlags & CERT_STORE_DELETE_FLAG)
808 {
809 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
810 store = NULL;
811 }
812 else
813 {
814 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
815 if (store)
816 {
817 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
818 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
819 StoreTypeCollection);
820 store->hdr.closeStore = CRYPT_CollectionCloseStore;
821 store->hdr.addCert = CRYPT_CollectionAddCert;
822 store->hdr.createCertRef = CRYPT_CollectionCreateCertRef;
823 store->hdr.enumCert = CRYPT_CollectionEnumCert;
824 store->hdr.deleteCert = CRYPT_CollectionDeleteCert;
825 store->hdr.freeCert = CRYPT_CollectionFreeCert;
826 InitializeCriticalSection(&store->cs);
827 list_init(&store->stores);
828 }
829 }
830 return (PWINECRYPT_CERTSTORE)store;
831 }
832
833 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
834 {
835 static const WCHAR fmt[] = { '%','0','2','X',0 };
836 DWORD i;
837
838 assert(hash);
839 assert(asciiHash);
840
841 for (i = 0; i < 20; i++)
842 wsprintfW(asciiHash + i * 2, fmt, hash[i]);
843 }
844
845 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
846 0 };
847 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
848 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
849 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
850
851 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
852 DWORD contextType)
853 {
854 LONG rc;
855 DWORD index = 0;
856 WCHAR subKeyName[MAX_PATH];
857
858 do {
859 DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
860
861 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
862 NULL);
863 if (!rc)
864 {
865 HKEY subKey;
866
867 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
868 if (!rc)
869 {
870 LPBYTE buf = NULL;
871
872 size = 0;
873 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
874 if (!rc)
875 buf = CryptMemAlloc(size);
876 if (buf)
877 {
878 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
879 &size);
880 if (!rc)
881 {
882 const void *context;
883 DWORD addedType;
884
885 TRACE("Adding cert with hash %s\n",
886 debugstr_w(subKeyName));
887 context = CRYPT_ReadSerializedElement(buf, size,
888 contextType, &addedType);
889 if (context)
890 {
891 const WINE_CONTEXT_INTERFACE *contextInterface;
892 BYTE hash[20];
893
894 switch (addedType)
895 {
896 case CERT_STORE_CERTIFICATE_CONTEXT:
897 contextInterface = &gCertInterface;
898 break;
899 case CERT_STORE_CRL_CONTEXT:
900 contextInterface = &gCRLInterface;
901 break;
902 case CERT_STORE_CTL_CONTEXT:
903 contextInterface = &gCTLInterface;
904 break;
905 default:
906 contextInterface = NULL;
907 }
908 if (contextInterface)
909 {
910 size = sizeof(hash);
911 if (contextInterface->getProp(context,
912 CERT_HASH_PROP_ID, hash, &size))
913 {
914 WCHAR asciiHash[20 * 2 + 1];
915
916 CRYPT_HashToStr(hash, asciiHash);
917 TRACE("comparing %s\n",
918 debugstr_w(asciiHash));
919 TRACE("with %s\n", debugstr_w(subKeyName));
920 if (!lstrcmpW(asciiHash, subKeyName))
921 {
922 TRACE("hash matches, adding\n");
923 contextInterface->addContextToStore(
924 store, context,
925 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
926 }
927 else
928 {
929 TRACE("hash doesn't match, ignoring\n");
930 contextInterface->free(context);
931 }
932 }
933 }
934 }
935 }
936 CryptMemFree(buf);
937 }
938 RegCloseKey(subKey);
939 }
940 /* Ignore intermediate errors, continue enumerating */
941 rc = ERROR_SUCCESS;
942 }
943 } while (!rc);
944 }
945
946 static void CRYPT_RegReadFromReg(PWINE_REGSTORE store)
947 {
948 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
949 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
950 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
951 DWORD i;
952
953 for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
954 {
955 HKEY key;
956 LONG rc;
957
958 rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
959 &key, NULL);
960 if (!rc)
961 {
962 CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
963 RegCloseKey(key);
964 }
965 }
966 }
967
968 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
969 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
970 DWORD len)
971 {
972 WCHAR asciiHash[20 * 2 + 1];
973 LONG rc;
974 HKEY subKey;
975 BOOL ret;
976
977 CRYPT_HashToStr(hash, asciiHash);
978 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
979 &subKey, NULL);
980 if (!rc)
981 {
982 rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
983 RegCloseKey(subKey);
984 }
985 if (!rc)
986 ret = TRUE;
987 else
988 {
989 SetLastError(rc);
990 ret = FALSE;
991 }
992 return ret;
993 }
994
995 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
996 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
997 {
998 const void *context = NULL;
999 BOOL ret;
1000
1001 do {
1002 context = contextInterface->enumContextsInStore(memStore, context);
1003 if (context)
1004 {
1005 BYTE hash[20];
1006 DWORD hashSize = sizeof(hash);
1007
1008 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1009 &hashSize);
1010 if (ret)
1011 {
1012 DWORD size = 0;
1013 LPBYTE buf = NULL;
1014
1015 ret = contextInterface->serialize(context, 0, NULL, &size);
1016 if (size)
1017 buf = CryptMemAlloc(size);
1018 if (buf)
1019 {
1020 ret = contextInterface->serialize(context, 0, buf, &size);
1021 if (ret)
1022 ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1023 }
1024 CryptMemFree(buf);
1025 }
1026 }
1027 else
1028 ret = TRUE;
1029 } while (ret && context != NULL);
1030 if (context)
1031 contextInterface->free(context);
1032 return ret;
1033 }
1034
1035 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTORE store)
1036 {
1037 static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1038 static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1039 &gCRLInterface, &gCTLInterface };
1040 struct list *listToDelete[] = { &store->certsToDelete, NULL, NULL };
1041 BOOL ret = TRUE;
1042 DWORD i;
1043
1044 for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1045 {
1046 HKEY key;
1047 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1048 KEY_ALL_ACCESS, NULL, &key, NULL);
1049
1050 if (!rc)
1051 {
1052 if (listToDelete[i])
1053 {
1054 PWINE_HASH_TO_DELETE toDelete, next;
1055 WCHAR asciiHash[20 * 2 + 1];
1056
1057 EnterCriticalSection(&store->cs);
1058 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1059 WINE_HASH_TO_DELETE, entry)
1060 {
1061 LONG rc;
1062
1063 CRYPT_HashToStr(toDelete->hash, asciiHash);
1064 TRACE("Removing %s\n", debugstr_w(asciiHash));
1065 rc = RegDeleteKeyW(key, asciiHash);
1066 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1067 {
1068 SetLastError(rc);
1069 ret = FALSE;
1070 }
1071 list_remove(&toDelete->entry);
1072 CryptMemFree(toDelete);
1073 }
1074 LeaveCriticalSection(&store->cs);
1075 }
1076 ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1077 store->memStore);
1078 RegCloseKey(key);
1079 }
1080 else
1081 {
1082 SetLastError(rc);
1083 ret = FALSE;
1084 }
1085 }
1086 return ret;
1087 }
1088
1089 /* If force is true or the registry store is dirty, writes the contents of the
1090 * store to the registry.
1091 */
1092 static BOOL CRYPT_RegFlushStore(PWINE_REGSTORE store, BOOL force)
1093 {
1094 BOOL ret;
1095
1096 if (store->dirty || force)
1097 ret = CRYPT_RegWriteToReg(store);
1098 else
1099 ret = TRUE;
1100 return ret;
1101 }
1102
1103 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1104 {
1105 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1106
1107 TRACE("(%p, %08lx)\n", store, dwFlags);
1108 if (dwFlags)
1109 FIXME("Unimplemented flags: %08lx\n", dwFlags);
1110
1111 CRYPT_RegFlushStore(store, FALSE);
1112 /* certsToDelete should already be cleared by this point */
1113 store->memStore->closeStore(store->memStore, 0);
1114 RegCloseKey(store->key);
1115 DeleteCriticalSection(&store->cs);
1116 CryptMemFree(store);
1117 }
1118
1119 static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
1120 DWORD dwAddDisposition)
1121 {
1122 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1123 BOOL ret;
1124
1125 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwAddDisposition);
1126
1127 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1128 {
1129 SetLastError(ERROR_ACCESS_DENIED);
1130 ret = FALSE;
1131 }
1132 else
1133 {
1134 ret = store->memStore->addCert(store->memStore, cert, dwAddDisposition);
1135 if (ret)
1136 store->dirty = TRUE;
1137 }
1138 return ret;
1139 }
1140
1141 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
1142 PWINE_CERT_CONTEXT context, HCERTSTORE store)
1143 {
1144 PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(
1145 sizeof(WINE_REG_CERT_CONTEXT));
1146
1147 if (ret)
1148 {
1149 CRYPT_InitCertRef((PWINE_CERT_CONTEXT_REF)ret, context, store);
1150 ret->childContext = NULL;
1151 }
1152 return (PWINE_CERT_CONTEXT_REF)ret;
1153 }
1154
1155 static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
1156 PWINE_CERT_CONTEXT_REF pPrev)
1157 {
1158 PWINE_REGSTORE rs = (PWINE_REGSTORE)store;
1159 PWINE_CERT_CONTEXT_REF child;
1160 PWINE_REG_CERT_CONTEXT prev = (PWINE_REG_CERT_CONTEXT)pPrev, ret = NULL;
1161
1162 TRACE("(%p, %p)\n", store, pPrev);
1163
1164 if (pPrev)
1165 {
1166 child = rs->memStore->enumCert(rs->memStore, prev->childContext);
1167 if (child)
1168 {
1169 ret = (PWINE_REG_CERT_CONTEXT)pPrev;
1170 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1171 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1172 ret->childContext = child;
1173 }
1174 }
1175 else
1176 {
1177 child = rs->memStore->enumCert(rs->memStore, NULL);
1178 if (child)
1179 {
1180 ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
1181
1182 if (ret)
1183 {
1184 memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
1185 ret->cert.cert.hCertStore = (HCERTSTORE)store;
1186 ret->childContext = child;
1187 }
1188 else
1189 CertFreeCertificateContext((PCCERT_CONTEXT)child);
1190 }
1191 }
1192 return (PWINE_CERT_CONTEXT_REF)ret;
1193 }
1194
1195 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1196 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1197 {
1198 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1199 BOOL ret;
1200
1201 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1202
1203 if (store->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
1204 {
1205 SetLastError(ERROR_ACCESS_DENIED);
1206 ret = FALSE;
1207 }
1208 else
1209 {
1210 PWINE_HASH_TO_DELETE toDelete =
1211 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1212
1213 if (toDelete)
1214 {
1215 DWORD size = sizeof(toDelete->hash);
1216
1217 ret = CertGetCertificateContextProperty(pCertContext,
1218 CERT_HASH_PROP_ID, toDelete->hash, &size);
1219 if (ret)
1220 {
1221 list_init(&toDelete->entry);
1222 EnterCriticalSection(&store->cs);
1223 list_add_tail(&store->certsToDelete, &toDelete->entry);
1224 LeaveCriticalSection(&store->cs);
1225 ret = store->memStore->deleteCert(store->memStore, pCertContext,
1226 dwFlags);
1227 }
1228 else
1229 CryptMemFree(toDelete);
1230 }
1231 else
1232 ret = FALSE;
1233 if (ret)
1234 store->dirty = TRUE;
1235 }
1236 return ret;
1237 }
1238
1239 static void CRYPT_RegFreeCert(PWINE_CERT_CONTEXT_REF ref)
1240 {
1241 PWINE_REG_CERT_CONTEXT context = (PWINE_REG_CERT_CONTEXT)ref;
1242
1243 TRACE("(%p)\n", ref);
1244
1245 if (context->childContext)
1246 CertFreeCertificateContext((PCCERT_CONTEXT)context->childContext);
1247 }
1248
1249 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1250 DWORD dwCtrlType, void const *pvCtrlPara)
1251 {
1252 PWINE_REGSTORE store = (PWINE_REGSTORE)hCertStore;
1253 BOOL ret;
1254
1255 switch (dwCtrlType)
1256 {
1257 case CERT_STORE_CTRL_RESYNC:
1258 CRYPT_RegFlushStore(store, FALSE);
1259 store->memStore->closeStore(store->memStore, 0);
1260 store->memStore = CRYPT_MemOpenStore(store->hdr.cryptProv,
1261 store->hdr.dwOpenFlags, NULL);
1262 if (store->memStore)
1263 {
1264 CRYPT_RegReadFromReg(store);
1265 ret = TRUE;
1266 }
1267 else
1268 ret = FALSE;
1269 break;
1270 case CERT_STORE_CTRL_COMMIT:
1271 ret = CRYPT_RegFlushStore(store,
1272 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1273 break;
1274 default:
1275 FIXME("%ld: stub\n", dwCtrlType);
1276 ret = FALSE;
1277 }
1278 return ret;
1279 }
1280
1281 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1282 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1283 {
1284 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1285 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1286 HKEY hSubKey = 0;
1287
1288 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1289
1290 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1291 if (!dwRet)
1292 {
1293 /* Find how many subkeys there are */
1294 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1295 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1296 if (!dwRet)
1297 {
1298 dwMaxSubkeyLen++;
1299 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1300 {
1301 /* Name too big: alloc a buffer for it */
1302 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1303 }
1304
1305 if (!lpszName)
1306 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1307 else
1308 {
1309 /* Recursively delete all the subkeys */
1310 for (i = 0; i < dwKeyCount && !dwRet; i++)
1311 {
1312 dwSize = dwMaxSubkeyLen;
1313 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1314 NULL, NULL, NULL);
1315 if (!dwRet)
1316 dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1317 }
1318
1319 if (lpszName != szNameBuf)
1320 {
1321 /* Free buffer if allocated */
1322 CryptMemFree(lpszName);
1323 }
1324 }
1325 }
1326
1327 RegCloseKey(hSubKey);
1328 if (!dwRet)
1329 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1330 }
1331 return dwRet;
1332 }
1333
1334 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1335 DWORD dwFlags, const void *pvPara)
1336 {
1337 PWINE_REGSTORE store = NULL;
1338
1339 TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1340
1341 if (dwFlags & CERT_STORE_DELETE_FLAG)
1342 {
1343 DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1344
1345 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1346 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1347 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1348 rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1349 if (rc == ERROR_NO_MORE_ITEMS)
1350 rc = ERROR_SUCCESS;
1351 SetLastError(rc);
1352 }
1353 else
1354 {
1355 HKEY key;
1356
1357 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1358 GetCurrentProcess(), (LPHANDLE)&key,
1359 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1360 TRUE, 0))
1361 {
1362 PWINECRYPT_CERTSTORE memStore;
1363
1364 memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1365 if (memStore)
1366 {
1367 store = CryptMemAlloc(sizeof(WINE_REGSTORE));
1368 if (store)
1369 {
1370 memset(store, 0, sizeof(WINE_REGSTORE));
1371 CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
1372 StoreTypeReg);
1373 store->hdr.closeStore = CRYPT_RegCloseStore;
1374 store->hdr.addCert = CRYPT_RegAddCert;
1375 store->hdr.createCertRef = CRYPT_RegCreateCertRef;
1376 store->hdr.enumCert = CRYPT_RegEnumCert;
1377 store->hdr.deleteCert = CRYPT_RegDeleteCert;
1378 store->hdr.freeCert = CRYPT_RegFreeCert;
1379 store->hdr.control = CRYPT_RegControl;
1380 store->memStore = memStore;
1381 store->key = key;
1382 InitializeCriticalSection(&store->cs);
1383 list_init(&store->certsToDelete);
1384 CRYPT_RegReadFromReg(store);
1385 store->dirty = FALSE;
1386 }
1387 }
1388 }
1389 }
1390 TRACE("returning %p\n", store);
1391 return (WINECRYPT_CERTSTORE *)store;
1392 }
1393
1394 /* FIXME: this isn't complete for the Root store, in which the top-level
1395 * self-signed CA certs reside. Adding a cert to the Root store should present
1396 * the user with a dialog indicating the consequences of doing so, and asking
1397 * the user to confirm whether the cert should be added.
1398 */
1399 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1400 DWORD dwFlags, const void *pvPara)
1401 {
1402 static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1403 LPCWSTR storeName = (LPCWSTR)pvPara;
1404 LPWSTR storePath;
1405 PWINECRYPT_CERTSTORE store = NULL;
1406 HKEY root;
1407 LPCWSTR base;
1408 BOOL ret;
1409
1410 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1411 debugstr_w((LPCWSTR)pvPara));
1412
1413 if (!pvPara)
1414 {
1415 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1416 return NULL;
1417 }
1418
1419 ret = TRUE;
1420 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1421 {
1422 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1423 root = HKEY_LOCAL_MACHINE;
1424 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1425 break;
1426 case CERT_SYSTEM_STORE_CURRENT_USER:
1427 root = HKEY_CURRENT_USER;
1428 base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1429 break;
1430 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1431 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1432 * SystemCertificates
1433 */
1434 FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1435 debugstr_w(storeName));
1436 return NULL;
1437 case CERT_SYSTEM_STORE_SERVICES:
1438 /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1439 * SystemCertificates
1440 */
1441 FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1442 debugstr_w(storeName));
1443 return NULL;
1444 case CERT_SYSTEM_STORE_USERS:
1445 /* hku\user sid\Software\Microsoft\SystemCertificates */
1446 FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1447 debugstr_w(storeName));
1448 return NULL;
1449 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1450 root = HKEY_CURRENT_USER;
1451 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1452 break;
1453 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1454 root = HKEY_LOCAL_MACHINE;
1455 base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1456 break;
1457 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1458 /* hklm\Software\Microsoft\EnterpriseCertificates */
1459 FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1460 debugstr_w(storeName));
1461 return NULL;
1462 default:
1463 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1464 return NULL;
1465 }
1466
1467 storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1468 sizeof(WCHAR));
1469 if (storePath)
1470 {
1471 LONG rc;
1472 HKEY key;
1473 REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1474 KEY_ALL_ACCESS;
1475
1476 wsprintfW(storePath, fmt, base, storeName);
1477 if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1478 rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1479 else
1480 {
1481 DWORD disp;
1482
1483 rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1484 &key, &disp);
1485 if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1486 disp == REG_OPENED_EXISTING_KEY)
1487 {
1488 RegCloseKey(key);
1489 rc = ERROR_FILE_EXISTS;
1490 }
1491 }
1492 if (!rc)
1493 {
1494 store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1495 RegCloseKey(key);
1496 }
1497 else
1498 SetLastError(rc);
1499 CryptMemFree(storePath);
1500 }
1501 return store;
1502 }
1503
1504 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1505 DWORD dwFlags, const void *pvPara)
1506 {
1507 int len;
1508 PWINECRYPT_CERTSTORE ret = NULL;
1509
1510 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1511 debugstr_a((LPCSTR)pvPara));
1512
1513 if (!pvPara)
1514 {
1515 SetLastError(ERROR_FILE_NOT_FOUND);
1516 return NULL;
1517 }
1518 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1519 if (len)
1520 {
1521 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1522
1523 if (storeName)
1524 {
1525 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1526 ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1527 CryptMemFree(storeName);
1528 }
1529 }
1530 return ret;
1531 }
1532
1533 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1534 DWORD dwFlags, const void *pvPara)
1535 {
1536 HCERTSTORE store = 0;
1537 BOOL ret;
1538
1539 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1540 debugstr_w((LPCWSTR)pvPara));
1541
1542 if (!pvPara)
1543 {
1544 SetLastError(ERROR_FILE_NOT_FOUND);
1545 return NULL;
1546 }
1547 /* This returns a different error than system registry stores if the
1548 * location is invalid.
1549 */
1550 switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1551 {
1552 case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1553 case CERT_SYSTEM_STORE_CURRENT_USER:
1554 case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1555 case CERT_SYSTEM_STORE_SERVICES:
1556 case CERT_SYSTEM_STORE_USERS:
1557 case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1558 case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1559 case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1560 ret = TRUE;
1561 break;
1562 default:
1563 SetLastError(ERROR_FILE_NOT_FOUND);
1564 ret = FALSE;
1565 }
1566 if (ret)
1567 {
1568 HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1569 0, hCryptProv, dwFlags, pvPara);
1570
1571 if (regStore)
1572 {
1573 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1574 CERT_STORE_CREATE_NEW_FLAG, NULL);
1575 if (store)
1576 {
1577 CertAddStoreToCollection(store, regStore,
1578 dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1579 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1580 CertCloseStore(regStore, 0);
1581 }
1582 }
1583 }
1584 return (PWINECRYPT_CERTSTORE)store;
1585 }
1586
1587 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1588 DWORD dwFlags, const void *pvPara)
1589 {
1590 int len;
1591 PWINECRYPT_CERTSTORE ret = NULL;
1592
1593 TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1594 debugstr_a((LPCSTR)pvPara));
1595
1596 if (!pvPara)
1597 {
1598 SetLastError(ERROR_FILE_NOT_FOUND);
1599 return NULL;
1600 }
1601 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1602 if (len)
1603 {
1604 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1605
1606 if (storeName)
1607 {
1608 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1609 ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1610 CryptMemFree(storeName);
1611 }
1612 }
1613 return ret;
1614 }
1615
1616 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1617 DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1618 const void* pvPara)
1619 {
1620 WINECRYPT_CERTSTORE *hcs;
1621 StoreOpenFunc openFunc = NULL;
1622
1623 TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1624 dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1625
1626 if (!HIWORD(lpszStoreProvider))
1627 {
1628 switch (LOWORD(lpszStoreProvider))
1629 {
1630 case (int)CERT_STORE_PROV_MEMORY:
1631 openFunc = CRYPT_MemOpenStore;
1632 break;
1633 case (int)CERT_STORE_PROV_REG:
1634 openFunc = CRYPT_RegOpenStore;
1635 break;
1636 case (int)CERT_STORE_PROV_COLLECTION:
1637 openFunc = CRYPT_CollectionOpenStore;
1638 break;
1639 case (int)CERT_STORE_PROV_SYSTEM_A:
1640 openFunc = CRYPT_SysOpenStoreA;
1641 break;
1642 case (int)CERT_STORE_PROV_SYSTEM_W:
1643 openFunc = CRYPT_SysOpenStoreW;
1644 break;
1645 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1646 openFunc = CRYPT_SysRegOpenStoreA;
1647 break;
1648 case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1649 openFunc = CRYPT_SysRegOpenStoreW;
1650 break;
1651 default:
1652 if (LOWORD(lpszStoreProvider))
1653 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1654 }
1655 }
1656 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1657 openFunc = CRYPT_MemOpenStore;
1658 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1659 openFunc = CRYPT_SysOpenStoreW;
1660 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1661 openFunc = CRYPT_CollectionOpenStore;
1662 else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1663 openFunc = CRYPT_SysRegOpenStoreW;
1664 else
1665 {
1666 FIXME("unimplemented type %s\n", lpszStoreProvider);
1667 openFunc = NULL;
1668 }
1669
1670 if (!openFunc)
1671 {
1672 /* FIXME: need to look for an installed provider for this type */
1673 SetLastError(ERROR_FILE_NOT_FOUND);
1674 hcs = NULL;
1675 }
1676 else
1677 hcs = openFunc(hCryptProv, dwFlags, pvPara);
1678 return (HCERTSTORE)hcs;
1679 }
1680
1681 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1682 LPCSTR szSubSystemProtocol)
1683 {
1684 HCERTSTORE ret = 0;
1685
1686 if (szSubSystemProtocol)
1687 {
1688 int len = MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, NULL,
1689 0);
1690 LPWSTR param = CryptMemAlloc(len * sizeof(WCHAR));
1691
1692 if (param)
1693 {
1694 MultiByteToWideChar(CP_ACP, 0, szSubSystemProtocol, -1, param, len);
1695 ret = CertOpenSystemStoreW(hProv, param);
1696 CryptMemFree(param);
1697 }
1698 }
1699 else
1700 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1701 return ret;
1702 }
1703
1704 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1705 LPCWSTR szSubSystemProtocol)
1706 {
1707 HCERTSTORE ret;
1708
1709 if (!szSubSystemProtocol)
1710 {
1711 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1712 return 0;
1713 }
1714
1715 /* FIXME: needs some tests. It seems to open both HKEY_LOCAL_MACHINE and
1716 * HKEY_CURRENT_USER stores, but I'm not sure under what conditions, if any,
1717 * it fails.
1718 */
1719 ret = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, hProv,
1720 CERT_STORE_CREATE_NEW_FLAG, NULL);
1721 if (ret)
1722 {
1723 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1724 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE, szSubSystemProtocol);
1725
1726 if (store)
1727 {
1728 CertAddStoreToCollection(ret, store,
1729 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1730 CertCloseStore(store, 0);
1731 }
1732 store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1733 0, hProv, CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1734 if (store)
1735 {
1736 CertAddStoreToCollection(ret, store,
1737 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1738 CertCloseStore(store, 0);
1739 }
1740 }
1741 return ret;
1742 }
1743
1744 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1745 DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1746 {
1747 FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore,
1748 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1749 return TRUE;
1750 }
1751
1752 PCCRL_CONTEXT WINAPI CertCreateCRLContext( DWORD dwCertEncodingType,
1753 const BYTE* pbCrlEncoded, DWORD cbCrlEncoded)
1754 {
1755 PCRL_CONTEXT pcrl;
1756 BYTE* data;
1757
1758 TRACE("%08lx %p %08lx\n", dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
1759
1760 /* FIXME: semi-stub, need to use CryptDecodeObjectEx to decode the CRL. */
1761 pcrl = CryptMemAlloc( sizeof (CRL_CONTEXT) );
1762 if( !pcrl )
1763 return NULL;
1764
1765 data = CryptMemAlloc( cbCrlEncoded );
1766 if( !data )
1767 {
1768 CryptMemFree( pcrl );
1769 return NULL;
1770 }
1771
1772 pcrl->dwCertEncodingType = dwCertEncodingType;
1773 pcrl->pbCrlEncoded = data;
1774 pcrl->cbCrlEncoded = cbCrlEncoded;
1775 pcrl->pCrlInfo = NULL;
1776 pcrl->hCertStore = 0;
1777
1778 return pcrl;
1779 }
1780
1781 /* Decodes the encoded certificate and creates the certificate context for it.
1782 * The reference count is initially zero, so you must create a reference to it
1783 * to avoid leaking memory.
1784 */
1785 static PWINE_CERT_CONTEXT CRYPT_CreateCertificateContext(
1786 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1787 {
1788 PWINE_CERT_CONTEXT cert = NULL;
1789 BOOL ret;
1790 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1791 PCERT_INFO certInfo = NULL;
1792 DWORD size = 0;
1793
1794 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1795 cbCertEncoded);
1796
1797 /* First try to decode it as a signed cert. */
1798 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, pbCertEncoded,
1799 cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1800 (BYTE *)&signedCert, &size);
1801 if (ret)
1802 {
1803 size = 0;
1804 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1805 signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
1806 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1807 (BYTE *)&certInfo, &size);
1808 LocalFree(signedCert);
1809 }
1810 /* Failing that, try it as an unsigned cert */
1811 if (!ret)
1812 {
1813 size = 0;
1814 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1815 pbCertEncoded, cbCertEncoded,
1816 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1817 (BYTE *)&certInfo, &size);
1818 }
1819 if (ret)
1820 {
1821 BYTE *data = NULL;
1822
1823 cert = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT));
1824 if (!cert)
1825 goto end;
1826 data = CryptMemAlloc(cbCertEncoded);
1827 if (!data)
1828 {
1829 CryptMemFree(cert);
1830 cert = NULL;
1831 goto end;
1832 }
1833 memcpy(data, pbCertEncoded, cbCertEncoded);
1834 cert->cert.dwCertEncodingType = dwCertEncodingType;
1835 cert->cert.pbCertEncoded = data;
1836 cert->cert.cbCertEncoded = cbCertEncoded;
1837 cert->cert.pCertInfo = certInfo;
1838 cert->cert.hCertStore = 0;
1839 cert->ref = 0;
1840 InitializeCriticalSection(&cert->cs);
1841 list_init(&cert->extendedProperties);
1842 }
1843
1844 end:
1845 return cert;
1846 }
1847
1848 static void CRYPT_FreeCert(PWINE_CERT_CONTEXT context)
1849 {
1850 PWINE_CERT_PROPERTY prop, next;
1851
1852 CryptMemFree(context->cert.pbCertEncoded);
1853 LocalFree(context->cert.pCertInfo);
1854 DeleteCriticalSection(&context->cs);
1855 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
1856 WINE_CERT_PROPERTY, entry)
1857 {
1858 list_remove(&prop->entry);
1859 CryptMemFree(prop->pbData);
1860 CryptMemFree(prop);
1861 }
1862 CryptMemFree(context);
1863 }
1864
1865 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
1866 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
1867 {
1868 PWINE_CERT_CONTEXT cert;
1869 PWINE_CERT_CONTEXT_REF ret = NULL;
1870
1871 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
1872 cbCertEncoded);
1873
1874 cert = CRYPT_CreateCertificateContext(dwCertEncodingType, pbCertEncoded,
1875 cbCertEncoded);
1876 if (cert)
1877 ret = CRYPT_CreateCertRef(cert, 0);
1878 return (PCCERT_CONTEXT)ret;
1879 }
1880
1881 /* Since the properties are stored in a list, this is a tad inefficient
1882 * (O(n^2)) since I have to find the previous position every time.
1883 */
1884 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
1885 DWORD dwPropId)
1886 {
1887 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1888 DWORD ret;
1889
1890 TRACE("(%p, %ld)\n", pCertContext, dwPropId);
1891
1892 EnterCriticalSection(&ref->context->cs);
1893 if (dwPropId)
1894 {
1895 PWINE_CERT_PROPERTY cursor = NULL;
1896
1897 LIST_FOR_EACH_ENTRY(cursor, &ref->context->extendedProperties,
1898 WINE_CERT_PROPERTY, entry)
1899 {
1900 if (cursor->hdr.propID == dwPropId)
1901 break;
1902 }
1903 if (cursor)
1904 {
1905 if (cursor->entry.next != &ref->context->extendedProperties)
1906 ret = LIST_ENTRY(cursor->entry.next, WINE_CERT_PROPERTY,
1907 entry)->hdr.propID;
1908 else
1909 ret = 0;
1910 }
1911 else
1912 ret = 0;
1913 }
1914 else if (!list_empty(&ref->context->extendedProperties))
1915 ret = LIST_ENTRY(ref->context->extendedProperties.next,
1916 WINE_CERT_PROPERTY, entry)->hdr.propID;
1917 else
1918 ret = 0;
1919 LeaveCriticalSection(&ref->context->cs);
1920 return ret;
1921 }
1922
1923 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
1924 PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
1925 {
1926 PWINE_CERT_PROPERTY prop;
1927 BOOL ret, found;
1928
1929 TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
1930
1931 EnterCriticalSection(&context->cs);
1932 ret = FALSE;
1933 found = FALSE;
1934 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
1935 WINE_CERT_PROPERTY, entry)
1936 {
1937 if (prop->hdr.propID == dwPropId)
1938 {
1939 if (!pvData)
1940 {
1941 *pcbData = prop->hdr.cb;
1942 ret = TRUE;
1943 }
1944 else if (*pcbData < prop->hdr.cb)
1945 {
1946 SetLastError(ERROR_MORE_DATA);
1947 *pcbData = prop->hdr.cb;
1948 }
1949 else
1950 {
1951 memcpy(pvData, prop->pbData, prop->hdr.cb);
1952 *pcbData = prop->hdr.cb;
1953 ret = TRUE;
1954 }
1955 found = TRUE;
1956 }
1957 break;
1958 }
1959 if (!found)
1960 {
1961 /* Implicit properties */
1962 switch (dwPropId)
1963 {
1964 case CERT_SHA1_HASH_PROP_ID:
1965 ret = CryptHashCertificate(0, CALG_SHA1, 0,
1966 context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
1967 pcbData);
1968 if (ret)
1969 {
1970 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
1971
1972 ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
1973 0, &blob);
1974 }
1975 break;
1976 case CERT_KEY_PROV_INFO_PROP_ID:
1977 case CERT_MD5_HASH_PROP_ID:
1978 case CERT_SIGNATURE_HASH_PROP_ID:
1979 case CERT_KEY_IDENTIFIER_PROP_ID:
1980 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
1981 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
1982 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
1983 FIXME("implicit property %ld\n", dwPropId);
1984 break;
1985 }
1986 }
1987 LeaveCriticalSection(&context->cs);
1988 TRACE("returning %d\n", ret);
1989 return ret;
1990 }
1991
1992 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
1993 DWORD dwPropId, void *pvData, DWORD *pcbData)
1994 {
1995 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
1996 BOOL ret;
1997
1998 TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
1999
2000 /* Special cases for invalid/special prop IDs.
2001 */
2002 switch (dwPropId)
2003 {
2004 case 0:
2005 case CERT_CERT_PROP_ID:
2006 case CERT_CRL_PROP_ID:
2007 case CERT_CTL_PROP_ID:
2008 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2009 return FALSE;
2010 case CERT_ACCESS_STATE_PROP_ID:
2011 if (!pvData)
2012 {
2013 *pcbData = sizeof(DWORD);
2014 return TRUE;
2015 }
2016 else if (*pcbData < sizeof(DWORD))
2017 {
2018 SetLastError(ERROR_MORE_DATA);
2019 *pcbData = sizeof(DWORD);
2020 return FALSE;
2021 }
2022 else
2023 {
2024 DWORD state = 0;
2025
2026 if (pCertContext->hCertStore)
2027 {
2028 PWINECRYPT_CERTSTORE store =
2029 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2030
2031 /* Take advantage of knowledge of the stores to answer the
2032 * access state question
2033 */
2034 if (store->type != StoreTypeReg ||
2035 !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
2036 state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
2037 }
2038 *(DWORD *)pvData = state;
2039 return TRUE;
2040 }
2041 }
2042
2043 ret = CRYPT_GetCertificateContextProperty(ref->context, dwPropId,
2044 pvData, pcbData);
2045 TRACE("returning %d\n", ret);
2046 return ret;
2047 }
2048
2049 /* Copies cbData bytes from pbData to the context's property with ID
2050 * dwPropId.
2051 */
2052 static BOOL CRYPT_SaveCertificateContextProperty(PWINE_CERT_CONTEXT context,
2053 DWORD dwPropId, const BYTE *pbData, size_t cbData)
2054 {
2055 BOOL ret = FALSE;
2056 LPBYTE data;
2057
2058 if (cbData)
2059 {
2060 data = CryptMemAlloc(cbData);
2061 if (data)
2062 memcpy(data, pbData, cbData);
2063 }
2064 else
2065 data = NULL;
2066 if (!cbData || data)
2067 {
2068 PWINE_CERT_PROPERTY prop;
2069
2070 EnterCriticalSection(&context->cs);
2071 LIST_FOR_EACH_ENTRY(prop, &context->extendedProperties,
2072 WINE_CERT_PROPERTY, entry)
2073 {
2074 if (prop->hdr.propID == dwPropId)
2075 break;
2076 }
2077 if (prop && prop->entry.next != &context->extendedProperties)
2078 {
2079 CryptMemFree(prop->pbData);
2080 prop->hdr.cb = cbData;
2081 prop->pbData = cbData ? data : NULL;
2082 ret = TRUE;
2083 }
2084 else
2085 {
2086 prop = CryptMemAlloc(sizeof(WINE_CERT_PROPERTY));
2087 if (prop)
2088 {
2089 prop->hdr.propID = dwPropId;
2090 prop->hdr.unknown = 1;
2091 prop->hdr.cb = cbData;
2092 list_init(&prop->entry);
2093 prop->pbData = cbData ? data : NULL;
2094 list_add_tail(&context->extendedProperties, &prop->entry);
2095 ret = TRUE;
2096 }
2097 else
2098 CryptMemFree(data);
2099 }
2100 LeaveCriticalSection(&context->cs);
2101 }
2102 return ret;
2103 }
2104
2105 static BOOL WINAPI CRYPT_SetCertificateContextProperty(
2106 PWINE_CERT_CONTEXT context, DWORD dwPropId, DWORD dwFlags, const void *pvData)
2107 {
2108 BOOL ret = FALSE;
2109
2110 TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
2111
2112 if (!pvData)
2113 {
2114 PWINE_CERT_PROPERTY prop, next;
2115
2116 EnterCriticalSection(&context->cs);
2117 LIST_FOR_EACH_ENTRY_SAFE(prop, next, &context->extendedProperties,
2118 WINE_CERT_PROPERTY, entry)
2119 {
2120 if (prop->hdr.propID == dwPropId)
2121 {
2122 list_remove(&prop->entry);
2123 CryptMemFree(prop->pbData);
2124 CryptMemFree(prop);
2125 }
2126 }
2127 LeaveCriticalSection(&context->cs);
2128 ret = TRUE;
2129 }
2130 else
2131 {
2132 switch (dwPropId)
2133 {
2134 case CERT_AUTO_ENROLL_PROP_ID:
2135 case CERT_CTL_USAGE_PROP_ID:
2136 case CERT_DESCRIPTION_PROP_ID:
2137 case CERT_FRIENDLY_NAME_PROP_ID:
2138 case CERT_HASH_PROP_ID:
2139 case CERT_KEY_IDENTIFIER_PROP_ID:
2140 case CERT_MD5_HASH_PROP_ID:
2141 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2142 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2143 case CERT_PVK_FILE_PROP_ID:
2144 case CERT_SIGNATURE_HASH_PROP_ID:
2145 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2146 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2147 case CERT_ENROLLMENT_PROP_ID:
2148 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2149 case CERT_RENEWAL_PROP_ID:
2150 {
2151 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
2152
2153 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2154 blob->pbData, blob->cbData);
2155 break;
2156 }
2157 case CERT_DATE_STAMP_PROP_ID:
2158 ret = CRYPT_SaveCertificateContextProperty(context, dwPropId,
2159 pvData, sizeof(FILETIME));
2160 break;
2161 default:
2162 FIXME("%ld: stub\n", dwPropId);
2163 }
2164 }
2165 TRACE("returning %d\n", ret);
2166 return ret;
2167 }
2168
2169 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
2170 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2171 {
2172 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2173 BOOL ret;
2174
2175 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
2176
2177 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
2178 * crashes on most of these, I'll be safer.
2179 */
2180 switch (dwPropId)
2181 {
2182 case 0:
2183 case CERT_ACCESS_STATE_PROP_ID:
2184 case CERT_CERT_PROP_ID:
2185 case CERT_CRL_PROP_ID:
2186 case CERT_CTL_PROP_ID:
2187 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2188 return FALSE;
2189 }
2190 ret = CRYPT_SetCertificateContextProperty(ref->context, dwPropId,
2191 dwFlags, pvData);
2192 TRACE("returning %d\n", ret);
2193 return ret;
2194 }
2195
2196 /* Only the reference portion of the context is duplicated. The returned
2197 * context has the cert store set to 0, to prevent the store's certificate free
2198 * function from getting called on partial data.
2199 * FIXME: is this okay? Needs a test.
2200 */
2201 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
2202 PCCERT_CONTEXT pCertContext)
2203 {
2204 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext, ret;
2205
2206 TRACE("(%p)\n", pCertContext);
2207 if (ref)
2208 {
2209 ret = CryptMemAlloc(sizeof(WINE_CERT_CONTEXT_REF));
2210 if (ret)
2211 {
2212 memcpy(ret, ref, sizeof(*ret));
2213 ret->cert.hCertStore = 0;
2214 InterlockedIncrement(&ret->context->ref);
2215 }
2216 }
2217 else
2218 ret = NULL;
2219 return (PCCERT_CONTEXT)ret;
2220 }
2221
2222 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
2223 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
2224 PCCERT_CONTEXT *ppStoreContext)
2225 {
2226 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2227 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2228 PWINE_CERT_CONTEXT cert;
2229 BOOL ret;
2230
2231 TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
2232 dwAddDisposition, ppStoreContext);
2233
2234 /* FIXME: some tests needed to verify return codes */
2235 if (!store)
2236 {
2237 SetLastError(ERROR_INVALID_PARAMETER);
2238 return FALSE;
2239 }
2240 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2241 {
2242 SetLastError(ERROR_INVALID_PARAMETER);
2243 return FALSE;
2244 }
2245
2246 cert = CRYPT_CreateCertificateContext(ref->context->cert.dwCertEncodingType,
2247 ref->context->cert.pbCertEncoded, ref->context->cert.cbCertEncoded);
2248 if (cert)
2249 {
2250 PWINE_CERT_PROPERTY prop;
2251
2252 ret = TRUE;
2253 EnterCriticalSection(&ref->context->cs);
2254 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2255 WINE_CERT_PROPERTY, entry)
2256 {
2257 ret = CRYPT_SaveCertificateContextProperty(cert, prop->hdr.propID,
2258 prop->pbData, prop->hdr.cb);
2259 if (!ret)
2260 break;
2261 }
2262 LeaveCriticalSection(&ref->context->cs);
2263 if (ret)
2264 {
2265 ret = store->addCert(store, (PCCERT_CONTEXT)cert, dwAddDisposition);
2266 if (ret && ppStoreContext)
2267 *ppStoreContext = (PCCERT_CONTEXT)store->createCertRef(cert,
2268 hCertStore);
2269 }
2270 if (!ret)
2271 CRYPT_FreeCert(cert);
2272 }
2273 else
2274 ret = FALSE;
2275 return ret;
2276 }
2277
2278 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
2279 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
2280 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
2281 {
2282 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2283 BOOL ret;
2284
2285 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
2286 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
2287
2288 if (!hcs)
2289 ret = FALSE;
2290 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2291 ret = FALSE;
2292 else
2293 {
2294 PWINE_CERT_CONTEXT cert = CRYPT_CreateCertificateContext(
2295 dwCertEncodingType, pbCertEncoded, cbCertEncoded);
2296
2297 if (cert)
2298 {
2299 ret = hcs->addCert(hcs, (PCCERT_CONTEXT)cert, dwAddDisposition);
2300 if (ret && ppCertContext)
2301 *ppCertContext = (PCCERT_CONTEXT)hcs->createCertRef(cert,
2302 hCertStore);
2303 if (!ret)
2304 CRYPT_FreeCert(cert);
2305 }
2306 else
2307 ret = FALSE;
2308 }
2309 return ret;
2310 }
2311
2312 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
2313 PCCERT_CONTEXT pPrev)
2314 {
2315 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2316 PWINE_CERT_CONTEXT_REF prev = (PWINE_CERT_CONTEXT_REF)pPrev;
2317 PCCERT_CONTEXT ret;
2318
2319 TRACE("(%p, %p)\n", hCertStore, pPrev);
2320 if (!hCertStore)
2321 ret = NULL;
2322 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2323 ret = NULL;
2324 else
2325 ret = (PCCERT_CONTEXT)hcs->enumCert(hcs, prev);
2326 return ret;
2327 }
2328
2329 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
2330 {
2331 BOOL ret;
2332
2333 TRACE("(%p)\n", pCertContext);
2334
2335 if (!pCertContext)
2336 ret = TRUE;
2337 else if (!pCertContext->hCertStore)
2338 {
2339 ret = TRUE;
2340 CertFreeCertificateContext(pCertContext);
2341 }
2342 else
2343 {
2344 PWINECRYPT_CERTSTORE hcs =
2345 (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2346
2347 if (!hcs)
2348 ret = TRUE;
2349 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2350 ret = FALSE;
2351 else
2352 {
2353 ret = hcs->deleteCert(hcs, pCertContext, 0);
2354 CertFreeCertificateContext(pCertContext);
2355 }
2356 }
2357 return ret;
2358 }
2359
2360 BOOL WINAPI CertAddEncodedCRLToStore(HCERTSTORE hCertStore,
2361 DWORD dwCertEncodingType, const BYTE *pbCrlEncoded, DWORD cbCrlEncoded,
2362 DWORD dwAddDisposition, PCCRL_CONTEXT *ppCrlContext)
2363 {
2364 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2365 dwCertEncodingType, pbCrlEncoded, cbCrlEncoded, dwAddDisposition,
2366 ppCrlContext);
2367 return FALSE;
2368 }
2369
2370 BOOL WINAPI CertAddCRLContextToStore( HCERTSTORE hCertStore,
2371 PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2372 PCCRL_CONTEXT* ppStoreContext )
2373 {
2374 FIXME("%p %p %08lx %p\n", hCertStore, pCrlContext,
2375 dwAddDisposition, ppStoreContext);
2376 return TRUE;
2377 }
2378
2379 BOOL WINAPI CertFreeCRLContext( PCCRL_CONTEXT pCrlContext)
2380 {
2381 FIXME("%p\n", pCrlContext );
2382
2383 return TRUE;
2384 }
2385
2386 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2387 {
2388 FIXME("(%p): stub\n", pCrlContext);
2389 return TRUE;
2390 }
2391
2392 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2393 PCCRL_CONTEXT pPrev)
2394 {
2395 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2396 return NULL;
2397 }
2398
2399 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2400 const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2401 {
2402 FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2403 cbCtlEncoded);
2404 return NULL;
2405 }
2406
2407 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2408 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2409 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2410 {
2411 FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2412 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2413 ppCtlContext);
2414 return FALSE;
2415 }
2416
2417 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2418 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2419 PCCTL_CONTEXT* ppStoreContext)
2420 {
2421 FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2422 dwAddDisposition, ppStoreContext);
2423 return TRUE;
2424 }
2425
2426 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2427 {
2428 FIXME("(%p): stub\n", pCtlContext );
2429 return TRUE;
2430 }
2431
2432 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2433 {
2434 FIXME("(%p): stub\n", pCtlContext);
2435 return TRUE;
2436 }
2437
2438 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2439 PCCTL_CONTEXT pPrev)
2440 {
2441 FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2442 return NULL;
2443 }
2444
2445
2446 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2447 {
2448 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2449
2450 TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2451
2452 if( ! hCertStore )
2453 return TRUE;
2454
2455 if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2456 return FALSE;
2457
2458 if (InterlockedDecrement(&hcs->ref) == 0)
2459 {
2460 TRACE("%p's ref count is 0, freeing\n", hcs);
2461 hcs->dwMagic = 0;
2462 if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2463 CryptReleaseContext(hcs->cryptProv, 0);
2464 hcs->closeStore(hcs, dwFlags);
2465 }
2466 else
2467 TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2468 return TRUE;
2469 }
2470
2471 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2472 DWORD dwCtrlType, void const *pvCtrlPara)
2473 {
2474 WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2475 BOOL ret;
2476
2477 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2478 pvCtrlPara);
2479
2480 if (!hcs)
2481 ret = FALSE;
2482 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2483 ret = FALSE;
2484 else
2485 {
2486 if (hcs->control)
2487 ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2488 else
2489 ret = TRUE;
2490 }
2491 return ret;
2492 }
2493
2494 BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2495 DWORD dwPropId, void *pvData, DWORD *pcbData)
2496 {
2497 FIXME("(%p, %ld, %p, %p): stub\n", pCRLContext, dwPropId, pvData, pcbData);
2498 return FALSE;
2499 }
2500
2501 BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
2502 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2503 {
2504 FIXME("(%p, %ld, %08lx, %p): stub\n", pCRLContext, dwPropId, dwFlags,
2505 pvData);
2506 return FALSE;
2507 }
2508
2509 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
2510 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2511 {
2512 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
2513 pcbElement);
2514 return FALSE;
2515 }
2516
2517 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2518 DWORD dwPropId, void *pvData, DWORD *pcbData)
2519 {
2520 FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2521 return FALSE;
2522 }
2523
2524 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2525 DWORD dwPropId, DWORD dwFlags, const void *pvData)
2526 {
2527 FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2528 pvData);
2529 return FALSE;
2530 }
2531
2532 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
2533 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2534 {
2535 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
2536 pcbElement);
2537 return FALSE;
2538 }
2539
2540 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
2541 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
2542 {
2543 BOOL ret;
2544
2545 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
2546 pcbElement);
2547
2548 if (pCertContext)
2549 {
2550 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2551 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
2552 pCertContext->cbCertEncoded;
2553 PWINE_CERT_PROPERTY prop;
2554
2555 EnterCriticalSection(&ref->context->cs);
2556 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2557 WINE_CERT_PROPERTY, entry)
2558 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + prop->hdr.cb;
2559 if (!pbElement)
2560 {
2561 *pcbElement = bytesNeeded;
2562 ret = TRUE;
2563 }
2564 else if (*pcbElement < bytesNeeded)
2565 {
2566 *pcbElement = bytesNeeded;
2567 SetLastError(ERROR_MORE_DATA);
2568 ret = FALSE;
2569 }
2570 else
2571 {
2572 PWINE_CERT_PROP_HEADER hdr;
2573
2574 LIST_FOR_EACH_ENTRY(prop, &ref->context->extendedProperties,
2575 WINE_CERT_PROPERTY, entry)
2576 {
2577 memcpy(pbElement, &prop->hdr, sizeof(WINE_CERT_PROP_HEADER));
2578 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2579 if (prop->hdr.cb)
2580 {
2581 memcpy(pbElement, prop->pbData, prop->hdr.cb);
2582 pbElement += prop->hdr.cb;
2583 }
2584 }
2585 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
2586 hdr->propID = CERT_CERT_PROP_ID;
2587 hdr->unknown = 1;
2588 hdr->cb = pCertContext->cbCertEncoded;
2589 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
2590 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
2591 ret = TRUE;
2592 }
2593 LeaveCriticalSection(&ref->context->cs);
2594 }
2595 else
2596 ret = FALSE;
2597 return ret;
2598 }
2599
2600 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
2601 * to its header if a valid header is found, NULL if not. Valid means the
2602 * length of thte property won't overrun buf, and the unknown field is 1.
2603 */
2604 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
2605 DWORD size, DWORD propID)
2606 {
2607 const WINE_CERT_PROP_HEADER *ret = NULL;
2608 BOOL done = FALSE;
2609
2610 while (size && !ret && !done)
2611 {
2612 if (size < sizeof(WINE_CERT_PROP_HEADER))
2613 {
2614 SetLastError(CRYPT_E_FILE_ERROR);
2615 done = TRUE;
2616 }
2617 else
2618 {
2619 const WINE_CERT_PROP_HEADER *hdr =
2620 (const WINE_CERT_PROP_HEADER *)buf;
2621
2622 size -= sizeof(WINE_CERT_PROP_HEADER);
2623 buf += sizeof(WINE_CERT_PROP_HEADER);
2624 if (size < hdr->cb)
2625 {
2626 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2627 done = TRUE;
2628 }
2629 else if (!hdr->propID)
2630 {
2631 /* assume a zero prop ID means the data are uninitialized, so
2632 * stop looking.
2633 */
2634 done = TRUE;
2635 }
2636 else if (hdr->unknown != 1)
2637 {
2638 SetLastError(ERROR_FILE_NOT_FOUND);
2639 done = TRUE;
2640 }
2641 else if (hdr->propID == propID)
2642 ret = hdr;
2643 else
2644 {
2645 buf += hdr->cb;
2646 size -= hdr->cb;
2647 }
2648 }
2649 }
2650 return ret;
2651 }
2652
2653 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
2654 DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType)
2655 {
2656 const void *context;
2657
2658 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
2659 pdwContentType);
2660
2661 if (!cbElement)
2662 {
2663 SetLastError(ERROR_END_OF_MEDIA);
2664 return NULL;
2665 }
2666
2667 _SEH_TRY
2668 {
2669 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2670 const WINE_CERT_PROP_HEADER *hdr = NULL;
2671 DWORD type = 0;
2672 BOOL ret;
2673
2674 ret = TRUE;
2675 context = NULL;
2676 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
2677 {
2678 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2679 if (hdr)
2680 type = CERT_STORE_CERTIFICATE_CONTEXT;
2681 else
2682 {
2683 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2684 if (hdr)
2685 type = CERT_STORE_CRL_CONTEXT;
2686 else
2687 {
2688 hdr = CRYPT_findPropID(pbElement, cbElement,
2689 CERT_CTL_PROP_ID);
2690 if (hdr)
2691 type = CERT_STORE_CTL_CONTEXT;
2692 }
2693 }
2694 }
2695 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
2696 {
2697 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
2698 type = CERT_STORE_CERTIFICATE_CONTEXT;
2699 }
2700 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
2701 {
2702 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
2703 type = CERT_STORE_CRL_CONTEXT;
2704 }
2705 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
2706 {
2707 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
2708 type = CERT_STORE_CTL_CONTEXT;
2709 }
2710
2711 switch (type)
2712 {
2713 case CERT_STORE_CERTIFICATE_CONTEXT:
2714 contextInterface = &gCertInterface;
2715 break;
2716 case CERT_STORE_CRL_CONTEXT:
2717 contextInterface = &gCRLInterface;
2718 break;
2719 case CERT_STORE_CTL_CONTEXT:
2720 contextInterface = &gCTLInterface;
2721 break;
2722 default:
2723 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2724 ret = FALSE;
2725 }
2726 if (!hdr)
2727 ret = FALSE;
2728
2729 if (ret)
2730 context = contextInterface->create(X509_ASN_ENCODING,
2731 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
2732 if (ret && context)
2733 {
2734 BOOL noMoreProps = FALSE;
2735
2736 while (!noMoreProps && ret)
2737 {
2738 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
2739 ret = FALSE;
2740 else
2741 {
2742 const WINE_CERT_PROP_HEADER *hdr =
2743 (const WINE_CERT_PROP_HEADER *)pbElement;
2744
2745 TRACE("prop is %ld\n", hdr->propID);
2746 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
2747 pbElement += sizeof(WINE_CERT_PROP_HEADER);
2748 if (cbElement < hdr->cb)
2749 {
2750 SetLastError(HRESULT_FROM_WIN32(
2751 ERROR_INVALID_PARAMETER));
2752 ret = FALSE;
2753 }
2754 else if (!hdr->propID)
2755 {
2756 /* Like in CRYPT_findPropID, stop if the propID is zero
2757 */
2758 noMoreProps = TRUE;
2759 }
2760 else if (hdr->unknown != 1)
2761 {
2762 SetLastError(ERROR_FILE_NOT_FOUND);
2763 ret = FALSE;
2764 }
2765 else if (hdr->propID != CERT_CERT_PROP_ID &&
2766 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
2767 CERT_CTL_PROP_ID)
2768 {
2769 /* Have to create a blob for most types, but not
2770 * for all.. arghh.
2771 */
2772 switch (hdr->propID)
2773 {
2774 case CERT_AUTO_ENROLL_PROP_ID:
2775 case CERT_CTL_USAGE_PROP_ID:
2776 case CERT_DESCRIPTION_PROP_ID:
2777 case CERT_FRIENDLY_NAME_PROP_ID:
2778 case CERT_HASH_PROP_ID:
2779 case CERT_KEY_IDENTIFIER_PROP_ID:
2780 case CERT_MD5_HASH_PROP_ID:
2781 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
2782 case CERT_PUBKEY_ALG_PARA_PROP_ID:
2783 case CERT_PVK_FILE_PROP_ID:
2784 case CERT_SIGNATURE_HASH_PROP_ID:
2785 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
2786 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
2787 case CERT_ENROLLMENT_PROP_ID:
2788 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
2789 case CERT_RENEWAL_PROP_ID:
2790 {
2791 CRYPT_DATA_BLOB blob = { hdr->cb,
2792 (LPBYTE)pbElement };
2793
2794 ret = contextInterface->setProp(context,
2795 hdr->propID, 0, &blob);
2796 break;
2797 }
2798 case CERT_DATE_STAMP_PROP_ID:
2799 ret = contextInterface->setProp(context,
2800 hdr->propID, 0, pbElement);
2801 break;
2802 default:
2803 FIXME("prop ID %ld: stub\n", hdr->propID);
2804 }
2805 }
2806 pbElement += hdr->cb;
2807 cbElement -= hdr->cb;
2808 if (!cbElement)
2809 noMoreProps = TRUE;
2810 }
2811 }
2812 if (ret)
2813 {
2814 if (pdwContentType)
2815 *pdwContentType = type;
2816 }
2817 else
2818 {
2819 contextInterface->free(context);
2820 context = NULL;
2821 }
2822 }
2823 }
2824 _SEH_EXCEPT(page_fault)
2825 {
2826 SetLastError(STATUS_ACCESS_VIOLATION);
2827 context = NULL;
2828 }
2829 _SEH_END
2830 return context;
2831 }
2832
2833 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
2834 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
2835 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
2836 {
2837 const void *context;
2838 DWORD type;
2839 BOOL ret;
2840
2841 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
2842 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
2843 pdwContentType, ppvContext);
2844
2845 /* Call the internal function, then delete the hashes. Tests show this
2846 * function uses real hash values, not whatever's stored in the hash
2847 * property.
2848 */
2849 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
2850 dwContextTypeFlags, &type);
2851 if (context)
2852 {
2853 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
2854
2855 switch (type)
2856 {
2857 case CERT_STORE_CERTIFICATE_CONTEXT:
2858 contextInterface = &gCertInterface;
2859 break;
2860 case CERT_STORE_CRL_CONTEXT:
2861 contextInterface = &gCRLInterface;
2862 break;
2863 case CERT_STORE_CTL_CONTEXT:
2864 contextInterface = &gCTLInterface;
2865 break;
2866 default:
2867 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2868 }
2869 if (contextInterface)
2870 {
2871 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
2872 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
2873 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
2874 NULL);
2875 if (pdwContentType)
2876 *pdwContentType = type;
2877 ret = contextInterface->addContextToStore(hCertStore, context,
2878 dwAddDisposition, ppvContext);
2879 contextInterface->free(context);
2880 }
2881 else
2882 ret = FALSE;
2883 }
2884 else
2885 ret = FALSE;
2886 return ret;
2887 }
2888
2889 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
2890 {
2891 TRACE("(%p)\n", pCertContext);
2892
2893 if (pCertContext)
2894 {
2895 PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
2896 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
2897
2898 if (InterlockedDecrement(&ref->context->ref) == 0)
2899 {
2900 TRACE("%p's ref count is 0, freeing\n", ref->context);
2901 CRYPT_FreeCert(ref->context);
2902 }
2903 else
2904 TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
2905 if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
2906 store->freeCert)
2907 store->freeCert(ref);
2908 CryptMemFree(ref);
2909 }
2910 return TRUE;
2911 }
2912
2913 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
2914 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType,
2915 const void *pvPara, PCCERT_CONTEXT pPrevCertContext)
2916 {
2917 FIXME("stub: %p %ld %ld %ld %p %p\n", hCertStore, dwCertEncodingType,
2918 dwFlags, dwType, pvPara, pPrevCertContext);
2919 SetLastError(CRYPT_E_NOT_FOUND);
2920 return NULL;
2921 }
2922
2923 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2924 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2925 {
2926 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2927 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2928 PWINE_STORE_LIST_ENTRY entry;
2929 BOOL ret;
2930
2931 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2932 dwUpdateFlags, dwPriority);
2933
2934 if (!collection || !sibling)
2935 return TRUE;
2936 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2937 {
2938 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2939 return FALSE;
2940 }
2941 if (collection->hdr.type != StoreTypeCollection)
2942 {
2943 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2944 return FALSE;
2945 }
2946 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2947 {
2948 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2949 return FALSE;
2950 }
2951
2952 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2953 if (entry)
2954 {
2955 InterlockedIncrement(&sibling->ref);
2956 TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2957 entry->store = sibling;
2958 entry->dwUpdateFlags = dwUpdateFlags;
2959 entry->dwPriority = dwPriority;
2960 list_init(&entry->entry);
2961 TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2962 EnterCriticalSection(&collection->cs);
2963 if (dwPriority)
2964 {
2965 PWINE_STORE_LIST_ENTRY cursor;
2966 BOOL added = FALSE;
2967
2968 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2969 WINE_STORE_LIST_ENTRY, entry)
2970 {
2971 if (cursor->dwPriority < dwPriority)
2972 {
2973 list_add_before(&cursor->entry, &entry->entry);
2974 added = TRUE;
2975 break;
2976 }
2977 }
2978 if (!added)
2979 list_add_tail(&collection->stores, &entry->entry);
2980 }
2981 else
2982 list_add_tail(&collection->stores, &entry->entry);
2983 LeaveCriticalSection(&collection->cs);
2984 ret = TRUE;
2985 }
2986 else
2987 ret = FALSE;
2988 return ret;
2989 }
2990
2991 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2992 HCERTSTORE hSiblingStore)
2993 {
2994 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2995 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2996 PWINE_STORE_LIST_ENTRY store, next;
2997
2998 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2999
3000 if (!collection || !sibling)
3001 return;
3002 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3003 {
3004 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3005 return;
3006 }
3007 if (collection->hdr.type != StoreTypeCollection)
3008 return;
3009 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
3010 {
3011 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3012 return;
3013 }
3014 EnterCriticalSection(&collection->cs);
3015 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
3016 WINE_STORE_LIST_ENTRY, entry)
3017 {
3018 if (store->store == sibling)
3019 {
3020 list_remove(&store->entry);
3021 CertCloseStore(store->store, 0);
3022 CryptMemFree(store);
3023 break;
3024 }
3025 }
3026 LeaveCriticalSection(&collection->cs);
3027 }
3028
3029 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
3030 CRYPT_ATTRIBUTE rgAttr[])
3031 {
3032 PCRYPT_ATTRIBUTE ret = NULL;
3033 DWORD i;
3034
3035 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
3036
3037 if (!cAttr)
3038 return NULL;
3039 if (!pszObjId)
3040 {
3041 SetLastError(ERROR_INVALID_PARAMETER);
3042 return NULL;
3043 }
3044
3045 for (i = 0; !ret && i < cAttr; i++)
3046 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
3047 ret = &rgAttr[i];
3048 return ret;
3049 }
3050
3051 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
3052 CERT_EXTENSION rgExtensions[])
3053 {
3054 PCERT_EXTENSION ret = NULL;
3055 DWORD i;
3056
3057 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
3058
3059 if (!cExtensions)
3060 return NULL;
3061 if (!pszObjId)
3062 {
3063 SetLastError(ERROR_INVALID_PARAMETER);
3064 return NULL;
3065 }
3066
3067 for (i = 0; !ret && i < cExtensions; i++)
3068 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
3069 rgExtensions[i].pszObjId))
3070 ret = &rgExtensions[i];
3071 return ret;
3072 }
3073
3074 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
3075 {
3076 PCERT_RDN_ATTR ret = NULL;
3077 DWORD i, j;
3078
3079 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
3080
3081 if (!pszObjId)
3082 {
3083 SetLastError(ERROR_INVALID_PARAMETER);
3084 return NULL;
3085 }
3086
3087 for (i = 0; !ret && i < pName->cRDN; i++)
3088 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
3089 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
3090 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
3091 ret = &pName->rgRDN[i].rgRDNAttr[j];
3092 return ret;
3093 }
3094
3095 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
3096 PCERT_INFO pCertInfo)
3097 {
3098 FILETIME fileTime;
3099 LONG ret;
3100
3101 if (!pTimeToVerify)
3102 {
3103 SYSTEMTIME sysTime;
3104
3105 GetSystemTime(&sysTime);
3106 SystemTimeToFileTime(&sysTime, &fileTime);
3107 pTimeToVerify = &fileTime;
3108 }
3109 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
3110 {
3111 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
3112 if (ret < 0)
3113 ret = 0;
3114 }
3115 return ret;
3116 }
3117
3118 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
3119 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
3120 DWORD *pcbComputedHash)
3121 {
3122 BOOL ret = TRUE;
3123 HCRYPTHASH hHash = 0;
3124
3125 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
3126 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
3127
3128 if (!hCryptProv)
3129 hCryptProv = CRYPT_GetDefaultProvider();
3130 if (!Algid)
3131 Algid = CALG_SHA1;
3132 if (ret)
3133 {
3134 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
3135 if (ret)
3136 {
3137 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
3138 if (ret)
3139 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
3140 pcbComputedHash, 0);
3141 CryptDestroyHash(hHash);
3142 }
3143 }
3144 return ret;
3145 }
3146
3147 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3148 DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
3149 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
3150 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
3151 {
3152 BOOL ret;
3153 ALG_ID algID;
3154 HCRYPTHASH hHash;
3155
3156 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
3157 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
3158 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
3159
3160 algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
3161 if (!algID)
3162 {
3163 SetLastError(NTE_BAD_ALGID);
3164 return FALSE;
3165 }
3166 if (!hCryptProv)
3167 {
3168 SetLastError(ERROR_INVALID_PARAMETER);
3169 return FALSE;
3170 }
3171
3172 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
3173 if (ret)
3174 {
3175 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
3176 if (ret)
3177 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
3178 pcbSignature);
3179 CryptDestroyHash(hHash);
3180 }
3181 return ret;
3182 }
3183
3184 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
3185 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
3186 PCERT_PUBLIC_KEY_INFO pPublicKey)
3187 {
3188 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
3189 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
3190 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
3191 }
3192
3193 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
3194 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
3195 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
3196 {
3197 BOOL ret = TRUE;
3198 CRYPT_DATA_BLOB subjectBlob;
3199
3200 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
3201 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
3202 dwFlags, pvReserved);
3203
3204 switch (dwSubjectType)
3205 {
3206 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
3207 {
3208 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
3209
3210 subjectBlob.pbData = blob->pbData;
3211 subjectBlob.cbData = blob->cbData;
3212 break;
3213 }
3214 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
3215 {
3216 PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
3217
3218 subjectBlob.pbData = context->pbCertEncoded;
3219 subjectBlob.cbData = context->cbCertEncoded;
3220 break;
3221 }
3222 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
3223 {
3224 PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
3225
3226 subjectBlob.pbData = context->pbCrlEncoded;
3227 subjectBlob.cbData = context->cbCrlEncoded;
3228 break;
3229 }
3230 default:
3231 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
3232 ret = FALSE;
3233 }
3234
3235 if (ret)
3236 {
3237 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
3238 DWORD size = 0;
3239
3240 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
3241 subjectBlob.pbData, subjectBlob.cbData,
3242 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3243 (BYTE *)&signedCert, &size);
3244 if (ret)
3245 {
3246 switch (dwIssuerType)
3247 {
3248 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
3249 {
3250 PCERT_PUBLIC_KEY_INFO pubKeyInfo =
3251 (PCERT_PUBLIC_KEY_INFO)pvIssuer;
3252 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
3253
3254 if (algID)
3255 {
3256 HCRYPTKEY key;
3257
3258 ret = CryptImportPublicKeyInfoEx(hCryptProv,
3259 dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
3260 if (ret)
3261 {
3262 HCRYPTHASH hash;
3263
3264 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
3265 if (ret)
3266 {
3267 ret = CryptHashData(hash,
3268 signedCert->ToBeSigned.pbData,
3269 signedCert->ToBeSigned.cbData, 0);
3270 if (ret)
3271 {
3272 ret = CryptVerifySignatureW(hash,
3273 signedCert->Signature.pbData,
3274 signedCert->Signature.cbData, key, NULL, 0);
3275 }
3276 CryptDestroyHash(hash);
3277 }
3278 CryptDestroyKey(key);
3279 }
3280 }
3281 else
3282 {
3283 SetLastError(NTE_BAD_ALGID);
3284 ret = FALSE;
3285 }
3286 break;
3287 }
3288 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
3289 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
3290 FIXME("issuer type %ld: stub\n", dwIssuerType);
3291 ret = FALSE;
3292 break;
3293 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
3294 if (pvIssuer)
3295 {
3296 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));