]> git.proxmox.com Git - efi-boot-shim.git/blame - SBAT.md
Update to the 15.4 release
[efi-boot-shim.git] / SBAT.md
CommitLineData
031e5cce
SM
1# UEFI shim bootloader secure boot life-cycle improvements
2
3## Background
4
5In the PC ecosystem, [UEFI Secure Boot](https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-secure-boot)
6is typically configured to trust 2 authorities for signing UEFI boot code, the
7Microsoft UEFI Certificate Authority (CA) and Windows CA. When malicious or
8security compromised code is detected, 2 revocation mechanisms are provided by
9compatible UEFI implementations, signing certificate or image hash. The UEFI
10Specification does not provides any well tested additional revocation
11mechanisms.
12
13Signing certificate revocation is not practical for the Windows and Microsoft
14UEFI CAs because it would revoke too many UEFI applications and drivers,
15especially for Option ROMs. This is true even for the UEFI CA leaf certificates
16as they generally sign 1 entire year of UEFI images. For this reason UEFI
17revocations have, until recently, been performed via image hash.
18
19The UEFI shim bootloader provides a level of digital signature indirection,
20enabling more authorities to participate in UEFI Secure Boot. Shims'
21certificates typically sign targeted UEFI applications, enabling
22certificate-based revocation where it makes sense. As part of the recent
23"BootHole" security incident
24[CVE-2020-10713](https://nvd.nist.gov/vuln/detail/CVE-2020-10713), 3
25certificates and 150 image hashes were added to the UEFI Secure Boot revocation
26database `dbx` on the popular x64 architecture. This single revocation event
27consumes 10kB of the 32kB, or roughly one third, of revocation storage
28typically available on UEFI platforms. Due to the way that UEFI merges
29revocation lists, this plus prior revocation events can result in a `dbx` that
30is almost 15kB in size, approaching 50% capacity.
31
32The large size of the BootHole revocation event is due to the inefficiency of
33revocation by image hash when there is a security vulnerability in a popular
34component signed by many authorities, sometimes with many versions.
35
36Coordinating the BootHole revocation has required numerous person months of
37planning, implementation, and testing multiplied by the number of authorities,
38deployments, & devices. It is not yet complete, and we anticipate many months
39of upgrades and testing with a long tail that may last years.
40
41Additionally, when bugs or features require updates to UEFI shim, the number of
42images signed are multiplied by the number of authorities.
43
44## Summary
45
46Given the tremendous cost and disruption of a revocation event like BootHole,
47and increased activity by security researchers in the UEFI Secure Boot space,
48we should take action to greatly improve this process. Updating revocation
49capabilities in the UEFI specification and system firmware implementations will
50take years to deploy into the ecosystem. As such, the focus of this document is
51on improvements that can be made to the UEFI shim, which are compatible with
52existing UEFI implementations. Shim can move faster than the UEFI system
53firmware ecosystem while providing large impact to the in-market UEFI Secure
54Boot ecosystem.
55
56The background section identified 2 opportunities for improvement:
57
581. Improving the efficiency of revocation when a number of versions have a
59 vulnerability
60
61 * For example, a vulnerability spans some number of versions, it might be
62 more efficient to be able to revoke by version, and simply modify the
63 revocation entry to modify the version each time a vulnerability is
64 detected.
65
662. Improving the efficiency of revocation when there are many shim variations
67
68 * For example, a new shim is released to address bugs or adding features. In
69 the current model, the number of images signed are multiplied by the
70 number of authorities as they sign shims to gain the fixes and features.
71
72Microsoft has brainstormed with partners possible solutions for evaluation and
73feedback:
74
751. To improve revocation when there are many versions of vulnerable boot
76 images, shim, GRUB, or otherwise, investigate methods of revoking by image
77 metadata that includes generation numbers. Once targeting data is
78 established (e.g. Company foo, product bar, boot component zed), each
79 revocation event ideally edits an existing entry, increasing the trusted
80 minimum security generation.
81
822. To improve revocation when there is a shim vulnerability, and there are many
83 shim images, standardize on a single image shared by authorities. Each
84 release of bug fixes and features result in 1 shim being signed, compressing
85 the number by dozens. This has the stellar additional benefit of reducing
86 the number of shim reviews, which should result in much rejoicing. The
87 certificates used by a vendor to sign individual boot components would be
88 picked up from additional PE files that are signed either by a shim-specific
89 key controlled by Microsoft, or controlled by a vendor, but used only to
90 sign additional key files. This key built into shim is functionally similar
91 to a CA certificate. The certificates built into shim can be revoked by
92 placing the image hash into dbx, similar to the many shim solution we have
93 today.
94
95## Proposals
96
97This document focuses on the shim bootloader, not the UEFI specification or
98updates to UEFI firmware.
99
100### Generation Number Based Revocation
101
102Microsoft may refer to this as a form of UEFI Secure Boot Advanced Targeting
103(SBAT), perhaps to be named EFI_CERT_SBAT. This introduces a mechanism to
104require a specific level of resistance to UEFI Secure Boot bypasses.
105
106#### Generation-Based Revocation Overview
107
108Metadata that includes the vendor, product family, product, component, version
109and generation are added to artifacts. This metadata is protected by the
110digital signature. New image authorization data structures, akin to the
111EFI_CERT_foo EFI_SIGNATURE_DATA structure (see Signature Database in UEFI
112specification), describe how this metadata can be incorporated into allow or
113deny lists. In a simple implementation, 1 SBAT entry with security generations
114could be used for each revocable boot module, replacing many image hashes with
1151 entry with security generations. To minimize the size of EFI_CERT_SBAT, the
116signature owner field might be omitted, and recommend that either metadata use
117shortened names, or perhaps the EFI_CERT_SBAT contains a hash of the
118non-generation metadata instead of the metadata itself.
119
120Ideally, servicing of the image authorization databases would be updated to
121support replacement of individual EFI_SIGNATURE_DATA items. However, if we
122assume that new UEFI variable(s) are used, to be serviced by 1 entity per
123variable (no sharing), then the existing, in-market SetVariable(), without the
124APPEND attribute, could be used. Microsoft currently issues dbx updates
125exclusively with the APPEND attribute under the assumption that multiple
126entities might be servicing dbx. When a new revocation event takes place,
127rather than increasing the size of variables with image hashes, existing
128variables can simply be updated with new security generations, consuming no
129additional space. This constrains the number of entries to the number of unique
130boot components revoked, independent of generations revoked. The solution may
131support several major/minor versions, limiting revocation to build/security
132generations, perhaps via wildcards.
133
134While previously the APPEND attribute guaranteed that it would not be possible
135to downgrade the set of revocations on a system using a previously signed
136variable update, this guarantee can also be accomplished by setting the
137EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute. This will verify
138that the timestamp value of the signed data is later than the current timestamp
139value associated with the data currently stored in that variable.
140
141#### Generation-Based Revocation Scenarios
142
143Products (**not** vendors, a vendor can have multiple products or even pass a
144product from one vendor to another over time) are assigned a name. Product
145names can specify a specific version or refer to the entire product family. For
146example mydistro and mydistro,12.
147
148Components that are used as a link in the UEFI Secure Boot chain of trust are
149assigned names. Examples of components are shim, GRUB, kernel, hypervisors, etc.
150
151We could conceivably support sub-components, but it's hard to conceive of a
152scenario that would trigger a UEFI variable update that wouldn't justify a
153hypervisor or kernel re-release to enforce that sub-component level from there.
154Something like a "level 1.5 hypervisor" that can exist between different kernel
155generations can be considered its own component.
156
157Each component is assigned a minimum global generation number. Vendors signing
158component binary artifacts with a specific global generation number are
159required to include fixes for any public or pre-disclosed issue required for
160that generation. Additionally, in the event that a bypass only manifests in a
161specific product's component, vendors may ask for a product-specific generation
162number to be published for one of their product's components. This avoids
163triggering an industry wide re-publishing of otherwise safe components.
164
165A product-specific minimum generation number only applies to the instance of
166that component that is signed with that product name. Another product's
167instance of the same component may be installed on the same system and would
168not be subject to the other product's product-specific minimum generation
169number. However, both of those components will need to meet the global minimum
170generation number for that component. A very likely scenario would be that a
171product is shipped with an incomplete fix required for a specific minimum
172generation number, but is labeled with that number. Rather than having the
173entire industry that uses that component re-release, just that product's
174minimum generation number would be incremented and that product's component
175re-released along with a UEFI variable update specifying that requirement.
176
177The global and product-specific generation number name spaces are not tied to
178each other. The global number is managed externally, and the vast majority of
179products will never publish a minimum product-specific generation number for
180any of their components. Unspecified, more specific generation numbers are
181treated as 0.
182
183A minimum feature set, for example enforced kernel lock down, may be required
184as well to sign and label a component with a specific generation number. As
185time goes on, it is likely that the minimum feature set required for the
186currently valid generation number will expand. (For example, hypervisors
187supporting UEFI Secure Boot guests may at some point require memory encryption
188or similar protection mechanism.)
189
190The footprint of the UEFI variable payload will expand as product-specific
191generation numbers ahead of the global number are added. However, it will
192shrink again as the global number for that component is incremented again. The
193expectation is that a product-specific or vendor-specific generation number is
194a rare event, and that the generation number for the upstream code base will
195suffice in most cases.
196
197A product-specific generation number is needed if a CVE is fixed in code that
198**only** exists in a specific product's branch. This would either be something
199like product-specific patches, or a mis-merge that only occurred in that
200product. Setting a product-specific generation number for such an event
201eliminates the need for other vendors to have to re-release the binaries for
202their products with an incremented global number.
203
204However, once the global number is bumped for the next upstream CVE fix there
205will be no further need to carry that product-specific generation number.
206Satisfying the check of the global number will also exclude any of the older
207product-specific binaries.
208
209For example: There is a global CVE disclosure and all vendors coordinate to
210release fixed components on the disclosure date. This release bumps the global
211generation number for GRUB to 4.
212
213SBAT revocation data would then require a GRUB with a global generation number
214of 4.
215
216However, Vendor C mis-merges the patches into one of their products and does
217not become aware of the fact that this mis-merge created an additional
218vulnerability until after they have published a signed binary in that,
219vulnerable, state.
220
221Vendor C's GRUB binary can now be used to compromise anyone's system.
222
223To remedy this, Vendor C will release a fixed binary with the same global
224generation number and the product-specific generation number set to 1.
225
226SBAT revocation data would then require a GRUB with a global generation number
227of 4, as well as a product-specific generation number of 1 for the product that
228had the vulnerable binary.
229
230If and when there is another upstream fix for a CVE that would bump the global
231number, this product-specific number can be dropped from the UEFI revocation
232variable.
233
234If this same Vendor C has a similar event after the global number is
235incremented, they would again set their product-specific or version-specific
236number to 1. If they have a second event on with the same component, they would
237set their product-specific or version-specific number to 2.
238
239In such an event, a vendor would set the product-specific or version-specific
240generation number based on whether the mis-merge occurred in all of their
241branches or in just a subset of them. The goal is generally to limit end
242customer impact with as few re-releases as possible, while not creating an
243unnecessarily large UEFI revocation variable payload.
244
245| | prior to<br>disclosure | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure |
246|--------------------------------------------------------------------------------------|------------------------|---------------------|----------------------------------|----------------------------------|---------------------------------|
247| GRUB global<br>generation number in<br>artifacts .sbat section | 3 | 4 | 4 | 4 | 5 |
248| Vendor C's product-specific<br>generation number in artifact's<br>.sbat section | 1 | 1 | 5 | 6 | 1 |
249| GRUB global<br>generation number in<br>UEFI SBAT revocation variable | 3 | 4 | 4 | 4 | 5 |
250| Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set | not set | 5 | 6 | not set |
251
252The product-specific generation number does not reset and continues to
253monotonically increase over the course of these events. Continuity of more
254specific generation numbers must be maintained in this way in order to satisfy
255checks against older revocation data.
256
257The variable payload will be stored publicly in the shim source base and
258identify the global generation associated with a product or version-specific
259one. The payload is also built into shim to additionally limit exposure.
260
261#### Retiring Signed Releases
262
263Products that have reached the end of their support life by definition no
264longer receive patches. They are also generally not examined for CVEs. Allowing
265such unsupported products to continue to participate in UEFI Secure Boot is at
266the very least questionable. If an EoSL product is made up of commonly used
267components, such as the GRUB and the Linux kernel, it is reasonable to assume
268that the global generation numbers will eventually move forward and exclude
269those products from booting on a UEFI Secure Boot enabled system. However a
270product made up of GRUB and a closed source kernel is just as conceivable. In
271that case the kernel version may never move forward once the product reaches
272its end of support. Therefor it is recommended that the product-specific
273generation number be incremented past the latest one shown in any binary for
274that product, effectively disabling that product on UEFI Secure Boot enabled
275systems.
276
277A subset of this case would be a beta-release that may contain eventually
278abandoned, experimental, kernel code. Such releases should have their
279product-specific generation numbers incremented past the latest one shown in
280any released, or unreleased, binary signed with a production key.
281
282Until a release is retired in this manner, vendors are responsible for keeping
283up with fixes for CVEs and ensuring that any known signed binaries containing
284known CVEs are denied from booting on UEFI Secure Boot enabled systems via the
285most up to date UEFI metadata.
286
287#### Vendor Key Files
288
289Even prior to or without moving to one-shim, it is desirable to get every
290vendor onto as few shims as possible. Ideally a vendor would have a single shim
291signed with their certificate embedded and then use that certificate to sign
292additional <Vendor>_key.EFI key files that then contain all the keys that the
293individual components for their products are signed with. This file name needs
294to be registered at the time of shim review and should not be changed without
295going back to a shim review. A vendor should be able to store as many
296certificated (or a CA certificate) as they need for all the components of all
297of their products. Older versions of this file can be revoked via SBAT. In
298order to limit the footprint of the SBAT revocation metadata, it is vital that
299vendors do not create additional key files beyond what they have been approved
300for at shim review.
301
302#### Key Revocations
303
304Since Vendor Product keys are brought into Shim as signed binaries, generation
305numbering can and should be used to revoke them in case of a private key
306compromise.
307
308#### Kernel support for SBAT
309
310The initial SBAT implementation will add SBAT metadata to Shim and GRUB and
311enforce SBAT on all components labeled with it. Until a component (e.g. the
312Linux kernel gains SBAT metadata) it can not be revoked via SBAT, but only by
313revoking the keys signing that component. These keys will should live in
314separate, product-specific signed PE files that contain **only** the
315certificate and SBAT metadata for the key files. These key files can then be
316revoked via SBAT in order to invalidate and replace a specific key. While
317certificates built into Shim can be revoked via SBAT and Shim introspection,
318this practice would still result in a proliferation of Shim binaries that would
319need to be revoked via dbx in the event of an early Shim code bug. Therefore,
320SBAT must be used in conjunction with separate Vendor Product Key binaries.
321
322At the time of this writing, revoking a Linux kernel with a lockdown compromise
323is not spelled out as a requirement for shim signing. In fact, with limited dbx
324space and the size of the attack surface for lockdown it would be impractical
325do so without SBAT. With SBAT it should be possible to raise the bar, and treat
326lockdown bugs that would allow a kexec of a tampered kernel as revocations.
327
328#### Kernels execing other kernels (aka kexec, fast reboot)
329
330It is expected that kexec and other similar implementations of kernels spawning
331other kernels will eventually consume and honor SBAT metadata. Until they do,
332the same Vendor Product Key binary based revocation will need to be used for
333them.
334
335#### Generation-Based Revocation Metadata
336
337Adding a .sbat section containing the SBAT metadata structure to PE images.
338
339| field | meaning |
340|---|---|
341| component_name | the name we're comparing
342| component_generation | the generation number for the comparison
343| vendor_name | human readable vendor name
344| vendor_package_name | human readable package name
345| vendor_version | human readable package version (maybe machine parseable too, not specified here)
346| vendor_url | url to look stuff up, contact, whatever.
347
348The format of this .sbat section is comma separated values, or more
349specifically UTF-8 encoded strings.
350
351## Example sbat sections
352
353For grub, a build from a fresh checkout of upstream might have the following in
354`.sbat`:
355```
356sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
357grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
358```
359
360A Fedora build believed to have exactly the same set of vulnerabilities plus
361one that was never upstream might have:
362```
363sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
364grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
365grub.fedora,1,The Fedora Project,grub2,2.04-31.fc33,https://src.fedoraproject.org/rpms/grub2
366```
367
368Likewise, Red Hat has various builds for RHEL 7 and RHEL 8, all of which have
369something akin to the following in `.sbat`:
370```
371sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
372grub,1,Free Software Foundation,grub,2.02,https://www.gnu.org/software/grub/
373grub.fedora,1,Red Hat Enterprise Linux,grub2,2.02-0.34.fc24,mail:secalert@redhat.com
374grub.rhel,1,Red Hat Enterprise Linux,grub2,2.02-0.34.el7_2,mail:secalert@redhat.com
375```
376
377The Debian package believed to have the same set of vulnerabilities as upstream
378might have:
379```
380sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
381grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
382grub.debian,1,Debian,grub2,2.04-12,https://packages.debian.org/source/sid/grub2
383```
384
385Another party known for less than high quality software who carry a bunch of
386out of tree grub patches on top of a very old grub version from before any of
387the upstream vulns were committed to the tree. They haven't ever had the
388upstream vulns, and in fact have never shipped any vulnerabilities. Their grub
389`.sbat` might have the following (which we'd be very suspect of signing, but
390hey, suppose it turns out to be correct):
391```
392sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
393grub.acme,1,Acme Corporation,grub,1.96-8191,https://acme.arpa/packages/grub
394```
395
396At the same time, we're all shipping the same `shim-16` codebase, and in our
397`shim` builds, we all have the following in `.sbat`:
398```
399sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
400shim,1,UEFI shim,shim,16,https://github.com/rhboot/shim
401```
402
403## How to add .sbat sections
404
405Components that do not have special code to construct the final PE files can
406simply add this section using objcopy(1):
407
408```
409objcopy --set-section-alignment '.sbat=512' --add-section .sbat=sbat.csv foo.efi
410
411```
412
413Older versions of objcopy(1) do not support --set-section-alignment which is
414required to force the correct alignment expected from a PE file. As long as
415there is another step, later in the build process, such as an linker invocation
416that forces alignment, objcopy(1) does not need to align an intermediate file.
417
418#### UEFI SBAT Variable content
419
420The SBAT UEFI variable contains a descriptive form of all components used by
421all UEFI signed Operating Systems, along with a minimum generation number for
422each one. It may also contain a product-specific generation number, which in
423turn may also specify version-specific generation numbers. It is expected that
424specific generation numbers will be exceptions that will be obsoleted if and
425when the global number for a component is incremented.
426
427Initially the SBAT UEFI variable will set generation numbers for
428components to 1, but is expected to grow as CVEs are discovered and
429fixed. The following show the evolution over a sample set of events:
430
431## Starting point
432
433Before CVEs are encountered, an undesirable moudule was built into the a fedora
434grub, so it's product-specific generation number has been bumped:
435
436```
437sbat,1
438shim,1
439grub,1
440grub.fedora,2
441```
442
443## Along comes bug 1
444
445Another kind security researcher shows up with a serious bug, and this one was
446in upstream grub-0.94 and every version after that, and is shipped by all
447vendors.
448
449At this point, each vendor updates their grub builds, and updates the
450`component_generation` in `.sbat` to `2`. The GRUB upstream build now looks like:
451```
452sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
453grub,2,Free Software Foundation,grub,2.05,https://www.gnu.org/software/grub/
454```
455
456But Fedora's now looks like:
457```
458sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
459grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
460grub.fedora,2,The Fedora Project,grub2,2.04-33.fc33,https://src.fedoraproject.org/rpms/grub2
461```
462
463Other distros either rebase on 2.05 or theirs change similarly to Fedora's. We
464now have two options for Acme Corp:
465- add a `grub.acme,2` entry to `SBAT`
466- have Acme Corp add
467 `grub,2,Free Software Foundation,grub,1.96,https://www.gnu.org/software/grub/`
468 to their new build's `.sbat`
469
470We talk to Acme and they agree to do the latter, thus saving flash real estate
471to be developed on another day. Their binary now looks like:
472```
473sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
474grub,2,Free Software Foundation,grub,1.96,https://www.gnu.org/software/grub/
475grub.acme,1,Acme Corporation,grub,1.96-8192,https://acme.arpa/packages/grub
476```
477
478The UEFI CA issues an update which looks like:
479```
480sbat,1
481shim,1
482grub,2
483grub.fedora,2
484```
485
486Which is literally the byte array:
487```
488{
489 's', 'b', 'a', 't', ',', '1', '\n',
490 's', 'h', 'i', 'm', ',', '1', '\n',
491 'g', 'r', 'u', 'b', ',', '2', '\n',
492 'g', 'r', 'u', 'b', '.', 'f', 'e', 'd', 'o', 'r', 'a', ',', '2', '\n',
493}
494```
495
496## Acme Corp gets with the program
497
498Acme at this point discovers some features have been added to grub and they
499want them. They ship a new grub build that's completely rebased on top of
500upstream and has no known vulnerabilities. Its `.sbat` data looks like:
501```
502sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
503grub,2,Free Software Foundation,grub,2.05,https://www.gnu.org/software/grub/
504grub.acme,1,Acme Corporation,grub,2.05-1,https://acme.arpa/packages/grub
505```
506
507## Someone was wrong on the Internet and bug 2
508
509Debian discovers that they actually shipped bug 0 as well (woops). They
510produce a new build which fixes it and has the following in `.sbat`:
511```
512sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
513grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
514grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2
515```
516
517Before the UEFI CA has released an update, though, another upstream issue is
518found. Everybody updates their builds as they did for bug 1. Debian also
519updates theirs, as they would, and their new build has:
520```
521sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
522grub,3,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/
523grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2
524```
525
526And the UEFI CA issues an update to SBAT which has:
527```
528sbat,1
529shim,1
530grub,3
531grub.fedora,2
532```
533
534The grub.fedora product-specific line could be dropped since a Fedora GRUB with
535a global generation number that also contained the bug that prompted the
536fedora-specific revocation was never published. This results in the following
537reduced UEFI SBAT revocation update:
538```
539sbat,1
540shim,1
541grub,3
542```
543
544Two key things here:
545- `grub.debian` still got updated to `2` in their `.sbat` data, because a
546 vulnerability was fixed that is only covered by that updated number.
547- There is still no `SBAT` update for `grub.debian`, because there's no binary
548 that needs it which is not covered by updating `grub` to `3`.