OpenSSL.psm1
Function New-PrivateKey { <# .SYNOPSIS Generate a private key. .DESCRIPTION The New-PrivateKey command generates a private key. The generated key can be optionally encrypted with a password. .PARAMETER KeyFile Output key file name. .PARAMETER KeySize Key size in bits (e.g. 2048). Default is 2048 bits. Minimum is 1 and maximum is 8192. .PARAMETER KeyPassword Password for key encryption. .PARAMETER Cipher Cipher for key encryption (e.g. DES, DES3, IDEA). Default is DES3. .PARAMETER Overwrite Overwrite the key file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE New-PrivateKey key.pem Generate a private key. Output the key to file 'key.pem'. .EXAMPLE New-PrivateKey key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) Generate a private key. Prompt for key encryption password. Output the key to file 'key.pem'. .EXAMPLE New-PrivateKey key.pem -KeySize 1024 -Overwrite Generate a 1024-bit private key. Output the key to file 'key.pem'. Overwrite file if exists. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Output key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Key size in bits", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateRange(512, 8192)] [Int] $KeySize=2048, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$false, HelpMessage="Cipher for key encryption", ParameterSetName="General")] [ValidateSet('DES', 'DES3', 'IDEA', 'AES128', 'AES192', 'AES256', 'CAMELLIA128', 'CAMELLIA192', 'CAMELLIA256')] [ValidateNotNullOrEmpty()] [String] $Cipher="DES3", [Parameter(Mandatory=$false, HelpMessage="Overwrite output key file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("genpkey") # Algorithm argument $arguments += "-algorithm RSA" # Pass and cipher argument if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password if (![string]::IsNullOrEmpty($password.Trim())) { $arguments += "-pass" $arguments += "pass:$password" $arguments += "-$Cipher".ToLower() } } # Pkeyopt argument if ($KeySize) { $arguments += "-pkeyopt" $arguments += "rsa_keygen_bits:$KeySize" } # Out argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid output key file name" Return } elseif ((Test-Path -PathType Leaf $KeyFile) -and (!$Overwrite)) { Write-Error "Key file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$KeyFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Get-PrivateKey { <# .SYNOPSIS Get private key details. .DESCRIPTION The Get-PrivateKey command gets the private key details from an input key file. .PARAMETER KeyFile Input Key file name. .PARAMETER KeyPassword Password for key encryption. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Get-PrivateKey key.pem Get private key details from input key file 'key.pem'. .EXAMPLE Get-PrivateKey key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) Get private key details from encrypted input key file 'key.pem'. Prompt for key encryption password. .INPUTS None .OUTPUTS System.String #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkey") # In argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-in" $arguments += "`"$KeyFile`"" } # Inform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Text argument $arguments += "-text" # Noout argument $arguments += "-noout" # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Convert-PrivateKey { <# .SYNOPSIS Convert private key file format. .DESCRIPTION The Convert-PrivateKey command converts a private key to PEM or DER format .PARAMETER KeyFile Input key file name. .PARAMETER KeyPassword Password for key encryption. .PARAMETER OutputFile Output file name .PARAMETER OutputFormat Output file format (PEM or DER). .PARAMETER OutputPassword Password for output key encryption. .PARAMETER OutputCipher Cipher for output key encryption (e.g. DES, DES3, IDEA). Default is DES3. .PARAMETER Overwrite Overwrite the output file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Convert-PrivateKey key.pem -OutputFile key.der -OutputFormat DER Convert private key file 'key.pem' to DER format. Output to file 'key.der'. .EXAMPLE Convert-PrivateKey key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) -OutputFile key.der -OutputFormat DER -Overwrite Convert private key file 'cert.pem' to DER format. Prompt for key encryption password. Output to file 'key.der'. Overwrite file if exists. .EXAMPLE Convert-PrivateKey key.pem -OutputFile key.der -OutputFormat DER -OutputPassword (Read-Host -Prompt Password -AsSecureString) Convert private key file 'cert.pem' to DER format. Output to file 'key.der'. Prompt for output encryption password. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Output key file name", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OutputFile, [Parameter(Mandatory=$true, HelpMessage="Output file format (PEM or DER)", ParameterSetName="General")] [ValidateSet('PEM', 'DER')] [ValidateNotNullOrEmpty()] [String] $OutputFormat, [Parameter(Mandatory=$false, HelpMessage="Password for output key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $OutputPassword, [Parameter(Mandatory=$false, HelpMessage="Cipher for output key encryption", ParameterSetName="General")] [ValidateSet('DES', 'DES3', 'IDEA', 'AES128', 'AES192', 'AES256', 'CAMELLIA128', 'CAMELLIA192', 'CAMELLIA256')] [ValidateNotNullOrEmpty()] [String] $OutputCipher="DES3", [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkey") # In argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-in" $arguments += "`"$KeyFile`"" } # Inform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Passout and cipher argument if ($OutputPassword) { $password = (New-Object PSCredential "User",$OutputPassword).GetNetworkCredential().Password if (![string]::IsNullOrEmpty($password.Trim())) { $arguments += "-passout" $arguments += "pass:$password" $arguments += "-$OutputCipher".ToLower() } } # Out argument if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$OutputFile`"" } # Outform argument $arguments += "-outform" $arguments += $OutputFormat # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Export-PublicKey { <# .SYNOPSIS Export public key. .DESCRIPTION The Export-PublicKey command exports the public key from an input key, certificate, or certificate request file. .PARAMETER KeyFile Input key file name. .PARAMETER KeyPassword Password for key encryption. .PARAMETER CertificateFile Input certificate file name. .PARAMETER RequestFile Input request file name. .PARAMETER OutputFile Output file name .PARAMETER Overwrite Overwrite the output file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Export-PublicKey -KeyFile key.pem -OutputFile keypub.pem Export public key from input key file 'key.pem'. Output to file 'keypub.pem'. .EXAMPLE Export-PublicKey -KeyFile key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) -OutputFile keypub.pem Export public key from encrypted input key file 'key.pem'. Prompt for key encryption password. Output to file 'keypub.pem'. .EXAMPLE Export-PublicKey -CertificateFile cert.pem -OutputFile keypub.pem Export public key from certificate input file 'cert.pem'. Output to file 'keypub.pem'. .EXAMPLE Export-PublicKey -RequestFile csr.pem -OutputFile keypub.pem Export public key from certificate signing request input file 'csr.pem'. Output to file 'keypub.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="Key", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="Key")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Input certificate file name", ParameterSetName="Certificate", Position=0)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$true, HelpMessage="Input request file name", ParameterSetName="Request", Position=0)] [ValidateNotNullOrEmpty()] [String] $RequestFile, [Parameter(Mandatory=$true, HelpMessage="Output file name", ParameterSetName="Key")] [Parameter(Mandatory=$true, HelpMessage="Output file name", ParameterSetName="Certificate")] [Parameter(Mandatory=$true, HelpMessage="Output file name", ParameterSetName="Request")] [ValidateNotNullOrEmpty()] [String] $OutputFile, [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="Key")] [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="Certificate")] [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="Request")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="Key")] [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="Certificate")] [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="Request")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # Key file if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkey") # In argument $arguments += "-in" $arguments += "`"$KeyFile`"" # Inform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Pubout argument $arguments += "-pubout" # Out argument if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$OutputFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } # Certificate file if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid certificate input file name" Return } elseif (!(Test-Path -PathType Leaf $CertificateFile)) { Write-Error "Input certificate file '$CertificateFile' not found" Return } # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $Path) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $Path)) { Write-Error "Openssl file '$Path' not found" Return } $opensslexe = $Path } # OpenSSL arguments $arguments = @("x509") # In argument $arguments += "-in" $arguments += "`"$CertificateFile`"" # Inform argument if (!(Get-Content $CertificateFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Pubkey argument $arguments += "-pubkey" # Noout argument $arguments += "-noout" # Output file if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Set-Content $OutputFile $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } # Request file if ($RequestFile) { if (Test-Path -PathType Container $RequestFile) { Write-Error "Invalid request input file name" Return } elseif (!(Test-Path -PathType Leaf $RequestFile)) { Write-Error "Input request file '$RequestFile' not found" Return } # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $Path) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $Path)) { Write-Error "Openssl file '$Path' not found" Return } $opensslexe = $Path } # OpenSSL arguments $arguments = @("req") # In argument $arguments += "-in" $arguments += "`"$RequestFile`"" # Inform argument if (!(Get-Content $RequestFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Pubkey argument $arguments += "-pubkey" # Noout argument $arguments += "-noout" # Output file if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Set-Content $OutputFile $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } } Function Get-PublicKey { <# .SYNOPSIS Get public key details. .DESCRIPTION The Get-PublicKey command gets the public key details from an input key file. .PARAMETER KeyFile Input Key file name. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Get-PublicKey keypub.pem Get public key details from input key file 'keypub.pem'. .EXAMPLE Get-PublicKey keypub.pem -OpenSslPath 'c:\openssl\openssl.exe' Get public key details from input key file 'keypub.pem'. Use the openssl path provided. .INPUTS None .OUTPUTS System.String #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkey") # In argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-in" $arguments += "`"$KeyFile`"" } # Inform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Pubin argument $arguments += '-pubin' # Text argument $arguments += "-text" # Noout argument $arguments += "-noout" # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Convert-PublicKey { <# .SYNOPSIS Convert public key file format. .DESCRIPTION The Convert-PublicKey command converts a public key to PEM or DER format .PARAMETER KeyFile Input key file name. .PARAMETER OutputFile Output file name .PARAMETER OutputFormat Output file format (PEM or DER). .PARAMETER Overwrite Overwrite the output file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Convert-PublicKey keypub.pem -OutputFile keypub.der -OutputFormat DER Convert public key file 'keypub.pem' to DER format. Output to file 'keypub.der'. .EXAMPLE Convert-PublicKey keypub.pem -OutputFile keypub.der -OutputFormat DER -Overwrite Convert public key file 'keypub.pem' to DER format. Output to file 'keypub.der'. Overwrite file if exists. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$true, HelpMessage="Output key file name", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OutputFile, [Parameter(Mandatory=$true, HelpMessage="Output file format (PEM or DER)", ParameterSetName="General")] [ValidateSet('PEM', 'DER')] [ValidateNotNullOrEmpty()] [String] $OutputFormat, [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkey") # In argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-in" $arguments += "`"$KeyFile`"" } # Inform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Pubin argument $arguments += '-pubin' # Out argument if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$OutputFile`"" } # Outform argument $arguments += "-outform" $arguments += $OutputFormat # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function New-SelfSignedCertificate { <# .SYNOPSIS Generate a self-signed certificate. .DESCRIPTION The New-SelfSignedCertificate command generates a self-signed certificate using the key provided and the certificate options specified. .PARAMETER KeyFile Input key file name. .PARAMETER KeyPassword Key encryption password. .PARAMETER SubjectName Subject name fields. Each field is prefixed with the corresponding identifier (i.e. CN for CommonName, E for E-mail, O for Organization, OU for OrganizationalUnit, C for Country, ST for State, or L for Locality). For example "CN:User, E:user@domain.com, C:AU" .PARAMETER CertificateFile Output certificate file name. .PARAMETER ValidDays Certificate validy in days. Default is 30 days. Minimum is 30 and maximum is 9125 (i.e. 25 years). .PARAMETER BasicUsage Certificate key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Key Usage" field added. .PARAMETER ExtendedUsage Certificate extended key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Enhanced key usage" field added. .PARAMETER SubjectAlternative Subject alternative name fields. Each field is prefixed with the corresponding identifier (i.e. IP, DNS, URI, RID, email, or otherName). For example "IP:10.1.1.1, DNS:server.net". .PARAMETER Authority Set certificate authority flag. .PARAMETER Overwrite Overwrite the certificate file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE New-SelfSignedCertificate key.pem CN:server.domain.com cert.pem Generate a self-signed certificate using input key file 'key.pem' and subject name provided. Output certificate to file 'cert.pem'. .EXAMPLE New-SelfSignedCertificate key.pem CN:server.domain.com cert.pem -ValidDays 3650 Generate a self-signed certificate, valid for 10 years, using input key file 'key.pem' and subject name provided. Output certificate to file 'cert.pem'. .EXAMPLE New-SelfSignedCertificate key.pem CN:user@domain.com cert.pem -ValidDays 3650 -SubjectAlternative "otherName:msUPN;UTF8:firstname lastname" Generate a self-signed certificate, valid for 10 years, using input key file 'key.pem' and subject and alternative subject names provided. Output certificate to file 'cert.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Key encryption password", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Subject name fields (e.g. C:AU, ST:NSW, CN:User)", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [ValidatePattern('^(CN|E|O|OU|C|ST|L):[^,:]+$', Options='IgnoreCase')] [String[]] $SubjectName, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General", Position=2)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="Certificate validity in days", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateRange(30, 9125)] [Int] $ValidDays, [Parameter(Mandatory=$false, HelpMessage="Certificate basic key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('digitalSignature', 'nonRepudiation', 'keyEncipherment', 'dataEncipherment', 'keyAgreement', 'keyCertSign', 'cRLSign', 'encipherOnly', 'decipherOnly', IgnoreCase=$false)] [String[]] $BasicUsage, [Parameter(Mandatory=$false, HelpMessage="Certificate extended key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('serverAuth', 'clientAuth', 'codeSigning', 'emailProtection', 'timeStamping', 'msCodeInd', 'msCodeCom', 'msCTLSign', 'msSGC', 'msEFS', 'nsSGC', IgnoreCase=$false)] [String[]] $ExtendedUsage, [Parameter(Mandatory=$false, HelpMessage="Subject alternative name fields (e.g. IP:10.1.1.1, DNS:server.net)", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidatePattern('^(IP|DNS|URI|RID|otherName|email):[^,]+$', Options='None')] [String[]] $SubjectAlternative, [Parameter(Mandatory=$false, HelpMessage="Set certificate authority flag", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Authority, [Parameter(Mandatory=$false, HelpMessage="Overwrite certificate file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("req") # New argument $arguments += "-new" # X509 argument $arguments += "-x509" # Rand argument $rand = Join-Path $env:TEMP "opensslrand" Get-Random | Set-Content $rand $arguments += "-rand" $arguments += "`"$rand`"" # Key argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-key" $arguments += "`"$KeyFile`"" } # Keyform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-keyform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Days argument if ($ValidDays) { $arguments += "-days" $arguments += $ValidDays } # Config argument $config = Join-Path $env:TEMP "opensslconf" "[req]" | Set-Content $config "default_md = sha1" | Add-Content $config "prompt = no" | Add-Content $config "distinguished_name = subject" | Add-Content $config "x509_extensions = extensions" | Add-Content $config $arguments += "-config" $arguments += "`"$config`"" # Config subject "[subject]" | Add-Content $config foreach ($part in $SubjectName) { $parts = $part.Split(':') if ($parts[0].ToUpper() -eq 'CN') { "commonName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'E') { "emailAddress = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'O') { "organizationName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'OU') { "organizationalUnitName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'C') { "countryName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'ST') { "stateOrProvinceName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'L') { "localityName = {0}" -f $parts[1] | Add-Content $config } } # Config extensions "[extensions]" | Add-Content $config "basicConstraints = CA:{0}" -f $Authority.ToString().ToUpper() | Add-Content $config "authorityKeyIdentifier = keyid, issuer" | Add-Content $config "subjectKeyIdentifier = hash" | Add-Content $config if ($BasicUsage) { "keyUsage = {0}" -f [String]::Join(', ', $BasicUsage) | Add-Content $config } if ($ExtendedUsage) { "extendedKeyUsage = {0}" -f [String]::Join(', ', $ExtendedUsage) | Add-Content $config } if ($SubjectAlternative) { "subjectAltName = {0}" -f [String]::Join(', ', $SubjectAlternative) | Add-Content $config } # Out argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid output certificate file name" Return } elseif ((Test-Path -PathType Leaf $CertificateFile) -and (!$Overwrite)) { Write-Error "Output certificate file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$CertificateFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Get-Certificate { <# .SYNOPSIS Get certificate details. .DESCRIPTION The Get-Certificate command gets certificate details from a certificate file. .PARAMETER CertificateFile Input certificate file name. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Get-Certificate cert.pem Get certificate from certificate file 'cert.pem'. .EXAMPLE Get-Certificate cert.pem -OpenSslPath C:\OpenSSL\bin\openssl.exe Get certificate from certificate file 'cert.pem'. Use OpenSSL execuable file provided. .INPUTS None .OUTPUTS System.String #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input certificate file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("x509") # In argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid input certificate file name" Return } elseif (!(Test-Path -PathType Leaf $CertificateFile)) { Write-Error "Input certificate file '$CertificateFile' not found" Return } $arguments += "-in" $arguments += "`"$CertificateFile`"" } # Inform argument if (!(Get-Content $CertificateFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Text argument $arguments += "-text" # Fingerprint argument $arguments += "-fingerprint" # Noout argument $arguments += "-noout" # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Convert-Certificate { <# .SYNOPSIS Convert certificate file format. .DESCRIPTION The Convert-Certificate command converts a certificate to PEM or DER format .PARAMETER CertificateFile Input certificate file name. .PARAMETER OutputFile Output file name .PARAMETER OutputFormat Output file format (PEM or DER). .PARAMETER Overwrite Overwrite the output file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Convert-Certificate cert.pem -OutputFile cert.der -OutputFormat DER Convert certificate file 'cert.pem' to DER format. Output to file 'cert.der'. .EXAMPLE Convert-Certificate cert.pem -OutputFile cert.der -OutputFormat DER -Overwrite Convert certificate file 'cert.pem' to DER format. Output to file 'cert.der'. Overwrite file if exists. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input certificate file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$true, HelpMessage="Output format (PEM or DER)", ParameterSetName="General")] [ValidateSet('PEM', 'DER')] [ValidateNotNullOrEmpty()] [String] $OutputFormat, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OutputFile, [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("x509") # In argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid input certificate file name" Return } elseif (!(Test-Path -PathType Leaf $CertificateFile)) { Write-Error "Input certificate file '$CertificateFile' not found" Return } $arguments += "-in" $arguments += "`"$CertificateFile`"" } # Inform argument if (!(Get-Content $CertificateFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Out argument if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$OutputFile`"" } # Outform argument $arguments += "-outform" $arguments += $OutputFormat # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function New-CertificateRequest { <# .SYNOPSIS Generate a certificate signing request. .DESCRIPTION The New-CertificateRequest command generates a certificate signing request using the key provided and the certificate options specified. .PARAMETER KeyFile Input key file name. .PARAMETER KeyPassword Key encryption password. .PARAMETER SubjectName Subject name fields. Each field is prefixed with the corresponding identifier (i.e. CN for CommonName, E for E-mail, O for Organization, OU for OrganizationalUnit, C for Country, ST for State, or L for Locality). For example "CN:User, E:user@domain.com, C:AU" .PARAMETER RequestFile Output request file name. .PARAMETER ValidDays Certificate validy in days. Default is 30 days. Minimum is 30 and maximum is 9125 (i.e. 25 years). .PARAMETER BasicUsage Certificate key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Key Usage" field added. .PARAMETER ExtendedUsage Certificate extended key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Enhanced key usage" field added. .PARAMETER SubjectAlternative Subject alternative name fields. Each field is prefixed with the corresponding identifier (i.e. IP, DNS, URI, RID, email, or otherName). For example "IP:10.1.1.1, DNS:server.net". .PARAMETER Overwrite Overwrite the certificate file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE New-CertificateRequest key.pem CN:server.domain.com csr.pem Generate a certificate signing request using input key file 'key.pem' and subject name provided. Output certificate request to file 'csr.pem'. .EXAMPLE New-CertificateRequest key.pem CN:server.domain.com csr.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) Generate a certificate signing request using input key file 'key.pem' and subject name provided. Prompt for key encryption password. Output certificate request to file 'csr.pem'. .EXAMPLE New-CertificateRequest key.pem CN:user@domain.com csr.pem -SubjectAlternative "otherName:msUPN;UTF8:firstname lastname" Generate a certificate signing request using input key file 'key.pem' and subject and alternative subject names provided. Output certificate request to file 'csr.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Key encryption password", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Subject name fields (e.g. C:AU, ST:NSW, CN:User)", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [ValidatePattern('^(CN|E|O|OU|C|ST|L):[^,:]+$', Options='IgnoreCase')] [String[]] $SubjectName, [Parameter(Mandatory=$true, HelpMessage="Output certificate request file name", ParameterSetName="General", Position=2)] [ValidateNotNullOrEmpty()] [String] $RequestFile, [Parameter(Mandatory=$false, HelpMessage="Certificate validity in days", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateRange(30, 9125)] [Int] $ValidDays, [Parameter(Mandatory=$false, HelpMessage="Certificate basic key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('digitalSignature', 'nonRepudiation', 'keyEncipherment', 'dataEncipherment', 'keyAgreement', 'keyCertSign', 'cRLSign', 'encipherOnly', 'decipherOnly', IgnoreCase=$false)] [String[]] $BasicUsage, [Parameter(Mandatory=$false, HelpMessage="Certificate extended key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('serverAuth', 'clientAuth', 'codeSigning', 'emailProtection', 'timeStamping', 'msCodeInd', 'msCodeCom', 'msCTLSign', 'msSGC', 'msEFS', 'nsSGC', IgnoreCase=$false)] [String[]] $ExtendedUsage, [Parameter(Mandatory=$false, HelpMessage="Subject alternative name fields (e.g. IP:10.1.1.1, DNS:server.net)", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidatePattern('^(IP|DNS|URI|RID|otherName|email):[^,]+$', Options='None')] [String[]] $SubjectAlternative, [Parameter(Mandatory=$false, HelpMessage="Overwrite certificate file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("req") # New argument $arguments += "-new" # Rand argument $rand = Join-Path $env:TEMP "opensslrand" Get-Random | Set-Content $rand $arguments += "-rand" $arguments += "`"$rand`"" # Key argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-key" $arguments += "`"$KeyFile`"" } # Keyform argument if (!(Get-Content $KeyFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-keyform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Days argument if ($ValidDays) { $arguments += "-days" $arguments += $ValidDays } # Config argument $config = Join-Path $env:TEMP "opensslconf" "[req]" | Set-Content $config "default_md = sha1" | Add-Content $config "prompt = no" | Add-Content $config "distinguished_name = subject" | Add-Content $config "req_extensions = extensions" | Add-Content $config $arguments += "-config" $arguments += "`"$config`"" # Config subject "[subject]" | Add-Content $config foreach ($part in $SubjectName) { $parts = $part.Split(':') if ($parts[0].ToUpper() -eq 'CN') { "commonName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'E') { "emailAddress = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'O') { "organizationName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'OU') { "organizationalUnitName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'C') { "countryName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'ST') { "stateOrProvinceName = {0}" -f $parts[1] | Add-Content $config } if ($parts[0] -eq 'L') { "localityName = {0}" -f $parts[1] | Add-Content $config } } # Config extensions "[extensions]" | Add-Content $config "subjectKeyIdentifier = hash" | Add-Content $config if ($BasicUsage) { "keyUsage = {0}" -f [String]::Join(', ', $BasicUsage) | Add-Content $config } if ($ExtendedUsage) { "extendedKeyUsage = {0}" -f [String]::Join(', ', $ExtendedUsage) | Add-Content $config } if ($SubjectAlternative) { "subjectAltName = {0}" -f [String]::Join(', ', $SubjectAlternative) | Add-Content $config } # Out argument if ($RequestFile) { if (Test-Path -PathType Container $RequestFile) { Write-Error "Invalid output request file name" Return } elseif ((Test-Path -PathType Leaf $RequestFile) -and (!$Overwrite)) { Write-Error "Output request file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$RequestFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Get-CertificateRequest { <# .SYNOPSIS Get certificate signing request details. .DESCRIPTION The Get-CertificateRequest command gets certificate request details from a request file. .PARAMETER RequestFile Input request file name. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Get-CertificateRequest csr.pem Get certificate signing request from request file 'csr.pem'. .EXAMPLE Get-CertificateRequest csr.pem -OpenSslPath C:\OpenSSL\bin\openssl.exe Get certificate signing request from request file 'csr.pem'. Use OpenSSL execuable file provided. .INPUTS None .OUTPUTS System.String #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input request file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $RequestFile, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("req") # In argument if ($RequestFile) { if (Test-Path -PathType Container $RequestFile) { Write-Error "Invalid input request file name" Return } elseif (!(Test-Path -PathType Leaf $RequestFile)) { Write-Error "Input request file '$RequestFile' not found" Return } $arguments += "-in" $arguments += "`"$RequestFile`"" } # Inform argument if (!(Get-Content $RequestFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Text argument $arguments += "-text" # Noout argument $arguments += "-noout" # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Convert-CertificateRequest { <# .SYNOPSIS Convert certificate request file format. .DESCRIPTION The Convert-CertificateRequest command converts a certificate signing request to PEM or DER format .PARAMETER RequestFile Input request file name. .PARAMETER OutputFile Output file name .PARAMETER OutputFormat Output file format (PEM or DER). .PARAMETER Overwrite Overwrite the output file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Convert-CertificateRequest csr.pem -OutputFile csr.der -OutputFormat DER Convert request file 'csr.pem' to DER format. Output to file 'csr.der'. .EXAMPLE Convert-CertificateRequest csr.pem -OutputFile csr.der -OutputFormat DER -Overwrite Convert request file 'csr.pem' to DER format. Output to file 'csr.der'. Overwrite file if exists. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input request file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $RequestFile, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OutputFile, [Parameter(Mandatory=$true, HelpMessage="Output format (PEM or DER)", ParameterSetName="General")] [ValidateSet('PEM', 'DER')] [ValidateNotNullOrEmpty()] [String] $OutputFormat, [Parameter(Mandatory=$false, HelpMessage="Overwrite output file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("req") # In argument if ($RequestFile) { if (Test-Path -PathType Container $RequestFile) { Write-Error "Invalid input request file name" Return } elseif (!(Test-Path -PathType Leaf $RequestFile)) { Write-Error "Input request file '$RequestFile' not found" Return } $arguments += "-in" $arguments += "`"$RequestFile`"" } # Inform argument if (!(Get-Content $RequestFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # Out argument if ($OutputFile) { if (Test-Path -PathType Container $OutputFile) { Write-Error "Invalid output file name" Return } elseif ((Test-Path -PathType Leaf $OutputFile) -and (!$Overwrite)) { Write-Error "Output file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$OutputFile`"" } # Outform argument $arguments += "-outform" $arguments += $OutputFormat # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Invoke-SignCertificateRequest { <# .SYNOPSIS Generate an authority-signed certificate. .DESCRIPTION The Invoke-SignCertificateRequest command generates an authority-signed certificate using the certificate signing request provided and the certificate options specified. .PARAMETER RequestFile Input request file name. .PARAMETER AuthorityCertificate Input authority certificate file name. .PARAMETER AuthorityKey Input authority key file name. .PARAMETER KeyPassword Key encryption password. .PARAMETER CertificateFile Output signed certificate file name. .PARAMETER ValidDays Certificate validy in days. Default is 30 days. Minimum is 30 and maximum is 9125 (i.e. 25 years). .PARAMETER BasicUsage Certificate key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Key Usage" field added. .PARAMETER ExtendedUsage Certificate extended key usage values. A combination of one or more of the predefined values can be supplied. If omitted the certificate will not have the "Enhanced key usage" field added. .PARAMETER SubjectAlternative Subject alternative name fields. Each field is prefixed with the corresponding identifier (i.e. IP, DNS, URI, RID, email, or otherName). For example "IP:10.1.1.1, DNS:server.net". .PARAMETER Authority Set certificate authority flag. .PARAMETER Overwrite Overwrite the certificate file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Invoke-SignCertificateRequest csr.pem cacert.pem cakey.pem cert.pem Generate an authority-signed certificate using input request file 'csr.pem' and authority key and certificate provided. Output certificate to file 'cert.pem'. .EXAMPLE Invoke-SignCertificateRequest csr.pem cacert.pem cakey.pem cert.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) Generate an authority-signed certificate using input request file 'csr.pem' and authority key and certificate provided. Prompt for key encryption password. Output certificate to file 'cert.pem'. .EXAMPLE Invoke-SignCertificateRequest csr.pem cacert.pem cakey.pem cert.pem -Overwrite Generate an authority-signed certificate using input request file 'csr.pem' and authority key and certificate provided. Output certificate to file 'cert.pem'. Overwrite file if exists. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input request file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $RequestFile, [Parameter(Mandatory=$true, HelpMessage="Authority certificate file name", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [String] $AuthorityCertificate, [Parameter(Mandatory=$true, HelpMessage="Authority key file name", ParameterSetName="General", Position=2)] [ValidateNotNullOrEmpty()] [String] $AuthorityKey, [Parameter(Mandatory=$false, HelpMessage="Password for key ", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General", Position=3)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="Certificate validity in days", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateRange(30, 9125)] [Int] $ValidDays, [Parameter(Mandatory=$false, HelpMessage="Certificate basic key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('digitalSignature', 'nonRepudiation', 'keyEncipherment', 'dataEncipherment', 'keyAgreement', 'keyCertSign', 'cRLSign', 'encipherOnly', 'decipherOnly', IgnoreCase=$false)] [String[]] $BasicUsage, [Parameter(Mandatory=$false, HelpMessage="Certificate extended key usage", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidateSet('serverAuth', 'clientAuth', 'codeSigning', 'emailProtection', 'timeStamping', 'msCodeInd', 'msCodeCom', 'msCTLSign', 'msSGC', 'msEFS', 'nsSGC', IgnoreCase=$false)] [String[]] $ExtendedUsage, [Parameter(Mandatory=$false, HelpMessage="Subject alternative name fields (e.g. IP:10.1.1.1, DNS:server.net)", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [ValidatePattern('^(IP|DNS|URI|RID|otherName|email):[^,]+$', Options='None')] [String[]] $SubjectAlternative, [Parameter(Mandatory=$false, HelpMessage="Set certificate authority flag", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Authority, [Parameter(Mandatory=$false, HelpMessage="Overwrite certificate file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("x509") # Req argument $arguments += "-req" # In argument if ($RequestFile) { if (Test-Path -PathType Container $RequestFile) { Write-Error "Invalid input request file name" Return } elseif (!(Test-Path -PathType Leaf $RequestFile)) { Write-Error "Input request file '$RequestFile' not found" Return } $arguments += "-in" $arguments += "`"$RequestFile`"" } # Inform argument if (!(Get-Content $RequestFile | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-inform DER" } # CA argument if ($AuthorityCertificate) { if (Test-Path -PathType Container $AuthorityCertificate) { Write-Error "Invalid input authority certificate file name" Return } elseif (!(Test-Path -PathType Leaf $AuthorityCertificate)) { Write-Error "Input authority certificate file '$AuthorityCertificate' not found" Return } $arguments += "-CA" $arguments += "`"$AuthorityCertificate`"" } # CAform argument if (!(Get-Content $AuthorityCertificate | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-CAform DER" } # CAkey argument if ($AuthorityKey) { if (Test-Path -PathType Container $AuthorityKey) { Write-Error "Invalid input authority key file name" Return } elseif (!(Test-Path -PathType Leaf $AuthorityKey)) { Write-Error "Input authority key file '$AuthorityKey' not found" Return } $arguments += "-CAkey" $arguments += "`"$AuthorityKey`"" } # CAkeyform argument if (!(Get-Content $AuthorityKey | Select-String "BEGIN" -SimpleMatch -Quiet)) { $arguments += "-CAkeyform DER" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # CAserial argument $serial = Join-Path $env:TEMP "opensslserial" $arguments += "-CAcreateserial" $arguments += "-CAserial" $arguments += "`"$serial`"" # Days argument if ($ValidDays) { $arguments += "-days" $arguments += $ValidDays } # Extfile argument $extfile = Join-Path $env:TEMP "opensslconf" "basicConstraints = CA:{0}" -f $Authority.ToString().ToUpper() | Set-Content $extfile "authorityKeyIdentifier = keyid, issuer" | Add-Content $extfile "subjectKeyIdentifier = hash" | Add-Content $extfile if ($BasicUsage) { "keyUsage = {0}" -f [String]::Join(', ', $BasicUsage) | Add-Content $extfile } if ($ExtendedUsage) { "extendedKeyUsage = {0}" -f [String]::Join(', ', $ExtendedUsage) | Add-Content $extfile } if ($SubjectAlternative) { "subjectAltName = {0}" -f [String]::Join(', ', $SubjectAlternative) | Add-Content $extfile } $arguments += "-extfile" $arguments += "`"$extfile`"" # Out argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid output certificate file name" Return } elseif ((Test-Path -PathType Leaf $CertificateFile) -and (!$Overwrite)) { Write-Error "Output certificate file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$CertificateFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function New-CertificateStore { <# .SYNOPSIS Generate a PKCS12 certificate store .DESCRIPTION The New-CertificateStore command generates a PKCS12 certificate store file. The generated store can be optionally encrypted with a password. .PARAMETER KeyFile Input key file name. .PARAMETER KeyPassword Key encryption password. .PARAMETER CertificateFile Input certificate file name. .PARAMETER AuthorityCertificate Input authority certificate file name. .PARAMETER StoreFile Output store file name. .PARAMETER StorePassword Password for store encryption. .PARAMETER Overwrite Overwrite the store file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE New-CertificateStore key.pem cert.pem certstore.pfx Generate a PKCS12 store containing key 'key.pem' and certificate 'cert.pem'. Output the store to file 'certstore.pfx'. .EXAMPLE New-CertificateStore key.pem cert.pem certstore.pfx -StorePassword (Read-Host -Prompt Password -AsSecureString) Generate a PKCS12 store containing key 'key.pem' and certificate 'cert.pem'. Prompt for store encryption password. Output the store to file 'certstore.pfx'. .EXAMPLE New-CertificateStore key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) cert.pem certstore.pfx -AuthorityCertificate cacert.pem Generate a PKCS12 store containing key 'key.pem' and certificate 'cert.pem' and authority certificate 'cacert.pem'. Prompt for input key encryption password. Output the store to file 'certstore.pfx'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input key file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$true, HelpMessage="Input certificate file name", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="Input authority certificate file name", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $AuthorityCertificate, [Parameter(Mandatory=$true, HelpMessage="Output store file name", ParameterSetName="General", Position=2)] [ValidateNotNullOrEmpty()] [String] $StoreFile, [Parameter(Mandatory=$false, HelpMessage="Password for store encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $StorePassword, [Parameter(Mandatory=$false, HelpMessage="Overwrite output store file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkcs12") # Export argument $arguments += "-export" # Inkey argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid input key file name" Return } elseif (!(Test-Path -PathType Leaf $KeyFile)) { Write-Error "Input key file '$KeyFile' not found" Return } $arguments += "-inkey" $arguments += "`"$KeyFile`"" } # Passin argument $password = '' if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Out argument if ($StoreFile) { if (Test-Path -PathType Container $StoreFile) { Write-Error "Invalid output store file name" Return } elseif ((Test-Path -PathType Leaf $StoreFile) -and (!$Overwrite)) { Write-Error "Store file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$StoreFile`"" } # In argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid input certificate file name" Return } elseif (!(Test-Path -PathType Leaf $CertificateFile)) { Write-Error "Input certificate file '$CertificateFile' not found" Return } $arguments += "-in" $arguments += "`"$CertificateFile`"" } # Certfile argument if ($AuthorityCertificate) { if (Test-Path -PathType Container $AuthorityCertificate) { Write-Error "Invalid input authority certificate file name" Return } elseif (!(Test-Path -PathType Leaf $AuthorityCertificate)) { Write-Error "Input authority certificate file '$AuthorityCertificate' not found" Return } $arguments += "-certfile" $arguments += "`"$AuthorityCertificate`"" } # Passout argument $password = '' if ($StorePassword) { $password = (New-Object PSCredential "User",$StorePassword).GetNetworkCredential().Password } $arguments += "-passout" $arguments += "pass:$password" # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Export-PrivateKey { <# .SYNOPSIS Export private key .DESCRIPTION The Export-PrivateKey command exports the private key from a PKCS12 input store file. .PARAMETER StoreFile Input store file name. .PARAMETER StorePassword Store encryption password. .PARAMETER KeyFile Output key file name. .PARAMETER KeyPassword Password for key encryption. .PARAMETER Cipher Cipher for key encryption (e.g. DES, DES3, IDEA). Default is DES3. .PARAMETER Overwrite Overwrite the key file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Export-PrivateKey certstore.pfx key.pem Export the private key from input store file 'certstore.pfx'. Output the key to file 'key.pem'. .EXAMPLE Export-PrivateKey certstore.pfx key.pem -KeyPassword (Read-Host -Prompt Password -AsSecureString) Export the private key from input store file 'certstore.pfx'. Prompt for key encryption password. Output the key to file 'key.pem'. .EXAMPLE Export-PrivateKey certstore.pfx -StorePassword (Read-Host -Prompt Password -AsSecureString) key.pem Export the private key from input store file 'certstore.pfx'. Prompt for store encryption password. Output the key to file 'key.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input store file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $StoreFile, [Parameter(Mandatory=$false, HelpMessage="Password for store encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $StorePassword, [Parameter(Mandatory=$true, HelpMessage="Output key file name", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [String] $KeyFile, [Parameter(Mandatory=$false, HelpMessage="Password for key encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $KeyPassword, [Parameter(Mandatory=$false, HelpMessage="Cipher for key encryption", ParameterSetName="General")] [ValidateSet('DES', 'DES3', 'IDEA', 'AES128', 'AES192', 'AES256', 'CAMELLIA128', 'CAMELLIA192', 'CAMELLIA256')] [ValidateNotNullOrEmpty()] [String] $Cipher="DES3", [Parameter(Mandatory=$false, HelpMessage="Overwrite output key file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkcs12") # In argument if ($StoreFile) { if (Test-Path -PathType Container $StoreFile) { Write-Error "Invalid input store file name" Return } elseif (!(Test-Path -PathType Leaf $StoreFile)) { Write-Error "Input store file '$StoreFile' not found" Return } $arguments += "-in" $arguments += "`"$StoreFile`"" } # Passin argument $password = '' if ($StorePassword) { $password = (New-Object PSCredential "User",$StorePassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Nocerts argument $arguments += "-nocerts" # Nodes argument if (!$KeyPassword) { $arguments += "-nodes" } # Passout and cipher argument if ($KeyPassword) { $password = (New-Object PSCredential "User",$KeyPassword).GetNetworkCredential().Password if ([string]::IsNullOrEmpty($password.Trim())) { $arguments += "-nodes" } else { $arguments += "-passout" $arguments += "pass:$password" $arguments += "-$Cipher".ToLower() } } # Out argument if ($KeyFile) { if (Test-Path -PathType Container $KeyFile) { Write-Error "Invalid output key file name" Return } elseif ((Test-Path -PathType Leaf $KeyFile) -and (!$Overwrite)) { Write-Error "Key file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$KeyFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Export-ClientCertificate { <# .SYNOPSIS Export client certificate .DESCRIPTION The Export-ClientCertificate command exports the client certificate from a PKCS12 input store file. .PARAMETER StoreFile Input store file name. .PARAMETER StorePassword Store encryption password. .PARAMETER CertificateFile Output certificate file name. .PARAMETER Overwrite Overwrite the certificate file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Export-ClientCertificate certstore.pfx cert.pem Export the client certificate from input store file 'certstore.pfx'. Output the certificate to file 'cert.pem'. .EXAMPLE Export-ClientCertificate certstore.pfx -StorePassword (Read-Host -Prompt Password -AsSecureString) cert.pem Export the client certificate from input store file 'certstore.pfx'. Prompt for store encryption password. Output the certificate to file 'cert.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input store file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $StoreFile, [Parameter(Mandatory=$false, HelpMessage="Password for store encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $StorePassword, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="Overwrite output certificate file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkcs12") # In argument if ($StoreFile) { if (Test-Path -PathType Container $StoreFile) { Write-Error "Invalid input store file name" Return } elseif (!(Test-Path -PathType Leaf $StoreFile)) { Write-Error "Input store file '$StoreFile' not found" Return } $arguments += "-in" $arguments += "`"$StoreFile`"" } # Passin argument $password = '' if ($StorePassword) { $password = (New-Object PSCredential "User",$StorePassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Nokeys argument $arguments += "-nokeys" # Clcerts argument $arguments += "-clcerts" # Out argument if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid output certificate file name" Return } elseif ((Test-Path -PathType Leaf $CertificateFile) -and (!$Overwrite)) { Write-Error "Certificate file exists (use -Overwrite to overwrite it)" Return } $arguments += "-out" $arguments += "`"$CertificateFile`"" } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } else { Write-Output $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } Function Export-AuthorityCertificate { <# .SYNOPSIS Export authority certificate .DESCRIPTION The Export-AuthorityCertificate command exports the authority certificate from a PKCS12 input store file. .PARAMETER StoreFile Input store file name. .PARAMETER StorePassword Store encryption password. .PARAMETER CertificateFile Output certificate file name. .PARAMETER Overwrite Overwrite the certificate file if it already exists. .PARAMETER OpenSslPath Full path to the OpenSSL executable file. Optional if 'openssl.exe' is already located in the shell's command search path. .EXAMPLE Export-AuthorityCertificate certstore.pfx cert.pem Export the authority certificate from input store file 'certstore.pfx'. Output the certificate to file 'cert.pem'. .EXAMPLE Export-AuthorityCertificate certstore.pfx -StorePassword (Read-Host -Prompt Password -AsSecureString) cert.pem Export the authority certificate from input store file 'certstore.pfx'. Prompt for store encryption password. Output the certificate to file 'cert.pem'. .INPUTS None .OUTPUTS None #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, HelpMessage="Input store file name", ParameterSetName="General", Position=0)] [ValidateNotNullOrEmpty()] [String] $StoreFile, [Parameter(Mandatory=$false, HelpMessage="Password for store encryption", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [SecureString] $StorePassword, [Parameter(Mandatory=$true, HelpMessage="Output certificate file name", ParameterSetName="General", Position=1)] [ValidateNotNullOrEmpty()] [String] $CertificateFile, [Parameter(Mandatory=$false, HelpMessage="Overwrite output certificate file if exists", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [Switch] $Overwrite, [Parameter(Mandatory=$false, HelpMessage="OpenSSL executable file path", ParameterSetName="General")] [ValidateNotNullOrEmpty()] [String] $OpenSslPath ) # OpenSSL executable $opensslexe = "openssl.exe" if ($OpenSslPath) { if (Test-Path -PathType Container $OpenSslPath) { Write-Error "Invalid openssl file name" Return } if (!(Test-Path -PathType Leaf $OpenSslPath)) { Write-Error "Openssl file '$OpenSslPath' not found" Return } $opensslexe = $OpenSslPath } # OpenSSL arguments $arguments = @("pkcs12") # In argument if ($StoreFile) { if (Test-Path -PathType Container $StoreFile) { Write-Error "Invalid input store file name" Return } elseif (!(Test-Path -PathType Leaf $StoreFile)) { Write-Error "Input store file '$StoreFile' not found" Return } $arguments += "-in" $arguments += "`"$StoreFile`"" } # Passin argument $password = '' if ($StorePassword) { $password = (New-Object PSCredential "User",$StorePassword).GetNetworkCredential().Password } $arguments += "-passin" $arguments += "pass:$password" # Nokeys argument $arguments += "-nokeys" # Clcerts argument $arguments += "-cacerts" # Output file if ($CertificateFile) { if (Test-Path -PathType Container $CertificateFile) { Write-Error "Invalid output certificate file name" Return } elseif ((Test-Path -PathType Leaf $CertificateFile) -and (!$Overwrite)) { Write-Error "Certificate file exists (use -Overwrite to overwrite it)" Return } } # Verbose output Write-Verbose "Command:`n`nopenssl $([RegEx]::Replace($arguments, 'pass:[^\s].* ', 'pass:*** '))`n`n" # Run command $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "$opensslexe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $arguments $pinfo.WorkingDirectory = Convert-Path . $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $pinfo $proc.Start() | Out-Null $proc.WaitForExit(10000) | Out-Null $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() # Check errors if ($proc.ExitCode) { Write-Error $stderr } elseif (!($stdout | Select-String "BEGIN" -SimpleMatch -Quiet)) { Write-Error "Store contains no authority certificate" } else { Set-Content $CertificateFile $stdout } # Verbose output Write-Verbose "Output:`n`n$stdout`n`n" Write-Verbose "Errors:`n`n$stderr`n`n" } |