If you ever try to use XEnroll.dll in your ASP.NET application (through Interop.XENROLLLib.dll, of course), you may face an issue like the following:
Your ASP.NET app impersonates the client user and tries to make a certificate request on her behalf:
CEnroll objEnroll = new CEnrollClass();
string strCertRequest = objEnroll.createRequest(XECR_CMC , “CN=Alex”, “18.104.22.168.4.1.322.214.171.124”);
But createRequest fails with the following exception:
System.IO.FileNotFoundException was unhandled by user code
Message=”The system cannot find the file specified. (Exception from HRESULT: 0x80070002)”
at XENROLLLib.CEnrollClass.createRequest(Int32 Flags, String strDNName, String Usage)
If we run the very same code from a VBScript, it works! Mmmmmm, this error looks familiar to me… Check this out: RSACryptoServiceProvider fails when used with ASP.NET.
The exception is a bit different, but the error message is the same and the cause, too. In order to create a request on user’s behalf, that user’s profile needs to be loaded. By default, ASP.NET won’t load user profiles for us as we already know. And we need the user profile to i.e. create keys associated to the cert request.
That also explains why the code works when running in a script. We logged on the server to run the script and the user profile got loaded.
Summing up (see the other post I mentioned for details), we have several options here:
1) Load user profile via LoadUserProfile API. This API requires many permissions to call it and I wouldn’t recommend promoting a standard user to admin to be able to call this API, for instance.
2) Load user profile via dummy Windows service. This is not feasible if we are impersonating many users.
3) Use machine profile instead of user profile. This way we don’t need to load user profile. We can use ICEnroll4::MyStoreFlags Property to select CERT_SYSTEM_STORE_LOCAL_MACHINE instead of the default CERT_SYSTEM_STORE_CURRENT_USER before calling createRequest.
I hope this helps.
Alex (Alejandro Campos Magencio)