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 "wine/list.h"
27 #include "crypt32_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
31 typedef struct _WINE_HASH_TO_DELETE
35 } WINE_HASH_TO_DELETE
, *PWINE_HASH_TO_DELETE
;
37 typedef struct _WINE_REGSTOREINFO
44 struct list certsToDelete
;
45 struct list crlsToDelete
;
46 struct list ctlsToDelete
;
47 } WINE_REGSTOREINFO
, *PWINE_REGSTOREINFO
;
49 static void CRYPT_HashToStr(const BYTE
*hash
, LPWSTR asciiHash
)
51 static const WCHAR fmt
[] = { '%','0','2','X',0 };
57 for (i
= 0; i
< 20; i
++)
58 wsprintfW(asciiHash
+ i
* 2, fmt
, hash
[i
]);
61 static const WCHAR CertsW
[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
63 static const WCHAR CRLsW
[] = { 'C','R','L','s',0 };
64 static const WCHAR CTLsW
[] = { 'C','T','L','s',0 };
65 static const WCHAR BlobW
[] = { 'B','l','o','b',0 };
67 static void CRYPT_RegReadSerializedFromReg(HKEY key
, DWORD contextType
,
72 WCHAR subKeyName
[MAX_PATH
];
75 DWORD size
= sizeof(subKeyName
) / sizeof(WCHAR
);
77 rc
= RegEnumKeyExW(key
, index
++, subKeyName
, &size
, NULL
, NULL
, NULL
,
83 rc
= RegOpenKeyExW(key
, subKeyName
, 0, KEY_READ
, &subKey
);
89 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, NULL
, &size
);
91 buf
= CryptMemAlloc(size
);
94 rc
= RegQueryValueExW(subKey
, BlobW
, NULL
, NULL
, buf
,
101 TRACE("Adding cert with hash %s\n",
102 debugstr_w(subKeyName
));
103 context
= CRYPT_ReadSerializedElement(buf
, size
,
104 contextType
, &addedType
);
107 const WINE_CONTEXT_INTERFACE
*contextInterface
;
112 case CERT_STORE_CERTIFICATE_CONTEXT
:
113 contextInterface
= pCertInterface
;
115 case CERT_STORE_CRL_CONTEXT
:
116 contextInterface
= pCRLInterface
;
118 case CERT_STORE_CTL_CONTEXT
:
119 contextInterface
= pCTLInterface
;
122 contextInterface
= NULL
;
124 if (contextInterface
)
127 if (contextInterface
->getProp(context
,
128 CERT_HASH_PROP_ID
, hash
, &size
))
130 WCHAR asciiHash
[20 * 2 + 1];
132 CRYPT_HashToStr(hash
, asciiHash
);
133 TRACE("comparing %s\n",
134 debugstr_w(asciiHash
));
135 TRACE("with %s\n", debugstr_w(subKeyName
));
136 if (!lstrcmpW(asciiHash
, subKeyName
))
138 TRACE("hash matches, adding\n");
139 contextInterface
->addContextToStore(
141 CERT_STORE_ADD_REPLACE_EXISTING
, NULL
);
144 TRACE("hash doesn't match, ignoring\n");
146 contextInterface
->free(context
);
154 /* Ignore intermediate errors, continue enumerating */
160 static void CRYPT_RegReadFromReg(HKEY key
, HCERTSTORE store
)
162 static const WCHAR
* const subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
163 static const DWORD contextFlags
[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG
,
164 CERT_STORE_CRL_CONTEXT_FLAG
, CERT_STORE_CTL_CONTEXT_FLAG
};
167 for (i
= 0; i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
172 rc
= RegCreateKeyExW(key
, subKeys
[i
], 0, NULL
, 0, KEY_READ
, NULL
,
176 CRYPT_RegReadSerializedFromReg(hKey
, contextFlags
[i
], store
);
182 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
183 static BOOL
CRYPT_WriteSerializedToReg(HKEY key
, const BYTE
*hash
, const BYTE
*buf
,
186 WCHAR asciiHash
[20 * 2 + 1];
191 CRYPT_HashToStr(hash
, asciiHash
);
192 rc
= RegCreateKeyExW(key
, asciiHash
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
,
196 rc
= RegSetValueExW(subKey
, BlobW
, 0, REG_BINARY
, buf
, len
);
209 static BOOL
CRYPT_SerializeContextsToReg(HKEY key
,
210 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE memStore
)
212 const void *context
= NULL
;
216 context
= contextInterface
->enumContextsInStore(memStore
, context
);
220 DWORD hashSize
= sizeof(hash
);
222 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
, hash
,
229 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
231 buf
= CryptMemAlloc(size
);
234 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
236 ret
= CRYPT_WriteSerializedToReg(key
, hash
, buf
, size
);
243 } while (ret
&& context
!= NULL
);
245 contextInterface
->free(context
);
249 static BOOL
CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store
)
251 static const WCHAR
* const subKeys
[] = { CertsW
, CRLsW
, CTLsW
};
252 const WINE_CONTEXT_INTERFACE
* const interfaces
[] = { pCertInterface
,
253 pCRLInterface
, pCTLInterface
};
254 struct list
*listToDelete
[] = { &store
->certsToDelete
, &store
->crlsToDelete
,
255 &store
->ctlsToDelete
};
259 for (i
= 0; ret
&& i
< sizeof(subKeys
) / sizeof(subKeys
[0]); i
++)
262 LONG rc
= RegCreateKeyExW(store
->key
, subKeys
[i
], 0, NULL
, 0,
263 KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
269 PWINE_HASH_TO_DELETE toDelete
, next
;
270 WCHAR asciiHash
[20 * 2 + 1];
272 EnterCriticalSection(&store
->cs
);
273 LIST_FOR_EACH_ENTRY_SAFE(toDelete
, next
, listToDelete
[i
],
274 WINE_HASH_TO_DELETE
, entry
)
278 CRYPT_HashToStr(toDelete
->hash
, asciiHash
);
279 TRACE("Removing %s\n", debugstr_w(asciiHash
));
280 rc
= RegDeleteKeyW(key
, asciiHash
);
281 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
286 list_remove(&toDelete
->entry
);
287 CryptMemFree(toDelete
);
289 LeaveCriticalSection(&store
->cs
);
291 ret
= CRYPT_SerializeContextsToReg(key
, interfaces
[i
],
304 /* If force is true or the registry store is dirty, writes the contents of the
305 * store to the registry.
307 static BOOL
CRYPT_RegFlushStore(PWINE_REGSTOREINFO store
, BOOL force
)
311 TRACE("(%p, %d)\n", store
, force
);
313 if (store
->dirty
|| force
)
314 ret
= CRYPT_RegWriteToReg(store
);
320 static void WINAPI
CRYPT_RegCloseStore(HCERTSTORE hCertStore
, DWORD dwFlags
)
322 PWINE_REGSTOREINFO store
= hCertStore
;
324 TRACE("(%p, %08x)\n", store
, dwFlags
);
326 FIXME("Unimplemented flags: %08x\n", dwFlags
);
328 CRYPT_RegFlushStore(store
, FALSE
);
329 RegCloseKey(store
->key
);
330 store
->cs
.DebugInfo
->Spare
[0] = 0;
331 DeleteCriticalSection(&store
->cs
);
335 static BOOL
CRYPT_RegWriteContext(PWINE_REGSTOREINFO store
,
336 const void *context
, DWORD dwFlags
)
340 if (dwFlags
& CERT_STORE_PROV_WRITE_ADD_FLAG
)
350 static BOOL
CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store
,
351 struct list
*deleteList
, const void *context
,
352 PCWINE_CONTEXT_INTERFACE contextInterface
)
356 if (store
->dwOpenFlags
& CERT_STORE_READONLY_FLAG
)
358 SetLastError(ERROR_ACCESS_DENIED
);
363 PWINE_HASH_TO_DELETE toDelete
=
364 CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE
));
368 DWORD size
= sizeof(toDelete
->hash
);
370 ret
= contextInterface
->getProp(context
, CERT_HASH_PROP_ID
,
371 toDelete
->hash
, &size
);
374 EnterCriticalSection(&store
->cs
);
375 list_add_tail(deleteList
, &toDelete
->entry
);
376 LeaveCriticalSection(&store
->cs
);
380 CryptMemFree(toDelete
);
392 static BOOL WINAPI
CRYPT_RegWriteCert(HCERTSTORE hCertStore
,
393 PCCERT_CONTEXT cert
, DWORD dwFlags
)
395 PWINE_REGSTOREINFO store
= hCertStore
;
397 TRACE("(%p, %p, %d)\n", hCertStore
, cert
, dwFlags
);
399 return CRYPT_RegWriteContext(store
, cert
, dwFlags
);
402 static BOOL WINAPI
CRYPT_RegDeleteCert(HCERTSTORE hCertStore
,
403 PCCERT_CONTEXT pCertContext
, DWORD dwFlags
)
405 PWINE_REGSTOREINFO store
= hCertStore
;
407 TRACE("(%p, %p, %08x)\n", store
, pCertContext
, dwFlags
);
409 return CRYPT_RegDeleteContext(store
, &store
->certsToDelete
, pCertContext
,
413 static BOOL WINAPI
CRYPT_RegWriteCRL(HCERTSTORE hCertStore
,
414 PCCRL_CONTEXT crl
, DWORD dwFlags
)
416 PWINE_REGSTOREINFO store
= hCertStore
;
418 TRACE("(%p, %p, %d)\n", hCertStore
, crl
, dwFlags
);
420 return CRYPT_RegWriteContext(store
, crl
, dwFlags
);
423 static BOOL WINAPI
CRYPT_RegDeleteCRL(HCERTSTORE hCertStore
,
424 PCCRL_CONTEXT pCrlContext
, DWORD dwFlags
)
426 PWINE_REGSTOREINFO store
= hCertStore
;
428 TRACE("(%p, %p, %08x)\n", store
, pCrlContext
, dwFlags
);
430 return CRYPT_RegDeleteContext(store
, &store
->crlsToDelete
, pCrlContext
,
434 static BOOL WINAPI
CRYPT_RegWriteCTL(HCERTSTORE hCertStore
,
435 PCCTL_CONTEXT ctl
, DWORD dwFlags
)
437 PWINE_REGSTOREINFO store
= hCertStore
;
439 TRACE("(%p, %p, %d)\n", hCertStore
, ctl
, dwFlags
);
441 return CRYPT_RegWriteContext(store
, ctl
, dwFlags
);
444 static BOOL WINAPI
CRYPT_RegDeleteCTL(HCERTSTORE hCertStore
,
445 PCCTL_CONTEXT pCtlContext
, DWORD dwFlags
)
447 PWINE_REGSTOREINFO store
= hCertStore
;
449 TRACE("(%p, %p, %08x)\n", store
, pCtlContext
, dwFlags
);
451 return CRYPT_RegDeleteContext(store
, &store
->ctlsToDelete
, pCtlContext
,
455 static BOOL WINAPI
CRYPT_RegControl(HCERTSTORE hCertStore
, DWORD dwFlags
,
456 DWORD dwCtrlType
, void const *pvCtrlPara
)
458 PWINE_REGSTOREINFO store
= hCertStore
;
461 TRACE("(%p, %08x, %d, %p)\n", hCertStore
, dwFlags
, dwCtrlType
,
466 case CERT_STORE_CTRL_RESYNC
:
468 HCERTSTORE memStore
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
469 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
471 CRYPT_RegFlushStore(store
, FALSE
);
472 CRYPT_RegReadFromReg(store
->key
, memStore
);
473 I_CertUpdateStore(store
->memStore
, memStore
, 0, 0);
474 CertCloseStore(memStore
, 0);
478 case CERT_STORE_CTRL_COMMIT
:
479 ret
= CRYPT_RegFlushStore(store
,
480 dwFlags
& CERT_STORE_CTRL_COMMIT_FORCE_FLAG
);
483 FIXME("%d: stub\n", dwCtrlType
);
489 static void *regProvFuncs
[] = {
491 NULL
, /* CERT_STORE_PROV_READ_CERT_FUNC */
494 NULL
, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
495 NULL
, /* CERT_STORE_PROV_READ_CRL_FUNC */
498 NULL
, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
499 NULL
, /* CERT_STORE_PROV_READ_CTL_FUNC */
502 NULL
, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
506 PWINECRYPT_CERTSTORE
CRYPT_RegOpenStore(HCRYPTPROV hCryptProv
, DWORD dwFlags
,
509 PWINECRYPT_CERTSTORE store
= NULL
;
511 TRACE("(%ld, %08x, %p)\n", hCryptProv
, dwFlags
, pvPara
);
513 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
515 DWORD rc
= RegDeleteTreeW((HKEY
)pvPara
, CertsW
);
517 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
518 rc
= RegDeleteTreeW((HKEY
)pvPara
, CRLsW
);
519 if (rc
== ERROR_SUCCESS
|| rc
== ERROR_NO_MORE_ITEMS
)
520 rc
= RegDeleteTreeW((HKEY
)pvPara
, CTLsW
);
521 if (rc
== ERROR_NO_MORE_ITEMS
)
529 if (DuplicateHandle(GetCurrentProcess(), (HANDLE
)pvPara
,
530 GetCurrentProcess(), (LPHANDLE
)&key
,
531 dwFlags
& CERT_STORE_READONLY_FLAG
? KEY_READ
: KEY_ALL_ACCESS
,
534 PWINECRYPT_CERTSTORE memStore
;
536 memStore
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, hCryptProv
,
537 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
540 PWINE_REGSTOREINFO regInfo
= CryptMemAlloc(
541 sizeof(WINE_REGSTOREINFO
));
545 CERT_STORE_PROV_INFO provInfo
= { 0 };
547 regInfo
->dwOpenFlags
= dwFlags
;
548 regInfo
->memStore
= memStore
;
550 InitializeCriticalSection(®Info
->cs
);
551 regInfo
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_REGSTOREINFO->cs");
552 list_init(®Info
->certsToDelete
);
553 list_init(®Info
->crlsToDelete
);
554 list_init(®Info
->ctlsToDelete
);
555 CRYPT_RegReadFromReg(regInfo
->key
, regInfo
->memStore
);
556 regInfo
->dirty
= FALSE
;
557 provInfo
.cbSize
= sizeof(provInfo
);
558 provInfo
.cStoreProvFunc
= sizeof(regProvFuncs
) /
559 sizeof(regProvFuncs
[0]);
560 provInfo
.rgpvStoreProvFunc
= regProvFuncs
;
561 provInfo
.hStoreProv
= regInfo
;
562 store
= CRYPT_ProvCreateStore(dwFlags
, memStore
, &provInfo
);
563 /* Reg store doesn't need crypto provider, so close it */
565 !(dwFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
566 CryptReleaseContext(hCryptProv
, 0);
571 TRACE("returning %p\n", store
);