src/TLS.ps1
# . $PSScriptRoot\WSL.ps1 $CaRootDir = Join-Path -Path $env:DEVOPTOOLS_HOME ca root $CaSubDir = Join-Path -Path $env:DEVOPTOOLS_HOME ca sub function New-RootCA() { [CmdletBinding()] param() if (Test-CA -Root $CaRootDir -Name root_ca) { Write-Warning 'Root CA already exists (skipping)' return } $rootCa = Initialize-CA -Root $CaRootDir -Name root_ca $script = "$PSScriptRoot\CA\create_root.sh" | ConvertTo-WSLPath bash $script --home $rootCa.Home } function New-SubordinateCA() { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Name, [string[]] $PermittedDNS ) if (-not (Test-CA -Root $CaRootDir -Name root_ca)) { Write-Warning 'Subordinate CA cannot be created without a root CA (creating)' New-RootCA } if (Test-CA -Root $CaSubDir -Name $Name) { Write-Warning "Subordinate CA with name '$Name' already exists (skipping)" return } $subCa = Initialize-CA -Root $CaSubDir -Name $Name $subCaExt = @" [sub_ca_ext] authorityKeyIdentifier = keyid:always basicConstraints = critical,CA:true,pathlen:0 extendedKeyUsage = serverAuth,clientAuth keyUsage = critical,keyCertSign,cRLSign subjectKeyIdentifier = hash "@ if ($PermittedDNS) { $subCaExt += @" nameConstraints = @name_constraints [name_constraints] excluded;IP.0 = 0.0.0.0/0.0.0.0 excluded;IP.1 = 0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0 $(($PermittedDNS | ForEach-Object { 'permitted;DNS.' + $i++ + " = $_" }) -join [System.Environment]::NewLine) "@ } Out-File -FilePath "$CaRootDir/root_ca/include/sub_ca_ext.conf" -InputObject $subCaExt $script = "$PSScriptRoot\CA\create_sub.sh" | ConvertTo-WSLPath bash $script ` --home $subCa.Home ` --home-root (Join-Path $CaRootDir root_ca | ConvertTo-WSLPath) ` --name $Name } function Get-SuboridinateCAName() { Get-ChildItem $CaSubDir -Name } function New-Certificate() { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Issuer, [Parameter(Mandatory)] [string] $Request, [ValidateSet('server', 'client')] [string] $Type = 'server', [string] $Name = 'tls', [string] $Destination = $(Resolve-Path .) ) if (-not (Test-CA -Root $CaSubDir -Name $Issuer)) { Write-Error "Subordinate CA '$Issuer' does not exist!" return } if (-not (Test-Path $Request)) { Write-Error "Request file '$Request' does not exist!" return } if (-not (Test-Path $Destination)) { New-Item $Destination -ItemType Directory 1> $null } $script = "$PSScriptRoot\CA\new_cert.sh" | ConvertTo-WSLPath bash $script ` --home (Join-Path $CaSubDir $Issuer | ConvertTo-WSLPath) ` --home-root (Join-Path $CaRootDir root_ca | ConvertTo-WSLPath) ` --request (ConvertTo-WSLPath -Path $Request) ` --destination (ConvertTo-WSLPath -Path $Destination) ` --name $Name ` --type $Type Remove-Item $Destination\$Name.csr -ErrorAction Ignore } function Install-RootCA() { $certPath = Join-Path -Path $CaRootDir root_ca ca.crt Install-Certificate -Path $certPath -StoreName Root -FriendlyName 'DevOpTools Development Root CA' } function Uninstall-RootCA() { $certPath = Join-Path -Path $CaRootDir root_ca ca.crt Uninstall-Certificate -Path $certPath -StoreName Root } function Install-Certificate() { [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [string]$StoreName, [string]$FriendlyName ) $storeLocation = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser $store = [System.Security.Cryptography.X509Certificates.X509Store]::new($StoreName, $storeLocation) if (-not $?) { Write-Error "Failed to access the $storeLocation\$StoreName certificate store!" return } $openFlag = [System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite $store.open($openFlag) if (-not $?) { Write-Error "Failed to open the $storeLocation\$StoreName certificate store with $openFlag privileges!" return } try { $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Path) if ($FriendlyName) { $cert.FriendlyName = $FriendlyName } $store.Add($cert) } finally { $store.Close() } return $cert } function Uninstall-Certificate() { param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [string]$StoreName ) $storeLocation = [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser $store = [System.Security.Cryptography.X509Certificates.X509Store]::new($StoreName, $storeLocation) if (-not $?) { Write-Error "Failed to access the $storeLocation\$StoreName certificate store!" return } $openFlag = [System.Security.Cryptography.X509Certificates.OpenFlags]::MaxAllowed $store.open($openFlag) if (-not $?) { Write-Error "Failed to open the $storeLocation\$StoreName certificate store with $openFlag privileges!" return } try { $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Path) $store.Remove($cert) } finally { $store.Close() } } function Test-CA() { [OutputType([bool])] param( [Parameter(Mandatory)] [string]$Root, [Parameter(Mandatory)] [string]$Name ) return [bool](Test-Path (Join-Path -Path $Root $Name ca.pfx)) } function Initialize-CA() { param( [Parameter(Mandatory)] [string]$Root, [Parameter(Mandatory)] [string]$Name ) $caHome = Join-Path $Root $Name Write-Verbose "Initializing CA '$Name' at '$caHome'" Remove-Item -Recurse -Force $caHome -ErrorAction Ignore $certs = Join-Path $caHome certs $db = Join-Path $caHome db $private = Join-Path $caHome private $include = Join-Path $caHome include New-Item $certs, $db, $private, $include -ItemType Directory 1> $null $dbIndex = Join-Path $db index New-Item $dbIndex -ItemType File 1> $null return [PSCustomObject]@{ Home = ConvertTo-WSLPath $caHome } } |