使用UniqueKeyContainerName获取证书绝对路径

时间:2013-12-03 20:49:55

标签: powershell ssl-certificate

鉴于证书指纹,我想找到本地文件系统上证书的绝对文件路径。

这个片段几乎总是有效。

$thumb    = <mythumbprint string>

$cert     = Get-ChildItem "Cert:\LocalMachine\My" | Where-Object {$_.Thumbprint -eq $thumb};
$keyName  = (($cert.PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$keyPath  = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"
$fullPath = $keyPath+$keyName

在PrivateKey不可导出的证书上失败。标记为NOT Exportable时,$cert.PrivateKey不再可访问,因此无法构建证书的完整路径。

是否有用于确定证书的UniqueKeyContainerName的powershell替代方案?

更新 我关注的所有证书都有私钥。问题是我不能假设它们被标记为可导出。如果未标记为可导出,则无法引用.PrivateKey。我需要另一种方法来获取UniqueKeyContainerName而不链接.Privatekey

2 个答案:

答案 0 :(得分:0)

关于此主题的有用信息似乎很少,更不用说 PowerShell 5.1 7.1 (.NET Core)。希望这 helps 个人。

我改编自 Vadims Podāns 'Retrieve CNG key container name and unique name'

请注意:

  • Cmdlet 的使用示例:Get-Item 'Cert:\LocalMachine\My\FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' | Get-CertificateContainerAbsolutePath
  • 我作弊,只是在 Microsoft Crypto 目录层次结构下递归搜索密钥文件,而不是搜索正确的特定子目录
  • 尽管使用了 CNG Provider,但这似乎对我创建的测试 CryptoAPI 提供的密钥有效
  • 我在 Windows 上的 Powershell 5.1 和 7.1 上对此进行了测试。
if(-not ('EmbeddedTemporary.PKITools' -as [type])) {
    $PKIToolsDefinition = @"
[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 $PKIToolsDefinition -Namespace 'EmbeddedTemporary' -Name 'PKITools'
}

Function Get-CertificateContainerAbsolutePath {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory,ValuefromPipeline)]
        $Certificate
    )
    $CERT_KEY_PROV_INFO_PROP_ID = 0x2 # from Wincrypt.h header file
    $pcbData = 0
    [EmbeddedTemporary.PKITools]::CertGetCertificateContextProperty($Certificate.Handle, $CERT_KEY_PROV_INFO_PROP_ID, [IntPtr]::Zero, [ref]$pcbData) | Out-Null
    $pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal($pcbData)
    [EmbeddedTemporary.PKITools]::CertGetCertificateContextProperty($Certificate.Handle, $CERT_KEY_PROV_INFO_PROP_ID, $pvData, [ref]$pcbData) | Out-Null
    $keyProv = [Runtime.InteropServices.Marshal]::PtrToStructure($pvData, [type][EmbeddedTemporary.PKITools+CRYPT_KEY_PROV_INFO])
    [Runtime.InteropServices.Marshal]::FreeHGlobal($pvData) | Out-Null

    $CngProvider = [System.Security.Cryptography.CngProvider]::new($keyProv.pwszProvName)
    $CngKey = [System.Security.Cryptography.CngKey]::Open($keyProv.pwszContainerName, $CngProvider, [System.Security.Cryptography.CngKeyOpenOptions]::MachineKey)
    $UniqueName = $CngKey.UniqueName
    $CngKey.Dispose()

    $Certificates = Get-ChildItem -Path (Join-Path -Path $Env:ProgramData -ChildPath 'Microsoft\Crypto') -Recurse -Filter $UniqueName
    $Certificates.FullName
}

答案 1 :(得分:-1)

如果我关注您,您可以过滤具有HasPrivateKey的证书:

Get-ChildItem Cert:\LocalMachine\my | 
Where-Object {$_.Thumbprint -eq $thumb -and $_.HasPrivateKey} | ForEach-Object {  
    Join-Path $env:ProgramData\Microsoft\Crypto\RSA\MachineKeys $_.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
}
相关问题