LIEF icon indicating copy to clipboard operation
LIEF copied to clipboard

Issue validating signature of EFI PE executable

Open 0xfede7c8 opened this issue 3 years ago • 6 comments

Don't want to file a bug for this because I'm not sure if it's a LIEF problem or a deviation from the standard of the EFI implementation of PE executables but here it goes:

There is this PE file (a EFI bootloader):

fwupdx64.zip

The certificate that validates this file is (not needed in this case because what fails is the signature validation but just in case):

cert.zip

From Python hooks, when I do:

import lief

pe = lief.parse('fwupdx64.efi')
signature = pe.signatures[0]
print(signature.check())

I get:

OK

I understand that signature.check() is not validating the actual hash on the signature and the file, so, when I do:

print(pe.verify_signature())

I get:

VERIFICATION_FLAGS.BAD_DIGEST | VERIFICATION_FLAGS.BAD_SIGNATURE

There is a common Linux tool used to validate this types of bootloaders called sbverify which code is here.

This tool uses OpenSSL to perform all the signature operations. This tools validates the signature hash correctly. The output is:

sbverify --cert cert.pem fwupdx64.efi  
warning: gap in section table:
    .rela   : 0x0000b400 - 0x0000c400,
    /4      : 0x0000c470 - 0x0000c670,
warning: gap in section table:
    /4      : 0x0000c470 - 0x0000c670,
    .sbat   : 0x0000c800 - 0x0000ca00,
gaps in the section table may result in different checksums
warning: data remaining[53120 vs 63976]: gaps between PE/COFF sections?
Signature verification OK

It throws a bunch of warnings regarding sections. I know there are some issues with the linkers for PE files regarding EFI. They do some hacks that may be confusing LIEF.

What I'm trying to understand are the following:

  1. Is this a LIEF bug?
  2. If it is not, what are the differences of this PE file that make it fail validation with LIEF?
  3. Is there a way I can fix the PE file to be able to validate it with LIEF? Or can I do something different withing LIEF to validate it?

At least if you could point me in any directions on how to continue with this issue, it would be useful.

Thanks in advance!

0xfede7c8 avatar Jun 24 '22 15:06 0xfede7c8

Also, why signature.check() didn't catch the VERIFICATION_FLAGS.BAD_SIGNATURE and pe.verify_signature() did? I understand the VERIFICATION_FLAGS.BAD_DIGEST is only part of verify_signature but I understand that the other code should be returned by check(). Correct me if I'm wrong please.

0xfede7c8 avatar Jun 24 '22 16:06 0xfede7c8

Interesting, I never thought about this test for an EFI binary. I'll take a look when I'll back from vacation

romainthomas avatar Jun 27 '22 09:06 romainthomas

Re, I investigated the issue. First, signature.check() verifies the integrity of the signature itself. You can have a consistent signature while having a binary that have been modified. On the other hand, pe.verify_signature() verifies both: that signature is valid AND that the binary integrity is valid according to the signature.

Secondly, I checked the binary you attached with other PE signature tools and it seems that the output of LIEF is correct. I suppose that sbverify only performs signature.check() and not the complete verification (even though sections seem implied).

I close the issue as it seems the correct behavior but feel free to re-open it if you find that something is still wrong.

romainthomas avatar Jul 03 '22 05:07 romainthomas

sbverify only performs signature.check() and not the complete verification

In fact, it does the complete verification. If I change any random byte on the binary, sbverify will tell me.

After a bit of research, I have come to the following conclusion regarding this:

There were hystorical issues on the toolchains used to create EFI PE executables that made the validation with regular tools not work in some cases. Instead of changing the already-compiled bootloader binaries, they added exceptions on the checkers (sbverify, tianocore, etc) to support them.

These exception I think that only involves non-executable and/or relocation sections. It may be worth investigating if supporting this types of files is something desired for LIEF. I don't know if adding them would be considered a deviation of the authenticode standard.

LMK if this is something you would like to see added and maybe I can prepare a patch.

0xfede7c8 avatar Jul 05 '22 19:07 0xfede7c8

Ok my bad for sbverify. Definitely if you can draft a patch it would help to think about how it can be integrated along the with regular authenticode.

romainthomas avatar Jul 06 '22 09:07 romainthomas

Ok. I need to understand several things still. But I'm interested in contributing this. Let's keep this open for me, please, and I will come back when I have something.

0xfede7c8 avatar Jul 06 '22 13:07 0xfede7c8

Any update on this?

romainthomas avatar Apr 28 '23 04:04 romainthomas