映射
(注:IMO的问题主要是关于WinAPI的和DACL,而不是关于CNG,所以请继续阅读!)映射
我目前正试图修改的样品CNG密钥微软的加密提供程序开发工具包的存储提供商以这种方式,它不会而不是将密钥存储在单个文件中。但是,我遇到了可以分配给私钥的安全描述符。
在Windows Server Management Console的证书管理单元中,可以管理证书的私钥,即密钥的所有者,DACL和SACL可以更改,从而导致NCryptSetProperty调用的安全描述符为参数。对于DACL,管理单元仅允许/拒绝“完全控制”或“读取”,这会导致GENERIC_ALL或GENERIC_READ位置于ACE的访问掩码中。
据我所知,这些通用位需要映射到特定于应用程序的权限 - 否则AccessCheck将无法工作。但是我真的需要手工做这个吗?
CreatePrivateObjectSecurity + SetPrivateObjectSecurity并不总是有效,因为CreatePrivateObjectSecurity对输入安全描述符中的所有者和组非常挑剔。而且,当应用映射时,通用位在访问掩码中被清除,导致管理单元显示错误的设置(正如我所说的,管理单元在显示当前权限时仅考虑GA和GR位)。
看来我错过了一些作品在这里...
在CPSetProvParam
实施PP_KEYSET_SEC_DESCR
你有SECURITY_DESCRIPTOR
的地址,你需要以某种方式应用到你的私人密钥存储。如果您的存储基于文件或注册表项(原则上是任何内核对象类型,但此处还可以使用什么内容?),则需要使用文件或密钥HANDLE
(必须具有WRITE_DAC
访问权限)调用SetKernelObjectSecurity
(可能如果你说有多个文件存储单键)。在内核中对对象的GENERIC访问将被自动转换为对象特定的权限。
如果存储的实现不是直接根据某些内核对象,但自定义 - 你需要自己在这一点上转换通用接入(0xF0000000
面膜)以特定的访问权限(0x0000FFFF
面罩)
__________________编辑____________________
经过更多检查后,我发现供应商不仅必须将CPSetProvParam
中的通用转换为特定访问,还要将其转换为CPGetProvParam
中的特定通用,尽管这并不直接指向文档。
这是MS_ENHANCED_PROV
(在rsaenh.dll
实现)如何约为做到这一点:
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);
}
}
所以FILE_READ_DATA
转化为GENERIC_READ
和FILE_WRITE_DATA
到GENERIC_ALL
(这正是算法) - 但是你可以看看自己的rsaenh.CheckAndChangeAccessMask
代码(名称来自pdb符号)
rsaenh
首先通过GetNamedSecurityInfoW
(SE_FILE_OBJECT
)从文件中获得SD,然后将其转换为通用配音SS。 这里调用图及修改DACL(在右上角的红色,修改ACCESS_MASK)
正如我上面写的:我不把所接收的安全描述符文件或任何其他内核对象,但需要在内部存储它。实际上,我尝试将所有关键数据(公钥和私钥以及属性!)存储在数据库中。因此,只有* PrivateObjectSecurity函数是可能的 - 但不起作用(s.a.)。 – dannyM
仅将GENERIC权限映射到特定权限**也是不正确的,因为当CPGetProvParam/NCryptGetPropertyFn应该返回SD时,我需要再次将其转换回来。原因是Windows Server Management Console **只识别GENERIC权限。似乎这里有一些缺失的功能... – dannyM
@dannyM - 对不起,我错了 - 编辑自我答案。 CP确实需要在'CPGetProvParam'中转换为通用掩码 - 我在编辑的答案中描述了这一点 – RbMm