2016-11-30 1 views
2

私は次のように実行しています。私はGoogleとStack Overflowに関するさまざまな手段を使い果たしてしまったような気がして、 。ストアに生成された証明書を追加し、IISサイトバインディングを更新する

私は既に所有しているCA証明書に基づいて(BouncyCastleを使用して)個人証明書を生成しようとしています。証明書を生成して「My」ストアに配置した後、IIS WebサイトのSSLバインドを更新してこの新しい証明書を使用しようとします。

IIS Webサイトのアップデート(ServerManagerを使用)が例外をスローしていないことに気づいていますが、IISマネージャコンソールにアクセスすると、WebサイトのバインディングにSSL証明書が選択されていません。私は(秘密鍵で)私の生成された証明書をエクスポートした試験として

A specified logon session does not exist. It may already have been terminated. (Exception from HRESULT: 0x80070520)

と:私は、私が作成した証明書を選択しようとすると、私は、次のエラーメッセージが表示されます(実行可能な選択肢として罰金を示しています)ウィザードを介してそれを再インストールして、もう一度動作したバインディング(IISマネージャー経由)を設定しようとしました。

この動作のため、私はそれがどのように証明書を生成したり、ストアに追加したかに問題があると想定しました。誰かが私が抱えている問題が何であるかを知りたいと思っていました。

CA証明書の秘密鍵を取得するために生成する主な機能は、自己証明書の秘密鍵を生成し、証明書を作成するために使用される関連する機能です(私は信じています)証明書に署名した、との結合部位更新: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; 
} 

を:

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のヘルプダイアログが私を知らせる
  • マシンが実行されている8.5
  • が発生した妥当性を検証したIIS証明書と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"); 

最後に、私が以前にやっていたように私は、バインディングを設定します。

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(); 
} 

はこの方法が働くそれをやって、私はTHENに読み込み、ファイルに証明書をエクスポートする必要がありますなぜ私は表示されませんX509Certificate2オブジェクトを作成し、ストアに追加し、最後にバインディングを設定します。

+0

私は同様のコードで同じ問題を抱えていましたが、 'X509KeyStorageFlags.MachineKeySet'を追加することで問題は確実に修正されました。 –

答えて

0

ToRSAメソッドは一時的なRSAキーを作成する可能性が高いので、参照がすべて消えたときにキーが削除されます。エフェメラル構造をPFXにエクスポートしてPersistKeySetを使用して再インポートすることは、永続キーに変換する1つの方法です。他にも存在するものがありますが、それはあまり回想されていないものの1つです。

実際にファイルに書き込む必要はありませんが、

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

のPrivateKeyプロパティを設定するように、起こっている他の機微がバイトからロードされたストアからロードされ、1た証明書のインスタンスごとに異なる振る舞いもありましたが... PFX/PKCS#12輸出/それらのすべてを取り巻くインポートは機能します。

+0

ありがとう、これは良い解決策です。 – Fizz

関連する問題