Created
July 18, 2022 13:14
-
-
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 …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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