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