Reputation: 4366
I am trying to import a certificate with a private key and although my script is "working" it is missing something which I can't seem to figure out.
I have an app which talks to KeyVault and uses this certificate for authorization. I have the password for said certificate and when I install the PFX
manually along with assigning the NETWORK SERVICE
account permission this works fine. However, using the following PowerShell I get the error Keyset does not exist
. Everything seems normal when I check this under cert manager. Clearly, the UI is doing something different.. any ideas?
EDIT
When I add the NETWORK SERVICE
account manually this works fine. PowerShell is running in admin mode when I execute the script so perhaps its some weirdness in that?
The script
cls
$certName = "certname.pfx"
$path = "C:\Certificates\$certName"
$serviceAccount = 'NETWORK SERVICE'
$permissionType = 'Read'
$password = 'somepassword'
try {
# Import the certificate maintaining the private key format
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($path, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
# Add the cert to personal store location
$store = Get-Item Cert:\LocalMachine\My
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite")
$store.Add($cert)
$store.Close()
# Get SecurityIdentifier value from current username
$currentUser = New-Object System.Security.Principal.NTAccount($env:USERNAME)
$strSID = $currentUser.Translate([System.Security.Principal.SecurityIdentifier])
$path = "$env:USERPROFILE\AppData\Roaming\Microsoft\Crypto\RSA\$($strSID.Value)\$($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)"
$acl = Get-Acl $path
$rule = New-Object Security.AccessControl.FileSystemAccessRule $serviceAccount, 'FullControl', Allow
$acl.AddAccessRule($rule)
Set-Acl $path $acl
Write-Host "Cert installed, press any key to continue" -ForegroundColor Green
Read-Host
}
catch {
Write-Error -Message $_
}
ANSWER For others experiencing the same issues as I was, simply provide multiple storage flags:
$flags = @([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"MachineKeySet", [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($path, $password, $flags)
Upvotes: 1
Views: 5905
Reputation: 33256
You probably want to import the certificate using both PersistKeySet
and MachineKeySet
. Looking at how you're doing things here you have
LocalMachine
store.The Windows Cert store, AFAIK, doesn't write down which user owns a key, just that this cert is paired with "user key {id}". So it needs to be the machine (shared) key store.
The "keyset does not exist" is because the Network Service user doesn't have a key named with that ID in their keystore.
So the difference, probably, is that the UI is asserting the MachineKeySet
(equivalent) because it knows you're importing into a LocalMachine store.
Upvotes: 3