Android HLOS CDI handover

When the Android HLOS receives its CDI values and the DICE chain from the previous stage, it reads them and then derives and wipes the necessary secrets (such as public and private key pairs and further CDI stages) for SDV Service Discovery.

This process takes place as soon as possible in the bootflow during early-init in the second stage init. Doing so makes sure that Android HLOS consumes and wipes the CDI values before any third-party code executes.

The Android Bootloader (or the guest loader in the hypervisor, if no Android Bootloader exists) passes the following values through the SDV's Linux Kernel to second stage init in Android user-space:

  • Attestation CDI value of the Android HLOS layer.
  • Sealing CDI value of the Android HLOS layer.
  • CBOR-encoded DICE chain until the Android HLOS layer.

These values use the SdvDiceHandover format. The SdvDiceHandover is a CBOR-encoded map described by this CDDL fragment:

SdvDiceHandover = {
   1 : bstr .size 32, ; CDI_Attest
   2 : bstr .size 32, ; CDI_Seal
   3 : DiceCertChain, ; Android SDV DICE chain
}

The IRemotelyProvisionedComponent HAL DiceCertChain specifies the format of the DiceCertChain. You don't require deterministically encoded CBOR for SdvDiceHandover, though it's highly recommended as it supports a wider range of DICE policies.

The SdvDiceHandover format is very similar to the:

  • AndroidDiceHandover format that the Open Profile for DICE reference implementation defines,

  • PvmfwDiceHandover format that the pvmfw uses to hand over the DICE chain to a pVM. For example, Microdroid.

In contrast to the AndroidDiceHandover and similarly to the PvmfwDiceHandover format, the DiceCertChain is required and not optional.

Open Profile for DICE kernel driver

The DICE handover of the Android HLOS CDI from the Android Bootloader (or the guest loader in the hypervisor, if there's no bootloader) to the Android HLOS relies on the Open Profile for DICE kernel driver. The Android Bootloader writes the DICE Chain entry to a region in the guest's memory that the Device Tree (DT) must specify.

The driver reads this memory region that the DT specifies and exposes it the user space as an /dev/open-dice0 device. The driver allows reading and wiping this memory region. The Open Profile for DICE driver only exists on arm64 architectures because device tree is an arm64-only concept.

Specify the memory region that the Open Profile for DICE driver exposes using a reserved-memory node in the DT that you tag for the driver by specifying "google,open-dice" in the compatible property. For example:

reserved-memory {
  // The number of u32 cells to represent the address of a memory region
  #address-cells = <2>;
  // The number of u32 cells to represent the size of a memory region
  #size-cells = <2>;
  ranges;
  // The unit address (after the @) must match the address in the reg property
  dice@D1C30000 {
    compatible = "google,open-dice";
    no-map;
    // The address and the size of the memory region that is passed to the Open
    // Profile for DICE driver. The address must be page-aligned, and the size a
    // multiple of the page size. The first two hex numbers (cells) represent
    // the address of the memory region, the last two represent its size.
    reg = <0x0 0xD1C30000 0x0 0x1000>;
  };
};