9

I'm writing a Windows service that needs several certificates in the certificate store in order to connect to a third party web service.

On my installer I call a small application (C#) that creates a user to run the service as.

It works fine.

I now need to install about 10 certificates (don't ask!) into the users certificate store, but can't find any succinct programmatic way to do so.

Any hints? Or am I going to have to use COM interop...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DavidWhitney
  • 4,290
  • 4
  • 24
  • 30

1 Answers1

13

Turns out you first need to impersonate the user.

Using the very nice library described in A small C# Class for impersonating a User, you can do the following:

using (new Impersonator("username", "", "password"))
{
    try
    {
        X509Store serviceRuntimeUserCertificateStore = new X509Store(StoreName.My);
        string baseDir = AppDomain.CurrentDomain.BaseDirectory;
        string certPath = Path.Combine(baseDir, certificateFolder);

        string certificateFile = "c:\\file.cert";
        string certificatePassword = "somePassword";
        string certificateLocation = certPath + "\\" + certificateFile;

        InstallCertificate(certificateLocation, certificatePassword);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

private static void InstallCertificate(string certificatePath, string certificatePassword)
{
    try
    {
        var serviceRuntimeUserCertificateStore = new X509Store(StoreName.My);
        serviceRuntimeUserCertificateStore.Open(OpenFlags.ReadWrite);

        X509Certificate2 cert;

        try
        {
            cert = new X509Certificate2(certificatePath, certificatePassword);
        }
        catch(Exception ex)
        {
            Console.WriteLine("Failed to load certificate " + certificatePath);
            throw new DataException("Certificate appeared to load successfully but also seems to be null.", ex);
        }

        serviceRuntimeUserCertificateStore.Add(cert);
        serviceRuntimeUserCertificateStore.Close();
    }
    catch(Exception)
    {
        Console.WriteLine("Failed to install {0}.  Check the certificate index entry and verify the certificate file exists.", certificatePath);
    }
}

Please add your own exception handling. If you're adding multiple certificates keep the X509Store open for the duration for efficiency.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DavidWhitney
  • 4,290
  • 4
  • 24
  • 30
  • Do you think that the reason you have to impersonate the user is because you need rights to read the private key? If so you could probably add permissions later if you absolutely had to. – Mike Cheel Nov 02 '12 at 19:39