3

秘密鍵のアクセス許可の管理など、証明書の展開を自動化しようとしています。この質問を使用して、証明書のアクセス許可を更新するコードをいくつかまとめました。

public static SetPermissionsResult SetPermissions(X509Certificate2 certificate, string userName)
{
    var account = new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null);

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

        var newCertificate = store.Certificates.Find(X509FindType.FindBySerialNumber, certificate.SerialNumber, false)[0];

        var rsa = newCertificate.PrivateKey as RSACryptoServiceProvider;
        if (rsa == null)
        {
            return SetPermissionsResult.Failure;
        }

        rsa.PersistKeyInCsp = true;

        var cspParams = new CspParameters(
            rsa.CspKeyContainerInfo.ProviderType,
            rsa.CspKeyContainerInfo.ProviderName,
            rsa.CspKeyContainerInfo.KeyContainerName)
                            {
                                Flags =
                                    CspProviderFlags.UseExistingKey
                                    | CspProviderFlags.UseMachineKeyStore,
                                CryptoKeySecurity =
                                    rsa.CspKeyContainerInfo.CryptoKeySecurity,
                                KeyNumber = (int)rsa.CspKeyContainerInfo.KeyNumber/*,
                                KeyPassword = password*/
                            };

        cspParams.CryptoKeySecurity.AddAccessRule(
            new CryptoKeyAccessRule(account, CryptoKeyRights.GenericRead, AccessControlType.Allow));

        using (var rsa2 = new RSACryptoServiceProvider(cspParams))
        {
        }

        return SetPermissionsResult.Success;
    }
}

読み取る行using (var rsa2 = new RSACryptoServiceProvider(cspParams))(新しい暗号化プロバイダーがインスタンス化されて新しいアクセス ルールが保持される場所) で、CryptographicException "Keyset does not exist" が発生します。

これは通常、現在のセキュリティ コンテキストに主キーへのアクセス許可がないことを意味することを経験から知っています。この可能性をトラブルシューティングするために、次のことを行いました。

  1. System.Security.Principal.WindowsIdentity.GetCurrent()イミディエイト ウィンドウで現在のユーザーが何を持っているかを把握する
  2. そのユーザーが証明書の MMC スナップインでフル コントロールのアクセス許可を持っていることを確認します (そして、証明書の適切なストアを見ていることを再確認します)。
  3. Everyone ユーザーにフル コントロールを付与します。
  4. KeyPassword を使用して、または使用せずに CspParameters オブジェクトを作成しようとしました (そこにコメントが付けられていることがわかります)。

私はアイデアがありません。証明書は偽の自己署名テスト証明書であるため、チェーン内の他の証明書に権限がないことは問題ではありません。どんな助けでも大歓迎です。

アップデート:

このコードは、このステップの前にある証明書のインストール用のフラグの一部を変更することで実行できました。これで、コードが正常に実行されたように見えますが、MMC で確認できる目に見える効果はありません。

4

1 に答える 1

4

多かれ少なかれ、この問題を解決しました。上記のアクセス許可を管理するためのコードは適切です。問題だったのは、証明書を追加する前に証明書を開始するためのコードでした。そのための常識的な方法は次のようになります。

var certificate = new X509Certificate2(bytes, password);

これの問題は、秘密鍵がストアに永続化されないことです。これは、アクセス許可コードが依存しているものです (duh)。これを行うには、次のように証明書をインスタンス化してストアに追加する必要があります。

var certificate = new X509Certificate2(bytes, "password123", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

そして、次のように追加します。

using (var store = new X509Store(storeName, StoreLocation.LocalMachine))
{
       store.Open(OpenFlags.MaxAllowed);

       store.Add(certificate);
}

最後のポイント: MMC スナップインは、更新されたアクセス許可を表示するのが面倒です。つまり、新しいアクセス許可が実際に変更されていても、新しいアクセス許可が表示されない場合があります。すべてが完璧に機能するところまで来ましたが、MMC が違うことを示していたので、それを認識していませんでした。MMC を閉じて再度開くと、何が表示されているか疑わしい場合は強制的に更新されます。

于 2016-02-17T15:16:50.780 に答える