我有一个 ASP.NET 应用程序,它可以访问证书存储中证书中的私钥。在 Windows Server 2003 上,我能够使用 winhttpcertcfg.exe 授予对 NETWORK SERVICE 帐户的私钥访问权限。如何在 IIS 7.5 网站的 Windows Server 2008 R2 上授予访问证书存储(本地计算机\个人)中证书中的私钥的权限?
我已经尝试为“Everyone”、“IIS AppPool\DefaultAppPool”、“IIS_IUSRS”以及我可以使用证书 MMC(Server 2008 R2)找到的所有其他安全帐户授予完全信任访问权限。但是,下面的代码表明该代码无权访问使用私钥导入的证书的私钥。每次访问私钥属性时,代码都会抛出错误。
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Import Namespace="System.Security.Cryptography.X509Certificates" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="repeater1" runat="server">
<HeaderTemplate>
<table>
<tr>
<td>
Cert
</td>
<td>
Public Key
</td>
<td>
Private Key
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%#((X509Certificate2)Container.DataItem).GetNameInfo(X509NameType.SimpleName, false) %>
</td>
<td>
<%#((X509Certificate2)Container.DataItem).HasPublicKeyAccess() %>
</td>
<td>
<%#((X509Certificate2)Container.DataItem).HasPrivateKeyAccess() %>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table></FooterTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Web.UI;
public partial class _Default : Page
{
public X509Certificate2Collection Certificates;
protected void Page_Load(object sender, EventArgs e)
{
// Local Computer\Personal
var store = new X509Store(StoreLocation.LocalMachine);
// create and open store for read-only access
store.Open(OpenFlags.ReadOnly);
Certificates = store.Certificates;
repeater1.DataSource = Certificates;
repeater1.DataBind();
}
}
public static class Extensions
{
public static string HasPublicKeyAccess(this X509Certificate2 cert)
{
try
{
AsymmetricAlgorithm algorithm = cert.PublicKey.Key;
}
catch (Exception ex)
{
return "No";
}
return "Yes";
}
public static string HasPrivateKeyAccess(this X509Certificate2 cert)
{
try
{
string algorithm = cert.PrivateKey.KeyExchangeAlgorithm;
}
catch (Exception ex)
{
return "No";
}
return "Yes";
}
}
创建/购买证书。确保它有一个私钥。将证书导入“本地计算机”帐户。最好使用证书 MMC。确保选中“允许导出私钥”基于此,IIS 7.5 应用程序池的标识使用以下之一。 IIS 7.5 网站在 ApplicationPoolIdentity 下运行。打开 MMC => 添加证书(本地计算机)管理单元 => 证书(本地计算机) => 个人 => 证书 => 右键单击感兴趣的证书 => 所有任务 => 管理私钥 => 添加 IIS AppPool\AppPoolName并授予它完全控制权。将“AppPoolName”替换为您的应用程序池的名称(有时是 IIS_IUSRS) IIS 7.5 网站在 NETWORK SERVICE 下运行。使用证书 MMC,将“网络服务”添加到“本地计算机\个人”中证书的完全信任中。 IIS 7.5 网站在“MyIISUser”本地计算机用户帐户下运行。使用证书 MMC,将“MyIISUser”(一个新的本地计算机用户帐户)添加到“本地计算机\个人”中证书的完全信任中。
根据@Phil Hale 评论更新:
请注意,如果您在域中,则默认情况下会在“来自位置框”中选择您的域。确保将其更改为“本地计算机”。将位置更改为“本地计算机”以查看应用程序池标识。
关于通过 MMC、证书、选择证书、右键单击、所有任务、“管理私钥”授予权限的注意事项
管理私钥仅在个人菜单列表中...因此,如果您将证书放在受信任的人等中,那么您就不走运了。
我们找到了一种对我们有用的方法。将证书拖放到 Personal,执行 Manage Private Keys 以授予权限。请记住设置为使用对象类型内置函数并使用本地计算机而不是域。我们将权限授予 DefaultAppPool 用户并将其保留。
完成后,将证书拖放回原来的位置。快速。
winhttpcertcfg
如果您尝试从 IIS 中的 .pfx 文件加载证书,解决方案可能就像为 Application Pool
启用此选项一样简单。
右键单击应用程序池并选择 Advanced Settings
。
然后启用 Load User Profile
https://i.stack.imgur.com/ZP8oX.png
我想出了如何在有人询问的 Powershell 中执行此操作:
$keyname=(((gci cert:\LocalMachine\my | ? {$_.thumbprint -like $thumbprint}).PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$keypath = $env:ProgramData + “\Microsoft\Crypto\RSA\MachineKeys\”
$fullpath=$keypath+$keyname
$Acl = Get-Acl $fullpath
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS AppPool\$iisAppPoolName", "Read", "Allow")
$Acl.SetAccessRule($Ar)
Set-Acl $fullpath $Acl
对我来说,无非是重新导入证书并选中“允许导出私钥”。
我想这是必要的,但它确实让我感到紧张,因为它是访问此证书的第三方应用程序。
虽然我参加过以上,但经过多次尝试,我走到了这一步。 1-如果您想从商店访问证书,您可以这样做作为示例 2-生成证书并通过路径使用它更加容易和清洁
Asp.net 核心 2.2 OR1:
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace Tursys.Pool.Storage.Api.Utility
{
class CertificateManager
{
public static X509Certificate2 GetCertificate(string caller)
{
AsymmetricKeyParameter caPrivateKey = null;
X509Certificate2 clientCert;
X509Certificate2 serverCert;
clientCert = GetCertificateIfExist("CN=127.0.0.1", StoreName.My, StoreLocation.LocalMachine);
serverCert = GetCertificateIfExist("CN=MyROOTCA", StoreName.Root, StoreLocation.LocalMachine);
if (clientCert == null || serverCert == null)
{
var caCert = GenerateCACertificate("CN=MyROOTCA", ref caPrivateKey);
addCertToStore(caCert, StoreName.Root, StoreLocation.LocalMachine);
clientCert = GenerateSelfSignedCertificate("CN=127.0.0.1", "CN=MyROOTCA", caPrivateKey);
var p12 = clientCert.Export(X509ContentType.Pfx);
addCertToStore(new X509Certificate2(p12, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), StoreName.My, StoreLocation.LocalMachine);
}
if (caller == "client")
return clientCert;
return serverCert;
}
public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey)
{
const int keyStrength = 2048;
// Generating Random Numbers
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Signature Algorithm
//const string signatureAlgorithm = "SHA256WithRSA";
//certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
// Issuer and Subject Name
X509Name subjectDN = new X509Name(subjectName);
X509Name issuerDN = new X509Name(issuerName);
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
// Valid For
DateTime notBefore = DateTime.UtcNow.Date;
DateTime notAfter = notBefore.AddYears(2);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Generating the Certificate
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);
// selfsign certificate
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
// correcponding private key
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
// merge into X509Certificate2
X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());
Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKeyAlgorithm.GetDerEncoded());
if (seq.Count != 9)
{
//throw new PemException("malformed sequence in RSA private key");
}
RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(info.ParsePrivateKey());
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);
try
{
var rsap = DotNetUtilities.ToRSA(rsaparams);
x509 = x509.CopyWithPrivateKey(rsap);
//x509.PrivateKey = ToDotNetKey(rsaparams);
}
catch(Exception ex)
{
;
}
//x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
return x509;
}
public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
{
var cspParams = new CspParameters
{
KeyContainerName = Guid.NewGuid().ToString(),
KeyNumber = (int)KeyNumber.Exchange,
Flags = CspProviderFlags.UseMachineKeyStore
};
var rsaProvider = new RSACryptoServiceProvider(cspParams);
var parameters = new RSAParameters
{
Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
P = privateKey.P.ToByteArrayUnsigned(),
Q = privateKey.Q.ToByteArrayUnsigned(),
DP = privateKey.DP.ToByteArrayUnsigned(),
DQ = privateKey.DQ.ToByteArrayUnsigned(),
InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
D = privateKey.Exponent.ToByteArrayUnsigned(),
Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
};
rsaProvider.ImportParameters(parameters);
return rsaProvider;
}
public static X509Certificate2 GenerateCACertificate(string subjectName, ref AsymmetricKeyParameter CaPrivateKey)
{
const int keyStrength = 2048;
// Generating Random Numbers
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Signature Algorithm
//const string signatureAlgorithm = "SHA256WithRSA";
//certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
// Issuer and Subject Name
X509Name subjectDN = new X509Name(subjectName);
X509Name issuerDN = subjectDN;
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
// Valid For
DateTime notBefore = DateTime.UtcNow.Date;
DateTime notAfter = notBefore.AddYears(2);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Generating the Certificate
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
// selfsign certificate
//Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);
// selfsign certificate
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());
CaPrivateKey = issuerKeyPair.Private;
return x509;
//return issuerKeyPair.Private;
}
public static bool addCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
bool bRet = false;
try
{
X509Store store = new X509Store(st, sl);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
}
catch
{
}
return bRet;
}
protected internal static X509Certificate2 GetCertificateIfExist(string subjectName, StoreName store, StoreLocation location)
{
using (var certStore = new X509Store(store, location))
{
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find(
X509FindType.FindBySubjectDistinguishedName, subjectName, false);
X509Certificate2 certificate = null;
if (certCollection.Count > 0)
{
certificate = certCollection[0];
}
return certificate;
}
}
}
}
或 2:
services.AddDataProtection()
//.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithCertificate(
new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "clientCert.pfx"), "Password")
)
.UnprotectKeysWithAnyCertificate(
new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "clientCert.pfx"), "Password")
);
在证书面板中,右键单击某些证书 -> 所有任务 -> 管理私钥 -> 添加具有完全控制权的 IIS_IUSRS 用户
就我而言,我不需要安装我的证书并选中“允许导出私钥”选项,就像其他答案中所说的那样。
IIS_IUSRS
对证书私钥的访问权限