Skip to content

Instantly share code, notes, and snippets.

@jrotello
Last active December 15, 2023 20:15
Show Gist options
  • Save jrotello/e3a744334f6324fcea32a6ec3941e0a2 to your computer and use it in GitHub Desktop.
Save jrotello/e3a744334f6324fcea32a6ec3941e0a2 to your computer and use it in GitHub Desktop.
A PowerShell module to ease creating a certificate authority and intermediate authority for development purposes
function New-SelfSignedRootCertificate {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $Name,
[Parameter(Mandatory = $true)]
[string] $CertStoreLocation,
[Parameter()]
[datetime] $NotAfter = (Get-Date).AddYears(50)
)
$cert = New-SelfSignedCertificate `
-Subject "$Name Certificate Authority" `
-FriendlyName "$Name Certificate Authority" `
-CertStoreLocation $CertStoreLocation `
-KeyUsage KeyEncipherment, DataEncipherment, CertSign `
-KeyUsageProperty Sign `
-HashAlgorithm SHA256 `
-KeyLength 4096 `
-TextExtension @("2.5.29.19 ={critical}{text}CA=1&pathlength=3") `
-NotAfter $NotAfter
Get-Item "Cert:\LocalMachine\CA\$($cert.Thumbprint)" | Move-Item -Destination Cert:\LocalMachine\Root -ErrorAction Stop | Out-Null
Write-Output $cert
}
function New-SelfSignedIntermediateCertificate {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $Name,
[Parameter(Mandatory = $true)]
[string] $CertStoreLocation,
[Parameter(Mandatory = $true)]
[System.Security.Cryptography.X509Certificates.X509Certificate2] $SigningCertificate,
[Parameter()]
[datetime] $NotAfter = (Get-Date).AddYears(25)
)
$cert = New-SelfSignedCertificate `
-Subject "$Name Intermediate Authority" `
-FriendlyName "$Name Intermediate Authority" `
-CertStoreLocation $CertStoreLocation `
-Signer $SigningCertificate `
-KeyUsage KeyEncipherment, DataEncipherment, CertSign `
-KeyUsageProperty Sign `
-HashAlgorithm SHA256 `
-KeyLength 4096 `
-TextExtension @("2.5.29.19 ={critical}{text}CA=1&pathlength=0") `
-NotAfter $NotAfter
Write-Output $cert
}
function Install-SelfSignedDevelopmentCertificateAuthority {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[securestring]$PrivateKeyPassword,
[Parameter()]
[switch]$NoEndEntityCertificate
)
$root = New-SelfSignedRootCertificate -Name $Name -CertStoreLocation Cert:\LocalMachine\My
Write-Host "Root Certificate = Cert:\LocalMachine\Root\$($root.Thumbprint)" -ForegroundColor Cyan
$intermediate = New-SelfSignedIntermediateCertificate -Name $Name -CertStoreLocation Cert:\LocalMachine\My -SigningCertificate $root
Write-Host "Intermediate Certificate = Cert:\LocalMachine\CA\$($intermediate.Thumbprint)" -ForegroundColor Cyan
if (-not $NoEndEntityCertificate) {
$edge = New-SelfSignedCertificate `
-CertStoreLocation Cert:\LocalMachine\My `
-DnsName "localhost", $env:COMPUTERNAME `
-NotAfter (Get-Date).AddYears(5) `
-FriendlyName "Local Development Certificate" `
-Signer $intermediate
Write-Host "End Entity Certificate = Cert:\LocalMachine\My\$($edge.Thumbprint)" -ForegroundColor Cyan
}
$keydir = "$env:USERPROFILE\.$($name.ToLower() -replace ' ')"
if (-not (Test-Path $keydir)) { mkdir $keydir | Out-Null }
Write-Host -NoNewline "Exporting key material to '$keydir'..."
@($intermediate, $root) | ForEach-Object {
Export-PfxCertificate -Cert $_ -FilePath "$keydir\$($_.Subject -replace 'CN=','').pfx" -Password $PrivateKeyPassword | Out-Null
Remove-Item $_.PSPath -DeleteKey | Out-Null
}
Write-Host Done!
}
# WIP
# function Uninstall-SelfSignedDevelopmentCertificateAuthority {
# [CmdletBinding()]
# param(
# [Parameter(Mandatory = $true)]
# [string]$Name
# )
# $root = Get-ChildItem Cert:\LocalMachine\ -Recurse -DnsName "$Name Certificate Authority"
# $intermediate = Get-ChildItem Cert:\LocalMachine -Recurse | Where-Object Issuer -eq $root[0].Subject
# $edge = Get-ChildItem Cert:\LocalMachine\My, Cert:\CurrentUser\My `
# | Where-Object Issuer -eq $intermediate[0].Subject
# $edge + $intermediate + $root | ForEach-Object { Write-Verbose "Removing $($_.PSPath)" | Remove-Item $_ }
# }
Export-ModuleMember -Function *
@volkankaban
Copy link

Can we use it under windows 10 localhost?

@jrotello
Copy link
Author

jrotello commented Nov 8, 2021

That is how I used it. I haven't used in quite sometime though. I just use dotnet dev-certs to generate my dev certificate now.

@volkankaban
Copy link

volkankaban commented Nov 9, 2021

That is how I used it. I haven't used in quite sometime though. I just use dotnet dev-certs to generate my dev certificate now.

Thanks for your response. I'm using windows 11 and, getting a blank screen when I run your .psm1 module with Powershell. Are you able to set up default values for everyone who wants to use it for iis, or apache, or any other platforms? My goal is to create one self-signed certificate for multiple localhost domains without OpenSSL, mkcert, or any other 3rd party.

ex: "localhost","dev.volkankaban","app.volkankaban","dev.leads","dev.members","127.0.0.1","::1"

I created another gist, and modified your current module. https://gist.github.com/volkankaban/16863cba8545eea6d2ec3b1f465e7f13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment