none
IX509PrivateKey::Create yields access denied when run as Network Service RRS feed

  • Question

  • 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.

    Wednesday, June 27, 2012 9:47 PM

Answers

  • 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.

    Much thanks to you, Andrew, for investing some of your time to help us out.

    Thursday, July 5, 2012 4:17 PM

All replies

  • Hi John,

      I created a command window as network service [using psexec] and ran the following vb script which is similar to your code:

    Dim oPrivateKey
    Set oPrivateKey = CreateObject("X509Enrollment.CX509PrivateKey")
    oPrivateKey.Length = 1024
    oPrivateKey.MachineContext = true
    oPrivateKey.ExportPolicy = 1 'allow export
    oPrivateKey.KeySpec = 2 'at_signature
    oPrivateKey.KeyUsage = 16777215 'allow all key usages
    call oPrivateKey.Create()
    WScript.Echo oPrivateKey.ContainerName

    It is vbscript that creates a machine key. Is it possible that you have ACL'd the machine keys folder on your system to not allow NetworkService to create keys?

    Andrew

    Thursday, June 28, 2012 6:30 PM
  • It's totally possible. The machine has been "hardened" by IT.

    Changing the ACLs doesn't work, though. If I give NS full control, it still doesn't have access to the created keys. I can't get the key files to inherit NS' permissions to the directory.

    And when I supply an appropriate SecurityDescriptor, NS has access to the key file (as shown in Explorer), but Create still throws.

    Thursday, June 28, 2012 8:41 PM
  • Can you enable logging for me:

    Enable Logging: certutil –setreg enroll\debug 0xffffffe3
    restart the process and reproduce the problem

    Supply the log file in %windir%\certenroll.log and/or %userprofile%\certenroll.log
    Disable Logging: certutil -delreg enroll\debug

    The certenroll log file should indicate to me where it is failing.

    Andrew

    Friday, June 29, 2012 4:19 PM
  • Thanks for the help Andrew, I really appreciate your time.

    My understanding is that CertUtil.exe is a tool for admin-ing the certificate server. Is that correct?

    My code is never even making a request to the server. What is failing is the generation of a key, in order to compose the request to Cert Services.

    Friday, June 29, 2012 4:32 PM
  • Additional information: The IX509PrivateKey::Create call succeeds when run interactively as "NT Authority\Network Service".

    It seems the problem is related to running in a service process rather than interactively.

    Setting these two properties before calling Create did not help:

                privateKey.Silent = true;
                privateKey.KeyProtection = X509PrivateKeyProtection.XCN_NCRYPT_UI_NO_PROTECTION_FLAG;
    

    Friday, June 29, 2012 4:46 PM
  • certutil does manage servers. But it also enables logging on the client-side component. This logging will tell me which specific api is failing and the specific error code [which is mostly likely Access Denied].

    Andrew

    Friday, June 29, 2012 6:52 PM
  • 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.

    Much thanks to you, Andrew, for investing some of your time to help us out.

    Thursday, July 5, 2012 4:17 PM