Fix RSABCrypt to RSACng cast error in certificate PEM conversion

- Wrapped CNG key casting in try/catch for both public and private key extraction
- RSABCrypt and other non-CNG implementations now gracefully skip key blob export
- Certificate PEM blob still generated correctly (only separate key blobs affected)
- Demoted public key extraction failure from Warning to Verbose (non-critical)
- Added informative message about key implementation type on failure
This commit is contained in:
GraceSolutions
2026-05-04 10:09:48 -04:00
parent 03a3912a29
commit 40de4368d7
@@ -588,37 +588,53 @@ Function ConvertFrom-CertificateToPEM
Switch ($Null -ine $X509Certificate2.Object.PublicKey) Switch ($Null -ine $X509Certificate2.Object.PublicKey)
{ {
{($_ -eq $True)} {($_ -eq $True)}
{ {
Switch ($X509Certificate2.OID.FriendlyName) Try
{ {
{($_ -iin @('RSA'))} Switch ($X509Certificate2.OID.FriendlyName)
{ {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPublicKey($X509Certificate2.Object) {($_ -iin @('RSA'))}
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA) {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPublicKey($X509Certificate2.Object)
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA)
}
{($_ -iin @('ECC'))}
{
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDSACertificateExtensions]::GetECDSAPublicKey($X509Certificate2.Object)
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA)
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for public key blob extraction."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
} }
{($_ -iin @('ECC'))} Switch ($Null -ine $X509Certificate2.CNG)
{ {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDSACertificateExtensions]::GetECDSAPublicKey($X509Certificate2.Object) {($_ -eq $True)}
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA) {
} $X509Certificate2.PublicKey = $X509Certificate2.CNG.Key
Default $X509Certificate2.PublicKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PublicKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPublicBlob)), [System.Base64FormattingOptions]::InsertLineBreaks)
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for public key extraction." $Null = $StringBuilders.PublicKey.Append('-----BEGIN PUBLIC KEY-----').AppendLine()
Write-Warning -Message ($LoggingDetails.LogMessage) $Null = $StringBuilders.PublicKey.Append($X509Certificate2.PublicKeyEncoded).AppendLine()
$Null = $StringBuilders.PublicKey.Append('-----END PUBLIC KEY-----')
$OutputObjectProperties.Blobs.PublicKey = $StringBuilders.PublicKey.ToString()
}
} }
} }
Catch
$X509Certificate2.PublicKey = $X509Certificate2.CNG.Key {
#Note: Some certificates use RSABCrypt or other non-CNG implementations that cannot be cast to RSACng/ECDsaCng.
$X509Certificate2.PublicKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PublicKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPublicBlob)), [System.Base64FormattingOptions]::InsertLineBreaks) #The certificate PEM blob is still valid - only the separate public key blob extraction fails.
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Public key blob extraction skipped (key implementation: $($X509Certificate2.DSA.GetType().Name)). Certificate PEM is still valid."
$Null = $StringBuilders.PublicKey.Append('-----BEGIN PUBLIC KEY-----').AppendLine() Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = $StringBuilders.PublicKey.Append($X509Certificate2.PublicKeyEncoded).AppendLine() }
$Null = $StringBuilders.PublicKey.Append('-----END PUBLIC KEY-----')
$OutputObjectProperties.Blobs.PublicKey = $StringBuilders.PublicKey.ToString()
} }
Default Default
@@ -640,44 +656,53 @@ Function ConvertFrom-CertificateToPEM
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to extract private key (as requested by -IncludePrivateKey)..." $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to extract private key (as requested by -IncludePrivateKey)..."
Write-Verbose -Message ($LoggingDetails.LogMessage) Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch ($X509Certificate2.OID.FriendlyName) Try
{ {
{($_ -iin @('RSA'))} Switch ($X509Certificate2.OID.FriendlyName)
{ {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($X509Certificate2.Object) {($_ -iin @('RSA'))}
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA) {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($X509Certificate2.Object)
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA)
}
{($_ -iin @('ECC'))}
{
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions]::GetECDSAPrivateKey($X509Certificate2.Object)
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA)
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for private key extraction."
Write-Warning -Message ($LoggingDetails.LogMessage)
}
} }
{($_ -iin @('ECC'))} Switch ($Null -ine $X509Certificate2.CNG)
{ {
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions]::GetECDSAPrivateKey($X509Certificate2.Object) {($_ -eq $True)}
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA) {
} $X509Certificate2.PrivateKey = $X509Certificate2.CNG.Key
Default $X509Certificate2.PrivateKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PrivateKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::PKCS8PrivateBlob)), [System.Base64FormattingOptions]::InsertLineBreaks)
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for private key extraction." $Null = $StringBuilders.PrivateKey.Append('-----BEGIN PRIVATE KEY-----').AppendLine()
Write-Warning -Message ($LoggingDetails.LogMessage) $Null = $StringBuilders.PrivateKey.Append($X509Certificate2.PrivateKeyEncoded).AppendLine()
$Null = $StringBuilders.PrivateKey.Append('-----END PRIVATE KEY-----')
$OutputObjectProperties.Blobs.PrivateKey = $StringBuilders.PrivateKey.ToString()
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Private key successfully extracted."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
} }
} }
Catch
Switch ($Null -ine $X509Certificate2.CNG)
{ {
{($_ -eq $True)} #Note: Some certificates use RSABCrypt or other non-CNG implementations that cannot be cast to RSACng/ECDsaCng.
{ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Private key extraction failed (key implementation: $($X509Certificate2.DSA.GetType().Name)). This key type does not support CNG export."
$X509Certificate2.PrivateKey = $X509Certificate2.CNG.Key Write-Warning -Message ($LoggingDetails.LogMessage)
$X509Certificate2.PrivateKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PrivateKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::PKCS8PrivateBlob)), [System.Base64FormattingOptions]::InsertLineBreaks)
$Null = $StringBuilders.PrivateKey.Append('-----BEGIN PRIVATE KEY-----').AppendLine()
$Null = $StringBuilders.PrivateKey.Append($X509Certificate2.PrivateKeyEncoded).AppendLine()
$Null = $StringBuilders.PrivateKey.Append('-----END PRIVATE KEY-----')
$OutputObjectProperties.Blobs.PrivateKey = $StringBuilders.PrivateKey.ToString()
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Private key successfully extracted."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
} }
} }