I need to download and install about 50 CRLs once a week and install them on several Windows servers. Downloading is the easy part, is there a way I could script the CRL import
Here is my final source (slightly scrubbed for the public) - but should work. I won't change the accepted answer, but I do hope this helps (as does upvoting the question and answers!).
Note: This will import both a CRL or a regular certificate into the LOCAL MACHINE Trusted Root store. Changing the below CERT_SYSTEM_STORE_LOCAL_MACHINE
to CERT_SYSTEM_STORE_CURRENT_USER
in the call CertOpenStore will change it to work for the Current User store.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
public struct CRYPTUI_WIZ_IMPORT_SRC_INFO
{
public Int32 dwSize;
public Int32 dwSubjectChoice;
[MarshalAs(UnmanagedType.LPWStr)]public String pwszFileName;
public Int32 dwFlags;
[MarshalAs(UnmanagedType.LPWStr)]public String pwszPassword;
}
[DllImport("CryptUI.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptUIWizImport(
Int32 dwFlags,
IntPtr hwndParent,
IntPtr pwszWizardTitle,
ref CRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc,
IntPtr hDestCertStore
);
[DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenStore(
int storeProvider,
int encodingType,
IntPtr hcryptProv,
int flags,
String pvPara
);
public const Int32 CRYPTUI_WIZ_IMPORT_SUBJECT_FILE = 1;
public const Int32 CRYPT_EXPORTABLE = 0x00000001;
public const Int32 CRYPT_USER_PROTECTED = 0x00000002;
public const Int32 CRYPTUI_WIZ_NO_UI = 0x0001;
private static int CERT_STORE_PROV_SYSTEM = 10;
private static int CERT_SYSTEM_STORE_CURRENT_USER = (1 << 16);
private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Usage: certimp.exe list.crl");
Environment.ExitCode = 1;
}
else
{
IntPtr hLocalCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
IntPtr.Zero,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
"ROOT"
);
CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc = new CRYPTUI_WIZ_IMPORT_SRC_INFO();
importSrc.dwSize = Marshal.SizeOf(importSrc);
importSrc.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
importSrc.pwszFileName = args[0];
importSrc.pwszPassword = null;
importSrc.dwFlags = CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED;
if (!CryptUIWizImport(
CRYPTUI_WIZ_NO_UI,
IntPtr.Zero,
IntPtr.Zero,
ref importSrc,
hLocalCertStore
))
{
Console.WriteLine("CryptUIWizImport error " + Marshal.GetLastWin32Error());
Environment.ExitCode = -1;
}
}
}
}
}
In Powershell there is a Cert:
provider which represents the certificate store. Manipulating it is done via the standard cmdlets so you might be able to integrate a revocation list there somewhere. I just don't know enough about how Windows handles certificates to be of any further help here.
Hm. Is there any reason not to use the certutil.exe utility? I can import a Certificate Revocation List into the appropriate store by running the following command:
certutil -addstore CA <FileName>.crl
I don't know a way to do it via script. Can you write C code? If I understand what you want to do, you will use the CryptUiWizImport function, and the CRYPTUI_WIZ_IMPORT_SRC_INFO structure.
Here's a sample of code that installs a Cert; the corresponding CRL import is similar.
Addendum:
This post points out that Win32 APIs (such as CryptUiWizImport) are not directly accessible from PowerShell, and then describes a possible workaround: from within the PowerShell script, dynamically generate and compile C# code that does the P/Invoke stuff, and then run the resulting assembly. This would allow you to do the CryptUiWizImport strictly from a powershell script, although it would be a pretty exotic one.