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