Private/Import-Pem.ps1
function Import-Pem { [CmdletBinding()] param( [Parameter(ParameterSetName='File',Mandatory,Position=0)] [string]$InputFile, [Parameter(ParameterSetName='String',Mandatory)] [string]$InputString ) # BouncyCastle has a lovely PemReader class that can spit out certs, keys, csrs, etc. # We have to do a little extra work for PKCS8 encoded private keys though. if ('File' -eq $PSCmdlet.ParameterSetName) { # normalize the file path and read it in $InputFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($InputFile) $pemStr = Get-Content $InputFile -Raw } else { # This should be a single string value with at least the header/footer # on their own line $pemStr = $InputString } # parse the PEM try { $sr = [IO.StringReader]::new($pemStr) $reader = [Org.BouncyCastle.OpenSsl.PemReader]::new($sr) $pemObj = $reader.ReadObject() } catch { throw } finally { if ($null -ne $sr) { $sr.Close() } } if ($pemObj -is [Org.BouncyCastle.X509.X509Certificate] -or $pemObj -is [Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest] -or $pemObj -is [Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair]) { # Certs, Requests, and private keys that get parsed as a full key pair # are all things we can just return as-is Write-Debug "PemReader found '$($pemObj.GetType())'. Returning as-is" return $pemObj } elseif ($pemObj -is [Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters]) { # A PKCS8 encoded RSA private key comes out as just the private key # parameters. We have to generate the public key parameters and fold # them into a full key pair object. Write-Debug "PemReader found '$($pemObj.GetType())'. Attempting to convert to AsymmetricCipherKeyPair." $pubSpec = [Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters]::new( $false,$pemObj.Modulus,$pemObj.PublicExponent ) # $pemObj is our private parameters return [Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair]::new($pubSpec,$pemObj) } elseif ($pemObj -is [Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters]) { # A PKCS8 encoded EC private key comes out as just the key parameters # We have to transform them into a full key pair object Write-Debug "PemReader found '$($pemObj.GetType())'. Attempting to convert to AsymmetricCipherKeyPair." $multiplier = [Org.BouncyCastle.Math.EC.Multiplier.FixedPointCombMultiplier]::new() $q = $multiplier.Multiply($pemObj.Parameters.G, $pemObj.D) $pubSpec = [Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters]::new( $pemObj.AlgorithmName, $q, $pemObj.PublicKeyParamSet ) # $pemObj is our private parameters return [Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair]::new($pubSpec,$pemObj) } else { # not sure what we ended up with throw "PemReader found unsupported '$($pemObj.GetType())'." } return $pemObj } |