One thing we’ve heard several times during the discussions of the UEFI
“Secure Boot” mechanism is that there’s no genuine security benefits. In
fact there are several. The ability to guard against “bootkit” systems has
been covered elsewhere, so I’ll not cover it here. Instead, I’d like to
focus on a less publicized aspect of Secure Boot’s mechanism.
With secure boot, it’s possible to verify any UEFI application which has
been signed. There’s a reasonable standard of attestation that if a binary
has been signed by our key, it was consciously signed by us.
A simple example
One side effect of this is that with a few hoops, we can sign arbitrary
data, and wrap it in a UEFI envelope. Such code would look something like:
data.c #include <efi.h>
</div></div>#include <efilib.h></span>
efi_main ( EFI_HANDLE image_handle , EFI_SYSTEM_TABLE * systab )
InitializeLib ( image_handle , systab );
Print ( L"This program contains data. \n " );
int data __attribute__ (( __section__ ( ".data.hellothere" ))) = 3 ;
</pre></div></figure>
At this point you'd build it like any ```gnu-efi``` application, and then
have it signed as a UEFI application.
At this point you've got an envelope for data which is signed and explicitly
trusted by your hardware platform. At runtime, you can verify the signature
against ```DB```, the UEFI key database, and verify that this is a trusted
binary. At that point in time you can unwrap the UEFI binary to get at
the ELF DSO that fundamentally lies underneath, and examine the DSO. If
you do "eu-readelf --section-headers ${file}" on the DSO, you'll see that
there are 21 section headers. Here's a subset:
> Section Headers:
> [Nr] Name Type Addr Off Size ES Flags Lk Inf Al
> [ 0] NULL 0000000000000000 00000000 00000000 0 0 0 0
> [ 1] .hash HASH 0000000000000000 00200000 00000690 4 A 9 0 8
> [ 2] .eh_frame PROGBITS 0000000000001000 00201000 000016b0 0 A 0 0 8
> [ 3] .text PROGBITS 0000000000003000 00203000 000053bd 0 AX 0 0 16
> [ 4] .reloc PROGBITS 0000000000009000 00209000 0000000a 0 A 0 0 1
> [ 5] .data.hellothere PROGBITS 000000000000a000 0020a000 00000004 0 WA 0 0 4
> [ 6] .data PROGBITS 000000000000a020 0020a020 00001770 8 WA 0 0 32
.data.hellothere starts at 0x20a000 and is 4 bytes long.
Something with more substance
What's this useful for, you ask? Well, let's assume we've got a slightly
different binary:
keys.c #include <efi.h>
</div></div>#include <efilib.h></span>
efi_main ( EFI_HANDLE image_handle , EFI_SYSTEM_TABLE * systab )
InitializeLib ( image_handle , systab );
Print ( L"This program contains a list of public keys. \n " );
#define KEYDATA \
</div></div>"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" \
"Version: GnuPG v1.4.5 (GNU/Linux)\n" \
"mQINBE8MkeIBEADfn8QtElquxUAVvS8th7UnVmfkExw7jC7SVy7dGlXo5rgxqETM\n" \
"AZorpDIvAtKX5VMr/lUfODB6sSymh0e6EdvYQfHrpImO05F7WBq2DhRW74j1DRNu\n" \
"8vohKPTsSZTEZo/mrUBDAAGtGOXcrsQxx4J2Ur73+r18ODd+v6O33YevlFmwmFYT\n" \
"uDcgdhxyxBdpJVES8MdxO349uP9bvrU+3KjpDDGHb/hMbY8az7lwLtBufRrAekhN\n" \
"5Cg7+zm+I+wVGzgzSw0yrIh4hdVts4RKZIrl2N3VeZcCY4IrNZFd2Do6HhIwA7l/\n" \
"/xpTEBTZ4BmnGP9iufUVa2h97/JmKy38rM88IovIcTSnYDG68k/NxUkC+dLriI4T\n" \
"BNc9kJLVo821x77WYViNXHscF8ujlf73HilfCnhEtNwViGO7x41guQrdv5k79UDf\n" \
"1CylSZ+76vKXziz6uNHzIagiViNOvYHOoEH8jDNnubqFTxYXUNks5l3/byllQ0XK\n" \
"Oj9RarmjsMS3udRB6RCiEnzDbPge2S9gmdmY8MA3QeZ3aWoZJqygDQ0WNUOjPZ0E\n" \
"80x+xbUyAK06/SCzs6bUx6GMXd5Iy5r3Gc+6LRt4WEG5r/vJEHPSj3qAoVqydsY0\n" \
"GjASPIQmYduCdi7Inf0w+2n+nJGPcK1k432xHD0z0kp1Q/xcOH/Tul3bcQARAQAB\n" \
"tCZGZWRvcmEgKDE3KSA8ZmVkb3JhQGZlZG9yYXByb2plY3Qub3JnPokCNgQTAQIA\n" \
"IAUCTwyR4gIbDwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEFDpTJkayjRlKxAQ\n" \
"AICtQT+j8Sum1J86yBwso1wuzK2sHOXbfC1LCdQw2u6QLfKSUsCnQ5AL+oCnS491\n" \
"5fjrYksT2siclLhgZX7/yF76XuYHHhRTO65NaPSCxxhN6S9zbExUPRoxFL1ay0cH\n" \
"p14WYI1/SGmKPcJmigV6n8+wGYl+zWlH9eiiFP/+JCxJ0ZvRg3mgT5zcPdIzTDOz\n" \
"4rTE3WfH3qqxYhw2ttDPomBSdbgJw2N6bj46t8rljIDGdeKpFHYMVXpUp0gDkEoY\n" \
"bAiQhvZaa2F6mGMfXRdr4Phs562+tF/Qy/JaK8uafYZPHTtC16NHf87DYceLzvci\n" \
"W1KNBYGrEHm5NMguBlqP348FYMp+6hJDYMl38Qx3BK9bz6lW0G75tgaAZ+sxAFGs\n" \
"/MUcjChkF9OcF7Y7W6hY3IQb/+FgB5eNpBqfmZZ76ywpS+D0sIqxzWoILtlXdHeN\n" \
"eM4YiX0gvVQXwn9S89O5vWKxWYspywfgV/aXHk14O6k7oi8wInJOvgxZKEHUT4XU\n" \
"K7DyogL45VV9iYoWYIym2L17VBnINE/Kwmc/81nYigE0tTOwaR+qMFBSRlkOA4+X\n" \
"ZlIvb5Cft7CdC183FYLIM+B6xNSKE/OhavHZsRJrLZC1aAP8MNh8Cy7Jqrn1/Qjj\n" \
"6sncrqaj/Yis4yAaINk4MrnbImN2MwzU70q0eR3kA6PY\n" \
"-----END PGP PUBLIC KEY BLOCK-----\n"</span>
struct keylist keyhdr __attribute__ (( __section__ ( ".keylist" ))) =
struct key key __attribute__ (( __section__ ( ".keylist" ))) =
uint8_t pubkey [] __attribute__ (( __section__ ( ".keylist" ))) = KEYDATA ;
</pre></div></figure>
With this code, the extracted DSO has a section like this:
> [ 5] .keylist PROGBITS 000000000000a000 0020a000 00000680 0 WA 0 0 32
But wait, there's more
One additional component here is packaging. If we package the file on a per-repo basis, with a well known name, there's a bit more.
So let's say, for example, that we can have ```${repo}-release``` provide a file, ```/etc/pki/sbkeys/${repo}-keys.efi```, which looks roughly like what's shown above.
At this point, we can add the extraction code to anaconda and kickstart, and we can automatically import trusted keys for any repository that includes a correctly signed keyfile. This is bug 253897 , a bug that's been open for 5 years.
Wait for it
There's an even larger goal here - bug 253897 is the remaining blocker on bug 998 , open since 1999.
With the above system, we can enable signature checking for all packages during installation.