Windows MachineKey 容器文件名是如何派生的?

Col*_*337 8 windows certificate access-control-list cryptography

C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys目录中有一个 Key Containers 的枚举。命名约定是<uniqueGUID>_<staticGUID>,我假设<staticGUID>是机器标识符。最终,我希望能够将密钥容器与其各自的证书配对,以便我可以针对 ACL 的特定密钥文件。为此,我需要知道<uniqueGUID>它是如何派生的以及它与证书的关系。

到目前为止,我检查过的 Microsoft 资源尚未阐明答案,但非常适合参考:

了解机器级和用户级 RSA 密钥容器(IIS 参考)

如何:更改 MachineKeys 目录的安全权限

Rya*_*ies 14

要解决查找哪个证书与哪个密钥文件匹配以修改私钥文件上的文件系统 ACL 的问题,请使用以下命令:

PS C:\Users\Ryan> $Cert = Get-Item Cert:\LocalMachine\My\2F6CB7D56BAA752BCCC0829DD829C0E2662FA1C6    

PS C:\Users\Ryan> $Cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName

fad662b360941f26a1193357aab3c12d_03f917b5-cb8b-45bd-b884-41c139a66ff7
Run Code Online (Sandbox Code Playgroud)

文件命名约定是 x_y,其中 x 是唯一标识密钥的随机 GUID,y 是在HKLM\SOFTWARE\Microsoft\Cryptography.

其中一些唯一标识符是众所周知的,例如其中一些 IIS 标识符:

6de9cb26d2b98c01ec4e9e8b34824aa2_GUID      iisConfigurationKey

d6d986f09a1ee04e24c949879fdb506c_GUID      NetFrameworkConfigurationKey

76944fb33636aeddb9590521c2e8815a_GUID      iisWasKey
Run Code Online (Sandbox Code Playgroud)

但其他人是随机生成的。

请注意,此信息仅适用于“本地计算机”或“机器”证书/密钥。用户证书存储在文件系统和注册表上相应的用户特定位置。


Cry*_*t32 6

Ryan Ries 仅提供了部分解决方案,因为它不适用于 CNG 密钥。以下代码将检索 CNG 密钥的容器名称(因此也是文件名):

$signature = @"
[DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CertGetCertificateContextProperty(
    IntPtr pCertContext,
    uint dwPropId,
    IntPtr pvData,
    ref uint pcbData
);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CRYPT_KEY_PROV_INFO {
    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwszContainerName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwszProvName;
    public uint dwProvType;
    public uint dwFlags;
    public uint cProvParam;
    public IntPtr rgProvParam;
    public uint dwKeySpec;
}
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenStorageProvider(
    ref IntPtr phProvider,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszProviderName,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptOpenKey(
    IntPtr hProvider,
    ref IntPtr phKey,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszKeyName,
    uint dwLegacyKeySpec,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern int NCryptGetProperty(
    IntPtr hObject,
    [MarshalAs(UnmanagedType.LPWStr)]
    string pszProperty,
    byte[] pbOutput,
    int cbOutput,
    ref int pcbResult,
    int dwFlags
);
[DllImport("ncrypt.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int NCryptFreeObject(
    IntPtr hObject
);
"@
Add-Type -MemberDefinition $signature -Namespace PKI -Name Tools

$CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file
$cert = dir cert:\currentuser\my\C541C66F490413302C845A440AFA24E98A231C3C
$pcbData = 0
[void][PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,[IntPtr]::Zero,[ref]$pcbData)
$pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData)
[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,$pvData,[ref]$pcbData)
$keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData,[type][PKI.Tools+CRYPT_KEY_PROV_INFO])
[Runtime.InteropServices.Marshal]::FreeHGlobal($pvData)
$phProvider = [IntPtr]::Zero
[void][PKI.Tools]::NCryptOpenStorageProvider([ref]$phProvider,$keyProv.pwszProvName,0)
$phKey = [IntPtr]::Zero
[void][PKI.Tools]::NCryptOpenKey($phProvider,[ref]$phKey,$keyProv.pwszContainerName,0,0)
$pcbResult = 0
[void][PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$null,0,[ref]$pcbResult,0)
$pbOutput = New-Object byte[] -ArgumentList $pcbResult
[void][PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$pbOutput,$pbOutput.length,[ref]$pcbResult,0)
[Text.Encoding]::Unicode.GetString($pbOutput)
[void][PKI.Tools]::NCryptFreeObject($phProvider)
[void][PKI.Tools]::NCryptFreeObject($phKey)
Run Code Online (Sandbox Code Playgroud)