Although the question was asked a long time ago, and perhaps it is not relevant, I will still propose a solution, since the problem is interesting. Its solution can be useful, for example, when you need to automate the updating of certificate revocation lists on dozens of servers.
Unfortunately, .NET does not provide any standard tools for solving this problem. You will have to use wrappers for crypt32.dll
and unsafe code. Below is an example solution. It is based on the CrlFile
class, which allows you to open a crl file and import it into standard storage ( System.Security.Cryptography.X509Certificates.X509Store
class).
Additional Information:
class Program { static void Main(string[] args) { var store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadWrite); var crl = new CrlFile(@"d:\tmp\ca\root.crl"); crl.Import(store, CrlAddDisposition.CERT_STORE_ADD_REPLACE_EXISTING); store.Close(); } } public class CrlFile { // по уму здесь нужна реализация SafeHandle, // но чтобы не удлинять код оставим, как есть private IntPtr _context; private readonly string _file; public CrlFile(string file) { _file = file; } public bool Import(X509Store store, CrlAddDisposition disp, ref IntPtr storeContext) { EnsureCrlContext(); return Crypto32Interop.CertAddCRLContextToStore(store.StoreHandle, _context, (uint)disp, storeContext); } public bool Import(X509Store store, CrlAddDisposition disp) { var storeContext = IntPtr.Zero; return Import(store, disp, ref storeContext); } private unsafe void EnsureCrlContext() { if (_context != IntPtr.Zero) return; var context = new IntPtr(Crypto32Interop.CERT_QUERY_CONTENT_CRL); var handle = GCHandle.Alloc(_file, GCHandleType.Pinned); var data = handle.AddrOfPinnedObject(); bool ret = Crypto32Interop.CryptQueryObject( Crypto32Interop.CERT_QUERY_OBJECT_FILE, data, Crypto32Interop.CERT_QUERY_CONTENT_FLAG_CRL, Crypto32Interop.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(&context)); _context = Crypto32Interop.CertDuplicateCRLContext(context); Crypto32Interop.CertFreeCRLContext(context); handle.Free(); } ~CrlFile() { if (_context != IntPtr.Zero) Crypto32Interop.CertFreeCRLContext(_context); } } public static class Crypto32Interop { public const uint CERT_QUERY_CONTENT_CTL = 2; public const uint CERT_QUERY_CONTENT_CRL = 3; public const uint CERT_QUERY_OBJECT_FILE = 1; public const uint CERT_QUERY_FORMAT_BINARY = 1; public const uint CERT_QUERY_FORMAT_BASE64_ENCODED = 2; public const uint CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3; public const uint CERT_QUERY_CONTENT_FLAG_CRL = (1 << (int)CERT_QUERY_CONTENT_CRL); public const uint CERT_QUERY_CONTENT_FLAG_CTL = (1 << (int)CERT_QUERY_CONTENT_CTL); public const uint CERT_QUERY_FORMAT_FLAG_BINARY = (1 << (int)CERT_QUERY_FORMAT_BINARY); public const uint CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = (1 << (int)CERT_QUERY_FORMAT_BASE64_ENCODED); public const uint CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = (1 << (int)CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED); public const uint CERT_QUERY_FORMAT_FLAG_ALL = (CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CertDuplicateCRLContext(IntPtr pCrlContext); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CertFreeCRLContext(IntPtr pCrlContext); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CertAddCRLContextToStore( [In] IntPtr hCertStore, [In] IntPtr pCrlContext, [In] uint dwAddDisposition, [Out] IntPtr ppStoreContext); [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptQueryObject( [In] uint dwObjectType, [In] IntPtr pvObject, [In] uint dwExpectedContentTypeFlags, [In] uint dwExpectedFormatTypeFlags, [In] uint dwFlags, [Out] IntPtr pdwMsgAndCertEncodingType, [Out] IntPtr pdwContentType, [Out] IntPtr pdwFormatType, [In, Out] IntPtr phCertStore, [In, Out] IntPtr phMsg, [In, Out] IntPtr ppvContext); } public enum CrlAddDisposition : uint { CERT_STORE_ADD_NEW = 1, CERT_STORE_ADD_USE_EXISTING = 2, CERT_STORE_ADD_REPLACE_EXISTING = 3, CERT_STORE_ADD_ALWAYS = 4, CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES = 5, CERT_STORE_ADD_NEWER = 6, CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES = 7, }