PSCredentialStore/src/Certificate/New-CSCertificate.ps1

137 lines
4.8 KiB
PowerShell

function New-CSCertificate {
<#
.SYNOPSIS
Creates a new PFX certificate for the CredentialStore encryption.
.DESCRIPTION
Use this function to create a custom self signed certificate used by the PSCredentialStore module.
.PARAMETER CRTAttribute
Provide certificate related attributes provided by function New-CRTAttribute.
.PARAMETER KeyName
Provide a custom full path and name for the private key. The file extension has to be `*.key`.
.PARAMETER CertName
Provide a custom full path and name for the PFX certificate file. The file extension has to be `*.pfx`
.INPUTS
[PSCredentialStore.Certificate.Attribute]
.OUTPUTS
[None]
.EXAMPLE
New-CSCertificate -CRTAttribute $CRTAttribute -KeyName './myprivate.key' -CertName './mycert.pfx'
#>
[CmdletBinding(SupportsShouldProcess = $true)]
[OutputType()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ValidateNotNullOrEmpty()]
[PSTypeName('PSCredentialStore.Certificate.Attribute')]$CRTAttribute,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$KeyName = './private.key',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$CertName = './certificate.pfx'
)
begin {
$ModuleBase = Get-ModuleBase
if ($isLinux -or $isMacOS) {
try {
$openssl = Get-Command -Name 'openssl' -ErrorAction Stop
}
catch {
$_.Exception.Message | Write-Error
$ErrorParams = @{
Message = 'Can not find the openssl binary!'
ErrorAction = 'Stop'
Exception = [System.IO.FileNotFoundException]::new()
}
Write-Error @ErrorParams
}
}
elseif (($PSVersionTable.PSEdition -eq 'Desktop' -and $PSVersionTable.PSVersion.Major -lt 6) -or ($IsWindows -eq $true)) {
$openssl = Join-Path -Path $ModuleBase -ChildPath '/Vendor/libressl255/openssl.exe'
}
$Env:OPENSSL_CONF = Join-Path $ModuleBase -ChildPath '/openssl.conf'
}
process {
$SubjPattern = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}"
$SubjValues = @(
$CRTAttribute.Subject.Country,
$CRTAttribute.Subject.State,
$CRTAttribute.Subject.City,
$CRTAttribute.Subject.Organization,
$CRTAttribute.Subject.OrganizationalUnitName,
$CRTAttribute.Subject.CommonName
)
$Subj = $SubjPattern -f $SubjValues
$PEMCertName = $CertName -replace '.pfx', '.crt'
$ExpPattern = '& ''{0}'' req -x509 -sha256 -nodes -days {1} -newkey rsa:2048 -keyout {2} -out {3} -subj "{4}" *>$null'
$ExpValues = @(
$openssl,
$CRTAttribute.Days
$KeyName,
$PEMCertName,
$Subj
)
$PEMExp = $ExpPattern -f $ExpValues
Write-Verbose -Message ( 'Expr string is: {0}' -f $PEMExp)
# Edit the Error action for the openSLL command to make the redirect *>$null work.
# There is always a stderr and stdout stream!
$EAP = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
Invoke-Expression -Command $PEMExp
$ErrorActionPreference = $EAP
# manually testing the openssl command results
if (! (Test-Path -Path $KeyName)) {
$ErrorParams = @{
Message = 'Could not create the private key ${0}' -f $KeyName
ErrorAction = 'Stop'
Exception = [System.UnauthorizedAccessException]::new()
}
Write-Error @ErrorParams
}
if (! (Test-Path -Path $PEMCertName)) {
$ErrorParams = @{
Message = 'Could not create the PEM certificate ${0}' -f $PEMCertName
ErrorAction = 'Stop'
Exception = [System.Exception]::new()
}
Write-Error @ErrorParams
}
$PfxPattern = '& ''{0}'' pkcs12 -export -out {1} -inkey {2} -in {3} -passout pass:'
$PfxValues = @(
$openssl,
$CertName,
$KeyName,
($CertName -replace '.pfx', '.crt')
)
$PfxExp = $PfxPattern -f $PfxValues
Write-Verbose -Message ( 'PfxExp string is: {0}' -f $PfxExp)
Invoke-Expression -Command $PfxExp
# Remove private key and crt file. Always ask user
Remove-Item -Path $KeyName
Remove-Item -Path ($CertName -replace '.pfx', '.crt')
}
end {
Remove-Item Env:\OPENSSL_CONF -Confirm:$False -Force -ErrorAction SilentlyContinue
}
}