crypt32: Import system root certs into volatile registry keys instead of dedicated root store.

Signed-off-by: Donat Enikeev <donat@enikeev.net>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Donat Enikeev 2016-11-07 17:37:29 +01:00 committed by Alexandre Julliard
parent 441fe55a4b
commit c2b0dfd73d
5 changed files with 56 additions and 97 deletions

View File

@ -336,7 +336,11 @@ WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
DWORD dwFlags, const void *pvPara) DECLSPEC_HIDDEN; DWORD dwFlags, const void *pvPara) DECLSPEC_HIDDEN;
WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
DWORD dwFlags, const void *pvPara) DECLSPEC_HIDDEN; DWORD dwFlags, const void *pvPara) DECLSPEC_HIDDEN;
WINECRYPT_CERTSTORE *CRYPT_RootOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags) DECLSPEC_HIDDEN;
void CRYPT_ImportSystemRootCertsToReg(void) DECLSPEC_HIDDEN;
BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *contextInterface,
HCERTSTORE memStore) DECLSPEC_HIDDEN;
BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert) DECLSPEC_HIDDEN; BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert) DECLSPEC_HIDDEN;
/* Allocates and initializes a certificate chain engine, but without creating /* Allocates and initializes a certificate chain engine, but without creating

View File

@ -49,7 +49,6 @@ BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, PVOID pvReserved)
if (pvReserved) break; if (pvReserved) break;
crypt_oid_free(); crypt_oid_free();
crypt_sip_free(); crypt_sip_free();
root_store_free();
default_chain_engine_free(); default_chain_engine_free();
if (hDefProv) CryptReleaseContext(hDefProv, 0); if (hDefProv) CryptReleaseContext(hDefProv, 0);
break; break;

View File

@ -179,7 +179,7 @@ static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store)
} }
/* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */ /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *buf, static BOOL CRYPT_WriteSerializedToReg(HKEY key, DWORD flags, const BYTE *hash, const BYTE *buf,
DWORD len) DWORD len)
{ {
WCHAR asciiHash[20 * 2 + 1]; WCHAR asciiHash[20 * 2 + 1];
@ -188,7 +188,7 @@ static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *b
BOOL ret; BOOL ret;
CRYPT_HashToStr(hash, asciiHash); CRYPT_HashToStr(hash, asciiHash);
rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL, rc = RegCreateKeyExW(key, asciiHash, 0, NULL, flags, KEY_ALL_ACCESS, NULL,
&subKey, NULL); &subKey, NULL);
if (!rc) if (!rc)
{ {
@ -205,7 +205,7 @@ static BOOL CRYPT_WriteSerializedToReg(HKEY key, const BYTE *hash, const BYTE *b
return ret; return ret;
} }
static BOOL CRYPT_SerializeContextsToReg(HKEY key, BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags,
const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
{ {
const void *context = NULL; const void *context = NULL;
@ -232,7 +232,7 @@ static BOOL CRYPT_SerializeContextsToReg(HKEY key,
{ {
ret = contextInterface->serialize(context, 0, buf, &size); ret = contextInterface->serialize(context, 0, buf, &size);
if (ret) if (ret)
ret = CRYPT_WriteSerializedToReg(key, hash, buf, size); ret = CRYPT_WriteSerializedToReg(key, flags, hash, buf, size);
} }
CryptMemFree(buf); CryptMemFree(buf);
} }
@ -287,8 +287,7 @@ static BOOL CRYPT_RegWriteToReg(WINE_REGSTOREINFO *store)
} }
LeaveCriticalSection(&store->cs); LeaveCriticalSection(&store->cs);
} }
ret = CRYPT_SerializeContextsToReg(key, interfaces[i], ret = CRYPT_SerializeContextsToReg(key, 0, interfaces[i], store->memStore);
store->memStore);
RegCloseKey(key); RegCloseKey(key);
} }
else else

View File

@ -435,53 +435,6 @@ static BOOL import_certs_from_path(LPCSTR path, HCERTSTORE store,
return ret; return ret;
} }
static BOOL WINAPI CRYPT_RootWriteCert(HCERTSTORE hCertStore,
PCCERT_CONTEXT cert, DWORD dwFlags)
{
/* The root store can't have certs added */
return FALSE;
}
static BOOL WINAPI CRYPT_RootDeleteCert(HCERTSTORE hCertStore,
PCCERT_CONTEXT cert, DWORD dwFlags)
{
/* The root store can't have certs deleted */
return FALSE;
}
static BOOL WINAPI CRYPT_RootWriteCRL(HCERTSTORE hCertStore,
PCCRL_CONTEXT crl, DWORD dwFlags)
{
/* The root store can have CRLs added. At worst, a malicious application
* can DoS itself, as the changes aren't persisted in any way.
*/
return TRUE;
}
static BOOL WINAPI CRYPT_RootDeleteCRL(HCERTSTORE hCertStore,
PCCRL_CONTEXT crl, DWORD dwFlags)
{
/* The root store can't have CRLs deleted */
return FALSE;
}
static void *rootProvFuncs[] = {
NULL, /* CERT_STORE_PROV_CLOSE_FUNC */
NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
CRYPT_RootWriteCert,
CRYPT_RootDeleteCert,
NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
CRYPT_RootWriteCRL,
CRYPT_RootDeleteCRL,
NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
NULL, /* CERT_STORE_PROV_CONTROL_FUNC */
};
static const char * const CRYPT_knownLocations[] = { static const char * const CRYPT_knownLocations[] = {
"/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/ca-certificates.crt",
"/etc/ssl/certs", "/etc/ssl/certs",
@ -790,55 +743,65 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store)
static HCERTSTORE create_root_store(void) static HCERTSTORE create_root_store(void)
{ {
HCERTSTORE root = NULL;
HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
if (memStore) if (memStore)
{ {
CERT_STORE_PROV_INFO provInfo = {
sizeof(CERT_STORE_PROV_INFO),
sizeof(rootProvFuncs) / sizeof(rootProvFuncs[0]),
rootProvFuncs,
NULL,
0,
NULL
};
read_trusted_roots_from_known_locations(memStore); read_trusted_roots_from_known_locations(memStore);
add_ms_root_certs(memStore); add_ms_root_certs(memStore);
root = CRYPT_ProvCreateStore(0, memStore, &provInfo);
} }
TRACE("returning %p\n", root);
return root; TRACE("returning %p\n", memStore);
return memStore;
} }
static WINECRYPT_CERTSTORE *CRYPT_rootStore; static const WCHAR certs_root_pathW[] =
{'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
'S','y','s','t','e','m','C','e','r','t','i','f','i','c','a','t','e','s','\\',
'R','o','o','t','\\', 'C','e','r','t','i','f','i','c','a','t','e','s', 0};
static const WCHAR semaphoreW[] =
{'c','r','y','p','t','3','2','_','r','o','o','t','_','s','e','m','a','p','h','o','r','e',0};
WINECRYPT_CERTSTORE *CRYPT_RootOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags) void CRYPT_ImportSystemRootCertsToReg(void)
{ {
TRACE("(%ld, %08x)\n", hCryptProv, dwFlags); HCERTSTORE store = NULL;
HKEY key;
LONG rc;
HANDLE hsem;
if (dwFlags & CERT_STORE_DELETE_FLAG) static BOOL root_certs_imported = FALSE;
if (root_certs_imported)
return;
hsem = CreateSemaphoreW( NULL, 0, 1, semaphoreW);
if (!hsem)
{ {
WARN("root store can't be deleted\n"); ERR("Failed to create semaphore\n");
SetLastError(ERROR_ACCESS_DENIED); return;
return NULL;
} }
if (!CRYPT_rootStore)
if(GetLastError() == ERROR_ALREADY_EXISTS)
WaitForSingleObject(hsem, INFINITE);
else
{ {
HCERTSTORE root = create_root_store(); if ((store = create_root_store()))
{
InterlockedCompareExchangePointer((PVOID *)&CRYPT_rootStore, root, rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, certs_root_pathW, 0, NULL, 0,
NULL); KEY_ALL_ACCESS, NULL, &key, 0);
if (CRYPT_rootStore != root) if (!rc)
CertCloseStore(root, 0); {
if (!CRYPT_SerializeContextsToReg(key, REG_OPTION_VOLATILE, pCertInterface, store))
ERR("Failed to import system certs into registry, %08x\n", GetLastError());
RegCloseKey(key);
}
CertCloseStore(store, 0);
} else
ERR("Failed to create root store\n");
} }
CRYPT_rootStore->vtbl->addref(CRYPT_rootStore);
return CRYPT_rootStore;
}
void root_store_free(void) root_certs_imported = TRUE;
{ ReleaseSemaphore(hsem, 1, NULL);
CertCloseStore(CRYPT_rootStore, 0); CloseHandle(hsem);
} }

View File

@ -424,21 +424,15 @@ static WINECRYPT_CERTSTORE *CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
SetLastError(E_INVALIDARG); SetLastError(E_INVALIDARG);
return NULL; return NULL;
} }
/* FIXME: In Windows, the root store (even the current user location) is
* protected: adding to it or removing from it present a user interface,
* and the keys are owned by the system process, not the current user.
* Wine's registry doesn't implement access controls, so a similar
* mechanism isn't possible yet.
*/
if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
CERT_SYSTEM_STORE_LOCAL_MACHINE && !lstrcmpiW(storeName, rootW))
return CRYPT_RootOpenStore(hCryptProv, dwFlags);
switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
{ {
case CERT_SYSTEM_STORE_LOCAL_MACHINE: case CERT_SYSTEM_STORE_LOCAL_MACHINE:
root = HKEY_LOCAL_MACHINE; root = HKEY_LOCAL_MACHINE;
base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH; base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
/* If the HKLM\Root certs are requested, expressing system certs into the registry */
if (!lstrcmpiW(storeName, rootW))
CRYPT_ImportSystemRootCertsToReg();
break; break;
case CERT_SYSTEM_STORE_CURRENT_USER: case CERT_SYSTEM_STORE_CURRENT_USER:
root = HKEY_CURRENT_USER; root = HKEY_CURRENT_USER;