0
votes

I have a WebApp under Azure that uses a SSL binding certificate ( that has been generated with Azure portal). I would like to retrieve the public key (PEM file) of this SSL certificate using Azure Powershell. I've managed to extract the public key in the C# backoffice using the mycertificate.GetPublicKeyString() function, but I don't know how to achieve that under PowerShell. Have you an idea ?

Many thanks.

3

3 Answers

1
votes

You can extract the public certificate from a PKCS#12 archive (.pfx/.p12) with Get-PfxCertificate

$pfx = Get-PfxCertificate -FilePath C:\archive.pfx
$pem = [Convert]::ToBase64String($pfx.GetRawCertData())
1
votes

I wrote a script that does just that; except it extracts the private key. The linchpin to success is to export your Public Key in Pkcs8 format. If you use the GetRSAPublicKey instead, this should lead you to a public-key PEM export.

<#
    FileName: pfx-2-pem.ps1
    Author: rashadrivera.com
    Description: This PowerShell script converts a PFX file into PEM format for use in WebPack's
                 Dev Server configurations.  This script is an alternative to using the common
                 OpenSSL, open-source tool; which is an untrusted, unmaintained, security risk.
#>

param (

    [Parameter(Mandatory=$true, HelpMessage="Path to your PFX file")]
    [string] $pfxPath,

    [Parameter(Mandatory=$false, HelpMessage="Optional PFX password")]
    [string] $pfxPassword,

    [Parameter(Mandatory=$false, HelpMessage="File path for certificate PEM export")]
    [string] $certFile = ".\your.cer.as.pem",

    [Parameter(Mandatory=$false, HelpMessage="Path to your private-key PEM export")]
    [string] $pvkFile = ".\your.private-key.as.pem"
)

$IMPORT_PFX_EXPORT_OPTIONS = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$HAS_PASSWORD = -Not([System.String]::IsNullOrEmpty($pfxPassword))

function Main() {

    [System.IO.Directory]::SetCurrentDirectory($(Get-Location))

    _validateParameters

    if (-NOT($HAS_PASSWORD)) {
        # Ensure NULL instead of empty or white-space string
        $pfxPassword = $null
    }

    $pfxAsCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath, $pfxPassword, $IMPORT_PFX_EXPORT_OPTIONS)

    _exportCertPEM $pfxAsCertificate $certFile
    _exportPrivateKeyPEM $pfxAsCertificate $pvkFile
}

function _exportCertPEM([System.Security.Cryptography.X509Certificates.X509Certificate2]$pfx, [System.String] $outputPath) {

    $base64CertText = [System.Convert]::ToBase64String($pfx.RawData, "InsertLineBreaks")

    $out = New-Object String[] -ArgumentList 3

    $out[0] = "-----BEGIN CERTIFICATE-----"
    $out[1] = $base64CertText
    $out[2] = "-----END CERTIFICATE-----"

    [System.IO.File]::WriteAllLines($outputPath, $out)
}

function _exportPrivateKeyPEM([System.Security.Cryptography.X509Certificates.X509Certificate2]$pfx, [System.String] $outputPath) {

    $key = _extractCngKeyFromCert $pfx

    $base64CertText = [System.Convert]::ToBase64String($key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob), "InsertLineBreaks");

    $out = New-Object String[] -ArgumentList 3

    $out[0] = "-----BEGIN PRIVATE KEY-----"
    $out[1] = $base64CertText
    $out[2] = "-----END PRIVATE KEY-----"

    [System.IO.File]::WriteAllLines($outputPath,$out)
}

function _extractCngKeyFromCert([System.Security.Cryptography.X509Certificates.X509Certificate2]$pfx) {

    $algorithmAsOidString = $pfx.GetKeyAlgorithm()
    $algorithmAsOid = [System.Security.Cryptography.Oid]::new($algorithmAsOidString)

    if ($algorithmAsOid.FriendlyName -eq "RSA") {

        $rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($pfx)
        $rsaCng = ([System.Security.Cryptography.RSACng]$rsa)
        return $rsaCng.Key
    } elseif ($algorithmAsOid.FriendlyName -eq "ECC") {

        $ecDsa = [System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions]::GetECDsaPrivateKey($pfx)
        $ecDsaCng = ([System.Security.Cryptography.ECDsaCng]$ecDsa)
        return $ecDsaCng.Key
    } else {

        throw "Certificate algorithm of '$algorithmAsOid.FriendlyName' is not supported"
    }
}

function _validateFilePathString($path) {

    try {

        [System.IO.FileInfo]::new($path) > $null
    } catch {

        throw "File path '$path' is invalid: $PSItem.Exception.Message"
    }
}

function _validateParameters() {

    if (-Not([System.IO.File]::Exists($pfxPath))) {

        throw "PFX file '$pfx' was not found"
    }
    try {

        if ($HAS_PASSWORD) {

            [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath, $pfxPassword, $IMPORT_PFX_EXPORT_OPTIONS) > $null
        } else {

            [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath, $null, $IMPORT_PFX_EXPORT_OPTIONS) > $null
        }
    } catch {

        if ($hasPassword) {

            throw "Source path of '$sourcePath' is not an X509 certificate file or the password specified is incorrect.  Error: `r`n$PSItem.Exception.Message"
        } else {

            throw "Source path of '$sourcePath' is not an X509 certificate file OR a password is required. Error: `r`n$PSItem.Exception.Message"
        }
    }
    _validateFilePathString($certFile)
    _validateFilePathString($pvkFile)
}

Main
0
votes

I've found this article:

https://blogs.msdn.microsoft.com/appserviceteam/2017/02/24/creating-a-local-pfx-copy-of-app-service-certificate/

On the $pfxCertObject you can call: $pfxCertObject.GetPublicKeyString() which gives you the public key in hex mode.

And using https://holtstrom.com/michael/tools/hextopem.php you can convert it to PEM format.

Hope this helps.