Assigning Read Access to Windows Private Key

I have written about authenticating with the Pure1 REST API, and my PowerShell module in the past:

https://www.codyhosterman.com/2019/01/using-the-pure1-rest-api-part-i-powershell/

NOTE: This workaround is not really needed anymore with the default behavior of the module. See this post: https://www.codyhosterman.com/2019/12/pure1-rest-api-authentication-made-easy/

One of the issues is that if you followed my default instructions, you would need to run the PowerShell window as an admin to be able to create the connection. The answer–now that I think about it is fairly obvious: non-admin users (or admins not running in admin mode) don’t have security rights to it. Duh!

The internal method used in the cmdlet is GetRSAPrivateKey:

You will see a cryptic error: “Exception calling “GetRSAPrivateKey” with “1” argument(s): “Invalid provider type specified.”

So a couple ways to fix this.

MMC

First in the GUI. Launch MMC, and add/remove snapin and choose certificates. Depending on where your cert is dictates which one you choose. My cert is stored in the personal folder on the local machine group:

Cert:\LocalMachine\my\6D75482829CBDB7FCF8AADD193A71BB4299AC1BD

You can see my cert here:

So right-click and choose Properties > Manage Private Keys…

Click Add then add the user you want to be able to access the private key.

It defaults to full control, but you do not need that, you can just give read access if you prefer:

Now you can run it without being in admin mode:

PowerShell

If you want to do this in PowerShell, it is fairly simple too. This part does need to be run as admin! But once done, the Pure1 module can be run as a regular user.

Grab your cert:

$CertObj= Get-ChildItem Cert:\LocalMachine\my\6D75482829CBDB7FCF8AADD193A71BB4299AC1BD

Pull out the key:

$rsaCert = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($CertObj)

Then grab the permissions of the key:

$fileName = $rsaCert.key.UniqueName
$path = "$env:ALLUSERSPROFILE\Microsoft\Crypto\Keys\$fileName"
$permissions = Get-Acl -Path $path

Now create the permission. In this case the username is “cody” and I want to provide “read” permissions:

 $rule = new-object security.accesscontrol.filesystemaccessrule "cody", "read", allow

Now apply the new permission:

$permissions.AddAccessRule($rule)
Set-Acl -Path $path -AclObject $permissions

All good now!

13 Replies to “Assigning Read Access to Windows Private Key”

  1. I appreciate your post. This helped me a ton, but was ultimately incomplete.

    I think you’re missing a variable in your powershell script. You reference $rsaCert but never define it. It should be:
    $rsaCert = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($CertObj)

  2. Very elegant script.

    My file path was slightly different to the unique file:
    $env:\ALLUSERSPROFILE\Microsoft\Crypto\RSA\MachineKeys\$fileName.

  3. very cool script, thank you.

    On Windows server 2016 Core I have got stuck:
    PS C:\Users\user1> $permissions = Get-Acl -Path $path
    Get-Acl : Cannot find path
    ‘C:\ProgramData\Microsoft\Crypto\Keys\a21bcefc54bc606d7991d5cc3092f26a_68d2a3f4-d951-404c-a8d1-4f9fce5b3323’ because
    it does not exist.
    At line:1 char:16
    + $permissions = Get-Acl -Path $path
    + ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
    + FullyQualifiedErrorId : GetAcl_PathNotFound_Exception,Microsoft.PowerShell.Commands.GetAclCommand

    PS C:\Users\user1> $filename
    a21bcefc54bc606d7991d5cc3092f26a_68d2a3f4-d951-404c-a8d1-4f9fce5b3323
    PS C:\Users\user1> $Path
    C:\ProgramData\Microsoft\Crypto\Keys\a21bcefc54bc606d7991d5cc3092f26a_68d2a3f4-d951-404c-a8d1-4f9fce5b3323

  4. Very Helpful script. Thank you.
    I am getting an error for the following line:
    $rsaCert = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($CertObj)

    The error is :
    Cannot convert argument “certificate”, with value: “624F8DDDA7B85966DE276B65DAFAE616BC63E4BD”, for “GetRSAPrivateKey”
    to type “System.Security.Cryptography.X509Certificates.X509Certificate2”: “Cannot convert value
    “” to type “System.Security.Cryptography.X509Certificates.X509Certificate2”.
    Error: “The system cannot find the file specified.

    Any ideas?

  5. Cody, I should mention that I tested your script successfully using a PowerShell-created self-signed certificate on Windows 10. Works like a champ. On Windows Server 2012 R2 and a PFX-formatted certificate from our CA, I get the “cannot convert value” error.

  6. Problem Solved. I was borrowing code from a previous line where I was actually grabbing the Thumbprint. So the error stems from the fact that I was calling Get-RSAPrivateKey with the thumbprint instead of the entire certificate object.

    Once I removed the extra “| Select -ExpandProperty Thumbprint” from the “$CertObj = ” line, the error cleared. Thank You for the script.

  7. Thanks so much, this was very helpful!
    I also had to change the path to $env:\ALLUSERSPROFILE\Microsoft\Crypto\RSA\MachineKeys\$fileName.

  8. I think the best is to use this :
    $File = get-childitem “C:\ProgramData\Microsoft\Crypto\” -Recurse $rsaCert.key.UniqueName

    $ACL = $file | get-acl

  9. Hello Cody, thank you so much for this detailed article!

    One observation after following the flow: when you say “So right-click and choose Properties > Manage Private Keys…” it should be “So right-click and choose All Tasks > Manage Private Keys…”. It took me a bit to figure it out hehe

    Thanks again!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.