映射

2016-12-05 77 views
0

(注:IMO的问题主要是关于WinAPI的和DACL,而不是关于CNG,所以请继续阅读!)映射

我目前正试图修改的样品CNG密钥微软的加密提供程序开发工具包的存储提供商以这种方式,它不会而不是将密钥存储在单个文件中。但是,我遇到了可以分配给私钥的安全描述符。

在Windows Server Management Console的证书管理单元中,可以管理证书的私钥,即密钥的所有者,DACL和SACL可以更改,从而导致NCryptSetProperty调用的安全描述符为参数。对于DACL,管理单元仅允许/拒绝“完全控制”或“读取”,这会导致GENERIC_ALL或GENERIC_READ位置于ACE的访问掩码中。

据我所知,这些通用位需要映射到特定于应用程序的权限 - 否则AccessCheck将无法工作。但是我真的需要手工做这个吗?

CreatePrivateObjectSecurity + SetPrivateObjectSecurity并不总是有效,因为CreatePrivateObjectSecurity对输入安全描述符中的所有者和组非常挑剔。而且,当应用映射时,通用位在访问掩码中被清除,导致管理单元显示错误的设置(正如我所说的,管理单元在显示当前权限时仅考虑GA和GR位)。

看来我错过了一些作品在这里...

回答

0

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_READFILE_WRITE_DATAGENERIC_ALL(这正是算法) - 但是你可以看看自己的rsaenh.CheckAndChangeAccessMask代码(名称来自pdb符号)

rsaenh首先通过GetNamedSecurityInfoWSE_FILE_OBJECT)从文件中获得SD,然后将其转换为通用配音SS。 这里调用图及修改DACL(在右上角的红色,修改ACCESS_MASK) enter image description here

+0

正如我上面写的:我不把所接收的安全描述符文件或任何其他内核对象,但需要在内部存储它。实际上,我尝试将所有关键数据(公钥和私钥以及属性!)存储在数据库中。因此,只有* PrivateObjectSecurity函数是可能的 - 但不起作用(s.a.)。 – dannyM

+0

仅将GENERIC权限映射到特定权限**也是不正确的,因为当CPGetProvParam/NCryptGetPropertyFn应该返回SD时,我需要再次将其转换回来。原因是Windows Server Management Console **只识别GENERIC权限。似乎这里有一些缺失的功能... – dannyM

+0

@dannyM - 对不起,我错了 - 编辑自我答案。 CP确实需要在'CPGetProvParam'中转换为通用掩码 - 我在编辑的答案中描述了这一点 – RbMm