我遇到以下情況,感覺我已經耗盡了Google和Stack Overflow的各種研究渠道後,我決定只問自己關於它的問題。將生成的證書添加到商店並更新IIS網站綁定
我試圖根據我已擁有和擁有的CA證書生成個人證書(使用BouncyCastle)。生成證書後,將其放入「我的」商店,然後嘗試更新我的IIS網站的SSL綁定以使用此新證書。
我注意到IIS網站的更新(使用ServerManager
)沒有拋出異常,但是當我轉到IIS管理器控制檯時,我注意到該網站的綁定沒有選擇SSL證書。當我嘗試選擇我創建的證書(顯示了罰款作爲一種可行的選擇),我收到以下錯誤信息:
A specified logon session does not exist. It may already have been terminated. (Exception from HRESULT: 0x80070520)
作爲測試我出口我生成的證書(使用私鑰)和通過嚮導重新安裝它,然後再次嘗試設置綁定(通過IIS管理器)哪些工作。
由於這種行爲,我認爲這是我如何生成或添加證書到商店的問題。我希望有人可能對我所遇到的問題有所瞭解。以下是在創建證書時使用的相關功能,將其添加到商店並以編程方式更新網站的綁定:
主要功能生成獲取CA證書私鑰的私鑰,簽名的證書,並更新站點綁定:
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
- 驗證所產生的效力證書和CA證書與CertUtil.exe
- 驗證生成的證書和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");
最後,我設置的結合,因爲我是較早做:
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對象,添加到商店,最後設置綁定。
我有類似的代碼相同的問題,並添加'X509KeyStorageFlags.MachineKeySet'無疑解決了這個問題。 –