【问题标题】:Setting a CA Certificate, with specific Enabled Purposes, using PowerShell使用 PowerShell 设置具有特定启用目的的 CA 证书
【发布时间】:2022-01-14 07:48:35
【问题描述】:

如何使用 PowerShell 在相关 Windows 证书存储区中以编程方式更改证书颁发机构的启用用途?

这可以在Certificates MMC snap-in中实现

这只能根据StackOverflow: How to set certificate purposes? {C#} 使用带有CertSetCertificateContextProperty 的P/Invoke 来实现吗

理想情况下,我想导入自定义的受信任的根证书颁发机构,并且仅出于客户端身份验证的目的启用它。

【问题讨论】:

  • 通常计算机上的受信任根 CA 用于服务器身份验证。提供由该 CA 交付的证书的服务器将被信任,因为您的本地计算机信任该 CA。只有当您拥有由 CA 提供的证书并且您希望将此证书提供给服务器时,您才会在服务器端信任 CA 以进行客户端身份验证。我没有找到比您找到的启用特定密钥用法更好的答案。这可以翻译成 Powershell。
  • 在我的用例中,我需要将证书导入个人存储以用于客户端身份验证。除非出于该目的信任签名证书,否则您无法执行此操作,但我不想通过客户端身份验证(例如:服务器身份验证)将此证书用于任何其他目的,因为它会使客户端面临不必要的风险,并且签名证书密钥持有者不必要的责任。

标签: powershell pki certificate-authority certificate-store


【解决方案1】:

一个以CertSetCertificateContextProperty 为核心的 PowerShell Cmdlet。感谢Crypt32 以及他们在另一篇文章中的回答以寻求指导。

示例用法:

Set-CertificateEku -StoreLocation 'CurrentUser' -StoreName 'Root' -CertificateThumbprint 'ffffffffffffffffffffffffffffffffffffffff' -Oids @("1.3.6.1.5.5.7.3.2") # Client Authentication
Function Set-CertificateEku {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory)]
        [ValidateSet('CurrentUser', 'LocalMachine')]
        $StoreLocation,
        
        [Parameter(Mandatory)]
        $StoreName,

        [Parameter(Mandatory)]
        $CertificateThumbprint,

        [Parameter(Mandatory)]
        $Oids
    )
    $StoreLocation = switch($StoreLocation) {
        'CurrentUser' {
            [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
        }
        'LocalMachine' {
            [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
        }
    }
    try {
        $CertificateStore = [System.Security.Cryptography.X509Certificates.X509Store]::new($StoreName, $StoreLocation)
        $CertificateStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite -bor [System.Security.Cryptography.X509Certificates.OpenFlags]::OpenExistingOnly)
    } catch {
        Write-Error "Could not Open Certificate Store $StoreName in $StoreLocation"
        return $false
    }
    $Certificates = $CertificateStore.Certificates.Find(
        [System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint,
        $CertificateThumbprint,
        $false
    )
    if($Certificates.Count -eq 0) {
        Write-Error "Could not find Certificate $CertificateThumbprint in $StoreName in $StoreLocation"
        return $false
    }
    $Certificate = $Certificates[0]
    

    $PKICrypt32 = @"
    [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool CertSetCertificateContextProperty(
        IntPtr pCertContext,
        uint dwPropId,
        uint dwFlags,
        IntPtr pvData
    );
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct CRYPTOAPI_BLOB {
        public uint cbData;
        public IntPtr pbData;
    }
"@
    Add-Type -MemberDefinition $PKICrypt32 -Namespace 'PKI' -Name 'Crypt32'

    $OIDs = [Security.Cryptography.OidCollection]::new()
    foreach($Oid in $Oids) {
        [void]$OIDs.Add([Security.Cryptography.Oid]::new($Oid))
    }
    $EKU = [Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]::new($OIDs, $false)
    $pbData = [Runtime.InteropServices.Marshal]::AllocHGlobal($EKU.RawData.Length)
    [Runtime.InteropServices.Marshal]::Copy($EKU.RawData, 0, $pbData, $EKU.RawData.Length)

    $Blob = New-Object PKI.Crypt32+CRYPTOAPI_BLOB -Property @{
        cbData = $EKU.RawData.Length;
        pbData = $pbData;
    }
    $pvData = [Runtime.InteropServices.Marshal]::AllocHGlobal([Runtime.InteropServices.Marshal]::SizeOf([type][PKI.Crypt32+CRYPTOAPI_BLOB]))
    [Runtime.InteropServices.Marshal]::StructureToPtr($Blob, $pvData, $false)

    $Result = [PKI.Crypt32]::CertSetCertificateContextProperty($Certificate.Handle, 9, 0, $pvData)
    [Runtime.InteropServices.Marshal]::FreeHGlobal($pvData)
    [Runtime.InteropServices.Marshal]::FreeHGlobal($pbData)
    $CertificateStore.Close()
    return $Result
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    相关资源
    最近更新 更多