So recently I have been working with JSON web Tokens authentication and wanted to make extra step with security. I decided to sign my tokens with certificates.
So without any further delays I have happily placed certificate within my storage location ( for sake of this post lets say it was local filesystem ) and created simple method to create my object from byte array of that certificate and my password.
byte binaryData = new byte;
// ... Removed for code visibility - binaryData contains raw certificate byte array
var cert = new X509Certificate2(binaryData, password);
The problem :
However when I have tried to invoke ctor on X509Certificate2 passing my raw array of certificate bytes I have received nasty error saying :
Object was not found.
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, String password)
//my code here
Tackling the challenge:
In this instance solution to the problem should be understanding whats going on in this instance.
To give you more details same problem occured on my local development environment and my Azure designated webApp.
My local website have dedicated application pool with specified domain user which app pool uses as identity.
It appears that that even though I was loading the certificate from byte the underlying Windows Cryptographic Service provider tried to use user store and since my application pool account profile was not available a cryotographic context was not available.
So initially seems like enabling to Load User Profile to true solves the problem. But wait …. ? Does it really ?
What happens then when you change that setting ? Well ApplicationPool is calling LoadProfile and all related implications of doing that follows.This of course includes possible security vulnerabilities / performance etc.
* this will also work in Azure WebApp *
X509Certificate2 ctor has extra flags ( X509KeyStorageFlags ) that can be used. If you investgate them you will notice one particklary interesting:
MachineKeySet – the key is written to a folder owned by the machine.
var cert = new X509Certificate2(bytes, password, X509KeyStorageFlags.MachineKeySet);
More info avaliable under link to a great post that discuss this in details
Its good to cleanup after yourself. If you have read the aforementioned blog you will find more info about temp files left behind when using byte within X509Certificate ctor.
So I have adapted method mentioned then and now use :
var file = Path.Combine(Path.GetTempPath(), "rafpe-" + Guid.NewGuid());
return new X509Certificate2(file,X509KeyStorageFlags.MachineKeySet);
Happy coding 😀