C# 如何设置对 .NET X.509 证书私钥文件的读取权限
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/425688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set read permission on the private key file of X.509 certificate from .NET
提问by Ray Lu
Here is the code to add a pfx to the Cert store.
这是将 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();
However, I couldn't find a way to set permission for NetworkService to access the private key.
但是,我找不到设置 NetworkService 访问私钥的权限的方法。
Can anyone shed some light? Thanks in advance.
任何人都可以透露一些信息吗?提前致谢。
采纳答案by Eric Rosenberger
To do it programmatically, you have to do three things:
要以编程方式执行此操作,您必须做三件事:
Get the path of the private key folder.
Get the file name of the private key within that folder.
Add the permission to that file.
获取私钥文件夹的路径。
获取该文件夹中私钥的文件名。
为该文件添加权限。
See this postfor some example code that does all three (specifically look at the "AddAccessToCertificate" method).
有关执行所有三个操作的示例代码,请参阅此帖子(特别是查看“AddAccessToCertificate”方法)。
回答by Enrico Campidoglio
You can use the WinHttpCertCfg.exe toolthat ships as part of the Windows Server 2003 Resource Kit Tools.
您可以使用作为Windows Server 2003 资源工具包工具的一部分提供的WinHttpCertCfg.exe工具。
Example:
例子:
winhttpcertcfg -g -c LOCAL_MACHINE\My -s test -a NetworkService
Alternatively, you could use the Find Private Key toolthat ships with the WCF SDK, to find the location on disk of the certificate's private key file. Then you can simply use ACL to set the right privileges on the file.
或者,您可以使用WCF SDK 附带的“查找私钥”工具来查找证书私钥文件在磁盘上的位置。然后您可以简单地使用 ACL 为文件设置正确的权限。
Example:
例子:
FindPrivateKey My LocalMachine -n "CN=test"
回答by Jim Flood
This answer is late but I wanted to post it for anybody else that comes searching in here:
这个答案来晚了,但我想将它发布给在这里搜索的其他人:
I found an MSDN blog article that gave a solution using CryptoKeySecurity here, and here is an example of a solution in C#:
我发现,使用CryptoKeySecurity给了一个解决方案的MSDN博客文章在这里,并在这里是在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
}
}
I'm using a SecurityIdentifier to identify the account but an NTAccount would work just as well.
我正在使用 SecurityIdentifier 来标识帐户,但 NTAccount 也可以正常工作。
回答by kennydust
This is the solution I found for windows server 2008 if anyone was interested: http://technet.microsoft.com/en-us/library/ee662329.aspx
如果有人感兴趣,这是我为 windows server 2008 找到的解决方案:http: //technet.microsoft.com/en-us/library/ee662329.aspx
Basically, I had to grant permissions to the service that needs to access the certificate using the MMC tool. Works like a charm.
基本上,我必须向需要使用 MMC 工具访问证书的服务授予权限。奇迹般有效。
回答by Russ
In case this helps anyone else out, I wrote Jim Flood's answer in Powershell
万一这对其他人有帮助,我在 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()
}
Note that the account parameter can be in the form of "DOMAIN\USER" as well (not just built in names) - I tested this in my environment and it automatically converted it to the appropriate SID
请注意,帐户参数也可以采用“DOMAIN\USER”形式(不仅仅是内置名称)-我在我的环境中对此进行了测试,它会自动将其转换为适当的 SID
回答by eddiewould
Based on @russ's answer,
根据@russ 的回答,
This version copes with both Key Storage Provider & the Legacy Crypto Service Provider.
此版本同时处理密钥存储提供程序和传统加密服务提供程序。
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()
}