FileNotFoundException when using XEnroll in ASP.NET
Hi all,
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:
using XENROLLLib;
CEnroll objEnroll = new CEnrollClass();
string strCertRequest = objEnroll.createRequest(XECR_CMC , "CN=Alex", "1.3.6.1.4.1.311.2.1.21");
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)"
Source="Interop.XENROLLLib"
StackTrace:
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.
Kind regards,
Alex (Alejandro Campos Magencio)
Comments
- Anonymous
June 12, 2009
How to do"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." in Vista?I set objPrivateKey.MachineContext = true;but receiving access denied... - Anonymous
June 12, 2009
If you get an Access Denied, it means you don't have permissions to write to file system or Windows registry. Only Admin users can i.e. create keys on machine profile by default. You may use Process Monitor (from Sysinternals) to detect which file/folder or registry key you are trying to access when you get Access Denied. - Anonymous
November 15, 2009
Hi, I think I'm getting a similar issue when using CertEnroll.System.IO.FileNotFoundException: CertEnroll::CX509CertificateRequestPkcs10::Encode: The system cannot find the file specified. 0x80070002 (WIN32: 2) at Interop.CERTENROLLLib.CX509CertificateRequestPkcs10Class.Encode()Though I'm not sure where i should be setting the Store Options to use the local machine like you suggest.Any thoughts?