A little background

When we talk about UEFI Secure Boot, a lot of times we talk about what we call the whitelist and the blacklist. These databases go by many names—formally EFI_IMAGE_SECURITY_DATABASE and EFI_IMAGE_SECURITY_DATABASE1, sometimes d719b2cb-3d3a-4596-a3bc-dad00e67656f:db and d719b2cb-3d3a-4596-a3bc-dad00e67656f:dbx, but most often just db and dbx. These two1 databases, stored in UEFI Authenticated Variables2, constitute lists of which binaries can and cannot be executed within a UEFI environment when Secure Boot is enabled.

When a UEFI binary is loaded, the system first checks to see if any revocations in dbx are applicable to that binary. A dbx entry may apply in three ways—it may contain the hash of a specific binary, an X.509 certificate, or the hash of a certificate3. If any of these matches the binary in question, UEFI raises the error EFI_SECURITY_VIOLATION, and your binary will not go to space today.

If a binary successfully passes that hurdle, then the same verification method is processed with db, the whitelist, but with the opposite policy: if any entry describes the binary in question, verification has succeeded. If no entry does, EFI_SECURITY_VIOLATION is raised.

The need for updates

When a UEFI binary is discovered to have a serious security flaw which would allow a malicious user to circumvent Secure Boot, it becomes necessary to prevent it from running on machines. When this happens, the UEFI CA issues a dbx update. The mechanism for the update is a file that’s structured as a UEFI Authenticated Variable append. This file gets distributed as part of an OS update, and when the update is applied, the UEFI variable is updated.

One mechanism for doing this in Linux is via dbxtool. In Fedora, the dbxtool package includes the current dbx updates in /usr/share/dbxtool/DBXUpdate-2014-04-13-22-14-00.bin, as well as a systemd service to apply them during boot4. In the special case of Fedora’s shim being added to a blacklist, we would include a dependency on the fixed version of shim in the dbxtool package so that systems would remain bootable.

The structure of a `dbx` update

The dbx variable is composed of an array of EFI_SIGNATURE_LIST structures, each themselves containing an array of EFI_SIGNATURE_DATA entries. A dbx update is that same structure, but wrapped in a EFI_VARIABLE_AUTHENTICATION_2 structure to authenticate it. The definitions look like this5:

<figcaption class='code-highlight-caption'>wincert.h</figcaption><div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'> efi_guid_t SignatureOwner; // who owns this entry </div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> uint8_t SignatureData[0]; // the data we want to </div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> // fish out of this thing </div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'>} EFI_SIGNATURE_DATA; </div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> efi_guid_t SignatureType; // type of structure in </div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> // EFI_SIGNATURE_DATA.SignatureData </div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> uint32_t SignatureListSize; // Total size of the signature </div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> // list, including this header. </div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> uint32_t SignatureHeaderSize; // Size of type-specific header </div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> uint32_t SignatureSize; // The size of each individual </div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> // EFI_SIGNATURE_DATA.SignatureData </div></div><div data-line='15' class='code-highlight-row numbered'><div class='code-highlight-line'> // in this list. </div></div><div data-line='16' class='code-highlight-row numbered'><div class='code-highlight-line'> // uint8_t SignatureHeader[SignatureHeaderSize] </div></div><div data-line='17' class='code-highlight-row numbered'><div class='code-highlight-line'> // this is a header defined by </div></div><div data-line='18' class='code-highlight-row numbered'><div class='code-highlight-line'> // and for each specific </div></div><div data-line='19' class='code-highlight-row numbered'><div class='code-highlight-line'> // signature type. Of course </div></div><div data-line='20' class='code-highlight-row numbered'><div class='code-highlight-line'> // none of them actually define </div></div><div data-line='21' class='code-highlight-row numbered'><div class='code-highlight-line'> // a header. </div></div><div data-line='22' class='code-highlight-row numbered'><div class='code-highlight-line'> // EFI_SIGNATURE_DATA[…][SignatureSize] // actual signature data </div></div><div data-line='23' class='code-highlight-row numbered'><div class='code-highlight-line'>} EFI_SIGNATURE_LIST; </div></div><div data-line='24' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='25' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='26' class='code-highlight-row numbered'><div class='code-highlight-line'> efi_guid_t HashType; </div></div><div data-line='27' class='code-highlight-row numbered'><div class='code-highlight-line'> uint8_t PublicKey[256]; </div></div><div data-line='28' class='code-highlight-row numbered'><div class='code-highlight-line'> uint8_t Signature[256]; </div></div><div data-line='29' class='code-highlight-row numbered'><div class='code-highlight-line'>} EFI_CERT_BLOCK_RSA_2048_SHA256; </div></div><div data-line='30' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='31' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='32' class='code-highlight-row numbered'><div class='code-highlight-line'> uint32_t dwLength; // Length of this structure </div></div><div data-line='33' class='code-highlight-row numbered'><div class='code-highlight-line'> uint16_t wRevision; // Revision of this structure (2) </div></div><div data-line='34' class='code-highlight-row numbered'><div class='code-highlight-line'> uint16_t wCertificateType; // The kind of signature this is </div></div><div data-line='35' class='code-highlight-row numbered'><div class='code-highlight-line'> //uint16_t bCertificate[0]; // The signature data itself. This </div></div><div data-line='36' class='code-highlight-row numbered'><div class='code-highlight-line'> // is actually, and not the least </div></div><div data-line='37' class='code-highlight-row numbered'><div class='code-highlight-line'> // bit confusingly, the rest of </div></div><div data-line='38' class='code-highlight-row numbered'><div class='code-highlight-line'> // the WIN_CERTIFICATE_EFI_GUID </div></div><div data-line='39' class='code-highlight-row numbered'><div class='code-highlight-line'> // structure wrapping this one. </div></div><div data-line='40' class='code-highlight-row numbered'><div class='code-highlight-line'>} WIN_CERTIFICATE; </div></div><div data-line='41' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='42' class='code-highlight-row numbered'><div class='code-highlight-line'>#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 </div></div><div data-line='43' class='code-highlight-row numbered'><div class='code-highlight-line'>#define WIN_CERT_TYPE_EFI_PKCS115 0x0ef0 </div></div><div data-line='44' class='code-highlight-row numbered'><div class='code-highlight-line'>#define WIN_CERT_TYPE_EFI_GUID 0x0ef1 </div></div><div data-line='45' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='46' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='47' class='code-highlight-row numbered'><div class='code-highlight-line'> WIN_CERTIFICATE Hdr; // Info about which structure this is </div></div><div data-line='48' class='code-highlight-row numbered'><div class='code-highlight-line'> efi_guid_t CertType; // Type of certificate in CertData </div></div><div data-line='49' class='code-highlight-row numbered'><div class='code-highlight-line'> uint8_t CertData[0]; // A certificate of some kind </div></div><div data-line='50' class='code-highlight-row numbered'><div class='code-highlight-line'>} WIN_CERTIFICATE_EFI_GUID; </div></div><div data-line='51' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='52' class='code-highlight-row numbered'><div class='code-highlight-line'>typedef struct { </div></div><div data-line='53' class='code-highlight-row numbered'><div class='code-highlight-line'> EFI_TIME TimeStamp; // monotonically increasing </div></div><div data-line='54' class='code-highlight-row numbered'><div class='code-highlight-line'> // timestamp to prevent replay </div></div><div data-line='55' class='code-highlight-row numbered'><div class='code-highlight-line'> // attacks. </div></div><div data-line='56' class='code-highlight-row numbered'><div class='code-highlight-line'> WIN_CERTIFICATE_EFI_GUID AuthInfo; // Information about how to </div></div><div data-line='57' class='code-highlight-row numbered'><div class='code-highlight-line'> // authenticate this variable </div></div><div data-line='58' class='code-highlight-row numbered'><div class='code-highlight-line'> // against some KEK entry </div></div><div data-line='59' class='code-highlight-row numbered'><div class='code-highlight-line'>} EFI_VARIABLE_AUTHENTICATION_2;</div></div></pre></div>

Conceptually, this means the structure we’ve got is:

<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>[ dbx update file: </div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'> [ Authentication structure: </div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> [ monotonic number | timestamp ] </div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> [ WIN_CERTIFICATE Header ] </div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> [ Cert Type ] </div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> [ Certificate Data ] ] </div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_LIST: </div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_DATA ] </div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_DATA ] </div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_DATA ] ] </div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_LIST: </div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_DATA ] </div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> … </div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> [ EFI_SIGNATURE_DATA ] ] </div></div><div data-line='15' class='code-highlight-row numbered'><div class='code-highlight-line'> … ]</div></div></pre></div>

So a full update looks something like this:
``` plain auth2.TimeStamp 00000000 da 07 03 06 13 11 15 00 00 00 00 00 00 00 00 00 |…………….|

2010-03-06 19:17:21 GMT+0000
``` plain auth2.AuthInfo.Hdr.DwLength
00000010  bd 0c 00 00                                       |....            |

It is 0x00000cbd bytes long6.
``` plain auth2.AuthInfo.Hdr.wRevision 00000010 00 02 | .. |

It's revision is 2.  It is always revision 2.
``` plain auth2.AuthInfo.Hdr.wCertificateType
00000010                    f1 0e                           |      ..        |

0x0ef1, which as we see above is WIN_CERT_TYPE_EFI_GUID. The interesting bit here is that .bCertificate isn’t quite a real thing. This is actually describing that auth2.AuthInfo is a WIN_CERTIFICATE_EFI_GUID, and .bCertificate is actually the fields other than auth2.AuthInfo.Hdrauth2.AuthInfo.CertType and auth2.AuthInfo.CertData. Again, this shouldn’t confuse you at all. As a result, next, in the place of .bCertificate, we have: ``` plain auth2.AuthInfo.CertType 00000010 9d d2 af 4a df 68 ee 49 | …J.h.I| 00000020 8a a9 34 7d 37 56 65 a7 |..4}7Ve. |

`4aafd29d-68df-49ee-8aa9-347d375665a7`, aka `EFI_GUID_PKCS7_CERT`, which
means that `.CertData` is verified against `EFI_SIGNATURE_DATA` entries in
the Key Exchange Keys database (`KEK`), but only those entries which are
contained in `EFI_SIGNATURE_LIST` structures with `.SignatureType` of
`EFI_CERT_X509_GUID`.  *Whew*.
``` plain auth2.AuthInfo.CertData
00000020                           30 82 0c a1 02 01 01 31  |        0......1|
00000030  0f 30 0d 06 09 60 86 48  01 65 03 04 02 01 05 00  |.0...`.H.e......|
[ what an X.509 certificate looks like is left as an exercise for the reader ]
00000cb0  b6 2b 89 02 73 c4 86 57  83 6f 28 57 e0 12 cb 05  |.+..s..W.o(W....|
00000cc0  6d d0 3e 60 8f 85 9f dd  fc 46 ac 54 44           |m.>`.....F.TD   |

Yep, that’s an ASN.1 DER encoding of a PKCS-7 Certificate.
That’s the end of the EFI_VARIABLE_AUTHENTICATION_2 structure, and so on to the actual data: ``` plain EFI_SIGNATURE_LIST.SignatureType 00000cc0 26 16 c4 | &..| 00000cd0 c1 4c 50 92 40 ac a9 41 f9 36 93 43 28 |.LP.@..A.6.C( |

That's c1c41626-504c-4092-aca9-41f936934328, aka `EFI_GUID_SHA256`
``` plain EFI_SIGNATURE_LIST.SignatureListSize
00000cd0                                          cc 01 00  |             ...|
00000ce0  00                                                |.               |

The list size is 0x00001cc bytes ``` plain EFI_SIGNATURE_LIST.SignatureHeaderSize: 00000ce0 00 00 00 00 | …. |

This is actually always 0.
``` plain EFI_SIGNATURE_LIST.SignatureSize
00000ce0                 30 00 00  00                       |     0...       |

0x00000030 bytes. That’s 16 bytes for the efi_guid_t, and since .SignatureType was EFI_GUID_SHA256, 32 bytes of SHA-256 data. ``` plain EFI_SIGNATURE_DATA[0].SignatureOwner 00000ce0 bd 9a fa 77 59 03 32 |…..0……wY.2| 00000cf0 4d bd 60 28 f4 e7 8f 78 4b |M.`(…xK |

77fa9abd-0359-4d32-bd60-28f4e78f784b , which is the GUID Microsoft uses
to identify themselves[^7]
``` plain EFI_SIGNATURE_DATA[0].SignatureData
00000cf0                              80 b4 d9 69 31 bf 0d  |         ...i1..|
00000d00  02 fd 91 a6 1e 19 d1 4f  1d a4 52 e6 6d b2 40 8c  |.......O..R.m.@.|
00000d10  a8 60 4d 41 1f 92 65 9f  0a                       |.`MA..e..       |

This is the actual SHA-256 data. It goes on like this: ``` plain EFI_SIGNATURE_DATA[1..8] 00000d10 bd 9a fa 77 59 03 32 | …wY.2| 00000d20 4d bd 60 28 f4 e7 8f 78 4b f5 2f 83 a3 fa 9c fb |M.(...xK./.....| 00000d30 d6 92 0f 72 28 24 db e4 03 45 34 d2 5b 85 07 24 |...r($...E4.[..$| 00000d40 6b 3b 95 7d ac 6e 1b ce 7a bd 9a fa 77 59 03 32 |k;.}.n..z...wY.2| 00000d50 4d bd 60 28 f4 e7 8f 78 4b c5 d9 d8 a1 86 e2 c8 |M.(…xK…….| 00000d60 2d 09 af aa 2a 6f 7f 2e 73 87 0d 3e 64 f7 2c 4e |-…*o..s..>d.,N| 00000d70 08 ef 67 79 6a 84 0f 0f bd |..gyj…. | … 00000e60 bd 9a fa 77 59 03 32 | …wY.2| 00000e70 4d bd 60 28 f4 e7 8f 78 4b 53 91 c3 a2 fb 11 21 |M.`(…xKS…..!| 00000e80 02 a6 aa 1e dc 25 ae 77 e1 9f 5d 6f 09 cd 09 ee |…..%.w..]o….| 00000e90 b2 50 99 22 bf cd 59 92 ea |.P.”..Y..|

<h2>How the structure is used</h2>
When you apply a database update, you're basically doing a `SetVariable()`
call to UEFI with a couple of flags set:
``` c
  rc = efi_set_variable(EFI_IMAGE_SECURITY_DATABASE_GUID, "dbx", data, len,
                        EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
                        EFI_VARIABLE_APPEND_WRITE |
                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
                        EFI_VARIABLE_RUNTIME_ACCESS |
                        EFI_VARIABLE_NON_VOLATILE);

These flags tell the firmware some crucial things - that this variable is authenticated with the EFI_VARIABLE_AUTHENTICATION_2 structure, that this is an append, that both Boot Services (i.e. the firmware) and Runtime Services (i.e. the OS) should have access to it, and that it should persist across a reboot. As a special case in the spec, an append has a special meaning for the UEFI security databases:

For variables with the GUID EFI_IMAGE_SECURITY_DATABASE_GUID (i.e. where the data buffer is formatted as EFI_SIGNATURE_LIST), the driver shallnot perform an append of EFI_SIGNATURE_DATA values that are already part of the existing variable value. Note: This situation is not considered an error, and shall in itself not cause a status code other than EFI_SUCCESS to be returned or the timestamp associated with the variable not to be updated.

UEFI Specification section 7.2.1 revision 2.4

As a result, what happens here is that the first time you write to dbx, any EFI_SIGNATURE_LIST structures and the EFI_SIGNATURE_DATA entries they contain get added to the variable, but not the EFI_VARIABLE_AUTHENTICATION_2 structure. Then when later dbx updates are issued, they contain a superset of the previous ones. When you apply them, the firmware only appends the difference to the variable.

Tools

Obviously a system this complex needs some tools. To manage these databases on linux, I’ve written a tool called dbxtool, which may be available in your linux distribution of choice. It can be used to apply dbx changes7, to list the contents of the UEFI Security Databases, and to list the contents of updates files:

<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>fenchurch:~$ dbxtool -l </div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'> 1: {microsoft} {sha256} 80b4d96931bf0d02fd91a61e19d14f1da452e66db2408ca8604d411f92659f0a </div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> 2: {microsoft} {sha256} f52f83a3fa9cfbd6920f722824dbe4034534d25b8507246b3b957dac6e1bce7a </div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> 3: {microsoft} {sha256} c5d9d8a186e2c82d09afaa2a6f7f2e73870d3e64f72c4e08ef67796a840f0fbd </div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> 4: {microsoft} {sha256} 363384d14d1f2e0b7815626484c459ad57a318ef4396266048d058c5a19bbf76 </div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> 5: {microsoft} {sha256} 1aec84b84b6c65a51220a9be7181965230210d62d6d33c48999c6b295a2b0a06 </div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> 6: {microsoft} {sha256} e6ca68e94146629af03f69c2f86e6bef62f930b37c6fbcc878b78df98c0334e5 </div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> 7: {microsoft} {sha256} c3a99a460da464a057c3586d83cef5f4ae08b7103979ed8932742df0ed530c66 </div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> 8: {microsoft} {sha256} 58fb941aef95a25943b3fb5f2510a0df3fe44c58c95e0ab80487297568ab9771 </div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> 9: {microsoft} {sha256} 5391c3a2fb112102a6aa1edc25ae77e19f5d6f09cd09eeb2509922bfcd5992ea </div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> 10: {microsoft} {sha256} d626157e1d6a718bc124ab8da27cbb65072ca03a7b6b257dbdcbbd60f65ef3d1 </div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> 11: {microsoft} {sha256} d063ec28f67eba53f1642dbf7dff33c6a32add869f6013fe162e2c32f1cbe56d </div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> 12: {microsoft} {sha256} 29c6eb52b43c3aa18b2cd8ed6ea8607cef3cfae1bafe1165755cf2e614844a44 </div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> 13: {microsoft} {sha256} 90fbe70e69d633408d3e170c6832dbb2d209e0272527dfb63d49d29572a6f44c</div></div></pre></div>

As usual, there are a couple of places where vendors have not gotten everything quite right, and sometimes things fail to work correctly—but that’s for another post.

  1. There is actually a third in this set, dbt, which can be used in revocation processing. 

  2. Strictly speaking these are only an analog to Authenticated Variables, which can only be appended to, replaced, or deleted by updates signed with the key that created them. Key database updates are instead controlled by a list of keys stored in another variable called KEK - the Key Exchange Keys. Otherwise the mechanism is the same. 

  3. That is, the digest of the certificate’s TBSCertificate as defined in RFC 5280 section 4.1.1.1, using the digest specified in the database entry itself. 

  4. This is currently disabled by default in Fedora. I’m looking at enabling this as an F22 feature. Getting these things right is important, and it takes time. 

  5. I have left out the definitions of EFI_TIME and efi_guid_t; they are quite boring. 

  6. Here dwLength includes the size of Hdr itself (that is, the size of dwLength, wRevision, and wCertificateType) as well as the data following it (bCertificate). Because we live in the best of all possible worlds, Authenticode signatures—the signatures on binaries themselves—use the same structure but only include the size of Hdr.bCertificate. This hasn’t ever confused anybody

  7. Also theoretically db updates, dbt updates, and KEK updates, but those are much more rare.