以下是将pfx添加到Cert商店的代码。
X509Store store = new X509Store( StoreName.My, StoreLocation.LocalMachine );
store.Open( OpenFlags.ReadWrite );
X509Certificate2 cert = new X509Certificate2( "test.pfx", "password" );
store.Add( cert );
store.Close();
但是,我找不到为NetworkService设置访问私钥的权限的方法。
任何人都能解开一些光明吗?提前谢谢。
答案 0 :(得分:41)
这个答案很晚,但我想把它发布给在这里搜索的其他人:
我发现了一篇MSDN博客文章,该文章使用CryptoKeySecurity here提供了一个解决方案,以下是C#中解决方案的示例:
var rsa = certificate.PrivateKey as RSACryptoServiceProvider;
if (rsa != null)
{
// Modifying the CryptoKeySecurity of a new CspParameters and then instantiating
// a new RSACryptoServiceProvider seems to be the trick to persist the access rule.
// cf. http://blogs.msdn.com/b/cagatay/archive/2009/02/08/removing-acls-from-csp-key-containers.aspx
var cspParams = new CspParameters(rsa.CspKeyContainerInfo.ProviderType, rsa.CspKeyContainerInfo.ProviderName, rsa.CspKeyContainerInfo.KeyContainerName)
{
Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore,
CryptoKeySecurity = rsa.CspKeyContainerInfo.CryptoKeySecurity
};
cspParams.CryptoKeySecurity.AddAccessRule(new CryptoKeyAccessRule(sid, CryptoKeyRights.GenericRead, AccessControlType.Allow));
using (var rsa2 = new RSACryptoServiceProvider(cspParams))
{
// Only created to persist the rule change in the CryptoKeySecurity
}
}
我正在使用SecurityIdentifier来识别帐户,但NTAccount也能正常运行。
答案 1 :(得分:16)
要以编程方式执行此操作,您必须执行以下三项操作:
获取私钥文件夹的路径。
获取该文件夹中私钥的文件名。
将权限添加到该文件中。
请参阅this post以获取完成所有这三项的示例代码(特别是查看“AddAccessToCertificate”方法)。
答案 2 :(得分:16)
如果这有助于其他人,我在Powershell写了Jim Flood的回答
function Set-PrivateKeyPermissions {
param(
[Parameter(Mandatory=$true)][string]$thumbprint,
[Parameter(Mandatory=$false)][string]$account = "NT AUTHORITY\NETWORK SERVICE"
)
#Open Certificate store and locate certificate based on provided thumbprint
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine")
$store.Open("ReadWrite")
$cert = $store.Certificates | where {$_.Thumbprint -eq $thumbprint}
#Create new CSP object based on existing certificate provider and key name
$csp = New-Object System.Security.Cryptography.CspParameters($cert.PrivateKey.CspKeyContainerInfo.ProviderType, $cert.PrivateKey.CspKeyContainerInfo.ProviderName, $cert.PrivateKey.CspKeyContainerInfo.KeyContainerName)
# Set flags and key security based on existing cert
$csp.Flags = "UseExistingKey","UseMachineKeyStore"
$csp.CryptoKeySecurity = $cert.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
$csp.KeyNumber = $cert.PrivateKey.CspKeyContainerInfo.KeyNumber
# Create new access rule - could use parameters for permissions, but I only needed GenericRead
$access = New-Object System.Security.AccessControl.CryptoKeyAccessRule($account,"GenericRead","Allow")
# Add access rule to CSP object
$csp.CryptoKeySecurity.AddAccessRule($access)
#Create new CryptoServiceProvider object which updates Key with CSP information created/modified above
$rsa2 = New-Object System.Security.Cryptography.RSACryptoServiceProvider($csp)
#Close certificate store
$store.Close()
}
请注意,account参数也可以采用“DOMAIN \ USER”的形式(不仅仅是内置名称) - 我在我的环境中对此进行了测试,并自动将其转换为相应的SID
答案 3 :(得分:11)
您可以使用WinHttpCertCfg.exe tool附带的Windows Server 2003 Resource Kit Tools。
实施例:
winhttpcertcfg -g -c LOCAL_MACHINE\My -s test -a NetworkService
或者,您可以使用WCF SDK附带的Find Private Key tool来查找证书私钥文件的磁盘位置。然后,您只需使用ACL为文件设置正确的权限。
实施例:
FindPrivateKey My LocalMachine -n "CN=test"
答案 4 :(得分:3)
如果有人对此感兴趣,这是我在Windows Server 2008中找到的解决方案:http://technet.microsoft.com/en-us/library/ee662329.aspx
基本上,我必须使用MMC工具向需要访问证书的服务授予权限。像魅力一样。
答案 5 :(得分:0)
基于@russ的答案,
此版本同时适用于密钥存储提供程序和旧式加密服务提供程序。
function Set-PrivateKeyPermissions {
param(
[Parameter(Mandatory=$true)]
[string]$thumbprint,
[Parameter(Mandatory=$true)]
[string]$account
)
#Open Certificate store and locate certificate based on provided thumbprint
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine")
$store.Open("ReadWrite")
$cert = $store.Certificates | where {$_.Thumbprint -eq $thumbprint}
if ($cert.PrivateKey -Eq $null) {
# Probably using Key Storage Provider rather than crypto service provider
$rsaCert = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
if ($rsaCert -Eq $null) {
throw "Private key on certificate $($cert.Subject) not available"
}
$fileName = $rsaCert.key.UniqueName
$path = "$env:ALLUSERSPROFILE\Microsoft\Crypto\Keys\$fileName"
$permissions = Get-Acl -Path $path
$access_rule = New-Object System.Security.AccessControl.FileSystemAccessRule($account, "FullControl", "Allow")
$permissions.AddAccessRule($access_rule)
Set-Acl -Path $path -AclObject $permissions
} else {
#Create new CSP object based on existing certificate provider and key name
$csp = New-Object System.Security.Cryptography.CspParameters($cert.PrivateKey.CspKeyContainerInfo.ProviderType, $cert.PrivateKey.CspKeyContainerInfo.ProviderName, $cert.PrivateKey.CspKeyContainerInfo.KeyContainerName)
# Set flags and key security based on existing cert
$csp.Flags = "UseExistingKey","UseMachineKeyStore"
$csp.CryptoKeySecurity = $cert.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
$csp.KeyNumber = $cert.PrivateKey.CspKeyContainerInfo.KeyNumber
# Create new access rule - could use parameters for permissions, but I only needed GenericRead
$access = New-Object System.Security.AccessControl.CryptoKeyAccessRule($account,"GenericRead","Allow")
# Add access rule to CSP object
$csp.CryptoKeySecurity.AddAccessRule($access)
#Create new CryptoServiceProvider object which updates Key with CSP information created/modified above
$rsa2 = New-Object System.Security.Cryptography.RSACryptoServiceProvider($csp)
}
#Close certificate store
$store.Close()
}