CertificateConversion.psm1
#region Functions #region Export-ServerCertificateFromPFX function Export-ServerCertificateFromPFX { [CmdletBinding()] Param ( # The path to the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ValueFromRemainingArguments=$false, Position=0)] [ValidateNotNullOrEmpty()] [string] $PFXFilePath, # The passphrase for the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, ValueFromRemainingArguments=$false, Position=1)] [ValidateNotNullOrEmpty()] [securestring] $PFXPassphrase, # The path to the certificate file to create [Parameter(Position=2)] [string] $DestinationCertificateFilePath, # Display OpenSSL output [Parameter()] [switch] $OpenSSLOutput = $false ) Begin { # Import the 'CPolydorou.FileSystem' module if((get-module).Name -notcontains "cpolydorou.security") { try { Import-Module CPolydorou.FileSystem -ErrorAction Stop -Verbose:$false -DisableNameChecking } catch { Throw "Failed to import the 'CPolydorou.FileSystem' module. This module is required and has to be installed." } } } Process { # Verbose output Write-Verbose "Extracting server certificate from PFX file: $PFXFilePath" # Test the installation of OpenSSL $OpenSSLPath = Get-OpenSSLPath # Test the OpenSSL files Test-OpenSSLInstallation Write-Verbose "Found OpenSSL binary at: $OpenSSLPath" # Check if the PFX file exists try { $pfx = (Resolve-Path -Path $PFXFilePath -ErrorAction Stop).Path } catch { Throw "Could not locate the PFX file." } # Check if the DestinationCertificateFilePath is null and create a path if(-Not $DestinationCertificateFilePath) { $base = (Get-Location).Path + "\" $filename = (Get-Item -Path $pfx).Name + ".crt" $DestinationCertificateFile = $base + $filename } else { $DestinationCertificateFile = (Resolve-NonExistentPath -Path $DestinationCertificateFilePath).Fullname } # Extract the passphrase $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PFXPassphrase) $UnsecurePassphrase = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) # Verbose output Write-Verbose "Saving exported certificate at: $DestinationCertificateFile" # Set the arguments $args = @("pkcs12", "-in", $pfx, "-clcerts", "-nokeys", "-out", $DestinationCertificateFile, "-passin", "pass:$UnsecurePassphrase") # Convert the file try { $result = Convert -OpenSSLPath $OpenSSLPath -arguments $args if($OpenSSLOutput) { Write-Output $result } if($result.ExitCode -ne 0) { Write-Error "OpenSSL failed to perform the requested operation." } } catch { Write-Error ("Failed to invoke OpenSSL. " + $_.Exception.Message) } } End { } } #endregion #region Export-CertificateChainFromPFX function Export-CertificateChainFromPFX { [CmdletBinding()] Param ( # The path to the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ValueFromRemainingArguments=$false, Position=0)] [ValidateNotNullOrEmpty()] [string] $PFXFilePath, # The passphrase for the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, ValueFromRemainingArguments=$false, Position=1)] [ValidateNotNullOrEmpty()] [securestring] $PFXPassphrase, # The path to the certificate file to create [Parameter(Position=2)] [string] $DestinationCertificateFilePath, # Display OpenSSL output [Parameter()] [switch] $OpenSSLOutput = $false ) Begin { # Import the 'CPolydorou.FileSystem' module if((get-module).Name -notcontains "cpolydorou.security") { try { Import-Module CPolydorou.FileSystem -ErrorAction Stop -Verbose:$false -DisableNameChecking } catch { Throw "Failed to import the 'CPolydorou.FileSystem' module. This module is required and has to be installed." } } } Process { # Verbose output Write-Verbose "Extracting certificate chain from PFX file: $PFXFilePath" # Test the installation of OpenSSL $OpenSSLPath = Get-OpenSSLPath # Test the 7Z files Test-OpenSSLInstallation Write-Verbose "Found OpenSSL binary at: $OpenSSLPath" # Check if the PFX file exists try { $pfx = (Resolve-Path -Path $PFXFilePath -ErrorAction Stop).Path } catch { Throw "Could not locate the PFX file." } # Check if the DestinationCertificateFilePath is null and create a path if(-Not $DestinationCertificateFilePath) { $base = (Get-Location).Path + "\" $filename = (Get-Item -Path $PFXFilePath).Name + ".chain.crt" $DestinationCertificateFile = $base + $filename } else { $DestinationCertificateFile = (Resolve-NonExistentPath -Path $DestinationCertificateFilePath).Fullname } # Extract the passphrase $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PFXPassphrase) $UnsecurePassphrase = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) # Verbose output Write-Verbose "Saving exported certificate at: $DestinationCertificateFile" # Set the arguments $args = @("pkcs12", "-in", $pfx, "-cacerts", "-nokeys", "-chain", "-out", $DestinationCertificateFile, "-password", "pass:$UnsecurePassphrase") # Convert the file try { $result = Convert -OpenSSLPath $OpenSSLPath -arguments $args if($OpenSSLOutput) { Write-Output $result } if($result.ExitCode -ne 0) { Write-Error "OpenSSL failed to perform the requested operation." } } catch { Write-Error ("Failed to invoke OpenSSL. " + $_.Exception.Message) } } End { } } #endregion #region Export-PrivateKeyFromPFX function Export-PrivateKeyFromPFX { [CmdletBinding()] Param ( # The path to the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ValueFromRemainingArguments=$false, Position=0)] [ValidateNotNullOrEmpty()] [string] $PFXFilePath, # The passphrase for the PFX file [Parameter(Mandatory=$true, ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, ValueFromRemainingArguments=$false, Position=1)] [ValidateNotNullOrEmpty()] [securestring] $PFXPassphrase, # The path to the certificate file to create [Parameter(Position=2)] [string] $DestinationCertificateFilePath, # The passphrase for the key file [Parameter(Mandatory=$true, ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, ValueFromRemainingArguments=$false, Position=1)] [ValidateNotNullOrEmpty()] [securestring] $KeyPassphrase, # Display OpenSSL output [Parameter()] [switch] $OpenSSLOutput = $false ) Begin { # Import the 'CPolydorou.FileSystem' module if((get-module).Name -notcontains "cpolydorou.security") { try { Import-Module CPolydorou.FileSystem -ErrorAction Stop -Verbose:$false -DisableNameChecking } catch { Throw "Failed to import the 'CPolydorou.FileSystem' module. This module is required and has to be installed." } } } Process { # Verbose output Write-Verbose "Extracting server certificate from PFX file: $PFXFilePath" # Test the installation of OpenSSL $OpenSSLPath = Get-OpenSSLPath # Test the OpenSSL files Test-OpenSSLInstallation Write-Verbose "Found OpenSSL binary at: $OpenSSLPath" # Check if the PFX file exists try { $pfx = (Resolve-Path -Path $PFXFilePath -ErrorAction Stop).Path } catch { Throw "Could not locate the PFX file." } # Check if the DestinationCertificateFilePath is null and create a path if(-Not $DestinationCertificateFilePath) { $base = (Get-Location).Path + "\" $filename = (Get-Item -Path $pfx).Name + ".key" $DestinationCertificateFile = $base + $filename } else { $DestinationCertificateFile = (Resolve-NonExistentPath -Path $DestinationCertificateFilePath).Fullname } # Extract the PFX passphrase $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PFXPassphrase) $UnsecurePassphrase = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) # Extract the Key passphrase $BSTR2 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($KeyPassphrase) $UnsecurePassphraseKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR2) # Verbose output Write-Verbose "Saving exported private key at: $DestinationCertificateFile" # Set the arguments $args = @("pkcs12", "-in", $pfx, "-cacerts", "-nocerts", "-out", $DestinationCertificateFile, "-passin", "pass:$UnsecurePassphrase", "-passout", "pass:$UnsecurePassphraseKey") # Convert the file try { $result = Convert -OpenSSLPath $OpenSSLPath -arguments $args if($OpenSSLOutput) { Write-Output $result } if($result.ExitCode -ne 0) { Write-Error "OpenSSL failed to perform the requested operation." } } catch { Write-Error ("Failed to invoke OpenSSL. " + $_.Exception.Message) } } End { } } #endregion #region Decrypt-PrivateKey function Decrypt-PrivateKey { [CmdletBinding()] Param ( # The path to the encrypted private key file [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ValueFromRemainingArguments=$false, Position=0)] [ValidateNotNullOrEmpty()] [string] $PrivateKeyFilePath, # The passphrase for the private key file [Parameter(Mandatory=$true, ValueFromPipeline=$false, ValueFromPipelineByPropertyName=$false, ValueFromRemainingArguments=$false, Position=1)] [ValidateNotNullOrEmpty()] [securestring] $PrivateKeyPassphrase, # The path to the certificate file to create [Parameter(Position=2)] [string] $DestinationCertificateFilePath, # Display OpenSSL output [Parameter()] [switch] $OpenSSLOutput = $false ) Begin { # Import the 'CPolydorou.FileSystem' module if((get-module).Name -notcontains "cpolydorou.security") { try { Import-Module CPolydorou.FileSystem -ErrorAction Stop -Verbose:$false -DisableNameChecking } catch { Throw "Failed to import the 'CPolydorou.FileSystem' module. This module is required and has to be installed." } } } Process { # Verbose output Write-Verbose "Extracting server certificate from PFX file: $PFXFilePath" # Test the installation of OpenSSL $OpenSSLPath = Get-OpenSSLPath # Test the OpenSSL files Test-OpenSSLInstallation Write-Verbose "Found OpenSSL binary at: $OpenSSLPath" # Check if the private key file exists try { $privatekey = (Resolve-Path -Path $PrivateKeyFilePath -ErrorAction Stop).Path } catch { Throw "Could not locate the private key file." } # Check if the DestinationCertificateFilePath is null and create a path if(-Not $DestinationCertificateFilePath) { $base = (Get-Location).Path + "\" $filename = (Get-Item -Path $privatekey).Name + ".plainkey" $DestinationCertificateFile = $base + $filename } else { $DestinationCertificateFile = (Resolve-NonExistentPath -Path $DestinationCertificateFilePath).Fullname } # Extract the PFX passphrase $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PrivateKeyPassphrase) $UnsecurePassphrase = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) # Verbose output Write-Verbose "Saving exported key at: $DestinationCertificateFile" # Set the arguments $args = @("rsa", "-in", $privatekey, "-out", $DestinationCertificateFile, "-passin", "pass:$UnsecurePassphrase") # Convert the file try { $result = Convert -OpenSSLPath $OpenSSLPath -arguments $args if($OpenSSLOutput) { Write-Output $result } if($result.ExitCode -ne 0) { Write-Error "OpenSSL failed to perform the requested operation." } } catch { Write-Error ("Failed to invoke OpenSSL. " + $_.Exception.Message) } } End { } } #endregion #endregion #region Helper Functions #region Get-OpenSSLPath Function Get-OpenSSLPath { # Get the path to the openssl.exe $SecurityModulePath = (Get-Module -Name CPolydorou.Security).Path $OpenSSLPath = $SecurityModulePath.Substring(0, $SecurityModulePath.Length - 25) + "\OpenSSL\openssl-1.0.2q-x64_86-win64\openssl.exe" return $OpenSSLPath } #endregion #region Test-OpenSSLInstallation Function Test-OpenSSLInstallation { $OpenSSLPath = Get-OpenSSLPath # Test if OpenSSL binaries exist if( -Not (Test-Path ($OpenSSLPath))) { Write-Error "Could not locate openssl.exe!" return } if( -Not (Test-Path ($OpenSSLPath.ToLower().Replace("openssl.exe","libeay32.dll")))) { Write-Error "Could not locate libeay32.dll!" return } if( -Not (Test-Path ($OpenSSLPath.ToLower().Replace("openssl.exe","ssleay32.dll")))) { Write-Error "Could not locate ssleay32.dll!" return } } #endregion #region Convert function Convert { Param ( [string]$OpenSSLPath, [string[]]$Arguments ) $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $OpenSSLPath $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.CreateNoWindow = $true $pinfo.Arguments = $Arguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() New-Object -TypeName PSObject ` -Property @{ "StandardOutput" = $stdout "StandardError" = $stderr "ExitCode" = $p.ExitCode } } #endregion #endregion #region Exports Export-ModuleMember -Function Export-ServerCertificateFromPFX Export-ModuleMember -Function Export-CertificateChainFromPFX Export-ModuleMember -Function Export-PrivateKeyFromPFX Export-ModuleMember -Function Decrypt-PrivateKey #endregion |