10

I'm trying to sign a .ps1 using self-signed certificates (the use case is for scripts I write myself on my private dev station, so no need to use - or pay for - a real CA). However, no matter how many guides on the topic of certificates generation and digital signatures I read, I can't seem to get it working.

Here's what I have accomplished so far:

# Create a certificate to use as trusted root of the signing chain
$root = New-SelfSignedCertificate `
    -Subject "CN=PowerShell Trusted Authority" `
    -FriendlyName "PowerShell Trusted Authority" `
    -KeyUsageProperty Sign `
    -KeyUsage CertSign, CRLSign, DigitalSignature `
    -CertStoreLocation Cert:\LocalMachine\My\ `
    -NotAfter (Get-Date).AddYears(10)

# Create a certificate to use for signing powershell scripts
New-SelfSignedCertificate `
    -Signer $root `
    -Subject "CN=PowerShell Code Signing" `
    -KeyAlgorithm RSA `
    -KeyLength 2048 `
    -Type CodeSigningCert `
    -CertStoreLocation Cert:\LocalMachine\My\

# Move the root cert into Trusted Root CAs
 Move-Item "Cert:\LocalMachine\My\$($root.Thumbprint)" Cert:\LocalMachine\Root

All of the above done from an administrative powershell instance. After that is done, I can see both certificates, in the expected locations, in the management console, and the certificate path of the signing cert checks out as valid.

I then open a regular PS prompt and attempt to sign the script:

# Obtain a reference to the signing certificate
PS> $cert = Get-ChildItem Cert:\LocalMachine\My\ -CodeSigningCert

# Attempt at signing
PS> Set-AuthenticodeSignature .\Microsoft.PowerShell_profile.ps1 $cert


    Directory: C:\Users\tomas\Documents\WindowsPowerShell


SignerCertificate          Status                Path
-----------------          ------                ----
                           UnknownError          Microsoft.PowerShell_profile.ps1

As you can see, the actual signing fails. Looking at the powershell file, I see that no signature has been appended to the script.

If I do the signing from an admin prompt, I seem to get a little further; a signature block is added to the script, and the thumbprint of the signing cert is printed in the output from Set-AuthenticodeSignature, but the status is still UnknownError and execution under the AllSigned policy is still not allowed.

# Output some info about the certificate:
PS> $cert | Format-List

Subject      : CN=PowerShell Code Signing
Issuer       : CN=PowerShell Trusted Authority
Thumbprint   : <omitted>
FriendlyName :
NotBefore    : 9/20/2017 10:48:59 PM
NotAfter     : 9/20/2018 11:08:59 PM
Extensions   : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, 
                System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

I've tried a multitude of variants of New-SelfSignedCertificate incantations, especially to generate the certificate for code signing, but always with the same status message (UnknownError).

My ultimate goal here is to be able to have Set-ExecutionPolicy AllSigned and still run scripts that I've created myself. What am I missing in this process to make that work?

16
  • Interesting. Any more details about the error? Commented Sep 20, 2017 at 21:31
  • @Bill_Stewart: Unfortunately, no. The $Error variable is empty after this failure, and I don't get any other output anywhere that shows why it fails. Any troubleshooting suggestions are very welcome :) Commented Sep 20, 2017 at 21:52
  • What type is the Status property in that output? Commented Sep 20, 2017 at 22:00
  • @Bill_Stewart: It's a System.Management.Automation.SignatureStatus enum value. Commented Sep 20, 2017 at 22:04
  • @Bill_Stewart: More info! When I looked closer at the output (by piping it to Format-List, I got the StatusMessage property too, with value "The certificate is not valid for the requested usage" (in the admin prompt; the non-admin seems to not be able to access the certificate, so I'm abandoning that route). Commented Sep 20, 2017 at 22:06

3 Answers 3

6

Thinking about this, you don't need a certificate chain trust, therefore, you don't need your first certificate. You can use the second certificate and move it into your Trusted Root folder and it will work. Using the first certificate and then creating another certificate seems to fail because the 'root' is self signed and then can't sign another certificate.

SELF SIGNED CERTIFICATE method

# Create a certificate to use for signing powershell scripts
$selfsigncert = New-SelfSignedCertificate `
                -Subject "CN=PowerShell Code Signing" `
                -KeyAlgorithm RSA `
                -KeyLength 2048 `
                -Type CodeSigningCert `
                -CertStoreLocation Cert:\LocalMachine\My\

# Move the root cert into Trusted Root CAs
Move-Item "Cert:\LocalMachine\My\$($selfsigncert.Thumbprint)" Cert:\LocalMachine\Root

# Obtain a reference to the code signing cert in Trusted Root
$selfsignrootcert = "Cert:\LocalMachine\Root\$($selfsigncert.Thumbprint)"

# Sign script
Set-AuthenticodeSignature C:\powershell.ps1 $selfsignrootcert

If you have access to an Enterprise Root CA, you can use the method you have used in your question.

ENTERPRISE ROOT CA method (same method as you have in your question) - you need to know your Root CA certificate thumbprint

# Get Enterprise Root CA thumbprint
$rootcert = get-childitem Cert:\LocalMachine\Root\XXXXXXXXXXXX


# Generate certificate
$fromrootcert = New-SelfSignedCertificate `
                -Signer $rootcert `
                -Subject "CN=PowerShell Code Signing" `
                -KeyAlgorithm RSA `
                -KeyLength 2048 `
                -Type CodeSigningCert `
                -CertStoreLocation Cert:\LocalMachine\My\

# Sign script
Set-AuthenticodeSignature C:\powershell.ps1 $fromrootcert
Sign up to request clarification or add additional context in comments.

7 Comments

Hi Tim - I know this is an old one, but I've just been trying to follow your instructions and I'm getting an error. Error: "The given path's format is not supported." I've re-created the certificate and followed your instructions again but am now stumped. Any ideas?
Hi Ross, are you using the self signed or Enterprise Root CA method? Which cmdlet are you getting the error on? Thanks, Tim.
@RossLyons not sure if you got the response as I didn't tag you. Sorry.
Sorry Tim - just been overwhelmed at work! I'm using the self-signed method.
No worries @RossLyons . Is the cert being generated correctly and being moved from Cert:\LocalMachine\My\cert to Cert:\LocalMachine\Root successfully? Or is that the one you are getting the error on? Thanks, Tim.
|
1
$cert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -Type CodeSigningCert -Subject "Code Signing"

Move-Item -Path $cert.PSPath -Destination "Cert:\CurrentUser\Root"

Set-AuthenticodeSignature -FilePath c:\go.ps1 -Certificate $cert

source https://blogs.u2u.be/u2u/post/creating-a-self-signed-code-signing-certificate-from-powershell

2 Comments

After much pain trying other things, this just works.
But, is it required to move it to Root?
0

I tried the first answer literally; the first 3 commands worked but the last one leads to following error: Set-AuthenticodeSignature: Cannot bind parameter 'Certificate'. Cannot convert value "Cert:\LocalMachine\Root\5B23597B139C09A75DE9BA4F9DA5A4691EDB338B" to type "System.Security.Cryptography.X509Certificates.X509Certificate2". Error: "Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch." (Note that there is no error at all in the .ps1 path, between "") The same errors occurred when I added the flags -filepath and -Certificate Thus, Self-Signing appears to work only for the administrator himself. The only solution to allow other users to run the adm's selfsigned .ps1 seems to be setting ExecutionPolicy to unrestricted…

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.