gpt4 book ai didi

c# - 将生成的证书添加到商店并更新 IIS 站点绑定(bind)

转载 作者:行者123 更新时间:2023-11-30 16:46:10 25 4
gpt4 key购买 nike

我遇到了以下问题,感觉我已经用尽了对 Google 和 Stack Overflow 的各种研究途径后,我决定只问我自己的问题。

我正在尝试根据我已经拥有的 CA 证书生成个人证书(使用 BouncyCaSTLe)。生成证书后,将其放在“我的”存储中,然后我尝试更新我的 IIS 网站的 SSL 绑定(bind)以使用这个新证书。

我注意到 IIS 网站的更新(使用 ServerManager)没有抛出异常,但是当我转到 IIS 管理器控制台时,我注意到该网站的绑定(bind)没有 SSL 证书选择。当我尝试选择我创建的证书时(显示为一个可行的选项)我收到以下错误消息:

指定的登录 session 不存在。它可能已经被终止。 (HRESULT 异常:0x80070520)

作为测试,我导出了我生成的证书(带有私钥)并通过向导重新安装它,然后再次尝试设置有效的绑定(bind)(通过 IIS 管理器)。

由于这种行为,我认为这是我生成证书或将证书添加到商店的方式的问题。我希望有人可能知道我遇到的问题可能是什么。以下是用于创建证书、将其添加到商店以及以编程方式更新网站绑定(bind)的相关函数(我相信):

主要函数生成获取CA证书私钥,生成个人自签名证书,更新站点绑定(bind):

public static bool GenerateServerCertificate(
X509Certificate2 CACert,
bool addToStore,
DateTime validUntil)
{
try
{
if (CACert.PrivateKey == null)
{
throw new CryptoException("Authority certificate has no private key");
}

var key = DotNetUtilities.GetKeyPair(CACert.PrivateKey).Private;

byte[] certHash = GenerateCertificateBasedOnCAPrivateKey(
addToStore,
key,
validUntil);

using (ServerManager manager = new ServerManager())
{
Site site = manager.Sites.Where(q => q.Name == "My Site").FirstOrDefault();

if (site == null)
{
return false;
}

foreach (Binding binding in site.Bindings)
{
if (binding.Protocol == "https")
{
binding.CertificateHash = certHash;
binding.CertificateStoreName = "MY";
}
}

manager.CommitChanges();
}
}
catch(Exception ex)
{
LOG.Error("Error generating certitifcate", ex);
return false;
}

return true;
}

根据CA私钥生成证书:

public static byte[] GenerateCertificateBasedOnCAPrivateKey(
bool addToStore,
AsymmetricKeyParameter issuerPrivKey,
DateTime validUntil,
int keyStrength = 2048)
{
string subjectName = $"CN={CertSubjectName}";

// Generating Random Numbers
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerPrivKey, random);

// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
certificateGenerator.AddExtension(
X509Extensions.ExtendedKeyUsage,
true,
new ExtendedKeyUsage((new List<DerObjectIdentifier> { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") })));

// Serial Number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);

// Issuer and Subject Name
X509Name subjectDN = new X509Name(subjectName);
X509Name issuerDN = new X509Name(CACertificateName);
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);

// Valid For
DateTime notBefore = DateTime.UtcNow.Date;
DateTime notAfter = validUntil > notBefore ? validUntil : notBefore.AddYears(1);

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
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);

// correcponding private key
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

// merge into X509Certificate2
X509Certificate2 x509 = new X509Certificate2(certificate.GetEncoded());

Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
if (seq.Count != 9)
{
throw new PemException("Malformed sequence in RSA private key");
}

RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
rsa.Modulus,
rsa.PublicExponent,
rsa.PrivateExponent,
rsa.Prime1,
rsa.Prime2,
rsa.Exponent1,
rsa.Exponent2,
rsa.Coefficient);

x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);

if (addToStore)
{
// Add certificate to the Personal store
AddCertToStore(x509, StoreName.My, StoreLocation.LocalMachine, "Certificate Friendly Name");
}

return x509.GetCertHash();
}

将证书添加到商店:

private static void AddCertToStore(X509Certificate2 cert, StoreName storeName, StoreLocation storeLocation, string friendlyName)
{
X509Store store = new X509Store(storeName, storeLocation);

try
{
store.Open(OpenFlags.ReadWrite);
store.Add(cert);

if (!string.IsNullOrWhiteSpace(friendlyName)) {
var certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, cert.Subject, true);
if (certs.Count > 0)
{
certs[0].FriendlyName = friendlyName;
}
}
}
finally
{
store.Close();
}
}

最后一点,我已经尝试了一些我在各种网站上看到的关于该错误的东西(似乎不太清楚问题是什么):

  • 这适用于不同的机器(我的个人开发机器),但我在服务器机器(运行 Windows Server 2012 R2)上遇到了这些障碍
  • IIS 帮助对话框告诉我机器正在运行 IIS 8.5
  • 使用 CertUtil.exe 验证生成的证书和 CA 证书的有效性
  • 验证了生成的证书和 CA 证书有一个可以找到的私钥
  • 经过验证的管理员(最终甚至是我的登录帐户)都可以访问 CA 证书和生成的证书的私钥文件所在的位置。

知道我的问题是什么吗?


更新:

我通过执行以下操作获得了一些结果:

通过执行 File.WriteAllBytes(filePath, cert.Export(X509ContentType.Pkcs12, password));

以编程方式将我的证书导出到文件

然后我通过执行以下操作将此证书文件导入商店:

var cert = new X509Certificate2(certFilePath, certPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

// My original AddCertToStore function
AddCertToStore(cert, StoreName.My, StoreLocation.LocalMachine, "Friendly Name");

最后,我像之前一样设置绑定(bind):

using (ServerManager manager = new ServerManager())
{
Site site = manager.Sites.Where(q => q.Name == "My Site").FirstOrDefault();

if (site == null)
{
return false;
}

foreach (Binding binding in site.Bindings)
{
if (binding.Protocol == "https")
{
binding.CertificateHash = certHash;
binding.CertificateStoreName = "MY";
}
}

manager.CommitChanges();
}

这样做可行,但我不明白为什么我要将证书导出到文件,然后将其加载到 X509Certificate2 对象中,添加到商店,最后设置绑定(bind)。

最佳答案

ToRSA 方法很可能会创建一个临时 RSA key ,因此当引用全部消失时, key 将被删除。将临时结构导出到 PFX,然后使用 PersistKeySet 重新导入它是将其转换为持久 key 的一种方法。其他的存在,但那个是不那么复杂的之一。

不过,您实际上不必将其写入文件。

byte[] pkcs12Blob = cert.Export(X509ContentType.Pkcs12, password);
ver certWithPersistedKey = new X509Certificate2(pkcs12Blob, password, allTheFlagsYouAlreadySet);

还有其他微妙之处,比如设置 PrivateKey 属性对于从商店加载的证书实例和从字节加载的证书实例具有不同的行为......PFX/PKCS#12 导出/导入解决了所有这些。

关于c# - 将生成的证书添加到商店并更新 IIS 站点绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40892512/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com