powershell - 使用 UniqueKeyContainerName 获取证书绝对路径

标签 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

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

是否有 Powershell 替代方案来确定证书的 UniqueKeyContainerName?

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

最佳答案

关于此主题的有用信息似乎很少,更不用说 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\FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' |获取证书容器绝对路径
  • 我作弊,只是在 Microsoft Crypto 目录层次结构下递归搜索 key 文件,而不是搜索正确的特定子目录
  • 尽管使用了 CNG Provider,但这似乎不利于我创建的测试 CryptoAPI 提供的 key
  • 我在 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
}

关于powershell - 使用 UniqueKeyContainerName 获取证书绝对路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20361395/

相关文章:

arrays - 如何使用 Powershell 简化多维数组?

powershell - 在 Powershell 中解析快捷方式

java - 从 TLS 获取证书链以使用 OCSP

ssl - Lua:如何在使用 LuaSec 成功进行客户端身份验证后获取客户端详细信息

java - 无法通过 SunCertPathBuilderException 连接到 MySQL 数据库

java - CF8 SSL 连接到 Postgres 失败

google-chrome - Chrome 会忽略给定域或证书的警告吗?

csv - PowerShell和CSV

python - 在 ipython 笔记本上导入 imblearn python 包时出现问题

PowerShell:如果 "mkdir"命令的文件已存在,如何抑制错误?