Search code examples
winapicryptographycryptoapix509

IX509PrivateKey::Create throws access denied when called as "Network Service"


I'm using IX509PrivateKey to create a key for an X.509 cert request (as "NT AUTHORITY\NETWORK SERVICE"), and the Create method is generating an access denied (I'm P/Invoke-ing the dispatch interface from C#, so the HRESULT is getting translated to a .NET exception). Process Monitor also shows an access denied attempt to access the key file (the key file is being created).

Here's the actual code:

        IX509PrivateKey privateKey = new CX509PrivateKey() as IX509PrivateKey;
        privateKey.Length = request.KeyLength;
        privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;
        privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
        privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
        privateKey.MachineContext = true;
        privateKey.Create();
        return privateKey; 

If I create a user key set instead (by setting MachineContext to false), I see a "File Not Found" instead of "Access Denied". But ProcMon shows nothing; no attempt to access any key files.

In Process Monitor, I was able to determine that "Network Service" did not have access to the key file, so I used the IX509PrivateKey::SecurityDescriptor property to set it. "Network Service" indeed then had access to the key file, but I still received the access denied from Create, and ProcMon still showed an access denied attempt on the file.

Much TIA for any and all ideas.


Solution

  • The cause of this issue has been determined.

    The call to IX509PrivateKey::Create was occurring within a web service. As a result, it was occurring under impersonation of IUSR. We edited ACLs enabling the wrong user. It turned out to be straightforward access denied, only for an obfuscated user account. This condition can be observed in ProcMon. ProcMon's "Detail" column will clearly indicate (you may have to enable "Advanced Output")that the call was under an impersonated user account.

    In order to more tightly control the user account under which the call is made, and the CA is accessed, we moved the request out-of-process. The enrollment API calls are now made from their own Windows service, and exposed via WCF (net.tcp) to the web service running in IIS. That would be my recommendation for others. IMO, the risk of having another "moving part" is outweighed by the lack of control of making the calls within IIS.