Skip to content

Instantly share code, notes, and snippets.

@BrandonStiff
Last active August 22, 2022 23:56
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BrandonStiff/d6a1b5ca27b71747b152457af96bff7b to your computer and use it in GitHub Desktop.
Save BrandonStiff/d6a1b5ca27b71747b152457af96bff7b to your computer and use it in GitHub Desktop.
OpenSsl Certificate PowerShell functions
function Invoke-OpenSsl
{
<#
.SYNOPSIS
Invokes a call to the openssl.exe program
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.PARAMETER Parameters
Specifies an array of parameters and values to pass into openssl.exe.
.PARAMETER ShowOutput
If specified, then the output from the openssl command is returned from the function.
#>
param
(
[string] $OpenSslPath,
[string[]] $Parameters,
[switch] $ShowOutput
)
if ( !$OpenSslPath )
{
$OpenSslPath = $script:DefaultOpenSslPath
}
if ( !(Test-Path -Path $OpenSslPath ) )
{
throw ("Unable to find openssl.exe at: $OpenSslPath!")
}
$output = & $OpenSslPath $Parameters
if ( $output )
{
if ( $ShowOutput )
{
$output
}
else
{
Write-Verbose ($output | out-string)
}
}
}
function New-OpenSslCertificate
{
<#
.SYNOPSIS
Generates a new certificate object. This can generate CA, SSL and CSRs.
.PARAMETER Type
Specifies the type of cert to generate: CSR, CA, SSL.
CSR - Certificate Signing Request
CA - Certificate Authority
SSL - Host SSL Cert (Signed by a CA)
.PARAMETER Name
Specifies the name of the entity on the certificate.
.PARAMETER Country
Specifies the country locality (default is US).
.PARAMETER State
Specifies the state locality.
.PARAMETER Company
Specifies the company.
.PARAMETER OrganizationalUnit
Specifies the OU locality.
.PARAMETER EmailAddress
Specifies the email address to associate with the cert.
.PARAMETER KeyLength
Specifies the length of the public key in bits (Default 4096).
.PARAMETER KeyPath
Specifies the path to the private key to be generated. Default is the same folder as -Path, with the name specified by -Name with .key extension.
.PARAMETER Path
Specifies the path to export the certificate to. Default is the current directory, with -Name as the name with extension .csr.
.PARAMETER Digest
Specifies the signing digest. sha256 | sha512 | md5 | sha1 | md2 | mdc2 | md4. Default is SHA512
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.PARAMETER PrivateKeyUnencrypted
Specifies the private key should not be encrytped. By default it will, and you will be prompted for a password.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[string] $Name,
[ValidateSet("CA","CSR","SSL")]
[string] $Type,
[string] $Country,
[string] $State,
[string] $Company,
[string] $OrganizationalUnit,
[string] $EmailAddress,
[Timespan] $Expiration = "3650.00:00:00",
[ValidateSet("DER","PEM")] [string] $OutputFormat = "PEM",
[int] $KeyLength = 2048,
[string] $Path,
[string] $KeyPath,
[ValidateSet("SHA1","SHA256","SHA512","MD5","MD2","MDC2","MD4")] [string] $Digest = "SHA256",
[switch] $PrivateKeyUnencrypted,
[string] $OpenSslPath
)
# Build the Certificate Subject:
$subject = @()
if ( $Country )
{
$subject += "C=$Country"
}
if ( $State )
{
$subject += "ST=$State"
}
if ( $Company )
{
$subject += "O=$Company"
}
if ( $OrganizationalUnit )
{
$subject += "OU=$OrganizationalUnit"
}
if ( $EmailAddress )
{
$subject += "E=$EmailAddress"
}
$subject += "CN=$Name"
$subjectString = "/" + ($subject -join "/")
# Determine the certificate Output Path:
$basePath = (Get-Location)
if ( $Path )
{
$basePath = Split-Path -Path $Path
}
else
{
$fileName = "$Name.pem"
if ( $Type -ieq "CSR" )
{
$fileName = "$Name.csr"
}
elseif ( $OutputFormat -ieq "DER" )
{
$fileName = "$Name.crt"
}
$Path = Join-Path -Path $basePath -ChildPath $fileName
}
if ( !$KeyPath )
{
$KeyPath = Join-Path -Path $basePath -ChildPath "$Name.key"
}
$params = @(
"req",
"-new",
"-outform",
$OutputFormat,
"-$($Digest.ToLower())",
"-newkey",
"rsa:$KeyLength",
"-subj",
$subjectString,
"-keyout",
"`"$KeyPath`"",
"-out",
"`"$Path`""
)
if ( $Type -ieq "CA")
{
$params += "-extensions"
$params += "v3_ca"
$params += "-days"
$params += $Expiration.TotalDays
$params += "-x509"
}
if ( $PrivateKeyUnencrypted )
{
$params += "-nodes"
}
if ( $PSCmdlet.ShouldProcess("Generate certificate type $Type with subject $subjectString.") )
{
Invoke-OpenSsl -Parameters $params -OpenSslPath $OpenSslPath
Get-Item -Path $Path
Get-Item -Path $KeyPath
}
}
function New-OpenSslCertificateRequest
{
<#
.SYNOPSIS
Generates a new certificate signing request (CSR).
.PARAMETER Name
Specifies the name of the entity on the certificate.
.PARAMETER Country
Specifies the country locality (default is US).
.PARAMETER State
Specifies the state locality.
.PARAMETER Company
Specifies the company.
.PARAMETER OrganizationalUnit
Specifies the OU locality.
.PARAMETER EmailAddress
Specifies the email address to associate with the cert.
.PARAMETER KeyLength
Specifies the length of the public key in bits (Default 4096).
.PARAMETER KeyPath
Specifies the path to the private key to be generated. Default is the same folder as -Path, with the name specified by -Name with .key extension.
.PARAMETER Path
Specifies the path to export the certificate to. Default is the current directory, with -Name as the name with extension .csr.
.PARAMETER Digest
Specifies the signing digest. sha256 | sha512 | md5 | sha1 | md2 | mdc2 | md4. Default is SHA512
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.PARAMETER PrivateKeyUnencrypted
Specifies the private key should not be encrytped. By default it will, and you will be prompted for a password.
.OUTPUTS
[System.Io.FileInfo[]]
Outputs the key and certificate files produced.
.EXAMPLE
# Generate a new CSR with unencrypted Private Key:
New-OpenSslCertificateRequest -Name dv-hds-rest-p01.plex.com -Country "US" -State MI -Company "Plex Systems Inc"
Generating a 2048 bit RSA private key
............+++
...+++
writing new private key to 'C:\temp\dv-hds-rest-p01.plex.com.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/22/2017 12:25 PM 985 dv-hds-rest-p01.plex.com.csr
-a---- 5/22/2017 12:25 PM 1834 dv-hds-rest-p01.plex.com.key
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[string] $Name,
[string] $Country,
[string] $State,
[string] $Company,
[string] $OrganizationalUnit,
[string] $EmailAddress,
[int] $KeyLength = 2048,
[string] $Path,
[string] $KeyPath,
[switch] $PrivateKeyUnencrypted,
[ValidateSet("SHA1","SHA256","SHA512","MD5","MD2","MDC2","MD4")] [string] $Digest = "SHA256",
[string] $OpenSslPath
)
New-OpenSslCertificate -Type "CSR" @PSBoundParameters
}
function New-OpenSslCaCertificate
{
<#
.SYNOPSIS
Generates a new self-signed CA Certificate.
.PARAMETER Name
Specifies the name of the entity on the certificate.
.PARAMETER Country
Specifies the country locality (default is US).
.PARAMETER State
Specifies the state locality.
.PARAMETER Company
Specifies the company.
.PARAMETER OrganizationalUnit
Specifies the OU locality.
.PARAMETER EmailAddress
Specifies the email address to associate with the cert.
.PARAMETER Expiration
Specifies how long, as a timespan, the certificate should be good for. Default is 3650.00:00:00 (10 years).
.PARAMETER KeyLength
Specifies the length of the public key in bits (Default 4096).
.PARAMETER OutputFormat
Specify either PEM or DER (Default is PEM).
.PARAMETER KeyPath
Specifies the path to the private key to be generated. Default is the same folder as -Path, with the name specified by -Name with .key extension.
.PARAMETER Path
Specifies the path to export the certificate to. Default is the current directory, with -Name as the name with extension .pem or .cer (depending on the -OutputFormat)
.PARAMETER Digest
Specifies the signing digest. sha256 | sha512 | md5 | sha1 | md2 | mdc2 | md4. Default is SHA512
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.PARAMETER PrivateKeyUnencrypted
Specifies the private key should not be encrytped. By default it will, and you will be prompted for a password.
.OUTPUTS
[System.Io.FileInfo[]]
Outputs the key and certificate files produced.
.EXAMPLE
# Generate a new PEM CA Certificate using 4096 bits SHA512 encryption:
New-CaCertificate -Name "HdsRESTCa.plex.com" -Country US -State MI -Company "Plex Systems Inc" -OutputFormat der -KeyLength 4096 -Path c:\temp\hdsrestca.pem -Digest sha512
Generating a 4096 bit RSA private key
...........................................++
.................................................................................................................................++
writing new private key to 'c:\temp\HdsRESTCa.plex.com.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/22/2017 9:18 AM 1403 hdsrestca.pem
-a---- 5/22/2017 9:18 AM 3406 HdsRESTCa.plex.com.key
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[string] $Name,
[string] $Country,
[string] $State,
[string] $Company,
[string] $OrganizationalUnit,
[string] $EmailAddress,
[Timespan] $Expiration = "3650.00:00:00",
[ValidateSet("DER","PEM")] [string] $OutputFormat = "PEM",
[int] $KeyLength = 2048,
[string] $Path,
[string] $KeyPath,
[ValidateSet("SHA1","SHA256","SHA512","MD5","MD2","MDC2","MD4")] [string] $Digest = "SHA256",
[switch] $PrivateKeyUnencrypted,
[string] $OpenSslPath
)
New-OpenSslCertificate -Type "CA" @PSBoundParameters
}
function Invoke-OpenSslSignCsr
{
<#
.SYNOPSIS
This function signs the given CSR by the given CA certificate.
.PARAMETER Csr
Specifies the path to the CSR to sign.
.PARAMETER CaCertificate
Specifies the CA Certificate to use to sign the request.
.PARAMETER CaPrivateKey
Specifies the CA Private key necessary to sign the request.
.PARAMETER Path
Specifies the path to export the certificate to. Default is the current directory, with -Name as the name with extension .pem or .cer (depending on the -OutputFormat)
.PARAMETER OutputFormat
Specify either PEM or DER (Default is PEM).
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.INPUTS
[System.Io.File] or [string]
You can specify the CSR or the path to the CSR on the pipeline.
.OUTPUTS
[System.Io.File]
Outputs the signed SSL certificate.
.EXAMPLE
# Use a CA Certificate to sign the given CSR:
Invoke-OpenSslSignCsr -Csr C:\temp\dv-hds-rest-p01.plex.com.csr -CaCertificate C:\temp\HdsRESTCa.plex.com.pem -CaCertificatePrivateKey C:\temp\HdsRESTCa.plex.com.key -Path c:\temp\dv-hds-rest-p01.plex.com.crt
Signature ok
subject=/C=US/ST=MI/O=Plex Systems Inc/CN=dv-hds-rest-p01.plex.com
Getting CA Private Key
Enter pass phrase for C:\temp\HdsRESTCa.plex.com.key:
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/22/2017 1:02 PM 1151 dv-hds-rest-p01.plex.com.pem
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string[]] $Csr,
[Parameter(Mandatory=$true)]
[string] $CaCertificate,
[string] $CaCertificatePrivateKey,
[string] $Path,
[ValidateSet("DER","PEM")] [string] $OutputFormat = "PEM",
[string] $OpenSslPath
)
begin
{
# Validate the CA Key and cert:
if ( !(Test-Path -Path $CaCertificate) )
{
throw ("No valid CA certificate exits at $CaCertificate!")
}
if ( $CaCertificatePrivateKey -and !(Test-Path -Path $CaCertificatePrivateKey) )
{
throw ("The CA private key specified at $CaCertificatePrivateKey does not exist!")
}
}
process
{
foreach ( $cs in $csr )
{
if ( Test-Path -Path $cs )
{
# Determine the output path:
$fileName = $Path
if ( !$Path )
{
$fileName = (Get-Item -Path $cs).Name -ireplace (([System.IO.Path]::GetExtension($cs) -ireplace "\.","\."),".pem")
if ( $OutputFormat -ieq "DER" )
{
$fileName = (Get-Item -Path $cs).Name -ireplace (([System.IO.Path]::GetExtension($cs) -ireplace "\.","\."),".crt")
}
$Path = Join-Path -Path (Get-Location) -ChildPath $fileName
}
$params = @(
"x509",
"-req",
"-outform",
$OutputFormat,
"-CA",
"`"$CaCertificate`"",
"-CAkey",
"`"$CaCertificatePrivateKey`"",
"-in",
"`"$cs`"",
"-out",
"`"$Path`"",
"-CAcreateserial"
)
if ( $PSCmdlet.ShouldProcess($cs, "Create SSL certificate from CSR?") )
{
Invoke-OpenSsl -OpenSslPath $OpenSslPath -Parameters $params
Get-Item -Path $Path
}
}
else
{
throw ("There is no CSR at $cs!")
}
}
}
}
function New-OpenSslServerCertificate
{
<#
.SYNOPSIS
Generates a new, signed or self-signed SSL Certificate.
.PARAMETER Name
Specifies the name of the entity on the certificate.
.PARAMETER Country
Specifies the country locality (default is US).
.PARAMETER State
Specifies the state locality.
.PARAMETER Company
Specifies the company.
.PARAMETER OrganizationalUnit
Specifies the OU locality.
.PARAMETER EmailAddress
Specifies the email address to associate with the cert.
.PARAMETER Expiration
Specifies how long, as a timespan, the certificate should be good for. Default is 3650.00:00:00 (10 years).
.PARAMETER KeyLength
Specifies the length of the public key in bits (Default 4096).
.PARAMETER OutputFormat
Specify either PEM or DER (Default is PEM).
.PARAMETER KeyPath
Specifies the path to the private key to be generated. Default is the same folder as -Path, with the name specified by -Name with .key extension.
.PARAMETER Path
Specifies the path to export the certificate to. Default is the current directory, with -Name as the name with extension .pem or .cer (depending on the -OutputFormat)
.PARAMETER Digest
Specifies the signing digest. sha256 | sha512 | md5 | sha1 | md2 | mdc2 | md4. Default is SHA512
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.PARAMETER PrivateKeyUnencrypted
Specifies the private key should not be encrytped. By default it will, and you will be prompted for a password.
.PARAMETER Csr
Specifies the path to the CSR to sign.
.PARAMETER CaCertificate
Specifies the CA Certificate to use to sign the CSR.
.PARAMETER CaCertificateKey
Specifies the CA private key to use to sign the CSR.
.OUTPUTS
[System.Io.FileInfo[]]
Outputs the key and certificate files produced.
.EXAMPLE
# Sign an existing CSR to create a new SSL Certificate:
New-OpenSslServerCertificate -CaCertificate C:\temp\HdsRESTCa.plex.com.pem -CaCertificatePrivateKey C:\temp\HdsRESTCa.plex.com.key
.EXAMPLE
# Create a new CSR and sign in in one step:
New-OpenSslServerCertificate -Name "dv-hds-rest-p01.plex.com" -Country US -State MI -Company "Plex Systems Inc" -CaCertificate C:\temp\HdsRESTCa.plex.com.pem -CaCertificatePrivateKey C:\temp\HdsRESTCa.plex.com.key
Generating a 2048 bit RSA private key
..........+++
....+++
writing new private key to 'C:\temp\dv-hds-rest-p01.plex.com.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Signature ok
subject=/C=US/ST=MI/O=Plex Systems Inc/CN=dv-hds-rest-p01.plex.com
Getting CA Private Key
Enter pass phrase for C:\temp\HdsRESTCa.plex.com.key:
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/22/2017 2:02 PM 1151 dv-hds-rest-p01.plex.com.pem
#>
[CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName="name")]
param
(
[Parameter(ParameterSetName="name")]
[string] $Name,
[Parameter(ParameterSetName="name")]
[string] $Country,
[Parameter(ParameterSetName="name")]
[string] $State,
[Parameter(ParameterSetName="name")]
[string] $Company,
[Parameter(ParameterSetName="name")]
[string] $OrganizationalUnit,
[Parameter(ParameterSetName="name")]
[string] $EmailAddress,
[Parameter(ParameterSetName="name")]
[Timespan] $Expiration = "3650.00:00:00",
[Parameter(ParameterSetName="name")]
[int] $KeyLength = 2048,
[Parameter(ParameterSetName="name")]
[ValidateSet("SHA1","SHA256","SHA512","MD5","MD2","MDC2","MD4")] [string] $Digest = "SHA256",
[Parameter(ParameterSetName="name")]
[switch] $PrivateKeyUnencrypted,
[Parameter(ParameterSetName="name")]
[string] $KeyPath,
[Parameter(ParameterSetName="csr",Mandatory=$true)]
[string] $Csr,
[ValidateSet("DER","PEM")] [string] $OutputFormat = "PEM",
[string] $Path,
[string] $OpenSslPath,
[Parameter(Mandatory=$true)]
[string] $CaCertificate,
[string] $CaCertificatePrivateKey
)
$csrPath = ""
if ( $PSCmdlet.ParameterSetName -ieq "name" )
{
# Generate the new SSL certificate by creating a new CSR and sign it:
$paramNames = (Get-Command -Name New-OpenSslServerCertificate).Parameters.GetEnumerator() | Where-Object { $_.Value.ParameterSets.name -or ($_.Key -iin "Path","KeyPath","OpenSslPath") } | Select-Object -ExpandProperty Key
$params = @{}
foreach ( $param in $PSBoundParameters.GetEnumerator() | Where-Object { $_.Key -iin $paramNames } )
{
$params.Add($param.key, $param.value)
}
$csrFiles = New-OpenSslCertificateRequest @params
if ( $csrFiles )
{
$csrPath = $csrFiles[0]
$csrFiles[1]
}
}
else
{
$csrPath = $csr
}
if ( $PSCMdlet.ShouldProcess("Sign SSL Certificate with CA Certificate $CaCertificate") )
{
if ( !(Test-Path -Path $csrpath) )
{
throw ("Unable to find a valid CSR at $csrPath!")
}
# Sign the CSR:
Invoke-OpenSslSignCsr -Csr $csrPath -CaCertificate $CaCertificate -CaCertificatePrivateKey $CaCertificatePrivateKey -Path $Path
}
}
function Test-OpenSslCertificate
{
<#
.SYNOPSIS
This function tests and returns detailed information about the given SSL certificate or CSR.
.PARAMETER Certificate
Specifies the SSL Certificate to verify.
.PARAMETER Csr
Specifies the .csr to verify.
.PARAMETER OpenSslPath
Specifies the path to the Openssl.exe executable. Default is C:\program files\Git\usr\bin\openssl.exe
.EXAMPLE
# Test all of the .pem certificates:
Get-Item *.pem | Test-OpenSslCertificate
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
eb:29:a8:f8:9e:72:b5:77
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=MI, O=Plex Systems Inc, CN=HdsRESTCa.plex.com
Validity
Not Before: May 22 14:28:36 2017 GMT
Not After : May 20 14:28:36 2027 GMT
Subject: C=US, ST=MI, O=Plex Systems Inc, CN=HdsRESTCa.plex.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:d6:58:01:aa:a1:58:79:39:7b:bf:ec:fd:e4:39:
...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
98:0F:7F:E9:6C:78:69:5F:6C:54:77:9E:0B:D9:1E:C3:98:47:BF:8A
X509v3 Authority Key Identifier:
keyid:98:0F:7F:E9:6C:78:69:5F:6C:54:77:9E:0B:D9:1E:C3:98:47:BF:8A
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
5b:5c:42:30:04:91:5f:df:3d:56:89:d8:60:d7:ab:f8:35:f8:
#>
[CmdletBinding(DefaultParameterSetName="certificate")]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="certificate")]
[string[]] $Certificate,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="csr")]
[string[]] $Csr,
[string] $OpenSslPath
)
begin
{
$collection = @()
$openSslParams = @()
if ( $PSCmdlet.ParameterSetName -ieq "csr" )
{
$openSslParams = @(
"req",
"-verify"
)
}
else
{
$openSslParams = @(
"x509"
)
}
}
process
{
if ( $PSCmdlet.ParameterSetName -ieq "csr" )
{
$collection += $Csr
}
else
{
$collection += $Certificate
}
$openSslParams += "-text"
$openSslParams += "-noout"
}
end
{
foreach ( $obj in $collection )
{
$finalParams = $openSslParams + @("-in","`"$obj`"")
Invoke-OpenSsl -OpenSslPath $OpenSslPath -Parameters $finalParams -ShowOutput
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment