2017-05-10 34 views
2

私はいくつかの証明書署名ツールを開発しています。現在の目標は、発行者として既存の証明書を使用して新しい証明書を生成するメソッドを作成することです。証明書とインストールの手動インストールとコードとの違いは何ですか?

public X509Certificate2 CreateCertificate(string subjectName, TimeSpan certificateLifespan, X509Certificate2 issuer = null) 
{ 
    var nameFormat = "CN={0}"; 

    var subject = string.Format(nameFormat, subjectName); 

    // create DN for subject and issuer 
    var dn = new CX500DistinguishedName(); 
    dn.Encode(subject); 

    var privateKey = new CX509PrivateKey 
    { 
     ProviderName = "Microsoft Strong Cryptographic Provider", 
     Length = 2048, 
     KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE, 
     KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_DECRYPT_FLAG | 
          X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_KEY_AGREEMENT_FLAG, 
       MachineContext = true, 
       ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG 
    }; 

    privateKey.Create(); 

    var hashobj = new CObjectId(); 
    hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, 
       ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, 
       AlgorithmFlags.AlgorithmFlagsNone, "SHA512"); 

    var cert = new CX509CertificateRequestCertificate(); 
    cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, ""); 
    cert.Subject = dn; 
    if (issuer == null) 
     cert.Issuer = dn; 
    else 
    { 
     var signerCertificate = new CSignerCertificate(); 
     signerCertificate.Initialize(true, X509PrivateKeyVerify.VerifyNone, EncodingType.XCN_CRYPT_STRING_HEXRAW, issuer.GetRawCertDataString()); 
       cert.SignerCertificate = signerCertificate; 
    } 
    cert.NotBefore = DateTime.Now.Date; 
    cert.NotAfter = cert.NotBefore + certificateLifespan; 
    cert.HashAlgorithm = hashobj; 
    cert.Encode(); 

    var enroll = new CX509Enrollment(); 
    enroll.InitializeFromRequest(cert); 
    enroll.CertificateFriendlyName = subjectName; 

    var csr = enroll.CreateRequest(); 
    enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, 
       csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); 

    //InstallResponse automatically installs certificate to My store. We should remove it, and manage it manually. 
    using(var store = new X509Store(StoreName.My, StoreLocation.LocalMachine)) 
    { 
     store.Open(OpenFlags.ReadWrite); 

     var certificate = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(
        c => c.Subject.StartsWith(subject, StringComparison.Ordinal)); 

     if (certificate != null) 
      store.Remove(certificate); 
     store.Close(); 
    } 

    //Self-signed certificates are also authomatically installed to Intermediate Authority store 
    if(issuer == null) 
    { 
     using (var store = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine)) 
     { 
      store.Open(OpenFlags.ReadWrite); 

      var certificate = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(
         c => c.Subject.StartsWith(subject, StringComparison.Ordinal)); 

      if (certificate != null) 
       store.Remove(certificate); 
      store.Close(); 
     } 
    } 

    var base64encoded = enroll.CreatePFX("", PFXExportOptions.PFXExportChainWithRoot); 

    return new X509Certificate2(Convert.FromBase64String(base64encoded), "", 
       X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); 
} 

実際には、ルート証明書を手動でインストールする場合、または証明書マネージャを使用する場合にのみ、問題なく動作します。しかし、コード内に埋め込みリソースから証明書をインストールしようとしています。

private void AddCertificateToStore(X509Certificate2 certificate, StoreName storeName) 
{ 
    using (var store = new X509Store(storeName, StoreLocation.LocalMachine)) 
    { 
     store.Open(OpenFlags.ReadWrite); 
     store.Add(certificate); 
     store.Close(); 
    } 
} 

var bytes = new BinaryReader(stream).ReadBytes((int)stream.Length); 
var root = new X509Certificate2(bytes, RootCertificatePassword); 

そして、ここでは、証明書のインストールのための私の方法です。私はそれを次の方法で初期化後

protected Stream ExtractResourceStream(string embeddedResourcePath) 
{ 
    var assembly = GetType().Assembly; 

    var pathConverted = embeddedResourcePath.Replace("\\", "."); 

    var matchingResources = assembly.GetManifestResourceNames() 
      .Where(n => n.EndsWith(pathConverted, StringComparison.InvariantCultureIgnoreCase)) 
      .ToArray(); 

    var resource = matchingResources.FirstOrDefault(); 
    if (resource == null) 
     throw new InvalidOperationException(string.Format("Resource {0} not found.", embeddedResourcePath)); 
    if (matchingResources.Length > 1) 
     throw new InvalidOperationException(string.Format("Resource {0} found more than once.", embeddedResourcePath)); 

    return assembly.GetManifestResourceStream(resource); 
} 

:ここ

は、ストリームに埋め込まれた証明書を抽出するための私の方法であり、

ルート証明書が正しくインストールされているようですが、「キーが見つかりません」という例外が発生していますsignerCertificate.Initializeに電話すると、2番目の証明書が生成されます。

パスワードで保護されたPFXルート証明書を使用しています。

私の質問は - 手動で証明書をインストールし、ストリームからコードでインストールするのとは何ですか?私はコードでそれをインストールしながらいくつかの部分を逃していますか?

答えて

0

まあ、それは愚かでした。どうやら、私は適切なキーセットが欠けていた。それは私がこのようなルート証明書を初期化すれば動作します:

var root = new X509Certificate2(bytes, RootCertificatePassword, 
       X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); 
関連する問題