2 * Copyright 2004-2007 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/debug.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
30 typedef struct _WINE_HASH_TO_DELETE
34 } WINE_HASH_TO_DELETE
;
36 typedef struct _WINE_REGSTOREINFO
43 struct list certsToDelete
;
44 struct list crlsToDelete
;
45 struct list ctlsToDelete
;
48 static void CRYPT_HashToStr(const BYTE
*hash
, LPWSTR asciiHash
)
55 for (i
= 0; i
< 20; i
++)
56 wsprintfW(asciiHash
+ i
* 2, L
"%02X", hash
[i
]);
59 void CRYPT_RegReadSerializedFromReg(HKEY key
, DWORD contextType
, HCERTSTORE store
, DWORD disposition
)
63 WCHAR subKeyName
[MAX_PATH
];
66 DWORD size
= ARRAY_SIZE(subKeyName
);
68 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
74 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
80 rc
= RegQueryValueExW(subKey
, L
"Blob", NULL
, NULL
, NULL
, &size
);
82 buf
= CryptMemAlloc(size
);
85 rc
= RegQueryValueExW(subKey
, L
"Blob", NULL
, NULL
, buf
,
92 TRACE("Adding cert with hash %s\n",
93 debugstr_w(subKeyName
));
94 context
= CRYPT_ReadSerializedElement(buf
, size
,
95 contextType
, &addedType
);
98 const WINE_CONTEXT_INTERFACE
*contextInterface
;
103 case CERT_STORE_CERTIFICATE_CONTEXT
:
104 contextInterface
= pCertInterface
;
106 case CERT_STORE_CRL_CONTEXT
:
107 contextInterface
= pCRLInterface
;
109 case CERT_STORE_CTL_CONTEXT
:
110 contextInterface
= pCTLInterface
;
113 contextInterface
= NULL
;
115 if (contextInterface
)
118 if (contextInterface
->getProp(context
,
119 CERT_HASH_PROP_ID
, hash
, &size
))
121 WCHAR asciiHash
[20 * 2 + 1];
123 CRYPT_HashToStr(hash
, asciiHash
);
124 TRACE("comparing %s\n",
125 debugstr_w(asciiHash
));
126 TRACE("with %s\n", debugstr_w(subKeyName
));
127 if (!wcscmp(asciiHash
, subKeyName
))
129 TRACE("hash matches, adding\n");
130 contextInterface
->addContextToStore(
135 TRACE("hash doesn't match, ignoring\n");
137 Context_Release(context_from_ptr(context
));
145 /* Ignore intermediate errors, continue enumerating */
151 static void CRYPT_RegReadFromReg(HKEY key
, HCERTSTORE store
, DWORD disposition
)
153 static const WCHAR
* const subKeys
[] = { L
"Certificates", L
"CRLs", L
"CTLs" };
154 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
155 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
158 for (i
= 0; i
< ARRAY_SIZE(subKeys
); i
++)
163 rc
= RegCreateKeyExW(key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
167 CRYPT_RegReadSerializedFromReg(hKey
, contextFlags
[i
], store
, disposition
);
173 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
174 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, DWORD flags
, const BYTE
*hash
, const BYTE
*buf
,
177 WCHAR asciiHash
[20 * 2 + 1];
182 CRYPT_HashToStr(hash
, asciiHash
);
183 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, flags
, KEY_ALL_ACCESS
, NULL
,
187 rc
= RegSetValueExW(subKey
, L
"Blob", 0, REG_BINARY
, buf
, len
);
200 BOOL
CRYPT_SerializeContextsToReg(HKEY key
, DWORD flags
,
201 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
203 const void *context
= NULL
;
207 context
= contextInterface
->enumContextsInStore(memStore
, context
);
211 DWORD hashSize
= sizeof(hash
);
213 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
220 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
222 buf
= CryptMemAlloc(size
);
225 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
227 ret
= CRYPT_WriteSerializedToReg(key
, flags
, hash
, buf
, size
);
234 } while (ret
&& context
!= NULL
);
236 Context_Release(context_from_ptr(context
));
240 static BOOL
CRYPT_RegWriteToReg(WINE_REGSTOREINFO
*store
)
242 static const WCHAR
* const subKeys
[] = { L
"Certificates", L
"CRLs", L
"CTLs" };
243 const WINE_CONTEXT_INTERFACE
* const interfaces
[] = { pCertInterface
,
244 pCRLInterface
, pCTLInterface
};
245 struct list
*listToDelete
[] = { &store
->certsToDelete
, &store
->crlsToDelete
,
246 &store
->ctlsToDelete
};
250 for (i
= 0; ret
&& i
< ARRAY_SIZE(subKeys
); i
++)
253 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
254 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
260 WINE_HASH_TO_DELETE
*toDelete
, *next
;
261 WCHAR asciiHash
[20 * 2 + 1];
263 EnterCriticalSection(&store
->cs
);
264 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
265 WINE_HASH_TO_DELETE
, entry
)
269 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
270 TRACE("Removing %s\n", debugstr_w(asciiHash
));
271 rc
= RegDeleteKeyW(key
, asciiHash
);
272 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
277 list_remove(&toDelete
->entry
);
278 CryptMemFree(toDelete
);
280 LeaveCriticalSection(&store
->cs
);
282 ret
= CRYPT_SerializeContextsToReg(key
, 0, interfaces
[i
], store
->memStore
);
294 /* If force is true or the registry store is dirty, writes the contents of the
295 * store to the registry.
297 static BOOL
CRYPT_RegFlushStore(WINE_REGSTOREINFO
*store
, BOOL force
)
301 TRACE("(%p, %d)\n", store
, force
);
303 if (store
->dirty
|| force
)
305 ret
= CRYPT_RegWriteToReg(store
);
307 store
->dirty
= FALSE
;
314 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
316 WINE_REGSTOREINFO
*store
= hCertStore
;
318 TRACE("(%p, %08lx)\n", store
, dwFlags
);
320 FIXME("Unimplemented flags: %08lx\n", dwFlags
);
322 CRYPT_RegFlushStore(store
, FALSE
);
323 RegCloseKey(store
->key
);
324 store
->cs
.DebugInfo
->Spare
[0] = 0;
325 DeleteCriticalSection(&store
->cs
);
329 static BOOL
CRYPT_RegWriteContext(WINE_REGSTOREINFO
*store
,
330 const void *context
, DWORD dwFlags
)
334 if (dwFlags
& CERT_STORE_PROV_WRITE_ADD_FLAG
)
344 static BOOL
CRYPT_RegDeleteContext(WINE_REGSTOREINFO
*store
,
345 struct list
*deleteList
, const void *context
,
346 const WINE_CONTEXT_INTERFACE
*contextInterface
)
350 if (store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
352 SetLastError(ERROR_ACCESS_DENIED
);
357 WINE_HASH_TO_DELETE
*toDelete
= CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
361 DWORD size
= sizeof(toDelete
->hash
);
363 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
,
364 toDelete
->hash
, &size
);
367 EnterCriticalSection(&store
->cs
);
368 list_add_tail(deleteList
, &toDelete
->entry
);
369 LeaveCriticalSection(&store
->cs
);
373 CryptMemFree(toDelete
);
385 static BOOL WINAPI
CRYPT_RegWriteCert(HCERTSTORE hCertStore
,
386 PCCERT_CONTEXT cert
, DWORD dwFlags
)
388 WINE_REGSTOREINFO
*store
= hCertStore
;
390 TRACE("(%p, %p, %ld)\n", hCertStore
, cert
, dwFlags
);
392 return CRYPT_RegWriteContext(store
, cert
, dwFlags
);
395 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
396 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
398 WINE_REGSTOREINFO
*store
= hCertStore
;
400 TRACE("(%p, %p, %08lx)\n", store
, pCertContext
, dwFlags
);
402 return CRYPT_RegDeleteContext(store
, &store
->certsToDelete
, pCertContext
,
406 static BOOL WINAPI
CRYPT_RegWriteCRL(HCERTSTORE hCertStore
,
407 PCCRL_CONTEXT crl
, DWORD dwFlags
)
409 WINE_REGSTOREINFO
*store
= hCertStore
;
411 TRACE("(%p, %p, %ld)\n", hCertStore
, crl
, dwFlags
);
413 return CRYPT_RegWriteContext(store
, crl
, dwFlags
);
416 static BOOL WINAPI
CRYPT_RegDeleteCRL(HCERTSTORE hCertStore
,
417 PCCRL_CONTEXT pCrlContext
, DWORD dwFlags
)
419 WINE_REGSTOREINFO
*store
= hCertStore
;
421 TRACE("(%p, %p, %08lx)\n", store
, pCrlContext
, dwFlags
);
423 return CRYPT_RegDeleteContext(store
, &store
->crlsToDelete
, pCrlContext
,
427 static BOOL WINAPI
CRYPT_RegWriteCTL(HCERTSTORE hCertStore
,
428 PCCTL_CONTEXT ctl
, DWORD dwFlags
)
430 WINE_REGSTOREINFO
*store
= hCertStore
;
432 TRACE("(%p, %p, %ld)\n", hCertStore
, ctl
, dwFlags
);
434 return CRYPT_RegWriteContext(store
, ctl
, dwFlags
);
437 static BOOL WINAPI
CRYPT_RegDeleteCTL(HCERTSTORE hCertStore
,
438 PCCTL_CONTEXT pCtlContext
, DWORD dwFlags
)
440 WINE_REGSTOREINFO
*store
= hCertStore
;
442 TRACE("(%p, %p, %08lx)\n", store
, pCtlContext
, dwFlags
);
444 return CRYPT_RegDeleteContext(store
, &store
->ctlsToDelete
, pCtlContext
,
448 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
449 DWORD dwCtrlType
, void const *pvCtrlPara
)
451 WINE_REGSTOREINFO
*store
= hCertStore
;
454 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
459 case CERT_STORE_CTRL_RESYNC
:
461 HCERTSTORE memStore
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
462 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
464 CRYPT_RegFlushStore(store
, FALSE
);
465 CRYPT_RegReadFromReg(store
->key
, memStore
, CERT_STORE_ADD_REPLACE_EXISTING
);
466 I_CertUpdateStore(store
->memStore
, memStore
, 0, 0);
467 CertCloseStore(memStore
, 0);
470 case CERT_STORE_CTRL_COMMIT
:
471 ret
= CRYPT_RegFlushStore(store
,
472 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
474 case CERT_STORE_CTRL_AUTO_RESYNC
:
475 FIXME("CERT_STORE_CTRL_AUTO_RESYNC: stub\n");
477 case CERT_STORE_CTRL_NOTIFY_CHANGE
:
478 FIXME("CERT_STORE_CTRL_NOTIFY_CHANGE: stub\n");
481 FIXME("%lu: stub\n", dwCtrlType
);
487 static void *regProvFuncs
[] = {
489 NULL
, /* CERT_STORE_PROV_READ_CERT_FUNC */
492 NULL
, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
493 NULL
, /* CERT_STORE_PROV_READ_CRL_FUNC */
496 NULL
, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
497 NULL
, /* CERT_STORE_PROV_READ_CTL_FUNC */
500 NULL
, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
504 WINECRYPT_CERTSTORE
*CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
, DWORD dwFlags
,
507 WINECRYPT_CERTSTORE
*store
= NULL
;
509 TRACE("(%Id, %08lx, %p)\n", hCryptProv
, dwFlags
, pvPara
);
511 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
513 DWORD rc
= RegDeleteTreeW((HKEY
)pvPara
, L
"Certificates");
515 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
516 rc
= RegDeleteTreeW((HKEY
)pvPara
, L
"CRLs");
517 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
518 rc
= RegDeleteTreeW((HKEY
)pvPara
, L
"CTLs");
519 if (rc
== ERROR_NO_MORE_ITEMS
)
527 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
528 GetCurrentProcess(), (LPHANDLE
)&key
,
529 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
532 WINECRYPT_CERTSTORE
*memStore
;
534 memStore
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, hCryptProv
,
535 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
538 WINE_REGSTOREINFO
*regInfo
= CryptMemAlloc(
539 sizeof(WINE_REGSTOREINFO
));
543 CERT_STORE_PROV_INFO provInfo
= { 0 };
545 regInfo
->dwOpenFlags
= dwFlags
;
546 regInfo
->memStore
= memStore
;
548 InitializeCriticalSection(®Info
->cs
);
549 regInfo
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_REGSTOREINFO->cs");
550 list_init(®Info
->certsToDelete
);
551 list_init(®Info
->crlsToDelete
);
552 list_init(®Info
->ctlsToDelete
);
553 CRYPT_RegReadFromReg(regInfo
->key
, regInfo
->memStore
, CERT_STORE_ADD_ALWAYS
);
554 regInfo
->dirty
= FALSE
;
555 provInfo
.cbSize
= sizeof(provInfo
);
556 provInfo
.cStoreProvFunc
= ARRAY_SIZE(regProvFuncs
);
557 provInfo
.rgpvStoreProvFunc
= regProvFuncs
;
558 provInfo
.hStoreProv
= regInfo
;
559 store
= CRYPT_ProvCreateStore(dwFlags
, memStore
, &provInfo
);
560 /* Reg store doesn't need crypto provider, so close it */
562 !(dwFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
563 CryptReleaseContext(hCryptProv
, 0);
568 TRACE("returning %p\n", store
);