We have some unit tests which have PFX certificates embedded in them. These certificates are read during test execution and turned into X509Certificate2
objects. Unfortunately, when run as an unprivileged user, we get Access Denied
exceptions:
using (var s = EmbeddedResourceUtilities.GetEmbeddedResourceAsStream(typeThatContainsEmbeddedResource, certFileName))
{
if (s == null)
{
throw new ApplicationException(String.Format("Embedded certificate {0} for type {1} not found.", certFileName, typeThatContainsEmbeddedResource.FullName));
}
try
{
var bytes = new byte[s.Length];
s.Read(bytes, 0, (int)s.Length);
return new X509Certificate2(bytes);
}
catch (Exception ex)
{
throw new ApplicationException(String.Format("Error loading embedded certificate {0} for type {1}.", certFileName, typeThatContainsEmbeddedResource.FullName), ex);
}
}
Here's the exception:
System.Security.Cryptography.CryptographicException : Access denied.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData)
I've tried modifying the constructor to use an empty password and explicit keyset flags, but that doesn't fix it:
// this doesn't work, either
return new X509Certificate2(bytes, String.Empty, X509KeyStorageFlags.MachineKeySet);
I've read elsewhere that I should give my unprivileged user increased permissions on the MachineKeys directory, but I'm loathe to do that as it would allow production code to assume those permissions are available on that directory outside the test environment.
Is there any way of allowing an unprivileged user to load an X509Certificate from a file?
This is my best guess about what's going on.
The X509Certificate2 constructor creates temporary public/private key objects in the Machine Keys directory (I believe via the Windows local security authority). Because the our unprivileged user doesn’t have access to these keys or the Machine Keys directory, the tests fail.
Our solution was to update our environment setup scripts to install these test certificates ahead of time, grant the unprivileged user permissions to them, and re-write the tests to load the certificates from the appropriate certificate store.
Using the "X509KeyStorageFlags.UserKeySet" flag in the X509Certificate2 constructor helped me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With