Sören Kuklau
Sören Kuklau

Reputation: 19950

How do I access X.509 certificates stored in a service account?

I'm trying to digitally sign a PDF document using Syncfusion PDF 10.4, like so:

PdfLoadedDocument document = new PdfLoadedDocument(inputStream);
PdfCertificate certificate = PdfCertificate.FindBySubject(certificateStoreType, certificateSubjectName);

PdfSignature signature = new PdfSignature(document, document.Pages[0], certificate, "Signatur");
signature.Bounds = new RectangleF(new PointF(5, 5), new SizeF(100, 100));

This works great for my local user account after installing a suitable certificate using MMC (adding the Certificates snap-in for My user account and storing it in Personal), but not for a service (choosing Service account this time, and picking my service). Running the same code results in no suitable certificate being found, i.e. certificate is null. Furthermore, PdfCertificate.GetCertificates() throws an AccessViolationException, which I assume is a bug on Syncfusion's end.

I can, however, reproduce the same problem without Syncfusion code:

var store = new System.Security.Cryptography.X509Certificates.X509Store("My");
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
foreach (var item in store.Certificates)
{
    …
}

Run as my own user, the certificate shows up (as do all the others shown in MMC under Personal), but if I debug the service (by running it, then invoking System.Diagnostics.Debugger.Launch()), I only get a "CN=LOCAL SERVICE" certificate, which doesn't show up in MMC at all.

I'm assuming that I need to A) tell it to open the correct certificate store, or B) change something about the way the service is installed or run, such as giving it a different identity, enabling UserInteraction, etc. Currently, it runs using LocalService and with UserInteraction disabled.

Upvotes: 3

Views: 6448

Answers (3)

user1898139
user1898139

Reputation: 11

I ran into this problem, and to solve it had to allow the "Local Service" account to access the "Local Computer" certificate store using the tool "WinHttpCertCfg"

It is described in detail here:

https://support.microsoft.com/en-us/help/901183/how-to-call-a-web-service-by-using-a-client-certificate-for-authentication-in-an-asp-net-web-application

Upvotes: 1

Sören Kuklau
Sören Kuklau

Reputation: 19950

The answer appears to be that .NET doesn't support accessing service account certificate stores without P/Invoke or the like:

I don't think that any of the .NET APIs allow access to the Services Certificate store.

However, you can install the certificate into the CurrentUser store of the account that the service runs under.

I've changed the service to run under its own user (which doesn't need admin rights), ran mmc.exe as that user using runas, and imported the certificate to that user's personal store.

Upvotes: 4

Wiktor Zychla
Wiktor Zychla

Reputation: 48279

From what I remember, Windows machine accounts (like LocalService) use the machine certificate store. This means that in your code, you have to access the store with StoreLocation.LocalMachine.

var store = 
   new System.Security.Cryptography.X509Certificates.X509Store(StoreLocation.LocalMachine);

Note that if you decide to run the service under specific identity, you should rather first login as the identity, then import the certificate to the Personal store and then, use StoreLocation.CurrentUser.

Upvotes: 4

Related Questions