Setting Permissions for a Private Key Using PowerShell

I have a PowerShell script that installs a pfx certificate in LocalMachine's certificate store. The function is as follows:

function Add-Certificate { param ( [Parameter(Position=1, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$pfxPath, [Parameter(Position=2, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$pfxPassword ) Write-Host "Installing certificate" -ForegroundColor Yellow try { $pfxcert = new-object system.security.cryptography.x509certificates.x509certificate2 $pfxcert.Import($pfxPath, $pfxPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet") $store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", LocalMachine $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite"); $store.Add($pfxcert); $store.Close(); return $pfxcert } catch { throw } } 

When I open the certificate manager to verify the installation, I see that it installed correctly.

The next step in my process is to assign permissions to the service account certificate.

 function Set-CertificatePermission { param ( [Parameter(Position=1, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$pfxThumbPrint, [Parameter(Position=2, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$serviceAccount ) $cert = Get-ChildItem -Path cert:\LocalMachine\My | Where-Object -FilterScript { $PSItem.ThumbPrint -eq $pfxThumbPrint; }; # Specify the user, the permissions and the permission type $permission = "$($serviceAccount)","Read,FullControl","Allow" $accessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permission; # Location of the machine related keys $keyPath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"; $keyName = $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName; $keyFullPath = $keyPath + $keyName; try { # Get the current acl of the private key # This is the line that fails! $acl = Get-Acl -Path $keyFullPath; # Add the new ace to the acl of the private key $acl.AddAccessRule($accessRule); # Write back the new acl Set-Acl -Path $keyFullPath -AclObject $acl; } catch { throw $_; } } 

This feature does not work. In particular, this function does not work when trying to evaluate the Get-Acl command with the following error: Get-Acl: Cannot find the path 'C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys \ 59f1e969a4f7e5de90224f68bc9be536_1d508f5e-0cbc-4eca- a402-3b

As it turned out, the key file was installed in my roaming profile C: \ Users \ MyUserName \ AppData \ Roaming \ Microsoft \ Crypto \ RSA \ S-1-5-21-1259098847-1967870486-1845911597 -155499

I am sure that something is wrong with the Add-Certificate function, but I can not understand what it is. How to make it install the key file in the directory C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys?

+7
powershell permissions pfx
source share
2 answers

The problem is that when the X509Certificate2 imported using the Import() method, the X509KeyStorageFlags were not configured to write the private key to the private key store of the computer. I updated the function to enable the corresponding X509KeyStorageFlags .

 function Add-Certificate { [CmdletBinding()] param ( [Parameter(Position=1, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Position=2, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$Password ) Write-Verbose -Message ('Installing certificate from path: {0}' -f $Path); try { # Create the certificate $pfxcert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ErrorAction Stop; $KeyStorageFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable -bxor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet -bxor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet; Write-Verbose ('Key storage flags is: {0}' -f $KeyStorageFlags); $pfxcert.Import($Path, $Password, $KeyStorageFlags); # Create the X509 store and import the certificate $store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList My, LocalMachine -ErrorAction Stop; $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite); $store.Add($pfxcert); $store.Close(); Write-Output -InputObject $pfxcert; } catch { throw $_; } } 
+10
source share

The script provided me with a job (thanks!) with one change due to a Windows error (see Why Set-Acl on the root hard drive tries to set ownership of the "object", " )

Below is the updated script:

 function Set-CertificatePermission { param ( [Parameter(Position=1, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$pfxThumbPrint, [Parameter(Position=2, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$serviceAccount ) $cert = Get-ChildItem -Path cert:\LocalMachine\My | Where-Object -FilterScript { $PSItem.ThumbPrint -eq $pfxThumbPrint; }; # Specify the user, the permissions and the permission type $permission = "$($serviceAccount)","Read,FullControl","Allow" $accessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permission; # Location of the machine related keys $keyPath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"; $keyName = $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName; $keyFullPath = $keyPath + $keyName; try { # Get the current acl of the private key $acl = (Get-Item $keyFullPath).GetAccessControl # Add the new ace to the acl of the private key $acl.AddAccessRule($accessRule); # Write back the new acl Set-Acl -Path $keyFullPath -AclObject $acl; } catch { throw $_; } } 
+2
source share

All Articles