修改密钥容器访问
CryptoAPI 创建的默认密钥容器不允许从 LocalService 或 NetworkService 帐户访问密钥。 可以使用 CryptSetProvParam 函数修改 PP_KEYSET_SEC_DESCR 参数,以编程方式更正此问题。
以下示例演示如何使用 CryptSetProvParam 函数修改 PP_KEYSET_SEC_DESCR 以允许访问 LocalService 或 NetworkService 帐户的密钥容器。
注意
以下代码作为工具提供,仅当绝对必要时才应使用。 只需在每台计算机上运行一次此代码即可允许访问密钥。
//-------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Example of how to modify the access restrictions for the default
// key container.
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
// Link with the Advapi32.lib file.
#pragma comment (lib, "advapi32")
// Local function prototypes.
BOOL GetHandleToCSP(HCRYPTPROV*, LPCTSTR, DWORD);
BOOL GenPrivateKeys(HCRYPTPROV,DWORD);
BOOL GetHandleToCSP(HCRYPTPROV*, LPCTSTR, DWORD);
SECURITY_DESCRIPTOR* GetProvSecurityDesc(HCRYPTPROV);
BOOL ModifyDacl(HCRYPTPROV hProv);
#define MY_CONTAINER_NAME TEXT("testcapiservicemachinecontainer")
int _tmain(int argc, _TCHAR* argv[])
{
HCRYPTKEY hKey = 0;
HCRYPTPROV hProv = 0;
if(!GetHandleToCSP(
&hProv,
MY_CONTAINER_NAME,
CRYPT_MACHINE_KEYSET))
{
printf("OpenCtxHandle failed.\n");
goto CommonReturn;
}
printf("Acquired a context.\n");
if(!GenPrivateKeys(hProv,0))
{
printf("GenPrivateKeys failed.\n");
goto CommonReturn;
}
printf("Generated Private keys.\n");
// Change the ACLs to allow read for local service.
if(!ModifyDacl(hProv))
{
printf("ModifyDacl failed.\n");
goto CommonReturn;
}
printf("Modified default ACLs on container.\n");
CommonReturn:
if(hProv)
{
CryptReleaseContext(hProv, 0);
}
return 0;
}
/********************************************************************
GetHandleToCSP
Acquire a handle to the cryptographic service provider.
********************************************************************/
BOOL GetHandleToCSP(
HCRYPTPROV *phProv,
LPCTSTR pszContainerName,
DWORD dwProvFlag)
{
if(!CryptAcquireContext(
phProv,
pszContainerName,
MS_STRONG_PROV,
PROV_RSA_FULL,
dwProvFlag))
{
if(NTE_BAD_KEYSET == GetLastError() ||
NTE_EXISTS == GetLastError())
{
if(!CryptAcquireContext(
phProv,
pszContainerName,
MS_STRONG_PROV,
PROV_RSA_FULL,
CRYPT_NEWKEYSET | dwProvFlag))
{
printf("Error 0x%08x.\n",GetLastError());
return FALSE;
}
}
else
{
printf(" Error in CryptAcquireContext 0x%08x.\n",
GetLastError());
return FALSE;
}
}
return TRUE;
}
/********************************************************************
GenPrivateKeys
Generates a signature and a key exchange key.
********************************************************************/
BOOL GenPrivateKeys(
HCRYPTPROV hProv,
DWORD dwflagkey)
{
BOOL fRet = FALSE;
HCRYPTKEY hSigKey = 0;
HCRYPTKEY hExchKey= 0;
// Generate the signature key.
if(!CryptGenKey(
hProv,
AT_SIGNATURE,
dwflagkey,
&hSigKey))
{
printf("CryptGenKey failed with 0x%08x.\n",GetLastError());
goto CommonReturn;
}
// Generate the key exchange key.
if(!CryptGenKey(
hProv,
AT_KEYEXCHANGE,
dwflagkey,
&hExchKey))
{
printf("CryptGenKey failed with 0x%08x.\n",GetLastError());
goto CommonReturn;
}
fRet = TRUE;
CommonReturn:
if(hSigKey)
{
CryptDestroyKey(hSigKey);
}
if(hExchKey)
{
CryptDestroyKey(hExchKey);
}
return fRet;
}
/********************************************************************
GetProvSecurityDesc
Retrieves the security descriptor for the specified provider.
********************************************************************/
SECURITY_DESCRIPTOR* GetProvSecurityDesc(HCRYPTPROV hProv)
{
SECURITY_DESCRIPTOR *psd = NULL;
unsigned long ulSize = 0;
// Get the size of the security descriptor.
if(!CryptGetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
0,
&ulSize,
DACL_SECURITY_INFORMATION))
{
int ret = GetLastError();
if (ret != ERROR_INSUFFICIENT_BUFFER)
{
fprintf(
stderr,
"Error getting file security DACL: %d.\n",
ret);
goto Error_Occurred;
}
}
// Allocate the memory for the security descriptor.
psd = (SECURITY_DESCRIPTOR *)LocalAlloc(LPTR, ulSize);
if (!psd)
{
fprintf(stderr, "Out of memory for security descriptor!\n");
goto Error_Occurred;
}
// Retrieve the security descriptor.
if(!CryptGetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
(BYTE*)psd,
&ulSize,
DACL_SECURITY_INFORMATION))
{
fprintf(
stderr,
"CryptGetProvParam failed with 0x%08x.\n",
GetLastError());
goto Error_Occurred;
}
return psd;
Error_Occurred:
// An error occurred, so if memory was allocated, free it.
if(psd)
{
LocalFree(psd);
psd = NULL;
}
return NULL;
}
/********************************************************************
GetDacl
Retrieves the DACL from the specified security descriptor.
********************************************************************/
ACL* GetDacl(SECURITY_DESCRIPTOR *psd)
{
ACL *pACL = NULL;
int defaulted = 0;
int present = 0;
if (!psd)
{
return NULL;
}
if (!GetSecurityDescriptorDacl(
psd,
&present,
&pACL,
&defaulted))
{
fprintf(
stderr,
"Error getting DACL from security descriptor: %d.\n",
GetLastError());
return 0;
}
if (!present)
{
fprintf(
stderr,
"Security descriptor has no DACL present.\n");
return 0;
}
return pACL;
}
/********************************************************************
ModifyDacl
Modifies the DACL for the key storage folder for the specified
provider.
********************************************************************/
BOOL ModifyDacl(HCRYPTPROV hProv)
{
PSID pSid = NULL;
DWORD cbSid = 0;
LPTSTR szDomainName = NULL;
DWORD cbDomainName = 0;
SID_NAME_USE SidType;
EXPLICIT_ACCESS ea[1] = {0};
DWORD dwRes = 0;
SECURITY_DESCRIPTOR *pCurrentSD = NULL;
PSECURITY_DESCRIPTOR pNewSD = NULL;
PACL pCurrentDACL = NULL;
PACL pNewACL = NULL;
while (!LookupAccountName(
NULL,
TEXT("LocalService"),
pSid,
&cbSid,
szDomainName,
&cbDomainName,
&SidType))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
pSid = LocalAlloc(LPTR, cbSid);
szDomainName = (LPTSTR)LocalAlloc(LPTR,
(cbDomainName * sizeof(TCHAR)));
if (pSid == NULL || szDomainName == NULL)
{
printf("LocalAlloc failed.\n");
goto CommonReturn;
}
}
else
{
printf("LookupAccountName error: %d.\n",
GetLastError());
goto CommonReturn;
}
}
//Get existing ACLs for the file.
pCurrentSD = GetProvSecurityDesc(hProv);
if (!pCurrentSD)
{
printf("Unable to retrieve SD.\n");
goto CommonReturn;
}
pCurrentDACL = GetDacl(pCurrentSD);
if (!pCurrentDACL)
{
printf("Unable to retrieve DACL.\n");
goto CommonReturn;
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow the user read access to the container.
ZeroMemory(&ea, 1 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = FILE_READ_DATA;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance= NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
ea[0].Trustee.ptstrName = (LPTSTR) pSid;
// Create a new ACL that contains the new ACEs as well as the
// old ones.
dwRes = SetEntriesInAcl(1, ea, pCurrentDACL, &pNewACL);
if (ERROR_SUCCESS != dwRes)
{
printf("SetEntriesInAcl error: %u.\n", GetLastError());
goto CommonReturn;
}
// Initialize a security descriptor.
pNewSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pNewSD)
{
printf("LocalAlloc error: %u.\n", GetLastError());
goto CommonReturn;
}
if (!InitializeSecurityDescriptor(pNewSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("InitializeSecurityDescriptor error: %u.\n",
GetLastError());
goto CommonReturn;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(
pNewSD,
TRUE,
pNewACL,
FALSE))
{
printf("SetSecurityDescriptorDacl error: %u.\n",
GetLastError());
goto CommonReturn;
}
// Set the new security descriptor.
if(!CryptSetProvParam(
hProv,
PP_KEYSET_SEC_DESCR,
(BYTE*)pNewSD,
DACL_SECURITY_INFORMATION))
{
printf("CryptSetProvParam error: 0x%08x.\n",
GetLastError());
goto CommonReturn;
}
CommonReturn:
if(pSid)
{
LocalFree(pSid);
}
if (pNewACL)
{
LocalFree(pNewACL);
}
if (pNewSD)
{
LocalFree(pNewSD);
}
if(pCurrentSD)
{
LocalFree(pCurrentSD);
}
return 1;
}