Signtool allows me to sign code but Set-AuthenticodeSignature says the "certificate is not suitable for code signing"
I had the same problem and the answer I figured out was that I had to create two certificates. First, a trusted root certificate authority using
makecert -n "CN=PowerShell Local Certificate Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine
And then a personal certificate from the above certificate authority using
makecert -pe -n "CN=PowerShell User" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer
Once these are created, use
$cert = @(Get-ChildItem cert:\CurrentUser\My -CodeSigning)[0]
for signing (assuming you have only one codesigning certificate). For example, if the script's name is xyz.ps1, use this command in PowerShell
Set-AuthenticodeSignature path/to/xyz.ps1 $cert
According to get-help certificate -CodeSigningCert
dynamic parameter from the certificate provider gets only those certificates with code-signing authority.
Now why signtool
can sign and not Set-AuthenticodeSignature
, the explanation is maybe in Introduction to Code Signing Microsoft document.
Here is my version of generation of Certification authority :
# Gen-CACert.ps1
clear-host
$scriptBlock = {.\Makecert -n `"CN=PowerShell Authorite de certification`" <# Sujet du certificat (conforme à la norme X50 #>`
-a sha1 <# Algorithme utilisé #>`
-eku 1.3.6.1.5.5.7.3.3 <# Option du certificat (signature de code) #>`
-r <# Certificat auto signé #>`
<# -ss `"$($args[0])`" Dossier de stockage du certificat #>`
-ss `"root`" <# Dossier de stockage du certificat #>`
-sr localMachine <# Magasin de stockage localmachine ou currentuser (defaut) #>`
-sv `"$($args[0]).pvk`" <# Nom du fichier contenant la clef privée #>`
`"$($args[0]).cer`"} <# Nom du fichier certificat #>
$PoshCARoot = "PoshCARoot"
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $PoshCARoot
Here is my version of generation of dev certificate :
# Gen-DevCert.ps1
clear-host
$scriptBlock = {.\Makecert -pe <# La clef privée est exportable #>`
-n `"CN=PowerShell Dev Team`" <# Sujet du certificat (conforme à la norme X509 #>`
-a sha1 <# Algorithme utilisé #>`
-eku 1.3.6.1.5.5.7.3.3 <# Option du certificat (signature de code) #>`
-ss `"My`" <# Dossier de stockage du certificat #>`
-sr currentuser <# Magasin de stockage localmachine ou currentuser (defaut) #>`
-iv `"$($args[0]).pvk`" <# Clef privée de l'autorité #>`
-ic `"$($args[0]).cer`" <# Certificat de l'autorité #>`
`"$($args[1]).cer`"} <# Nom du fichier certificat #>
$PoshCARoot = "PoshCARoot"
$PoshDevTeam = "PoshDevTeam"
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $PoshCARoot,$PoshDevTeam
The issue is the signing certificate is malformed and missing the correct KUs & EKUs.
To resolve, create a self-signed CA using openssl
and the openssl.cnf
linked to below, a code signing ICA signed by the self-signed CA, and finally a code signing cert signed by the ICA
Pre-built openssl.cnf
contains all info & commands required beginning on Line 430:
- Prerequisite:
- Windows: Install OpenVPN (includes
openssl-utils
)
(add to SystemPATH
:%ProgramFiles%\OpenVPN\bin
) - BSD/Linux: Install
openssl
||openssl-utils
|| Compile
- Windows: Install OpenVPN (includes
- Create CA:
# CA key should have a secure passphrase of at least 20 characters, containing # at least 2 uppercase, 2 lowercase, 2 numbers, and 2 symbols # PreReqs: Create files crlnumber, index, rand, & serial mkdir cert crl echo 01 > crl\crlnumber ; echo > index ; echo > rand ; echo 00 > serial # Create CA: openssl req -x509 -new -sha512 -days 3650 -newkey rsa:4096 -keyout "CA.key.pem" -out "CA.crt.pem" -config "openssl.cnf" -extensions v3_ca
- Create ICA:
# ICA key should have a secure passphrase of at least 20 characters, containing # at least 2 uppercase, 2 lowercase, 2 numbers, and 2 symbols # Request: openssl req -out "code-signing-ICA.csr" -new -days 3650 -sha512 -newkey rsa:4096 -keyout "code-signing-ICA.key" -config "openssl.cnf" -extensions v3_signing_ica # Sign: openssl x509 -req -sha512 -days 3650 -in "code-signing-ICA.csr" -CA "CA.crt.pem" -CAkey "CA.key.pem" -CAserial "serial" -out "code-signing-ICA.crt.pem" -extfile "openssl.cnf" -extensions v3_signing_ica # Create Concatenated CA - ICA Cert Chain: # Windows: cmd /c type "code-signing-ICA.crt.pem" "CA.crt.pem" > "code-signing-ICA-Chain.crt.pem" # BSD/Linux: cat "code-signing-ICA.crt.pem" "CA.crt.pem" > "code-signing-ICA-Chain.crt.pem"
- Create Signing Cert:
# Request: openssl req -out "code-signing.csr" -new -days 3650 -sha512 -newkey rsa:2048 -keyout "code-signing.key.pem" -config "openssl.cnf" -extensions v3_codesign # Sign: openssl x509 -req -sha512 -days 3650 -in "code-signing.csr" -CA "code-signing-ICA-chain.crt.pem" -CAkey "code-signing-ICA.key.pem" -CAserial "serial" -out "code-signing.crt.pem" -extfile "openssl.cnf" -extensions v3_codesign # Export: openssl pkcs12 -export -out "code-signing.p12" -inkey "code-signing.key.pem" -in "code-signing.crt.pem" -certfile "code-signing-ICA-chain.crt.pem"
OpenSSL KUs & EKUs
Code signing certificates should have the following set:
-
keyUsage = critical, nonRepudiation, digitalSignature
nonRepudiation
:
Certificate may be used to sign data as above but the certificate public key may be used to provide non-repudiation services
(Prevents the signing entity from falsely denying some action)digitalSignature
:
Certificate may be used to apply a digital signature
(Used for entity authentication & data origin authentication with integrity)
-
extendedKeyUsage = critical, codeSigning, msCodeInd, msCodeCom, mcCTLSign, timeStamping
codeSigning
:
Code SigningmsCodeInd
:
Microsoft Individual Code Signing (authenticode)msCodeCom
:
Microsoft Commerical Code Signing (authenticode)mcCTLSign
:
Microsoft Trust List SigningtimeStamping
:
Trusted Timestamping
SignTool
Prerequisites:
- Install Windows SDK
- +R →
sysdm.cpl
→ OK
Advanced → Environment Variables... → System variables → Path → Edit... - Add to PATH:
%ProgramFiles(x86)%\Windows Kits\10\bin\10.0.15063.0\x64
- Ensure
\10\bin\10.0.15063.0\x64
reflects the proper path for your Windows version
- Ensure
# Establish $TS variable:
Set-Variable -Name TS -Value "http://sha256timestamp.ws.symantec.com/sha256/timestamp" -Scope "Global"
# Sign:
SignTool sign /s "MY" /fd "SHA256" /ph /td "SHA256" /tr $TS "Path\to\File"
sign
:
Sign files using an embedded signature/s
<name>
:
Specify the Store to open when searching for the cert (Default:MY
Store)/fd
:
Specifies the file digest algorithm to use for creating file signatures (Default: SHA1)/ph
:
Generate page hashes for executable files if supported/td
<alg>
:
Used with/tr
or/tseal
to request a digest algorithm used by the RFC3161 timestamp server/tr
<URL>
:
Specifies the RFC3161 timestamp server's URL (warning is generated if timestamping fails)- If
/tr
or/t
is not specified, the signed file will not be timestamped
- If
PowerShell
# Establish $cert variable:
$cert = Get-PfxCertificate -FilePath "Path\to\Signing\Cert"
# Establish $TS variable (if not already set above):
Set-Variable -Name TS -Value "http://sha256timestamp.ws.symantec.com/sha256/timestamp" -Scope "Global"
# Sign:
Set-AuthenticodeSignature -HashAlgorithm "sha256" -IncludeChain "all" -FilePath "File" -Certificate $cert -TimestampServer $TS
Set-AuthenticodeSignature
:
Adds an Authenticode signature to a PowerShell script or other files-HashAlgorithm
:
Specifies hashing algorithm used to compute the digital signature
(PowerShell 2: sha1 || PowerShell 3+: sha256)-IncludeChain
<String>
:
Determines which certs in the chain of trust are included in the digital signature (default:NotRoot
); Acceptable values:Signer
: Includes only the signer's certificateNotRoot
: Includes all certs in the certificate chain, except for the root authorityAll
: Includes all certs in the certificate chain
-Certificate
<X509Certificate>
:
Certificate that will be used to sign the script or file; enter a variable that stores an object representing the certificate or an expression that gets the certificate- To find a cert, use
Get-PfxCertificate
orGet-ChildItem
in the Certificate [Cert:
] drive; command fails if certificate isn't valid or does not havecodeSigning
authority
- To find a cert, use