问题
(Note: IMO the question is mainly about WinAPI and DACL and not about CNG, so please read on!)
I'm currently trying to modify the sample CNG key storage provider of Microsoft's Cryptographic Provider Development Kit in such a way that it does not store the keys in single files. However, I'm in trouble with the security descriptors that can be assigned to the private keys.
In the Certificates Snap-in of the Windows Server Management Console, private keys of certificates can be managed, i.e. the owner, DACL and SACL of a key can be changed, which results in a NCryptSetProperty call with a security descriptor as parameter. For the DACL, the snap-in only allows to allow/deny "full control" or "read", which results in the GENERIC_ALL or GENERIC_READ bit to be set in the access mask of the ACE.
As I have learnt, these generic bits need to be mapped to application specific rights - otherwise AccessCheck will not work. But do I really need to do this by hand???
CreatePrivateObjectSecurity+SetPrivateObjectSecurity does not always work since CreatePrivateObjectSecurity is very picky about the owner and group in the input security descriptor. Moreover, when the mapping is applied, the generic bits are cleared in the access mask, which results in the snap-in showing wrong settings (as I said, the snap-in only considers the GA and GR bits when displaying current permissions).
Seems I'm missing some pieces here...
回答1:
in your CPSetProvParam implementation for PP_KEYSET_SEC_DESCR
you got address of a SECURITY_DESCRIPTOR
, which you need somehow apply to your private key storage. if your storage based on file(s) or registry key(s) ( in principle any kernel object type, but what more can be used here ?) you need call SetKernelObjectSecurity with file or key HANDLE
(which must have WRITE_DAC
access) (may be multiple time if you say have multiple files for store single key). in kernel GENERIC access to object will be auto converted to object specific rights.
if your implementation of storage not direct based on some kernel object, but custom - you need yourself at this point convert GENERIC access (0xF0000000
mask) to specific access rights (0x0000FFFF
mask)
__________________ EDIT ____________________
after more check i found that provider must not only convert generic to specific access in CPSetProvParam but also convert specific to generic in CPGetProvParam despite this not directly point in documentation.
this is how MS_ENHANCED_PROV (implemented in rsaenh.dll
) approximately do this:
void CheckAndChangeAccessMask(PSECURITY_DESCRIPTOR SecurityDescriptor)
{
BOOL bDaclPresent, bDaclDefaulted;
PACL Dacl;
ACL_SIZE_INFORMATION asi;
if (
GetSecurityDescriptorDacl(SecurityDescriptor, &bDaclPresent, &Dacl, &bDaclDefaulted)
&&
bDaclPresent
&&
Dacl
&&
GetAclInformation(Dacl, &asi, sizeof(asi), AclSizeInformation)
&&
asi.AceCount
)
{
union{
PVOID pAce;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paa;
};
do
{
if (GetAce(Dacl, --asi.AceCount, &pAce))
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
ACCESS_MASK Mask = paa->Mask, Gen_Mask = 0;
if (Mask & FILE_READ_DATA)
{
Gen_Mask |= GENERIC_READ;
}
if (Mask & FILE_WRITE_DATA)
{
Gen_Mask |= GENERIC_ALL;
}
paa->Mask = Gen_Mask;
break;
}
}
} while (asi.AceCount);
}
}
so FILE_READ_DATA
converted to GENERIC_READ
and FILE_WRITE_DATA
to GENERIC_ALL
(this is exactly algorithm) - however you can look yourself code of rsaenh.CheckAndChangeAccessMask
(name from pdb symbols)
rsaenh
first get SD from file by GetNamedSecurityInfoW (SE_FILE_OBJECT
) and then convert it specific to generic access.
here the call graph and modified DACL (in the top-right, modified ACCESS_MASK in red color)
来源:https://stackoverflow.com/questions/40984950/mapping-of-access-mask-in-dacl-for-cng-keys