A self-signed code signing certificate lets you sign code on your own development machine or internal network without purchasing a certificate from a Certificate Authority. It is appropriate for local testing, MSIX package development, PowerShell script signing in controlled environments, and internal enterprise distribution where you manage the trust stores.

A self-signed certificate is not appropriate for distributing software to external users. Without a trusted CA in the chain, Windows shows the same ‘Unknown Publisher’ UAC warning as unsigned software for any user who hasn’t manually trusted your certificate. For public distribution, you need an OV or EV certificate from a trusted CA.

 

When a Self-Signed Certificate Is Appropriate

 

Use case Self-signed works? Notes
Testing signing workflows during development Yes Sign and verify locally without CA cost or validation delays
MSIX/AppX packages for local sideloading Yes Install the cert to your test machine’s trust stores first
PowerShell scripts under AllSigned on controlled machines Yes Deploy the cert to TrustedPublishers via Group Policy or manual import
Internal enterprise distribution (managed machines) Yes Deploy the cert via MDM/Group Policy before deploying software
Public distribution to external users No Users see ‘Unknown Publisher’; get an OV/EV cert from a trusted CA
Commercial software distribution No Requires trusted CA cert; self-signed unacceptable
Windows Hardware Dev Center / driver signing No Requires EV certificate from approved CA

 

The Critical Requirement: Code Signing EKU

A code signing certificate must include the Code Signing Extended Key Usage (EKU), OID 1.3.6.1.5.5.7.3.3. Without this EKU, signtool and other code signing tools will reject the certificate with an error. This is the most common mistake when generating self-signed code signing certificates: generating a general-purpose certificate without the Code Signing EKU, then being surprised when signtool refuses to use it.

Both methods below include the Code Signing EKU in the certificate generation command. Verify the EKU is present in any certificate before attempting to sign.

 

Method 1: PowerShell (Windows, Simplest)

The New-SelfSignedCertificate cmdlet in PowerShell generates a self-signed certificate and stores it directly in the Windows Certificate Store. This is the quickest method on Windows.

 

Step 1: Generate the certificate

# Run PowerShell as Administrator

# Generate a self-signed code signing certificate:

> $cert = New-SelfSignedCertificate `

-Type CodeSigningCert `

-Subject “CN=My Dev Certificate” `

-CertStoreLocation “Cert:\CurrentUser\My” `

-KeyUsage DigitalSignature `

-TextExtension @(“2.5.29.37={text}1.3.6.1.5.5.7.3.3”) `

-NotAfter (Get-Date).AddYears(3)

 

# View the generated certificate:

> $cert | Select-Object Subject, Thumbprint, NotAfter

 

# Note the Thumbprint for use in later steps

 

The -Type CodeSigningCert parameter sets the certificate type, but also include the -TextExtension parameter with the Code Signing OID (1.3.6.1.5.5.7.3.3) explicitly to ensure maximum compatibility with signing tools. Some versions of New-SelfSignedCertificate handle -Type CodeSigningCert differently; the explicit OID inclusion is more reliable.

 

Step 2: Export the certificate for trust store import

# Export the public certificate (no private key) for trust store import:

> Export-Certificate -Cert $cert -FilePath “C:\DevCert\MyDevCert.cer”

 

# Export as PFX with private key for use on other machines:

> $password = ConvertTo-SecureString -String ‘YourPassword’ -Force -AsPlainText

> Export-PfxCertificate -Cert $cert -FilePath “C:\DevCert\MyDevCert.pfx” -Password $password

 

Step 3: Install to trust stores (required for local use)

# Install to Trusted Root CA store (required for chain trust):

# Run as Administrator:

> Import-Certificate -FilePath “C:\DevCert\MyDevCert.cer” `

-CertStoreLocation “Cert:\LocalMachine\Root”

 

# Install to Trusted Publishers store (required for PowerShell AllSigned):

> Import-Certificate -FilePath “C:\DevCert\MyDevCert.cer” `

-CertStoreLocation “Cert:\LocalMachine\TrustedPublishers”

 

# For CurrentUser scope only (no admin required, affects only your user account):

> Import-Certificate -FilePath “C:\DevCert\MyDevCert.cer” `

-CertStoreLocation “Cert:\CurrentUser\Root”

> Import-Certificate -FilePath “C:\DevCert\MyDevCert.cer” `

-CertStoreLocation “Cert:\CurrentUser\TrustedPublishers”

 

Installing a certificate to the LocalMachine\Root store makes it trusted for all users on the machine. Only do this on development machines you control. Never instruct end users to install your self-signed certificate to their trust stores as part of a distribution process: this is a significant security risk and is a technique used by malware to establish trust.

 

Method 2: OpenSSL (Cross-Platform)

OpenSSL can generate a self-signed code signing certificate on Windows, macOS, or Linux. The resulting certificate can be imported into the Windows Certificate Store or used directly with tools that accept PEM or PFX files.

 

Generate the key and certificate

# Generate a 2048-bit RSA private key:

$ openssl genrsa -out mydev.key 2048

 

# Create an OpenSSL config file with Code Signing EKU (mydev.cnf):

# [req]

# distinguished_name = req_distinguished_name

# x509_extensions = v3_cs

# prompt = no

#

# [req_distinguished_name]

# CN = My Dev Certificate

#

# [v3_cs]

# subjectKeyIdentifier = hash

# authorityKeyIdentifier = keyid:always,issuer

# basicConstraints = CA:false

# keyUsage = critical, digitalSignature

# extendedKeyUsage = codeSigning

 

# Generate the self-signed certificate:

$ openssl req -new -x509 -key mydev.key -out mydev.crt -days 1095 -config mydev.cnf

 

# Convert to PFX for use with signtool:

$ openssl pkcs12 -export -out mydev.pfx -inkey mydev.key -in mydev.crt -passout pass:YourPassword

 

# Verify the certificate has the Code Signing EKU:

$ openssl x509 -in mydev.crt -text -noout | grep -A1 ‘Extended Key Usage’

# Should show: Code Signing

 

Import the OpenSSL certificate into Windows

# Import the .crt file to trust stores (PowerShell, run as Admin):

> Import-Certificate -FilePath “.\mydev.crt” `

-CertStoreLocation “Cert:\LocalMachine\Root”

> Import-Certificate -FilePath “.\mydev.crt” `

-CertStoreLocation “Cert:\LocalMachine\TrustedPublishers”

 

# Or use certutil:

> certutil -addstore Root mydev.crt

> certutil -addstore TrustedPublisher mydev.crt

 

Signing Code With Your Self-Signed Certificate

 

Sign a Windows executable with signtool

# Sign using the certificate thumbprint (from step 1):

signtool sign /sha1 YOUR_CERT_THUMBPRINT /fd sha256

/tr http://timestamp.digicert.com /td sha256

/v YourApp.exe

 

# Sign using a PFX file:

signtool sign /f mydev.pfx /p YourPassword /fd sha256

/tr http://timestamp.digicert.com /td sha256

/v YourApp.exe

 

# Verify the signature:

signtool verify /pa /v YourApp.exe

# Note: verification will pass on machines where the cert is trusted.

# On machines without the cert in trust stores, verification fails.

 

Sign a PowerShell script

# Sign a PowerShell script with the self-signed certificate:

> $cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object {$_.Subject -like “*My Dev*”}

> Set-AuthenticodeSignature -FilePath .\MyScript.ps1 -Certificate $cert[0]

-TimestampServer “http://timestamp.digicert.com”

 

# Verify:

> Get-AuthenticodeSignature .\MyScript.ps1

# Status should be: Valid (on machines with the cert in TrustedPublishers)

 

Using a Self-Signed Certificate for MSIX Development

MSIX packages must be signed before they can be installed, even during development. A self-signed certificate is appropriate for development and local testing. The certificate’s Subject must match the Publisher attribute in your Package.appxmanifest exactly.

# Get the exact Subject string from your certificate:

> Get-ChildItem Cert:\CurrentUser\My | Where-Object {$_.Subject -like “*Dev*”}

| Select-Object Subject, Thumbprint

 

# Your appxmanifest Identity element should use this exact Subject string:

# <Identity Name=’com.yourcompany.yourapp’

#          Publisher=’CN=My Dev Certificate’

#          Version=’1.0.0.0′ />

 

# Sign the MSIX package:

signtool sign /sha1 YOUR_CERT_THUMBPRINT /fd sha256 /v YourApp.msix

 

# Install the MSIX on your test machine:

# The certificate must be in LocalMachine\TrustedPeople before installation:

> Import-Certificate -FilePath “.\mydev.cer”

-CertStoreLocation “Cert:\LocalMachine\TrustedPeople”

# Then install normally via Add-AppxPackage or double-click

 

When to Stop Using a Self-Signed Certificate

A self-signed certificate is appropriate while software is in development and distribution is limited to machines you control. The signal to move to a CA-issued certificate is when software moves beyond controlled machines to external users or when any of the following applies:

  • You are ready for public beta testing or general release and users will need to install without manual certificate trust steps
  • Enterprise customers or prospects need to evaluate the software on their managed machines
  • Users are reporting ‘Unknown Publisher’ warnings and you want to eliminate them
  • You need to submit to the Microsoft Store, Hardware Dev Center, or other platform submission processes
  • A security review or compliance framework identifies the absence of a CA-issued certificate as a gap

 

The transition from self-signed to a CA-issued certificate is a normal part of software development. Build your signing workflow with the self-signed certificate so the pipeline is tested and working, then swap in the CA-issued certificate when you are ready for external distribution. The signing commands are the same; only the certificate changes.

 

Frequently Asked Questions

 

Will a self-signed code signing certificate remove the Unknown Publisher warning?

Only on machines where you have manually installed the certificate in the Trusted Root and Trusted Publishers certificate stores. On any other machine, the UAC dialog will still show ‘Unknown Publisher’ and the yellow or orange warning header, because Windows cannot verify the certificate chain to a trusted root. For external users, a self-signed certificate provides no visible improvement over unsigned software. Only a certificate from a trusted public CA (DigiCert, Sectigo, SSL.com, etc.) removes the warning universally.

 

Do I need to include a timestamp when signing with a self-signed certificate?

Including a timestamp is good practice even with a self-signed certificate. A timestamp from a trusted Timestamp Authority records the signing time cryptographically, so the signature remains valid after the self-signed certificate expires. Without a timestamp, when the certificate’s validity period ends, the signature becomes invalid. Most trusted timestamp servers are free to use and the command is simply an additional flag in the signtool or Set-AuthenticodeSignature command.

 

Can I use a self-signed certificate for MSIX packages?

Yes, for development and local testing. Before installing a self-signed MSIX on a test machine, install the certificate to the LocalMachine\TrustedPeople store (for MSIX installation) and optionally to LocalMachine\Root and LocalMachine\TrustedPublishers. The Publisher attribute in appxmanifest.xml must exactly match the certificate’s Subject field. For distribution to other users, a CA-issued certificate is required because users cannot install the MSIX without trusting your certificate manually.

 

My signtool command fails saying no certificate found. Why?

The most common causes are: the certificate does not have the Code Signing EKU (1.3.6.1.5.5.7.3.3) and signtool cannot find a valid code signing certificate; the thumbprint specified with /sha1 does not match any certificate in the certificate store; the certificate is in the CurrentUser\My store and you are running signtool in a different user context; or the certificate has expired. Verify with Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert to see all code signing certificates in the current user store.

 

Published: Dec 2022   |   Last Reviewed: May 2026   |   Category: Code Signing / Self-Signed Certificate / PowerShell / OpenSSL / Development

Previous Post
Next Post