Skip to content

Instantly share code, notes, and snippets.

@JohnLBevan
Created July 18, 2022 13:14
Show Gist options
  • Save JohnLBevan/92546c392d64c4882313dd42c0a8469f to your computer and use it in GitHub Desktop.
Save JohnLBevan/92546c392d64c4882313dd42c0a8469f to your computer and use it in GitHub Desktop.
The start of a function for working with PEM certs in PS. Note: functionality for handling encrypted private keys was too complex wtihout third party libraries (e.g. BouncyCastle), so this doesn't full work yet / is a work in progress. There are some potential solutions for .net 6 out there (PemEncoding.Write), but that wasn't an option for the …
Function Export-X509CertToPemFiles {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
,
[Parameter(Mandatory = $true)]
[System.IO.FileInfo]$FullChainPath
,
[Parameter(Mandatory = $true)]
[System.IO.FileInfo]$PrivateKeyPath
,
[Parameter(Mandatory = $true)]
[System.Security.SecureString]$PrivateKeyExportPassword
,
[Parameter()]
[System.Text.Encoding]$Encoding = [System.Text.Encoding]::ASCII # no need for UTF8 for most of the content; not sure if there may be special chars in the subject; but that won't have a functional impact on the certs themselves.
)
$chain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$chain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck
if (!$chain.Build($Certificate)) {throw 'Could not build certificate chain'}
$chainCerts = $chain.ChainElements.Certificate
$sb = [System.Text.StringBuilder]::new()
foreach ($chainCert in $chainCerts) {
$sb.AppendLine("Subject: $($chainCert.Subject)") | Out-Null
$sb.AppendLine("Thumbprint: $($chainCert.Thumbprint)") | Out-Null
$sb.AppendLine("-----BEGIN CERTIFICATE-----") | Out-Null
$sb.AppendLine([System.Convert]::ToBase64String($cert.RawData,[System.Base64FormattingOptions]::InsertLineBreaks)) | Out-Null
$sb.AppendLine("-----END CERTIFICATE-----") | Out-Null
}
[System.IO.File]::WriteAllLines($FullChainPath.FullName,$sb.ToString(),$Encoding)
# this works fine for the full chain; but exporting the encrypted private key is insanely complex: https://stackoverflow.com/a/43782555/361842
# instead I ended up just using openssl (https://wiki.openssl.org/index.php/Binaries)
Write-Warning "Private key export functionality not implemented"
}
# Example usage; pulls a cert from windows cert store and creates a PEM for FZ
$friendlyName = 'MyCustomCert.mydomain.example.com'
$cert = Get-ChildItem -Path Cert:\LocalMachine\My\ | ?{($_.FriendlyName -eq $friendlyName ) -and ('Client Authentication' -in $_.EnhancedKeyUsageList.Friendlyname) -and ('Server Authentication' -in $_.EnhancedKeyUsageList.Friendlyname)} | Sort-Object NotAfter -Descending | Select-Object -First 1
if (($null -eq $cert) -or ($cert.NotAfter -lt (Get-Date))) {throw 'Could not find a valid certificate'}
$fzSettings = [xml](Get-Content 'C:\Program Files (x86)\FileZilla Server\FileZilla Server.xml' -Raw)
$exportPassword = $fzSettings.SelectSingleNode("/FileZillaServer/Settings/Item[@name = 'SSL Key Password']/text()").Value | ConvertTo-SecureString -AsPlainText -Force
Export-X509CertToPemFiles -Certificate $cert -FullChainPath 'c:\Program Files (x86)\FileZilla Server\certificates\fullchain.crt' -PrivateKeyPath 'c:\Program Files (x86)\FileZilla Server\certificates\fullchain.key' -PrivateKeyExportPassword $exportPassword
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment