2016-11-30 1 views
2

다음과 같이 실행 중이며 Google 및 스택 오버플로에 대한 여러 가지 방법을 다 써 버린 것처럼 느껴본 후에 필자는 자신의 질문을하기로했습니다. .생성 된 인증서를 저장소에 추가하고 IIS 사이트 바인딩을 업데이트하십시오.

나는 이미 소유하고 소유하고있는 CA 인증서를 기반으로하는 개인 인증서 (BouncyCastle 사용)를 생성하려고합니다. 인증서를 생성 한 후 'My'저장소에 저장 한 다음 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 실행 중임을 알립니다.
  • 유효성이 검증되었습니다. 인증서 및 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(); 
} 

이 방법은 작업을 수행,하지만 난 그런 다음 인증서를 파일로 내 보냅니다 가지고에로드 할 이유는 표시되지 않습니다 X509Certificate2 개체를 만들고 저장소에 추가 한 다음 마지막으로 바인딩을 설정합니다.

+0

비슷한 코드에서 같은 문제가 발생했으며'X509KeyStorageFlags.MachineKeySet'을 추가하면 확실히 문제가 해결됩니다. –

답변

0

ToRSA 메서드는 일시적인 RSA 키를 생성 할 가능성이 높습니다. 따라서 참조가 모두 사라지면 키가 삭제됩니다. 임시 구조를 PFX로 내 보낸 다음 PersistKeySet을 사용하여 다시 가져 오는 것은 지속 된 키로 변환하는 한 가지 방법입니다. 다른 것들은 존재하지만, 그 중 하나는 덜 복잡한 것 중 하나입니다.

실제로 파일에 쓸 필요는 없습니다.

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

PrivateKey의 속성을 설정처럼, 무슨 다른 미묘한 바이트에서로드 된 저장소에서로드와 하나 된 인증서 예를 들어 다른 행동도했다입니다 ... PFX/PKCS # 12 수출/import는 그 모든 것들을 처리합니다.

+0

고마워요,이게 더 좋은 해결책입니다. – Fizz

관련 문제