Skip to content

Instantly share code, notes, and snippets.

@magnuswatn
Created June 23, 2022 16:46
Show Gist options
  • Save magnuswatn/f53ebf304f877850f2a362361d5e279c to your computer and use it in GitHub Desktop.
Save magnuswatn/f53ebf304f877850f2a362361d5e279c to your computer and use it in GitHub Desktop.
New-CSR.ps1
<#
.Synopsis
Script som genererer en CSR for et SSL/TLS-sertifikat.
.DESCRIPTION
Scriptet genererer en nøkkel og CSR på lokal maskin, for innsendelse til en CA.
Som standard vil det genereres en RSA-nøkkel (2048 bits) som vil være eksporterbar
og legges i LocalMachine-storen, men dette kan endres med -ECDSA, -CurrentUser og -NotExportable.
Vær obs på at nøkkelen blir en såkalt "CNG-nøkkel", så noe eldre programvare kan
få problemer med dette. Men det er på tide å støtte det nå altså.
.NOTES
Author : Magnus Watn
#>
using namespace System.Security.Cryptography
param(
[String[]]$dnsNames,
[System.Net.Dns[]]$ipAddresses,
[switch] $ECDSA,
[switch] $CurrentUser,
[switch] $NotExportable,
[switch] $NoSubject
)
$ErrorActionPreference = "Stop"
if ($dnsNames.Length -gt 0) {
[string]$DistinguishedName = "CN=$($dnsNames[0])"
}
elseif ($ipAddresses.Length -gt 0) {
[string]$DistinguishedName = "CN=$($ipAddresses[0])"
}
else {
throw New-Object System.ArgumentException "Either -dnsNames or -ipAdresses must be specified"
}
if ($NoSubject) {
[string]$DistinguishedName = $null
}
$keyCreationParamters = [CngKeyCreationParameters]::new()
if (!$CurrentUser) {
$keyCreationParamters.KeyCreationOptions = [CngKeyCreationOptions]::MachineKey
}
if (!$NotExportable) {
$keyCreationParamters.ExportPolicy = [CngExportPolicies]::AllowExport
}
try {
if ($ECDSA) {
$key = [CngKey]::create(
[CngAlgorithm]::ECDsaP256,
[Guid]::NewGuid().toString(),
$keyCreationParamters
)
}
else {
$keyCreationParamters.Parameters.Add(
[CngProperty]::new(
"Length",
[System.BitConverter]::GetBytes(2048),
[CngPropertyOptions]::None
)
)
$key = [CngKey]::create(
[CngAlgorithm]::Rsa,
[Guid]::NewGuid().toString(),
$keyCreationParamters
)
}
}
catch [CryptographicException] {
if (!$CurrentUser -and "Access denied.`r`n" -eq $_.ToString()) {
throw "Access denied: try running as admin"
}
throw $_
}
if ($ECDSA) {
$csr = [X509Certificates.CertificateRequest]::new(
$DistinguishedName,
[ECDsaCng]::new($key),
[HashAlgorithmName]::SHA256
)
}
else {
$csr = [X509Certificates.CertificateRequest]::new(
$DistinguishedName,
[RSACng]::new($key),
[HashAlgorithmName]::SHA256,
[RSASignaturePadding]::Pkcs1
)
}
$sanBuilder = [X509Certificates.SubjectAlternativeNameBuilder]::new()
foreach ($dnsName in $dnsNames) {
$sanBuilder.AddDnsName($dnsName)
}
foreach ($ipAddress in $ipAddresses) {
$sanBuilder.AddIpAddress($ipAddress)
}
# SAN-utvidelsen skal være kritisk hvis
# vi ikke har med emne i sertifikatet.
$sanExt = $sanBuilder.Build($NoSubject)
$csr.CertificateExtensions.Add($sanExt)
# Vi må genererer et selvsignert sertifikat
# og lagre i storen, så Windows skjønner
# at det ferdige sertifikatet skal kobles
# opp mot nøkkelen.
$cert = $csr.CreateSelfSigned(
[System.DateTimeOffset]::UtcNow,
[System.DateTimeOffset]::UtcNow.AddYears(1)
)
if ($CurrentUser) {
$store = [X509Certificates.StoreLocation]::CurrentUser
}
else {
$store = [X509Certificates.StoreLocation]::LocalMachine
}
$store = [X509Certificates.X509Store]::new(
"REQUEST",
$store
)
$store.open([X509Certificates.OpenFlags]::ReadWrite)
try {
$store.add($cert)
}
finally {
$store.close()
}
$base64encodedCsr = [Convert]::ToBase64String($csr.CreateSigningRequest())
$pemCsr = "-----BEGIN CERTIFICATE REQUEST-----`r`n"
$i = 0
foreach ($char in $base64encodedCsr.ToCharArray()) {
if ($i -eq 64) {
$pemCsr += "`r`n$char"
$i = 0
}
else {
$pemCsr += $char
}
$i += 1
}
$pemCsr += "`r`n-----END CERTIFICATE REQUEST-----"
Write-Output "Generated key and CSR:"
Write-Output ""
Write-Output $pemCsr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment