PowerShell / PowerShell/PowerShell

Get-AuthenticodeSignature needs to use embedded signatures

Open
#23,820 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

In-PR Issue-Enhancement Needs-Triage WG-Reviewed WG-Security
Dominant language
C#
Stars
55.5k
Forks
8.5k
Avg merge
1d 2h
Merged PRs (30d)
88

Description

Summary of the new feature / enhancement

TL;DR we need Get-AuthenticodeSignature to consider embedded (Authenticode) signatures even if the file is catalog signed. This is continuation of #8401 but with some new context.

Rationale

Windows ships with a boot manager signed by “Microsoft Windows Production PCA 2011” certificate. This certificate is associated with known security issues, and will eventually be revoked from UEFI, rendering the old boot manager unusable. Therefore, Windows updates distribute a new boot manager signed by “Windows UEFI CA 2023” certificate. This boot manager is meant to eventually replace the old boot manager on all machines.

Because there are a lot of moving parts in the process (OS updates, UEFI trust list, OEMs, 3rd party boot loaders and UEFI modules, etc.) the process of replacing the boot manager is convoluted and spans across multiple phases. Not everyone gets the new boot manager at once, and it's not always safe to have it replaced on your machine right away. Extreme caution is advised.

With that, users have a legitimate need to know how this or that boot file is signed.

Details

The issue is easy to illustrate since both old and new boot managers are present on a sufficiently up to date Windows machine.

  • copy of the original boot manager is located at C:\Windows\Boot\EFI\bootmgfw.efi
  • the updated boot manager is placed to C:\Windows\Boot\EFI_EX\bootmgfw_EX.efi

(However, worth noting that the problem is not limited to just these two particular files, since other boot loaders and UEFI modules may be present on the machine which need to be assessed.)

The easiest way to check the signature is GUI. File properties in Windows Explorer do reflect the differences in signatures correctly, and it is currently documented as the only way a user can validate those signatures. (Scroll down the page and expand “Step 2: Install the PCA2023-signed boot manager” section to see that guidance.)

image

There are a lot of obvious reasons why GUI is not a great choice for this task. For instance, one cannot use Windows Explorer to peek into EFI system partition (ESP). Therefore, official documentation includes a multi-step process which includes assigning a temporary drive letter to that partition and using command line tools to copy the file over, and only after that using Explorer to observe the properties of the copy. This is highly inefficient, not scalable and error prone. Ideally, it should be one or two lines in PowerShell to validate the actual boot manager in use.

Unfortunately, the Windows boot files are dual-signed, and the catalog signature is not updated in the new boot manager. (Perhaps because UEFI only cares for the embedded signature.) Therefore, Get-AuthenticodeSignature is not very helpful here.

PS C:\Users\artemp> $old = Get-Item -Path 'C:\Windows\Boot\EFI\bootmgr.efi'
PS C:\Users\artemp> Get-AuthenticodeSignature -FilePath $old.FullName | Select-Object -ExpandProperty 'SignerCertificate' | Select-Object -ExpandProperty 'issuer'
CN=Microsoft Windows Production PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US

PS C:\Users\artemp> $new = Get-Item -Path 'C:\Windows\Boot\EFI_EX\bootmgfw_EX.efi'
PS C:\Users\artemp> Get-AuthenticodeSignature -FilePath $new.FullName | Select-Object -ExpandProperty 'SignerCertificate' | Select-Object -ExpandProperty 'issuer'
CN=Microsoft Windows Production PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
PS C:\Users\artemp>

This behavior is understood, thanks to documentation and the discussion in #8401. However, it is suboptimal since it does not help us distinguish between the old and new boot managers. In other words, as a user, I cannot tell whether the effective boot manager on my machine was updated to use the new certificate, and it's safe to proceed revoking the old certificate.

Ultimately, we need a way for Get-AuthenticodeSignature to use embedded Authenticode signature even if catalog signature is also present.

Alternative solutions

One option is to use sigcheck.exe from Sysinternals. It does show the difference in Authenticode signatures as expected. But it's not very suitable for automation.

PS C:\Users\artemp> sigcheck.exe -noBanner -i $old.FullName | Select-Object -First 10
c:\windows\boot\efi\bootmgr.efi:
        Verified:       Signed
        Link date:      11:21 PM 10/17/1964
        Signing date:   12:50 AM 3/22/2024
        Catalog:        c:\windows\boot\efi\bootmgr.efi
        Signers:
           Microsoft Windows
                Cert Status:    Valid
                Valid Usage:    NT5 Crypto, Code Signing
                Cert Issuer:    Microsoft Windows Production PCA 2011
PS C:\Users\artemp> sigcheck.exe -noBanner -i $new.FullName | Select-Object -First 10
c:\windows\boot\efi_ex\bootmgfw_EX.efi:
        Verified:       Signed
        Link date:      11:14 PM 12/10/1983
        Signing date:   9:55 AM 3/29/2024
        Catalog:        c:\windows\boot\efi_ex\bootmgfw_EX.efi
        Signers:
           Microsoft Windows
                Cert Status:    Valid
                Valid Usage:    Code Signing, NT5 Crypto
                Cert Issuer:    Windows UEFI CA 2023
PS C:\Users\artemp>

We can also rely on workaround suggested in #8401. Currently it looks like a best option, but it's not very obvious.

PS C:\Users\artemp> $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate]::CreateFromSignedFile( $old.FullName )
PS C:\Users\artemp> [System.Security.Cryptography.X509Certificates.X509Certificate2]::new( $certificate ) | Select-Object -ExpandProperty 'issuer'
CN=Microsoft Windows Production PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
PS C:\Users\artemp> $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate]::CreateFromSignedFile( $new.FullName )
PS C:\Users\artemp> [System.Security.Cryptography.X509Certificates.X509Certificate2]::new( $certificate ) | Select-Object -ExpandProperty 'issuer'
CN=Windows UEFI CA 2023, O=Microsoft Corporation, C=US
PS C:\Users\artemp>

Finally, it looks like the community has realized the shortcoming of Get-AuthenticodeSignature because alternative solutions emerged, such as Get-DigitalSignature script. Unfortunately, it has a large dependency which is difficult to audit and therefore it's not very suitable for use in security-cautious production environments.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Get-AuthenticodeSignature entry point and the discussion in #8401, then reproduce the old and new boot-manager examples using both catalog and embedded signatures. Done means the cmdlet reports the embedded signer when both signatures exist, distinguishing the two certificates while preserving appropriate behavior for other files.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, powershell
Domain
cli, operating-systems, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.