Authenticode is a Microsoft code signing technology software publishers use to guarantee the origin and integrity of their applications. The vast majority of modern software applications are actively using it and depend on its integrity validation system. The core principle of Authenticode is code immutability - providing firm guarantees that, once an application is signed, its code cannot change without breaking the envelope integrity. This way, the application users can be certain that the only code they are executing is the one created by the software publisher that signed it.



Authenticode is a very well-designed system. Its plethora of verification checks --- before and after the code is signed --- takes into consideration a huge number of possible misuses. However, both Authenticode and the executable format it is signing are extremely complex in their design. And the more moving parts a system has, the more likely it is that one of them will fail. Breaking the Authenticode security model equals attacking the complexity it is designed to protect.

Issue #1: Validation of signed Windows applications

The Authenticode implementation for Windows applications places the digital signature at the end of the portable executable file. This file region is commonly referred to as overlay. By its design, it is a part of the file that is never loaded into memory during image execution. However, the Windows application loader can mistakenly map certain portable executable files in a way that commits the overlay content into the loaded image memory.



A specially crafted application can misuse this by placing its entire code into the extended Authenticode signature - a data region that isn’t part of the image integrity validation. By doing so, the code of the application can be changed post-signing, and the application can be made to behave differently while keeping its original integrity intact.



When inspected with Authenticode signature validation tools, both the original and the modified applications report that the signature is valid. The issue itself is affecting multiple Windows versions and can be traced back to Windows XP - making this issue at least 18 years old.

Impact The Authenticode signature validation process needs to be augmented to take into account additional executable format integrity checks before validating the overall file integrity. Changes to the existing validation process will ensure that the envelope integrity guarantee can be trusted. Limitations This issue requires portable executable files that are specially prepared before they are signed. Because of this, every Windows application signed before this publication remains just as secure as it ever was. We have not found any real-world applications that can have their code modified post-signing without breaking the envelope integrity validation. Details A detailed technical description of this issue can be found here.

Issue #2: Validation of signed UEFI drivers and applications

Unified Extensible Firmware Interface (UEFI) is a specification that defines the interfaces between the operating system and the platform firmware. UEFI supports two very similar executable types. Firmware can simultaneously load the portable executable and the terse executable image format. However, only the portable executable format supports digital signing. UEFI digital signatures are therefore equivalent to their Windows desktop counterparts. Since they are both Authenticode signatures, they are both applied to the file by the exact same toolchain.



UEFI executes before the operating system and, as a part of its operation, it needs to load additional firmware drivers and applications. Because of that, it implements the executable image parsing and loading independently from the operating system code.



The UEFI image loader loads the executable format from disk to memory and reserves a single page after the image for debugging information. During image loading, this reserved page is filled with the path to debugging symbols stored in the first debug table entry. The way the UEFI image loader locates this reserved page is problematic, as it relies on the fact that this page must come after the last portable executable section. However, the section order isn’t enforced, which allows a specially crafted file to select where the debug table content will be written.



With this arbitrary memory copy within image bounds, a specially crafted UEFI image can overwrite the application code with the content from the debug table. Since the debug table can be placed in the overlay, its contents can also be a part of the extended Authenticode signature and thus not a part of integrity validation check.



When inspected with Authenticode signature validation tools, both the original and modified UEFI applications report that the signature is valid. The issue itself is affecting multiple UEFI versions and can be traced back to version 2.1 - making this issue at least 11 years old.

Impact The Authenticode signature validation process needs to be augmented to take into account additional executable format integrity checks before validating the overall file integrity. Changes to the existing validation process will ensure that the envelope integrity guarantee can be trusted.



Additionally, the UEFI portable executable image loader needs to be reworked to resolve the issues with image validation. Limitations This issue requires that the portable executable files are specially prepared before they are signed. Because of this, every UEFI driver and application signed before this publication remain just as secure as they ever were. We have not found any real-world applications that can have their code modified post-signing without breaking the envelope integrity validation. Details A detailed technical description of this issue can be found here.

Issue #3: Linux and open source signature validation bugs

Portable executable is probably the most prolific application format used for code distribution. It can be found on a wide variety of hardware and software platforms. No wonder, then, that many systems other than its native Windows end up supporting it in one way or another.



Regardless of how the format got onto the platform, it is usually accompanied by its digital signing system, Authenticode, whose entire parsing and integrity validation procedures need to be completely reimplemented for portability. That is a huge challenge for open source developers, as there are many unwritten rules when it comes to digital signature validation.



Some of these unwritten rules specify how portable executable headers should be validated. Authenticode integrity validation is a function of hashing the content which precedes the digital signature. However, two very small data regions are excluded from the integrity validation. Namely, the checksum of the portable executable (a four-byte region), and the information about the Authenticode signature (an eight-byte structure containing its location and size).



The location of the Authenticode signature can be physically overlapped with section headers. Because the sections are loaded from a file on the disk, this overlap would map the certificate in memory. This would break the assumption of Authenticode being an object present only on the disk, and never in memory. Since the Authenticode signature can be extended with no consequence to integrity validation, it can also be made to host application code. That code can be changed post-signing, making the code immutability validation void.



When inspected with open source Authenticode signature validation tools, both the original and modified applications report that the signature is valid. The issue itself is affecting multiple osslsigncode versions and can be traced back to version 1.3 - making this issue at least 10 years old.

Impact The Authenticode signature validation process needs to be augmented to take into account additional executable format integrity checks before validating the overall file integrity. Changes to the existing validation process will ensure that the envelope integrity guarantee can be trusted. Limitations This issue requires portable executable files that are specially prepared before they are signed. Because of this, every application signed before this publication remains just as secure as it ever was. We have not found any real-world applications that can have their code modified post-signing without breaking the envelope integrity validation.



Furthermore, this issue is found only to affect open source and custom Authenticode validation software. Windows and Microsoft signtool reports these kinds of portable executable images as improperly signed. Details A detailed technical description of this issue can be found here.

The goal of this research project was to explore the effects of portable executable format malformations on Authenticode signature validation. The conclusion is that the importance of proper portable executable format parsing can not be overstated. The complexity this format entails makes designing any validation process a non-trivial task. This big problem is only made worse by incomplete documentation and the existence of non-written validation rules.



For as long as Authenticode has existed, many open and closed source solutions for its validation have been created. It is impossible to truly know how many software products would be affected by the disclosed issues. By disclosing our findings, we hope to encourage developers to take another look at the Authenticode validation code they’ve written or are currently using.

Read our blogs in this Digital Certificate series:



Blog 9: Breaking the Linux Authenticode security model

Blog 8: Breaking the UEFI firmware Authenticode security model

Blog 7: Breaking the Windows Authenticode security model

Blog 6: A new kind of certificate fraud: Executive impersonation

Blog 5: Subverting trust with digital counterfeits

Blog 4: You are you, but so am I - certificate impersonation

Blog 3: Tampering with signed objects without breaking the integrity seal

Blog 2: Trust-based models in the age of supply chain attacks

Blog 1: Building secure certificate whitelists