我正在尝试从powershell脚本中找到一种授予私钥权限的方法。证书存储在CNG中。欢迎所有的想法。
答案 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?