Search code examples
.netvb.netwindows-serviceswindows-server-2008x509certificate2

Cannot retrieve programmatically a certificate installed through mmc for a service account


I'm trying to turn an application into a service (.NET). This service has to log in remote server through a Web Service (FileNet P8 .NET credential system).

However, the URL is HTTPS so it requires a certificate.

I followed Microsoft's instructions to install a certificate for a service account with MMC. The certificate (self-signed) is installed in Trusted Root Certification Authorities Certificate Store. (Disclaimer: I don't really understand yet how MMC works, especially when changes made with are effective).

The certificate is present in HKLM\SOFTWARE\Microsoft\Cryptography\ Services\<ServiceName>\SystemCertificates\Root\Certificates\<digitalFootprint>.

However, this piece of code doesn't retrieve the certificate :

' Environment.UserName = SERVICE LOCAL (french)
LOGGER.info("Certifs for " & Environment.UserName)
Dim store As X509Certificates.X509Store =
    New X509Certificates.X509Store(X509Certificates.StoreName.Root,
                                   X509Certificates.StoreLocation.CurrentUser)
store.Open(X509Certificates.OpenFlags.ReadOnly)
For Each certificate As X509Certificates.X509Certificate2 In store.Certificates
    LOGGER.info(certificate.Issuer & ": " & 
                If(certificate.Verify, "Valid", "Invalid"))
Next 
LOGGER.info("End Certifs")

Of course, the test code below fails:

Dim wq As Net.WebRequest = Net.WebRequest.Create("https://<URL>")
Dim reader As IO.StreamReader = New IO.StreamReader(wq.GetResponse.GetResponseStream)
LOG.info(reader.ReadToEnd)

But if I run the service with a user account which does have the certificate, it runs. What did I do wrong?

Additional question: is there a way to run Internet Explorer with a service account to perform the certificate installation with it? (As a workaround)


Solution

  • .NET doesn't support certificate lookup in service account stores. The underlying API CertOpenStore function has support for service account stores via CERT_SYSTEM_STORE_CURRENT_SERVICE and CERT_SYSTEM_STORE_SERVICES values. .NET has support only for CERT_SYSTEM_STORE_LOCAL_MACHINE and CERT_SYSTEM_STORE_CURRENT_USER values in StoreLocation enumeration.

    MMC uses native APIs, thus you can access services certificate stores from MMC. This is sort of known limitation in .NET. The only way to overcome it is to use CertOpenStore function directly (via p/invoke).