如何从powershell授予私钥的权限

时间:2013-06-19 07:35:56

标签: powershell cng

我正在尝试从powershell脚本中找到一种授予私钥权限的方法。证书存储在CNG中。欢迎所有的想法。

3 个答案:

答案 0 :(得分:5)

上面的答案在技术上是正确的,但在我寻找相同的东西时它没有帮助我,因为它没有提到你需要在codeplex https://clrsecurity.codeplex.com/上使用从CLRSecurity项目加载的程序集。

以下是我如何实现相同功能的摘录,包括加载您需要使用Security.Cryptography.dll的CLR安全程序集。首先需要一些函数声明。我将这些包含在模块中,但您可以根据需要使用它们。

Function Load-Assembly()
{
    [CmdletBinding(PositionalBinding=$false)]   
    param(
        [Parameter(Mandatory)][string][ValidateScript({Test-Path $_})] $DirectoryPath,
        [Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Name
    )

    $assemblyFileNameFullPath = Join-Path -Path $DirectoryPath -ChildPath $Name

    If (Test-Path -Path  $assemblyFileNameFullPath -PathType Leaf)
    {
        Write-Verbose "Loading .NET assembly from path ""$assemblyFileNameFullPath"""

        #Load the assembly using the bytes as this gets around security restrictions that stop certain assemblies from loading from external sources
        $assemblyBytes = [System.IO.File]::ReadAllBytes($assemblyFileNameFullPath)
        $assemblyLoaded = [System.Reflection.Assembly]::Load($assemblyBytes);

        if ($assemblyLoaded -ne $null)
        {
            return $assemblyLoaded
        }
        else
        {
            Throw "Cannot load .NET assembly ""$Name"" from directory ""$DirectoryPath"""
        }
    }
    else
    {
        Write-Error "Cannot find required .NET assembly at path ""$assemblyFileNameFullPath"""
    }
}

Function Get-PrivateKeyContainerPath()
{
    [CmdletBinding(PositionalBinding=$false)]
    Param(
        [Parameter(Mandatory=$True)][string][ValidateNotNullOrEmpty()] $Name,
        [Parameter(Mandatory=$True)][boolean] $IsCNG
    )

    If ($IsCNG)
    {
        $searchDirectories = @("Microsoft\Crypto\Keys","Microsoft\Crypto\SystemKeys")
    }
    else
    {
        $searchDirectories = @("Microsoft\Crypto\RSA\MachineKeys","Microsoft\Crypto\RSA\S-1-5-18","Microsoft\Crypto\RSA\S-1-5-19","Crypto\DSS\S-1-5-20")
    }

    foreach ($searchDirectory in $searchDirectories)
    {
        $machineKeyDirectory = Join-Path -Path $([Environment]::GetFolderPath("CommonApplicationData")) -ChildPath $searchDirectory
        $privateKeyFile = Get-ChildItem -Path $machineKeyDirectory -Filter $Name -Recurse
        if ($privateKeyFile -ne $null)
        {
           return $privateKeyFile.FullName
        }
    }

    Throw "Cannot find private key file path for key container ""$Name"""
}


#Extracted code of how to obtain the private key file path (taken from a function)
#Requires an x509Certificate2 object in variable $Certificate and string variable $CertificateStore that contains the name of the certificate store

#Need to use the Security.Cryptography assembly
    $assembly = Load-Assembly -DirectoryPath $PSScriptRoot -Name Security.Cryptography.dll

    #Uses the extension methods in Security.Cryptography assembly from (https://clrsecurity.codeplex.com/)
    If ([Security.Cryptography.X509Certificates.X509CertificateExtensionMethods]::HasCngKey($Certificate))
    {
        Write-Verbose "Private key CSP is CNG"
        $privateKey = [Security.Cryptography.X509Certificates.X509Certificate2ExtensionMethods]::GetCngPrivateKey($Certificate)
        $keyContainerName = $privateKey.UniqueName
        $privateKeyPath = Get-PrivateKeyContainerPath -Name $keyContainerName -IsCNG $true
    }
    elseif ($Certificate.PrivateKey -ne $null)
    {
        Write-Verbose "Private key CSP is legacy"
        $privateKey = $Certificate.PrivateKey        
        $keyContainerName = $Certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName      
        $privateKeyPath = Get-PrivateKeyContainerPath -Name $keyContainerName -IsCNG $false
    }
    else
    {
        Throw "Certificate ""$($Certificate.GetNameInfo("SimpleName",$false))"" in store ""$CertificateStore"" does not have a private key, or that key is inaccessible, therefore permission cannot be granted"
    }

很抱歉,如果这似乎是从上面重复,正如我所说它确实使用相同的技术,但希望其他人可能会发现这更有用,因为它解释了如何使用CLR安全项目中的方法,包括如何加载程序集。

答案 1 :(得分:1)

用于获取私钥文件名的Cmdlet代码。

[Cmdlet("Get", "PrivateKeyName")]
public class GetKeyNameCmdlet : Cmdlet
{
    [Parameter(Position = 0, Mandatory = false)]
    public X509Certificate2 Cert;

    protected override void ProcessRecord()
    {
        WriteObject(GetUniqueKeyName(Cert));
    }

    private static string GetUniqueKeyName(X509Certificate2 cert)
    {
        if (cert == null)
            throw new ArgumentNullException("cert");

        var cngPrivateKey = cert.GetCngPrivateKey();

        if (cngPrivateKey != null)
            return cngPrivateKey.UniqueName;

        var rsaPrivateKey = cert.PrivateKey as RSACryptoServiceProvider;
        if (rsaPrivateKey != null)
            return rsaPrivateKey.CspKeyContainerInfo.UniqueKeyContainerName;

         throw new Exception("cert");
    }
}

使用cmdlet。 CngCrypt.dll - 带有cmdlet代码的DLL。

  Import-Module .\CngCrypt.dll
  $local:certificateRootPath = join-path $env:ALLUSERSPROFILE      '\Microsoft\Crypto\RSA\MachineKeys\'
  $WorkingCert = Get-ChildItem CERT:\LocalMachine\My |where {$_.Subject -match 'Test'}| sort 
  Get-PrivateKeyName ($WorkingCert) 

答案 2 :(得分:0)

如果您已在计算机/服务器上安装了证书,并且只是在寻找如何使用PowerShell授予特定用户权限。

这是答案 How to Grant permission to user on Certificate private key using powershell?