1

I'm trying to store a few objects as Clixml from PowerShell.

I can successfully store my array and certificate, but the private key is not exported with it.

Example:

PS > $cert.HasPrivateKey
true

PS > $outObject = $array
PS > $outObject += $cert
PS > $outObject | Export-Clixml -Path .\file.xml

PS > $inObject = Import-Clixml -Path .\file.xml
PS > $newcert = $inObject | Where-Object { $_.GetType().Name -like "*X509Certificate2" }

PS > $newcert.HasPrivateKey
false

I noted that there is a method for $cert.PrivateKey:

ExportParameters     Method     System.Security.Cryptography.RSAParameters ExportParameters(bool includePrivateParameters)

This script is not specifically running in Windows and the certificate isn't installed in the CABI store, only the variable imported from Get-PfxCertificate.

Long story short, I'm building a module that connects to an API with client authentication. I'm trying to pull client authentication from the Clixml file.

Bennett
  • 99
  • 9
  • I don't have the time to do any real investigation but I will say that `Export-CliXML` does not store exact copies of objects that can be identically rehydrated into a clone of the original object. – EBGreen Aug 02 '18 at 01:01
  • I do get that but, I am getting all of the rest of the data I'm looking for back, including public key and all other properties. Thanks for the quick response though. – Bennett Aug 02 '18 at 01:03
  • So I still don't have time to really dig in but see if this along with `Import-PFXCertificate` will help: https://stackoverflow.com/questions/43799755/export-certificate-with-private-key-including-all-certificates-in-path-using-pow – EBGreen Aug 02 '18 at 02:21
  • As I am trying to keep this cross platform the only command for working with PFX/PKCS12 in Powershell Core is Get-PFXCertificate which does successfully store the whole certificate in a variable/object for me and work when used with the other commands. The solutions available work by exporting as PFX. I'm trying to put a few objects into one saved file with the certificate only being portion of it. I'd like to keep everything to one file if I can. – Bennett Aug 02 '18 at 02:45
  • I'm not sure someone will have a good answer for me but again, I appreciate what you've offered already and anything else you might find or know. – Bennett Aug 02 '18 at 02:48
  • Ooof. If you are trying to keep it PowerShell core compatible you nasty have to look at what was ported over in .net core and go that route.that or roll your own function that will detect the OS and shell out to existing utilities on Linux boxes – EBGreen Aug 02 '18 at 03:58

2 Answers2

1

The private key is not a part of X509Certificate2 object, thus it is not exported along with the public certificate. The private key is linked to the public certificate.

In order to export a certificate with a private key, you have to serialize the certificate and private key object before passing it to Export-CliXml.

Use the X509Certificate2.Export(X509Content​Type, Secure​String) method to export the certificate with the associated private key to PFX (PKCS#12 container). The private key material is password-protected.

Use the X509Certificate2.Import(Byte[], Secure​String, X509Key​Storage​Flags) method to import the certificate and associated private key after calling the Import-CliXml cmdlet.

This is the only option you have. Also, be aware that this approach works only when the private key is exportable. If the private key is non-exportable, the Export method will fail.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Crypt32
  • 12,850
  • 2
  • 41
  • 70
  • Thank you though I'm still stuck. when I run `$cert.Export('X509Certificate2', 'Pa$$w0rd')` I get the following output: `"Unable to match the identifier name X509Certificate2 to a valid enumerator name. Specify one of the following enumerator names and try again: Unknown, Cert, SerializedCert, Pfx, Pkcs12, SerializedStore, Pkcs7, Authenticode"` I assume I want SerializedStore? – Bennett Aug 10 '18 at 20:10
  • You want `PFX`. – Crypt32 Aug 10 '18 at 20:21
  • I'm not sure how to specify my enumerator. – Bennett Aug 10 '18 at 20:21
  • Replace `X509Certificate2` with `Pfx`. – Crypt32 Aug 10 '18 at 20:24
  • Doh. Thanks. It worked after I specified exportable for X509KeyStorageFlags – Bennett Aug 10 '18 at 20:28
0

By converting the certificate object to PFX format (as suggested by Crypt32) and saving my objects in a hash table I was able to successfully export and import the array and certificate with private key.

PS > $cert.HasPrivateKey                                                             
true

PS > $pfx = $cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx,'Pa$$w0rd')
PS > $outObject = @{
>> myArray = $array
>> myCert = $pfx 
>> }

PS > Export-Clixml -InputObject $outObject -Path .\file.xml


PS > $inObject = Import-Clixml -Path .\file.xml   
PS > $newCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($inObject.myCert,'Pa$$w0rd')
PS > $newCert.HasPrivateKey
true
Bennett
  • 99
  • 9