20

As the title suggests I would like to export my private key without using OpenSSL or any other third party tool. If I need a .cer file or .pfx file I can easily export these via MMC or PowerShell pkiclient but I can't find a way to get the private key.

https://docs.microsoft.com/en-us/powershell/module/pkiclient/export-certificate?view=win10-ps

Using an online tool like https://www.sslshopper.com/ssl-converter.html is not OK.

PSVersion:

PS C:\Users\oscar> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.17134.228
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17134.228
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

I can get the public key like this:

(Get-PfxCertificate -FilePath C:\Users\oscar\Desktop\localhost.pfx).GetPublicKey()

And export the entire certificate like this:

(Get-PfxCertificate -FilePath C:\Users\oscar\Desktop\localhost.pfx).GetRawCertData()

Result from

PS C:\Users\oscar> $mypwd = ConvertTo-SecureString -String "MyPassword" -Force -AsPlainText
PS C:\Users\oscar> $mypfx = Get-PfxData -FilePath C:\Users\oscar\Desktop\localhost.pfx -Password $mypwd
PS C:\Users\oscar> $mypfx

OtherCertificates EndEntityCertificates
----------------- ---------------------
{}                {[Subject]...


PS C:\Users\oscar> $mypfx.EndEntityCertificates

Thumbprint                                Subject
----------                                -------
8ED4971564E35099D6DB490C3756E2AD43AAAAAA  CN=localhost

Tested the command from @Brad but I got the error below.

Private key is NOT plain text exportable

certutil -exportPFX -p "myPassword" -privatekey -user my <Certificate Serial Number> C:\localhost.pfx

enter image description here

Similar to Certificate Export Wizard in MMC certificates, only export to .pfx available if the key is included.

enter image description here

Ogglas
  • 50,115
  • 30
  • 272
  • 333
  • You certainly need a `.pfx` file as `.cer` files don't store private keys. What's your `$PSVersionTable` ? Can you use `Get-PfxData -FilePath 'mycertificate.pfx' -Password (ConvertTo-SecureString -Force -AsPlainText -String 'MyClearTextPassword')` ? – Petru Zaharia Oct 23 '18 at 05:38
  • @PetruZaharia Yes I'm aware, wrote that as an example of what you can export. :) Updated the question with PSVersion and what I have tried. I can but I have not found a way to export the private key. – Ogglas Oct 23 '18 at 06:19

7 Answers7

9

I had the same problem and solved it with the help of PSPKI Powershell module from PS Gallery. While I understand that you look for a solution that preferably uses some built in functionality in Windows, installing a module from PS Gallery might be acceptable. At least it was in my case.

First install the PSPKI module (I assume hat the PSGallery repository has already been set up):

Install-Module -Name PSPKI

The PSPKI module provides a Cmdlet Convert-PfxToPem which converts a pfx-file to a pem-file which contains the certificate and pirvate key as base64-encoded text:

Convert-PfxToPem -InputFile C:\path\to\pfx\file.pfx -Outputfile C:\path\to\pem\file.pem

Now, all we need to do is splitting the pem-file with some regex magic. For example, like this:

(Get-Content C:\path\to\pem\file.pem -Raw) -match "(?ms)(\s*((?<privatekey>-----BEGIN PRIVATE KEY-----.*?-
----END PRIVATE KEY-----)|(?<certificate>-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----))\s*){2}"

$Matches["privatekey"] | Set-Content "C:\path\to\key\file.pem"
$Matches["certificate"] | Set-Content "C:\path\to\certificate\file.pem"
Christoph Böhme
  • 3,412
  • 1
  • 16
  • 27
  • 3
    Good answer but I would prefer to not use any third party library as you say. However since this is the best answer so far I will mark it as accepted until there is a better alternative. :) – Ogglas Nov 03 '20 at 13:12
  • I added a PowerShell script that incorporates the .NET approach to exporting the private key to a Pkcs8 PEM file. I want to also point out that the PSPKI Convert-PfxToPem is very low level; using PInvoke to call Win32 methods. Since .NET added support for CNG (Crypto Next Gen), we have all the capability we need via the System.Security.Cryptography namespace. – RashadRivera Jul 21 '21 at 13:21
  • You can do this **without** the **third party** library: `$cert = Get-PfxCertificate -FilePath $pfxFilePath; Export-Certificate -FilePath $derFilePath -Cert $cert; certutil -encode $derFilePath $pemFilePath | Out-Null` Now that you have pem file follow the rest of the posted answer. (I wish we could format code better in comments...) – S. Melted Dec 06 '21 at 16:59
1

Based on what PowerShellGuy mentioned.

Will that work for you?

# first get your cert, either via pure .NET, or through the PSDrive (Cert:\)

# this is just an example

# get cert from PSDrive
$cert = Get-ChildItem Cert:\LocalMachine\My | where Subject -eq 'CN=MySubject'

# get cert from .NET
$My     = [System.Security.Cryptography.X509Certificates.StoreName]::My
$Store  = [System.Security.Cryptography.X509Certificates.X509Store]::new($My,'localmachine')
$Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::MaxAllowed)

$cert   = $Store.Certificates | where Subject -eq 'CN=MySubject'

# get private key
# PKCS8, way #1
$BytesPkcs8 = $cert.PrivateKey.ExportPkcs8PrivateKey()
[System.Convert]::ToBase64String($BytesPkcs8)

# PKCS8, way #2
$Pkcs = [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob
$BytesPkcs8 = $cert.PrivateKey.Key.Export($Pkcs)
[System.Convert]::ToBase64String($BytesPkcs8)

# RSA
$BytesRsa = $cert.PrivateKey.ExportRSAPrivateKey()
[System.Convert]::ToBase64String($BytesRsa)

So is that Base64 string what you're looking for?

Uwe Keim
  • 38,279
  • 56
  • 171
  • 280
Panos.G
  • 9
  • 1
1

Try this script which exports the private key in Pkcs8 format

Azure PowerShell - Extract PEM from SSL certificate

RashadRivera
  • 673
  • 8
  • 17
  • Great answer. Though this finally extracts my private key where each row length is 76 characters. I don't know if this actually makes a difference but usually the line length is 64 characters. When I used an Online SSL tool to extract my private key, the results were the same as compared to your script except for the difference in line lengths. – Anupam Chand Oct 27 '21 at 16:52
  • @AnupamChand, I have not ran into any issues with line break length. In fact, I've seen cases where there are no line breaks with no formatting issues. Line breaks are put in to make it more readable. – RashadRivera Dec 30 '21 at 17:27
  • Yes I can confirm that. My comment was just based on my observation when I compared the output PEM with the actual PEM. But when I used the 'non formatted' PEM for my application, it worked fine. Thanks for your script. – Anupam Chand Dec 31 '21 at 02:37
0

If I understand correctly certutil should do it for you.

certutil -exportPFX -p "ThePasswordToKeyonPFXFile" my [serialNumberOfCert] [fileNameOfPFx]

Brad
  • 1
  • 1
  • Looked good but even though the helper said `Export certificate and private key` I got the message `Private key is NOT plain text exportable`. I could only export to `.pfx`. See updated question for print screen. – Ogglas Aug 27 '20 at 15:39
0

The Key, when exportable, can be exported using several APIs to several formats. The most common would be PKCS#8 (industry standard) and XML (MSFT properitary afaik).

Have a look at these answers:

Daniel Fisher lennybacon
  • 3,493
  • 1
  • 28
  • 34
  • 1
    Good answer but I would prefer to use some sort of built in Windows util and not have to write my own program to solve it. – Ogglas Sep 02 '20 at 13:33
0

Try something like this:

$mypwd = ConvertTo-SecureString -String "MyPassword" -Force -AsPlainText
$mypfx = Get-PfxData -FilePath C:\Users\oscar\Desktop\localhost.pfx -Password $mypwd
Export-PfxCertificate -PFXData $mypfx -FilePath C:\Users\oscar\Desktop\localhost.pfx -Password $NewPwd
Mike Kennedy
  • 326
  • 2
  • 6
  • 1
    `Export-PfxCertificate` - "Exports a certificate or a PFXData object to a Personal Information Exchange (PFX) file." I want the private key only. https://docs.microsoft.com/en-us/powershell/module/pkiclient/export-pfxcertificate?view=win10-ps – Ogglas Aug 27 '20 at 14:54
0

Hm. Have you tried opening the cert store, and getting the private key that way? Pretty sure this will only work with RSA/DSA certs though.

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store([System.Security.Cryptography.X509Certificates.StoreName]::My,"localmachine")
$store.Open("MaxAllowed")
$cert = $store.Certificates | ?{$_.subject -match "^CN=asdasd"}
$cert.PrivateKey.ToXmlString($false)
$store.Close()

PowerShellGuy
  • 705
  • 1
  • 8
  • I did get a value from this but it has to be modified. Your code results in:`base64 valueAQAB`. However with `$cert.PrivateKey.ToXmlString(1)` and then converting that with RSA Key Converter - XML to PEM I do get the private key in base64. I have not found a way to do this with a built in Windows util though. – Ogglas Nov 03 '20 at 13:39