public/New-CertificateSigningRequest.ps1
<# .SYNOPSIS Create a new Certificate Signing Request. .DESCRIPTION Create a new Certificate Signing Request with EnhancedKeyUsages of "Server Authentication" and "Client Authentication". .PARAMETER CommonName The CommonName for the certificate SubjectName. .PARAMETER Organization The Organization (O) for the certificate SubjectName. .PARAMETER OrganizationalUnit The OrganizationalUnit (OU) for the certificate SubjectName. .PARAMETER Locality The Locality (L) for the certificate SubjectName. .PARAMETER State The State (S) or ProvinceName for the certificate SubjectName. .PARAMETER CountryCode The CountryCode (C) or Region for the certificate SubjectName. .PARAMETER SubjectAlternativeNames A list of SAN DNS Names. .PARAMETER RSAKeyLength Generate and use an RSA key pair of this size for the certificate. .PARAMETER ECDSAKey Generate and use an ECDSA key pair for the certifice. Not yet implemented. .PARAMETER Path A directory path to store the key and csr PEM files. Default is the current directory. .PARAMETER PassThru Optionally send the CSR PEM content to the pipeline. .NOTES https://stackoverflow.com/questions/48196350/generate-and-sign-certificate-request-using-pure-net-framework https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.certificaterequest.-ctor?view=net-8.0 .LINK Join-CertificateWithKey #> function New-CertificateSigningRequest { [CmdletBinding()] [OutputType('string')] [Alias('New-CSR')] param ( [Parameter(Mandatory , Position = 0)] [Alias('CN')] [string] $CommonName, [Parameter(Position = 1)] [String] $Organization, [Parameter(Position = 2)] [Alias('OU')] [String] $OrganizationalUnit, [Parameter()] [Alias('L')] [string] $Locality, [Parameter()] [Alias('S', 'ProvinceName')] [string] $State, [Parameter()] [Alias('C', 'Region')] [string] $CountryCode, [Parameter()] [Alias('SAN')] [string[]] $SubjectAlternativeNames, [Parameter(ParameterSetName = 'RSA')] [ValidateSet(1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360)] [int] $RSAKeyLength, [Parameter(ParameterSetName = 'ECDSA')] [switch] $ECDSAKey, [Parameter()] [string] $Path = $PWD.Path, [Parameter()] [switch] $PassThru ) if ($ECDSAKey) { throw "ECDSA Key support is not yet implemented" } $privateKey = [System.Security.Cryptography.RSA]::Create($RSAKeyLength) $distinguishedNameBuilder = [System.Security.Cryptography.X509Certificates.X500DistinguishedNameBuilder]::new() switch ($PSBoundParameters.Keys) { 'CommonName' { $distinguishedNameBuilder.AddCommonName($CommonName) } 'Organization' { $distinguishedNameBuilder.AddOrganizationName($Organization) } 'OrganizationalUnit' { $distinguishedNameBuilder.AddOrganizationalUnitName($OrganizationalUnit) } 'Locality' { $distinguishedNameBuilder.AddLocalityName($Locality) } 'State' { $distinguishedNameBuilder.AddStateOrProvinceName($State) } 'CountryCode' { $distinguishedNameBuilder.AddCountryOrRegion($CountryCode) } } $dn = $distinguishedNameBuilder.Build() Write-Verbose $dn.Name $request = [System.Security.Cryptography.X509Certificates.CertificateRequest]::new( $dn, $privateKey, [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 ) $request.CertificateExtensions.Add( [System.Security.Cryptography.X509Certificates.X509KeyUsageExtension]::new( ([System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::DigitalSignature -bor [System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::KeyEncipherment), $true)) $oids = [System.Security.Cryptography.OidCollection]::new() $oids.Add([System.Security.Cryptography.Oid]::new("1.3.6.1.5.5.7.3.1")) | Write-Debug # Server Authentication $oids.Add([System.Security.Cryptography.Oid]::new("1.3.6.1.5.5.7.3.2")) | Write-Debug # Client Authentication $enhancedKeyUsage = [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]::new($oids, $false) $request.CertificateExtensions.Add($enhancedKeyUsage) if ($PSBoundParameters.ContainsKey('SubjectAlternativeNames')) { $sanBuilder = [System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder]::new() $SubjectAlternativeNames.ForEach({ $sanBuilder.AddDnsName($_) }) } $request.CertificateExtensions.Add( [System.Security.Cryptography.X509Certificates.X509Extension]::new($sanBuilder.Build(), $false)) $request.CertificateExtensions.Add( [System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension]::new($request.PublicKey, $false)) $fileBaseName = ScrubCommonName -CommonName $CommonName $keyFile = Join-Path -Path $Path -ChildPath "$fileBaseName.key" $csrFile = Join-Path -Path $Path -ChildPath "$fileBaseName.csr" $privateKey.ExportRSAPrivateKeyPem() | Set-Content -Path $keyFile -Encoding Ascii $pem = $request.CreateSigningRequestPem() $pem | Set-Content -Path $csrFile -Encoding Ascii if ($PassThru) { $pem } } |