32

这是将 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 访问私钥的权限的方法。

任何人都可以解释一下吗?提前致谢。

4

7 回答 7

45

这个答案很晚,但我想将它发布给其他在这里搜索的人:

我在这里找到了一篇 MSDN 博客文章,该文章给出了使用 CryptoKeySecurity 的解决方案,这里是 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 也可以。

于 2011-02-04T19:17:53.887 回答
18

万一这对其他人有帮助,我在 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()

}

请注意,帐户参数也可以采用“DOMAIN\USER”的形式(不仅仅是内置名称) - 我在我的环境中对此进行了测试,它会自动将其转换为适当的 SID

于 2015-07-02T03:29:03.883 回答
17

要以编程方式执行此操作,您必须做三件事:

  1. 获取私钥文件夹的路径。

  2. 获取该文件夹中私钥的文件名。

  3. 将权限添加到该文件。

请参阅这篇文章,了解所有这三个方面的一些示例代码(特别是查看“AddAccessToCertificate”方法)。

于 2009-01-08T22:11:11.280 回答
11

您可以使用作为Windows Server 2003 资源工具包工具的一部分提供的WinHttpCertCfg.exe工具。

例子:

winhttpcertcfg -g -c LOCAL_MACHINE\My -s test -a NetworkService


或者,您可以使用 WCF SDK 附带的Find Private Key 工具来查找证书私钥文件在磁盘上的位置。然后,您可以简单地使用 ACL 为文件设置正确的权限。

例子:

FindPrivateKey My LocalMachine -n "CN=test"
于 2009-01-08T21:56:54.087 回答
4

根据@russ 的回答,

此版本同时适用于 Key Storage Provider 和 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()
}
于 2019-10-30T23:59:04.497 回答
3

如果有人感兴趣,这是我为 Windows Server 2008 找到的解决方案:http ://technet.microsoft.com/en-us/library/ee662329.aspx

基本上,我必须向需要使用 MMC 工具访问证书的服务授予权限。奇迹般有效。

于 2012-10-03T04:14:34.820 回答
1

如果PrivateKeyofCertificate是类型RSACng,你可以走这条路:

对于本地机器:

 var rsaPrivateKey = certificate.GetRSAPrivateKey();
 var privateKey = rsaPrivateKey as RSACng;
 var keyUniqueName = privateKey.Key.UniqueName;
 var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
 var keyPath = Path.Combine(folderPath, "Microsoft", "Crypto", "RSA", "MachineKeys", keyUniqueName);
 var fileInfo = new FileInfo(keyPath);
 var accessControl = fileInfo.GetAccessControl();
 accessControl.AddAccessRule(new FileSystemAccessRule(new NTAccount("<account>"), FileSystemRights.FullControl, AccessControlType.Allow));
 fileInfo.SetAccessControl(accessControl);

如果它是用户证书,请使用Environment.SpecialFolder.ApplicationDatasid在文件夹中找到roaming\microsoft\crypto\rsa

于 2021-11-17T23:32:54.523 回答