This script creates a self-signed certificate for document signing from Windows PowerShell 5.1, with the class X509CertificateGenerator of the library: an RSA 2048 bits key or an ECDSA key (NIST P-256), the key usages of a signing certificate, saved in a PFX file protected by a password and, next to it, the public part in a .cer file.

How to run it

powershell -ExecutionPolicy Bypass -File createCertificate.ps1 my.pfx -Subject "CN=John Smith, O=Company, E=john@example.com"
powershell -ExecutionPolicy Bypass -File createCertificate.ps1 ecdsa.pfx -Ecdsa -ValidityDays 730 -PfxPassword "S3cret!"

Then sign with it, for example: signPdfFile.ps1 test.pdf -PfxFile my.pfx -PfxPassword 123456.

The script

<#
.SYNOPSIS
    Creates a self-signed PFX certificate for document signing (Windows PowerShell 5.1, SignLib for .NET Framework).

.DESCRIPTION
    Creates a self-signed certificate (RSA or ECDSA key) with the key usages of a document signing certificate, and saves it in a
    PFX file protected by a password. The public part of the certificate is saved next to it, in a .cer file that can be shared.
    The certificate can sign PDF, CAdES, XML and Office documents, or it can be installed in the Windows certificate store.
    It is meant for testing and for internal use: the other computers do not trust it unless it is installed on them.
    Library manual: https://www.signfiles.com/manuals/signature-library/

.PARAMETER PfxFile        The PFX file to create. Default: certificate[new].pfx in the current folder.
.PARAMETER PfxPassword    The password of the PFX file (default: 123456).
.PARAMETER Subject        The subject of the certificate, for example "CN=John Smith, O=Company, E=john@example.com".
.PARAMETER ValidityDays   The validity of the certificate, in days (default: 365). The demo version limits it to 30 days.
.PARAMETER Ecdsa          An ECDSA key (NIST P-256) instead of an RSA 2048 bits key.
.PARAMETER SerialNumber   The serial number of the library (or the environment variable SIGNLIB_SERIAL).

.EXAMPLE
    powershell -ExecutionPolicy Bypass -File createCertificate.ps1 my.pfx -Subject "CN=John Smith, O=Company, E=john@example.com"

.EXAMPLE
    powershell -ExecutionPolicy Bypass -File createCertificate.ps1 ecdsa.pfx -Ecdsa -ValidityDays 730 -PfxPassword "S3cret!"
#>
[CmdletBinding()]
param(
    [Parameter(Position = 0)][string]$PfxFile = 'certificate[new].pfx',
    [string]$PfxPassword = '123456',
    [string]$Subject = 'CN=Self signed certificate, OU=Organization Unit, E=selfsigned@email.com',
    [int]$ValidityDays = 365,
    [switch]$Ecdsa,
    [string]$SerialNumber
)

$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'SignLibCommon.ps1')

try
{
    Initialize-SignLib

    $generator = New-Object SignLib.Certificates.X509CertificateGenerator (Get-SerialNumber $SerialNumber)

    # The validity period. On the demo version of the library it is limited to 30 days.
    $generator.ValidFrom = [DateTime]::Now
    $generator.ValidTo = [DateTime]::Now.AddDays($ValidityDays)

    if ($Ecdsa)
    {
        # For an ECDSA key the size is given by the elliptic curve.
        $generator.KeyAlgorithm = [SignLib.Certificates.KeyAlgorithm]::ECDSA
        $generator.EllipticCurve = [SignLib.Certificates.EllipticCurve]::NistP256
        $generator.SignatureAlgorithm = [SignLib.Certificates.SignatureAlgorithm]::SHA256WithECDSA
    }
    else
    {
        $generator.KeySize = [SignLib.Certificates.KeySize]::KeySize2048Bit
        $generator.SignatureAlgorithm = [SignLib.Certificates.SignatureAlgorithm]::SHA256WithRSA
    }

    $generator.Subject = $Subject

    # The key usages and the enhanced key usages of a certificate used to sign documents.
    $generator.Extensions.AddKeyUsage([SignLib.Certificates.CertificateKeyUsage]::DigitalSignature)
    $generator.Extensions.AddKeyUsage([SignLib.Certificates.CertificateKeyUsage]::NonRepudiation)
    $generator.Extensions.AddEnhancedKeyUsage([SignLib.Certificates.CertificateEnhancedKeyUsage]::DocumentSigning)
    $generator.Extensions.AddEnhancedKeyUsage([SignLib.Certificates.CertificateEnhancedKeyUsage]::SecureEmail)

    # No root certificate is loaded: the certificate is signed with its own private key (self-signed).
    # The second parameter (isRootCertificate) is false: an end-entity (user) certificate is created.
    Write-Host "Create the certificate..."
    $pfx = $generator.GenerateCertificate($PfxPassword, $false)

    # The PFX file (certificate and private key) and the public part of the certificate (.cer).
    $path = Get-FullPath $PfxFile
    [System.IO.File]::WriteAllBytes($path, $pfx)
    $certificate = [SignLib.Certificates.DigitalCertificate]::LoadCertificate($path, $PfxPassword)
    [System.IO.File]::WriteAllBytes([System.IO.Path]::ChangeExtension($path, '.cer'), $certificate.RawData)

    Write-Host "Certificate file: $PfxFile"
    Write-Host ("Subject: " + $certificate.Subject + ", valid until " + $certificate.NotAfter + ", thumbprint " + $certificate.Thumbprint)
}
catch
{
    Write-SignatureError $_
    exit 1
}

Run the full sample. Save the script as createCertificate.ps1 in the folder PowerShell Scripts of the library download, next to SignLib.dll and SignLibCommon.ps1, and run it in Windows PowerShell 5.1. Without a serial number the library runs in demo mode. Download the library and the samples · User manual

Frequently asked questions

Can I issue the certificate from my own root certificate?

Yes. Call $generator.LoadRootCertificate([IO.File]::ReadAllBytes("root.pfx"), "password") before GenerateCertificate, as in the C# sample.

Will other computers trust the certificate?

No. A self-signed certificate is trusted only where it is installed. It is meant for testing and for internal use.