2016-11-07 25 views
3

デバイスごとに自己署名証明書から証明書のペアに切り替える必要があります。その1つは事前に生成され、信頼できるルート証明機関ストアに置かれ、デバイスごとに生成されパーソナルストアに配置された2番目の証明書のルートCAとして機能します。自己署名されていない証明書を作成しようとした際の例外

私は避けたい署名付き証明書の表示を作成するので、makecertは使用しません。また、OpenSSLはいくつかのライセンス関連のもののために使用することはできません。ですから、私はCertEnrollのlibに基づいた小さなC#ツールを使って作業しています。

これは、最初のルートCA証明書のpfxを作成する方法です。 C#コードから証明書を作成するには

makecert -n "CN=Root CA" -cy authority -r -a sha256 -len 2048 -sv root.pvk root.cer 
pvk2pfx -pvk root.pvk -spc root.cer -pfx root.pfx -pi 123 -po 123 

、私が質問How to create self-signed certificate programmatically for WCF service?C# Generate a non self signed client CX509Certificate Request without a CA using the certenroll.dllを参照しました。

これまでのところ、次のコードがあります。証明書の生成方法:

/// <summary> 
/// Generates self-signed certificate with specified subject, which will expire after specified timespan. 
/// </summary> 
public X509Certificate2 CreateCertificate(string subjectName, TimeSpan expirationLength, X509Certificate2 issuer = null) 
{ 
    // create DN for subject and issuer 
    var dn = new CX500DistinguishedName(); 
    dn.Encode("CN=" + subjectName); 

    var issuerName = new CX500DistinguishedName(); 
    if(issuer != null) 
    { 
     issuerName.Encode(issuer.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(); 

    // Use the stronger SHA512 hashing algorithm 
    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 = issuerName; 
    else 
     cert.Issuer = dn; 
    cert.NotBefore = DateTime.Now.Date; 
    cert.NotAfter = cert.NotBefore + expirationLength; 
    cert.HashAlgorithm = hashobj; // Specify the hashing algorithm 

    if(issuer != null) 
    { 
     var signerCertificate = new CSignerCertificate(); 
     signerCertificate.Initialize(true, X509PrivateKeyVerify.VerifyAllowUI, EncodingType.XCN_CRYPT_STRING_HEX, issuer.GetRawCertDataString()); 
     cert.SignerCertificate = signerCertificate; 
    } 
    cert.Encode(); 

    // Do the final enrollment process 
    var enroll = new CX509Enrollment(); 
    enroll.InitializeFromRequest(cert); // load the certificate 
    enroll.CertificateFriendlyName = subjectName; // Optional: add a friendly name 

    var csr = enroll.CreateRequest(); // Output the request in base64 
    // and install it back as the response 
    enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, 
      csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password 
    // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes 
    var base64encoded = enroll.CreatePFX("", // no password, this is for internal consumption 
      PFXExportOptions.PFXExportChainWithRoot); 

    // instantiate the target class with the PKCS#12 data (and the empty password) 
    return new X509Certificate2(Convert.FromBase64String(base64encoded), "", 
     X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); 
} 

シンプルなアプリケーション既存の証明書を見つけ、それに基づいて新しいものを作成するために:

static void Main(string[] args) 
{ 
    var certificateGenerator = new CertificateGenerator(); 

    X509Certificate2 rootCA; 

    using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) 
    { 
     store.Open(OpenFlags.ReadWrite); 

     rootCA = store.Certificates.OfType<X509Certificate2>() 
      .FirstOrDefault(c => c.Subject.StartsWith("CN=Root CA", StringComparison.Ordinal)); 

     store.Close(); 
    } 

    if (rootCA == null) 
     throw new Exception("Can't find root CA certificate"); 

    var testCert = certificateGenerator.CreateCertificate("Test", new TimeSpan(3650, 0, 0, 0), rootCA); 
    using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine)) 
    { 
     store.Open(OpenFlags.ReadWrite); 
     store.Add(testCert); 
     store.Close(); 
    } 
} 

事は、私がいない中で、証明書を参照しようとした場合、それは、素晴らしい作品ということであり、信頼されたルート認証局が、個人で(たとえ私が証明書にパスワードを持っていても)。しかし、私は信頼されたルート証明機関からのCA証明書に基づいて証明書を作成しようとすると、私はそう

Cannot find object or property. 0x80092004 (-2146885628 CRYPT_E_NOT_FOUND) 

を言って、signerCertificate.Initialize上の例外を受け取り、私が何をしないのですか?

答えて

2

ISignerCertificate::Initializeは、秘密鍵が要求またはマイストアを介して結合されている必要があります:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa376832(v=vs.85).aspx

秘密鍵が必要な場合は、唯一の個人的な要求店舗を が検索されます。

秘密鍵が必要ない場合は、ルートと中間のCA ストアも検索されます。

Windowsはあなたが唯一のCA(中間)またはルート/ ThirdPartyRoot店にCAの公開部分を置くことを期待していますが、発行者なら、あなたも秘密鍵で(それがインストールされているだろうということ現在)をCurrentUser \ MyまたはLocalMachine \ Myにコピーします。

+0

プライベートキーを持つバージョンが既にMy storeにある場合、証明書の中のポイント(その公開部分だけ)がCAストアにあるのは何ですか?生成された証明書は、ルート/ CAストアではなく、私のストアからCA証明書を参照するため、削除することはできません。 – lentinant

+0

@lentinantそれはどういう仕組みではない。 "My"ストアは、署名を生成する秘密鍵を探すときに使用されますが、発行者が書き留める情報は「Myストアにあった」識別子ではありません。 CAストアは、チェーン構築の迅速な検索のためだけであり、Root/TrustedRootはチェーン構築における信頼の決定のためのものです。 「証明書」にはストアがないか、ストアが何であるかを知っています...ストアは、特定のコード実行パスの間だけ関数を提供します。 – bartonjs

+0

それが働いた。あなたが言ったのと同じように、CA証明書はPersonal Storeに置かれるべきです。また、アプリケーションはそれ自体で 'Issuer'プロパティを割り当ててはいけません。Encodeの前に' IssuerCertificate'プロパティが割り当てられていれば自動的に設定されます。手動で設定すると、ほとんどの場合、証明書情報に「Windowsはこの証明書を確認するのに十分な情報がありません」と表示されます。 – lentinant

関連する問題