Powershell: Cannot Export PFX certificate with key marked as exportable.

Created on 8 Mar 2020  路  3Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

The following steps work on Windows PowerShell 5.1. This issue is present on both x86 and x64 versions and can be reproduced on multiple machines.

I can export the certificate successfully using X509 .Net classes in PowerShell 7.

$TestCertificate = New-SelfSignedCertificate -Subject 'TestCertificate' -KeyExportPolicy 'Exportable'
Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertificate.pfx -Password (ConvertTo-SecureString 'TestPassword' -AsPlainText -Force)

Expected behavior

Creation of PFX file.

Actual behavior

Export-PfxCertificate: Cannot export non-exportable private key.

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.0
PSEdition                      Core
GitCommitId                    7.0.0
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Issue-Question Resolution-Answered

All 3 comments

/cc @anmenaga for information

Looks like this is run on a system with an older version of PKI module.
This older version will engage WinCompat feature and each certificate cmdlet in repro steps will be doing PS Remoting Serialization twice.
Looks like X509Certificate2 is losing its PrivateKey when going over Serialization boundary.
Here is a repro in Windows PowerShell 5.1 with WinRM Remoting session:

PS C:\> $PSVersionTable.PSVersion.ToString()
5.1.14393.3471
PS C:\> $s = New-PSSession localhost
PS C:\> # original X509Certificate2 in remote session has PrivateKey
PS C:\> icm $s {(New-SelfSignedCertificate -Subject 'TestCertFromWinPS' -KeyExportPolicy 'Exportable').HasPrivateKey}
True
PS C:\> # deserialized local copy does Not have PrivateKey
PS C:\> $TestCertificate = icm $s {New-SelfSignedCertificate -Subject 'TestCertFromWinPS' -KeyExportPolicy 'Exportable'}
PS C:\> $TestCertificate.HasPrivateKey
False
PS C:\> # attempt to export deserialized local copy of X509Certificate2 will fail
PS C:\> Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertificate.pfx -Password (ConvertTo-SecureString 'Test
Password' -AsPlainText -Force)
Export-PfxCertificate : Cannot export non-exportable private key.
At line:1 char:1
+ Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertific ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Export-PfxCertificate], Win32Exception
    + FullyQualifiedErrorId : System.ComponentModel.Win32Exception,Microsoft.CertificateServices.Commands.ExportPfxCertifi
   cate

As a workaround in PS 7 the entire operation can be done in WinCompat session:

PS C:\A> $PSVersionTable.PSVersion.ToString()
7.0.0
PS C:\A> Import-Module PKI -UseWindowsPowerShell # this will create WinPSCompatSesion PS Remoting session
WARNING: Module PKI is loaded in Windows PowerShell using WinPSCompatSession remoting session; please note that all input and output of commands from this module will be deserialized objects. If you want to load this module into PowerShell Core please use 'Import-Module -SkipEditionCheck' syntax.
PS C:\A> $s = Get-PSSession -Name WinPSCompatSession
PS C:\A> icm $s {$TestCertificate = New-SelfSignedCertificate -Subject 'TestCertificate' -KeyExportPolicy 'Exportable'}
PS C:\A> $pass = ConvertTo-SecureString 'TestPassword' -AsPlainText -Force
PS C:\A> icm $s {Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertificate.pfx -Password $using:pass | Out-Null}

@PaulHigin can you please confirm that this is expected behavior of private keys for de/serialized certificate objects? Thank you.

Yes, looking at the code, PowerShell remoting rehydrates the dotNet certificate object but without the private key.

Was this page helpful?
0 / 5 - 0 ratings