Al's Website

Just another WordPress site

Playing with UEFI Secure Boot – Part 3: Chains of Trust


In this part I will cover certificate chains, how to include them in an executable, and how this could be used. Remember that I’m not an expert on this stuff, and I am learning as I go.

In part two we learned what the Platform Key and Key Exchange Keys do – at least in the OVMF implementation. We signed an EFI binary directly using an enrolled KEK and verified that it could run.

Now let’s try something else. We will make a new key called KekChild which is issued by KekRoot – we do this as follows:

$ makecert -n "CN=KekChild" -iv KekRoot.pvk -ic KekRoot.cer -sv KekChild.pvk KekChild.cer

Now make a PFX for this key and use it to sign another copy of HelloWorld.efi:

$ pvk2pfx -pvk KekChild.pvk -spc KekChild.cer -pfx KekChild.pfx -f
$ signtool sign /f KekChild.pfx /fd sha256 HelloWorldChild.efi

Now copy the new HelloWorld.efi to hda. Boot up QEMU and enroll PkRoot and KekRoot exactly as before. Do not enroll KekChild.cer.

Now try to run HelloWorldSignedChild.efi. It runs, even though we did not enroll KekChild.cer. Why? When we say KekRoot “issued” KekChild.cer, we mean that KekChild.cer was signed with KekRoot’s private key, indicating that KekRoot trusts KekChild. That relationship can be verified using KekRoot’s public key in the same way that signed executables are verified. KekChild.cer is placed in the PFX file and ultimately ends up inside the executable signature. UEFI checks that the executable was signed using KekChild.cer and then checks that KekChild.cer was signed with KekRoot.cer, which is enrolled. The executable is allowed to run. This is called a chain of trust.

Now, what if we make a child of the child key?

$ makecert -n "CN=KekChildChild" -iv KekChild.pvk -ic KekChild.cer -sv KekChildChild.pvk KekChildChild.cer
$ pvk2pfx -pvk KekChildChild.pvk -spc KekChildChild.cer -pfx KekChildChild.pfx -f
$ signtool sign /f KekChildChild.pfx /fd sha256 HelloWorldChildChild.efi

As before, enroll only PkRoot and KekRoot in OVMF and attempt to run HelloWorldChildChild.efi.

The new binary will not run. Why? Because the chain of trust is incomplete. The chain of certificates looks like this:

KekRoot.cer -> KekChild.cer -> KekChildChild.cer

KekRoot.cer is enrolled in the firmware. When we ran pvk2pfx we only included KekChildChild.cer in the PFX file. That means we cannot establish a chain of trust back to KekRoot.cer because KekChild.cer is not available at runtime. It is not in the executable signature, and it is not enrolled in the UEFI key database.

To include KekChild.cer in KekChildChild.pfx we must use an intermediate file: an SPC (software publisher certificate). This is just a list of certificates. There is one gotcha though. The SPC file must contain both the certificate and the issuer’s certificate for every certificate you want to put into the executable. That means that in order to get KekChild.cer and KekChildChild.cer into the exe, we must also include KekRoot.cer in the SPC, because KekRoot issued KekChild. Commands:

$ cert2spc KekRoot.cer KekChild.cer KekChildChild.cer KekChildChild.spc
$ pvk2pfx -pvk KekChildChild.pvk -spc KekChildChild.spc -pfx KekChildChild.pfx -f
$ signtool sign /f KekChildChild.pfx /fd sha256 HelloWorldChildChild.efi

You should now be able to run HelloWorldChildChild.efi after enrolling only the usual Pkroot and KekRoot.

How is this useful to the end user?

Suppose that KekRoot offers a signing service to Alice and Bob (and potentially hundreds of other software developers.) KekRoot could simply sign both Alice and Bob’s software with the KekRoot private key. In this case, the end user would have only two options: either trust both Alice and Bob and anyone else that KekRoot signs for, or trust nobody at all and manually verify every software update that is ever installed. Neither of these options is particularly appealing.

There is an alternative though: KekRoot can issue keys called KekAlice and KekBob, and then uses these keys to sign software written by Alice and Bob respectively. This can be set up such that KekRoot retains the keys and signs software for Alice and Bob on request, or the keys can be held by Alice and Bob to sign their own software.

Now the end user has a choice. If KekRoot is enrolled, (perhaps at the factory,) then software from either Alice or Bob will be trusted on their system. If they are happy with that they need do nothing more. But they could also remove KekRoot and enroll only the KekAlice key, and then Alice’s software will run, while Bob’s will not. The user would be able to receive updates for Alice’s software without having to manually whitelist them, and would not have to worry about vulnerabilities in Bob’s software.

We can see this working by generating two sub-keys and signing HelloWorld with them:

$ makecert -n "CN=KekAlice" -iv KekRoot.pvk -ic KekRoot.cer -sv KekAlice.pvk KekAlice.cer
$ pvk2pfx -pvk KekAlice.pvk -spc KekAlice.cer -pfx KekAlice.pfx -f
$ signtool sign /f KekAlice.pfx /fd sha256 HelloWorldAlice.efi
$ makecert -n "CN=KekBob" -iv KekRoot.pvk -ic KekRoot.cer -sv KekBob.pvk KekBob.cer
$ pvk2pfx -pvk KekBob.pvk -spc KekBob.cer -pfx KekBob.pfx -f
$ signtool sign /f KekBob.pfx /fd sha256 HelloWorldBob.efi

As before, enroll PkRoot and KekRoot and verify that both HelloWorldAlice.efi and HelloWorldBob.efi run. HelloWorldChild.efi, HellowWorldChildChild.efi, and HelloWorldSigned.efi should all also run too if you have not regenerated their associated keys. Now restart QEMU and enroll only PkRoot and KekAlice and verify that HelloWorldAliceSigned.efi runs while HelloWorldBobSigned.efi does not – and neither do any of the others.

My conclusion is that it is technically possible to run a signing service in a way which does not require end users to trust everything signed by that service. It is also technically possible to not do it that way. As a result, many of the perceived difficulties with UEFI Secure Boot can not be resolved one way or the other by simply looking at the UEFI specification and software implementations, as it will depend entirely on the policies of those offering signing services.

That’s it for this part. You can find Windows batch files which demonstrate all the things I’ve covered so far in my uefi-tests repository on GitHub.

Leave a Reply

Required fields are marked *.