Hi!!
It’s been awhile since I’ve posted something but last week I wrote a small script which I think will be useful to you!
Part of my many tasks where I work is to manage our PKI and in general work with and issue certificates. When issuing certificates (which include the private key) using a Windows PKI you normally export the file in PFX format. This is useful when working with Windows servers or applications. However in Linux servers or applications it’s more common that you need the certificate split into two files e.g. cert.crt/cert.key which separate the public/private keys.
In order to convert/split the PFX file into two files and separate the public/private keys you need to use openssl and manually run specific commands. This can be a bit tricky if you aren’t familiar with openssl and certificates in general.
The script I wrote does this for you automatically and can also optionally convert the private key to PEM format or decrypt the private key so it isn’t password protected (some applications need this). This can save you a lot of time and hopefully make your lives easier š
Prerequisites
You need to install OpenSSL as the script uses this to perform the different actions.
I have built the script in three different sections – Parameters, Initialize and Script Main. To begin with I will quickly explain the Parameters section.
PARAMETERS
#PARAMETERS $openssl = 'C:\OpenSSL-Win64\bin\openssl.exe' $sourcePFX = 'c:\mycert.pfx' $sourcePFX_Passphrase = 'somepassword' $convertToPEM = $true $decryptPrivateKey = $true
$openssl – Path to your openssl.exe here.
$sourcePFX – Path to the PFX you want to connvert/split.
$sourcePFX_Passphrase – password of the $sourcePFX file.
$convertToPEM – Set to $true to convert the private key to PEM format. $false to ignore/not do it.
$decryptPrivateKey – Set to $true to decrypt the private key and remove the password protection (don’t give it out to anyone who’s not supposed to have it after this…). $false to ignore/not do it.
INITIALIZE
$sourcePFX_Dir = (Get-ChildItem $sourcePFX).DirectoryName $PrivateKeyFile = $sourcePFX.Replace('.pfx', '-encrypted.key') $PublicKeyFile = $sourcePFX.Replace('.pfx', '.crt') $ErrorActionPreference = 'SilentlyContinue'
In this section use the parameters given to create some variables I will using in the script main.
$sourcePFX_Dir = (Get-ChildItem $sourcePFX).DirectoryName
Here I get the path of the directory of the source PFX so we can create the new certificates in the same place.
$PrivateKeyFile = $sourcePFX.Replace(‘.pfx’, ‘-encrypted.key’)
$PublicKeyFile = $sourcePFX.Replace(‘.pfx’, ‘.crt’)
Here I create file names of the new certs based on source PFX name.
$ErrorActionPreference = ‘SilentlyContinue’
Here I tell powershell to not display errors when running the script. This is because openssl returns messages that cause powershell to error out (even when it succeeds). This is a bit confusing so I chose to remove the errors displayed. You can remove this if you want as it’s not crucial.
SCRIPT MAIN
The embedded comments in this section should be enough to tell you what I’m doing here. Basically I start with running commands that extract the public and private keys into two new files. Then I add a few if statements that convert the converts to PEM and/or decrypts the private key if you set those params to true earlier.
#SCRIPT MAIN #Extract the private key & $openssl 'pkcs12' -in $sourcePFX -nocerts -out $PrivateKeyFile -password pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase #Extract the public key & $openssl pkcs12 -in $sourcePFX -clcerts -nokeys -out $PublicKeyFile -password pass:$sourcePFX_Passphrase #if specified convert private key to PEM if ($convertToPEM) { $PrivateKeyPEMFile = $PrivateKeyFile.Replace('.key', '-pem.key') & $openssl rsa -in $PrivateKeyFile -outform PEM -out $PrivateKeyPEMFile -passin pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase } #If specified decrypt the private key if ($decryptPrivateKey) { if ($convertToPEM) { $PrivateKeyFile = $PrivateKeyPEMFile } $decryptedKeyFile = $PrivateKeyFile.Replace('.key', '-decrypted.key').Replace('-encrypted','') & $openssl rsa -in $PrivateKeyFile -out $decryptedKeyFile -passin pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase }
That’s it!!
I hope you find the script useful!
I have copied in the full script below for you to copy if needed.
<# .NOTES =========================================================================== Created on: 29-Mar-2017 12:16 PM Created by: Noam Wajnman Filename: Split-PFXCertificate.ps1 =========================================================================== .DESCRIPTION Splits a PFX certificate into a public/private key pair. See the Parameters section to optionally convert to PEM and/or decrypt the private key. #> #PARAMETERS $openssl = 'C:\OpenSSL-Win64\bin\openssl.exe' $sourcePFX = 'c:\mycert.pfx' $sourcePFX_Passphrase = 'somepassword' $convertToPEM = $true $decryptPrivateKey = $true #INITIALIZE $sourcePFX_Dir = (Get-ChildItem $sourcePFX).DirectoryName $PrivateKeyFile = $sourcePFX.Replace('.pfx', '-encrypted.key') $PublicKeyFile = $sourcePFX.Replace('.pfx', '.crt') $ErrorActionPreference = 'SilentlyContinue' #SCRIPT MAIN #Extract the private key & $openssl 'pkcs12' -in $sourcePFX -nocerts -out $PrivateKeyFile -password pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase #Extract the public key & $openssl pkcs12 -in $sourcePFX -clcerts -nokeys -out $PublicKeyFile -password pass:$sourcePFX_Passphrase #if specified convert private key to PEM if ($convertToPEM) { $PrivateKeyPEMFile = $PrivateKeyFile.Replace('.key', '-pem.key') & $openssl rsa -in $PrivateKeyFile -outform PEM -out $PrivateKeyPEMFile -passin pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase } #If specified decrypt the private key if ($decryptPrivateKey) { if ($convertToPEM) { $PrivateKeyFile = $PrivateKeyPEMFile } $decryptedKeyFile = $PrivateKeyFile.Replace('.key', '-decrypted.key').Replace('-encrypted','') & $openssl rsa -in $PrivateKeyFile -out $decryptedKeyFile -passin pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase }
I know this is a relatively old post, however, I am having an issue with the RSA part of this. It errors out with the following:
openssl.exe : writing RSA key
At line:1 char:1
+ & openssl rsa -in test.key -out testRSA.key -passin pass:’$ynsmart201 …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (writing RSA key:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
I have tried all manner of outputting the errors to $null but it still produces the error. The fun part is that it still creates the RSA file without issue. I think it has something to do with the openssl.exe’s output of “writing RSA key” when generating the file for the rsa command. Any ideas on suppressing that message and/or the errors it is generating?
Hi Josh, I actually mention that in the script with the $erroractionpreference value that is set in the Initialize part of the script. Try seeing if that is being set properly in the PS environment you are running the script in.
If that doesn’t work for you, you could try to append out-null to the lines that execute the openssl commands. something like this:
& $openssl ‘pkcs12’ -in $sourcePFX -nocerts -out $PrivateKeyFile -password pass:$sourcePFX_Passphrase -passout pass:$sourcePFX_Passphrase | out-null.
I haven’t tested it in this case but the out-null command is commonly used to suppress error and unwanted messages.
And yes – you are right it’s weird that it throws these errors even when it does everything correctly š
Good luck!
If you do this, then you don’t get the red error text “NotSpecified: (writing RSA key:String) [], RemoteException” and this allows you to continue to use $ErrorActionPreference = ‘Stop’ (which is actually required if you want try/catch to work.)
use CMD /C and redirect stdout and stderr to null. reference:
“https://stackoverflow.com/questions/2095088/error-when-calling-3rd-party-executable-from-powershell-when-using-an-ide”
“https://unix.stackexchange.com/questions/99263/what-does-21-in-this-command-mean”
$decrypt_key = {& cmd /c ‘openssl 2>&1’ rsa -in $PrivateKeyFile -out $decryptedKeyFile -passin pass:$password}
.$decrypt_key
here’s another example:
#displays the decrypted private key
&cmd /c ‘openssl 2>&1’ rsa -in $PrivateKeyFile -passin file:$passphrase_file
Thanks! Good to use this to get around the error behavior.