Chapter 6

Trusted Boot

As described in Chapter 1, “Introduction to Trusted Computing,” one of the goals of TCG is to establish at boot time that the booted operating system has not been compromised. This “trusted boot” has to establish that the entire boot chain, including master boot record, boot loader, kernel, drivers, and all files referenced or executed during boot, have not changed in any way. There are two ways that TGC defines to establish this trust during boot: static root of trust and dynamic root of trust. This chapter discusses how you create a trusted boot state using the following:

  • The static root of trust
  • Trust chains
  • The dynamic root of trust
  • Localities

Trusted Boot with Static Root of Trust

In the static root of trust method, all trust starts with a fixed or immutable piece of trusted code in the BIOS. This trusted piece of code measures the next piece of code that is going to be executed, and extends a Platform Configuration Register (PCR) based on the measurement, before control is transferred to the next piece. If each new piece of code in turn measures the next before transferring control, a chain of trust is established. If this measurement chain continues through the entire boot sequence, the resultant PCR values reflect the measurement of all files used.

If an attacker successfully compromises one of the pieces of software in the boot chain, then the next time the system is booted, this compromised piece of code will be measured before it is executed. It cannot avoid being measured if it is part of the boot chain, and once it is executed, it cannot “take back” its own measurement, as the PCR extension operation can only hash in additional measurements. After the malicious code is executed, it is free to fake all the subsequent measurements, but there is no way for the malicious code to reset or “fix” the PCR back to the value it would have been in an uncompromised boot. Because the PCR extend operation is based on SHA-1 hash, which is cryptographically strong, it is computationally infeasible for the malicious code to calculate an extension value that would “fix” the PCR values.

The only assumption in the static root of trust chain model is that the first piece of software itself has not been compromised. Since most PC systems have reflashable BIOS software, which could allow an attacker to modify the BIOS and destroy the root of trust, TCG-compliant systems must have immutable initial BIOS code. This can be a small, fixed piece of BIOS, which can then measure the flashable bulk of the BIOS, but the initial part must be fixed.

Given an immutable static root of trust, after boot, the PCR values will reflect all measurements given to the chip. Any deviation of these values from the prior or expected values indicates that something has been changed. The question then is, how can the TPM enforce a trusted boot? Well, it can’t—at least not directly. The TPM cannot control the operation of the main processor. It’s just a character device that responds to any submitted request packets. So while the TPM’s PCR values can indicate that the software is or is not trusted, there has to be some way to act on this knowledge.

One thing that the TPM can enforce is the use of keys, which are wrapped under a specific set of PCR values, or the unsealing of data that was sealed under a specific set of PCR values. If some part of the software has been compromised, the PCR values will be different, and the TPM will refuse to unwrap keys or unseal data for the “trusted” PCR values. If the boot can be made to depend at least in part on wrapped keys or sealed data, then the TPM can enforce that the boot is trusted.

There are several ways to create this dependency on wrapped keys or sealed data. One simple way is to encrypt the root filesystem under a symmetric key, which is sealed under the PCR values of a trusted kernel and trusted init ramdisk images. When control reaches the init ramdisk startup script, it can attempt to unseal the symmetric encryption key, which will succeed only if the kernel and init ramdisk images are trusted. If the unsealing is successful, then the startup script can mount the encrypted root filesystem and continue the boot. If the unsealing is unsuccessful, then some software in the boot sequence must have been compromised; no matter how hard the malicious code tries, it will not be able to trick the TPM into unsealing the key for the encrypted root filesystem, and thus will not be able to access its files.

Note that this technique does not prevent the malicious code from booting; it simply prevents it from being able to access any TPM-protected keys or data. Going back to the original threat analysis, however, we can see that this is exactly what we wanted the TPM to do—to protect our sensitive private keys from being stolen, and to protect them from being used by malicious software.

There is one more step needed to more fully protect any wrapped keys or sealed data used in the trusted boot. So far, in a trusted boot, the key use or data unsealing was possible because the PCR values matched. If we leave the PCR values unchanged, then after the trusted boot, malicious code could be introduced that could continue to use the TPM to use the trusted boot keys or unseal the trusted boot data. For this reason, it is good practice to extend one or more of the PCRs used in the trusted boot with a random value. This “locks” the keys or sealed data against any further use until they are needed during the next trusted boot.

If any code or data that is measured into PCRs needs to change, it is necessary for the administrative action that takes this action to also unseal all the data values while in the old state and then reseal those values to what will become the new trusted state, so they will continue to be accessible.

Dynamic Root of Trust Measurements

The original TCG 1.1b specification outlined an authenticated bootstrap processor, known as static root of trust measurement. It essentially assumes that a machine is in a secure state and starts in an immutable environment (ROM BIOS) when it is booted. This trust is then maintained by measuring the next layer and storing the measurement inside a TPM before executing that next layer. The process is then repeated. This measure before you execute paradigm leads to a chain of trust that can be evaluated by a remote party to assess the trustworthiness of a system.

Although conceptually simple, this static root of trust measurement approach has some considerable challenges, as follows:

  • Scalability: A large chain of trust does not scale. In order for a recipient to determine the trustworthiness of a system, it needs to know the trustworthiness of all executable components that make up the chain. When you consider that a typical machine has some revision of a ROM BIOS and VGA BIOS, a number of extension ROMs, and some revision of an operating system with a set of patches applied, combined with the fact that some measurements are hashed into a single PCR and are thus dependent on the measurement order, it is easy to see that this problem can become intractable very quickly.
  • Time of measurement: A lot can happen between the time when a machine was started securely and when its trustworthiness is determined. For example, attackers could have exploited a buffer overflow and replaced the running executable. It is important to realize that a static root of trust gives you a load-time guarantee, not a run-time guarantee—that is, it guarantees what program is loaded, not necessarily what is running.
  • Inclusivity: For a static root of trust to be meaningful to a remote verifier, all executable content within the trusted computing base (TCB) needs to be measured. Many systems—for example, Linux and Windows—have an ill-defined TCB and therefore require all executable content to be measured (executables, libraries, shell scripts, and perl scripts) because all of them are security sensitive.

These shortcomings were identified by TCG, and as part of the TCG 1.2 specification, they defined a new mechanism for authenticated boot: dynamic root of trust measurement, or DRTM for short. Unlike static root of trust, with DRTM the root of trust can start at any moment in time and can be repeated as often as necessary.

DRTM is the underlying trust mechanism for Intel’s Lagrande Technology (LT) and AMD’s Presidio secure platform technology and requires processor as well as chipset changes. Although LT and Presidio include much more than just DRTM technology, DRTM does provide the core trust foundation for these systems.

The key concept behind DRTM is the introduction of a new CPU instruction that creates a controlled and attested execution environment. This environment cannot be influenced by any component in the system and therefore guarantees untampered execution of the secure loader that is typically started as a result of this new instruction. Intel calls this new instruction SENTER, and AMD calls it SKINIT. Although both DRTM mechanisms are functionally similar, they differ quite a bit when it comes to the details.

At the time of writing this book, only AMD has released a public specification on their Secure Virtual Machine CPU extensions (formerly known under the development name Pacifica), which includes support for hardware virtualization and DRTM instructions. In the following section, we examine this architecture more closely.

AMD’s Secure Virtual Machine

In 2005, AMD released a specification that describes their virtual machine and security extensions that are going to be part of their next-generation CPUs. Among the extensions is a new instruction, SKINIT, which is the basis for dynamic root of trust measurement support.

The SKINIT instruction reinitializes the processor and establishes a secure execution environment for the secure loader. That is an environment where the interrupts are disabled, virtual memory is turned off, DMA is inhibited, and all processors are quiesced except for the processor executing the SKINIT instruction. The secure loader of the virtual machine manager is wrapped inside a secure loader block, and before the CPU jumps into the secure loader, the secure loader block is measured and its measurement is stored in PCR17 inside the TPM. This PCR can be written only using special LPC bus cycles, which cannot be emulated in software. This ensures that only the CPU could have written the PCR17 value. It is this value that forms the dynamic root of trust measurement. To prevent any tampering with the SKINIT procedure, all the steps and conditions described previously are performed atomically.

The following function illustrates how to invoke the SKINIT instruction from C using the GNU compiler assembly extensions:

      #define EFER_SVME (1 << 12)
      #define MSR_EFER 0xc0000080             /* extended feature
                                               * register */

      int skinit(struct slb *slb)
      {
          unsigned long eax, edx;
          rdmsr(MSR_EFER, eax, edx);
          if (eax & EFER_SVME) {
              /* movl $slb, %eax; skinit */
              __asm__ __volatile__(
                      " .byte 0x0F, 0x01, 0xDE"
                      : : "a" (slb)
              );
          }
          return 0; /* failed */
      }

The skinit C function is called with the physical address of the secure loader block. After making sure the processor supports the SVM extensions (identified by bit 12 in the EFER model specific register), it stores the address of the secure loader block in the EAX register and then executes the SKINIT instruction. Unless SKINIT fails, it is guaranteed not to return to the caller.

The secure loader block consists of a header that specifies an entry point where the secure loader starts as well as the size of the block in bytes. The secure loader block should be aligned on a 64KB boundary, and its total size is limited to 64KB. The secure loader is invoked with the physical base address of the secure loader block in register EAX, the CPU model/family/stepping information is stored in register EDX, and the stack pointer ESP is initialized with the value of secure loader base address + 64KB. As far as the segment registers are concerned, CS and SS point to a 4GB 32-bit segment and the remaining segment registers are initialized with 16-bit descriptors.

Listing 6.1 is the skeleton for a secure loader in the GNU assembly file format.

Listing 6.1. Secure Loader in GNU Assembly Format

/* secure loader CS and DS descriptors */
#define SL_CS           0x08
#define SL_DS           0x10

        .text

sl_start:
        /* Secure loader block header */
        .word   sl_entry-sl_start        /* entry point offset */
        .word   sl_end-sl_start          /* size of SL */

        /* Secure loader runtime startoff */
        .align  4
        .globl  sl_entry
sl_entry:
        lgdt    %cs:sl_gdtr         /* only %cs and %ss are valid */

        movw    $SL_DS, %bx         /* secure loader data segment */
        movw    %bx, %ds
        movw    %bx, %ss
        movw    %bx, %es
        movw    %bx, %fs
        movw    %bx, %gs

        ljmp    $SL_CS, $1f         /* secure loader code segment */
1:

        pushl   %edx                /* model/family/stepping */
                pushl   %eax        /* secure loader base */

                /* ... REMAINDER OF THE SECURE LOADER CODE ... */

                jmp     .                       /* just in case */


                .align 32
                .global sl_gdt_start
        sl_gdt_start:
                .quad 0x0000000000000000        /* reserved */
                .quad 0x00cf9a000000ffff        /* secure loader CS */
                .quad 0x00cf92000000ffff        /* secure loader DS */
        sl_gdt_end:

        sl_gdtr:
                .word sl_gdt_end - sl_gdt_start - 1 /* limit for gdt*/
                .long sl_gdt_start                   /* gdt base */
sl_end:

The secure loader code is located right after the header. Part of the calling guarantee of this code is that interrupts are disabled, virtual memory is disabled, DMA is inhibited, and only one processor is executing. The first order of business for the secure loader is to reinitialize the segment registers to flat 32-bit descriptors that allow the secure loader to access all of the 4GB address space (see Intel Architecture manuals for more details). Once the secure loader is initialized, it should prepare the system for the execution of a trusted operating system.

Proof of Locality

The key idea behind the dynamic root of trust is that once the secure loader has bootstrapped a trusted operating system (OS), this OS will create multiple isolated security domains in which it can run guest OS or applications. A problem arises when the trusted OS, the guest OS, and the applications all use the TPM. How can you distinguish between measurements originating from the trusted OS, the guest OS, or the application?

To solve this dilemma, TCG introduced as part of their 1.2 specification the notion of a locality. A locality authenticates the originator of a TPM request. The specification defines five different localities. Locality 0 is intended for legacy support and behaves similar to a 1.1b TPM. The use of localities 1 to 3 are not specified, but they are typically associated with a trusted OS, guest OS, and the application. Locality 4 is special in that it authenticates the CPU, and it is used to authenticate the SKINIT instruction that is the basis for the dynamic root of trust.

Access to the localities 1–3 is controlled by the trusted OS. Each locality has its own interface to the TPM, and it is up to the trusted OS to assign the interfaces to the guest OS and application (see Chapter 4, “Writing a TPM Device Driver,” for more details).

Attestation in a Trusted Computing Group sense is done by having the TPM use a special type of signing key (called an AIK) to sign (attest) to data values stored internal to the TPM, and thus to provide evidence of the state of the machine on which the TPM was placed.

To assist in the attestation process, the 1.2 specification introduced new PCRs whose access is controlled by the current locality. For example, PCR17 can be written only as part of the SKINIT instruction (locality 4). It cannot be written from any other software locality and thus ensures that the PCR17 value came directly from the CPU. The same is true for PCR20, where only requests from locality 1 can write it. Table 6.1 lists all the PCRs that are part of the 1.2 specification and their usage.

Table 6.1. Listing of PCRs for the 1.2 Specification

image

Another feature that was introduced as part of the dynamic root of trust mechanism was the ability to reset certain PCRs. Only when the trusted OS is in control as a result of a SKINIT instruction can PCRs be reset according to the access control matrix listed in Table 6.1. Only PCRs that play a role in the DRTM mechanism can be reset.

Summary

This chapter has covered how the TPM can be used to launch an OS, which can later attest to its “trusted” state in several ways. The static root of trust (available in 1.1 TPMs) and the dynamic root of trust (available in both 1.1 and 1.2) are covered, and a specific implementation for the AMD Secure Virtual Machine is given. Understanding the dynamic root of trust also provides the added value of motivating the “locality” attributes of the TPM. With these understood, the reader should be able to understand how to handle machine state attestation as provided by a TPM.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.243.32