在C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
目录中有一个Key Containers的枚举。 命名约定是<uniqueGUID>_<staticGUID>
,我认为<staticGUID>
是一个机器标识符。 最终,我希望能够将密钥容器与其各自的证书配对,以便我可以将特定的密钥文件作为ACL的目标。 为此,我需要知道<uniqueGUID>
是如何派生的以及它如何与证书相关联。
到目前为止,我所检查的微软资源并没有阐明一个答案,但是可供参考:
了解机器级别和用户级别的RSA密钥容器(IIS参考)
如何更改MachineKeys目录的安全权限
为了解决您在修改私钥文件中的文件系统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
文件命名约定是x_y,其中x是唯一标识密钥的随机GUID,y是在HKLM\SOFTWARE\Microsoft\Cryptography
find的机器GUID。
其中一些独特的标识符是众所周知的,比如这些IIS中的一些标识符:
6de9cb26d2b98c01ec4e9e8b34824aa2_GUID iisConfigurationKey d6d986f09a1ee04e24c949879fdb506c_GUID NetFrameworkConfigurationKey 76944fb33636aeddb9590521c2e8815a_GUID iisWasKey
但其他人是随机产生的。
请注意,此信息仅适用于“本地计算机”或“机器”证书/密钥。 用户证书存储在文件系统和registry的相应用户特定位置。
瑞安Ries只提供部分解决scheme,因为它不会在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)
我使用了CryptoGuy的代码,对它进行了大量扩展,并将其转换为函数。 不过,它还有改进的空间。 谢谢,CryptoGuy!
function Get-KeyContainer { [CmdletBinding()] Param([Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [string]$Thumbprint, [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$false)] [switch]$MachineStore) $MemberDefinition=@" [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 $MemberDefinition -Namespace PKI -Name Tools $CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file # from Ncrypt.h header file if ($MachineStore.IsPresent) { $NCRYPT_MACHINE_KEY_FLAG = 0x20 } else { $NCRYPT_MACHINE_KEY_FLAG = 0 } $cert=Get-Item -Path ("Cert:\LocalMachine\My\"+$Thumbprint) $pcbData = 0 $result=[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,[IntPtr]::Zero,[ref]$pcbData) if ($result -ne $true) { switch ($result) { -2146885628 { Write-Error "ERROR: CRYPT_E_NOT_FOUND 0x80092004 (-2146885628)`r`nThe certificate does not have the specified property." } -2005270525 { Write-Error "ERROR: ERROR_MORE_DATA 0x887A0003 (-2005270525)`r`nIf the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbData." } } exit } $pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData) $result=[PKI.Tools]::CertGetCertificateContextProperty($cert.Handle,$CERT_KEY_PROV_INFO_PROP_ID,$pvData,[ref]$pcbData) if ($result -ne $true) { switch ($result) { -2146885628 { Write-Error "ERROR: CRYPT_E_NOT_FOUND 0x80092004 (-2146885628)`r`nThe certificate does not have the specified property." } -2005270525 { Write-Error "ERROR: ERROR_MORE_DATA 0x887A0003 (-2005270525)`r`nIf the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pcbData." } } exit } $keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData,[type][PKI.Tools+CRYPT_KEY_PROV_INFO]) [Runtime.InteropServices.Marshal]::FreeHGlobal($pvData) $phProvider = [IntPtr]::Zero $result=[PKI.Tools]::NCryptOpenStorageProvider([ref]$phProvider,$keyProv.pwszProvName,0) if ($result -ne 0) { switch ($result) { -2146893815 { Write-Error "ERROR: NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nInvalid flags specified" } -2146893785 { Write-Error "ERROR: NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" } -2146893810 { Write-Error "ERROR: NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" } } exit } $phKey = [IntPtr]::Zero $result=[PKI.Tools]::NCryptOpenKey($phProvider,[ref]$phKey,$keyProv.pwszContainerName,0,$NCRYPT_MACHINE_KEY_FLAG) if ($result -ne 0) { switch ($result) { -2146893815 { Write-Error "ERROR: NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." } -2146893802 { Write-Error "ERROR: NTE_BAD_KEYSET 0x80090016 (-2146893802)`r`nThe specified key was not found. Try using the -MachineKey flag to look in the Machine's store instead of the User's store." } -2146893786 { Write-Error "ERROR: NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." } -2146893785 { Write-Error "ERROR: NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" } -2146893810 { Write-Error "ERROR: NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" } } exit } $pcbResult = 0 $result=[PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$null,0,[ref]$pcbResult,0) if ($result -ne 0) { switch ($result) { -2146893815 { Write-Error "ERROR: NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." } -2146893786 { Write-Error "ERROR: NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." } -2146893785 { Write-Error "ERROR: NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" } -2146893810 { Write-Error "ERROR: NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" } -2146893783 { Write-Error "ERROR: NTE_NOT_SUPPORTED 0x80090029 (-2146893783)`r`nThe specified property is not supported for the object." } } exit } $pbOutput = New-Object byte[] -ArgumentList $pcbResult $result=[PKI.Tools]::NCryptGetProperty($phKey,"Unique Name",$pbOutput,$pbOutput.length,[ref]$pcbResult,0) if ($result -ne 0) { switch ($result) { -2146893815 { Write-Error "ERROR: NTE_BAD_FLAGS 0x80090009 (-2146893815)`r`nThe dwFlags parameter contains a value that is not valid." } -2146893786 { Write-Error "ERROR: NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid." } -2146893785 { Write-Error "ERROR: NTE_INVALID_PARAMETER 0x80090027 (-2146893785)`r`nThe parameter is incorrect" } -2146893810 { Write-Error "ERROR: NTE_NO_MEMORY 0x8009000E (-2146893810)`r`nInsufficient memory available for the operation" } -2146893783 { Write-Error "ERROR: NTE_NOT_SUPPORTED 0x80090029 (-2146893783)`r`nThe specified property is not supported for the object." } } exit } [Text.Encoding]::Unicode.GetString($pbOutput) $result=[PKI.Tools]::NCryptFreeObject($phProvider) if ($result -ne 0) { Write-Error "ERROR: NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid."; exit } [void][PKI.Tools]::NCryptFreeObject($phKey) if ($result -ne 0) { Write-Error "ERROR: NTE_INVALID_HANDLE 0x80090026 (-2146893786)`r`nThe hProvider parameter is not valid."; exit } } Get-KeyContainer -Thumbprint "xxxxxxxxx" -MachineStore