# DICE chain policies DICE policy is the mechanism for specifying constraints on a DICE chain. A DICE chain policy verifier takes a policy and a DICE chain, and returns whether the DICE chain meets the constraints set out in the policy. ## Navigating this project This directory exports Rust crates for matching Dice Chains against Dice Policies as well building Dice Policies. 1. [./building/](https://cs.android.com/android/platform/superproject/main/+/main:system/secretkeeper/dice_policy/building/src/lib.rs): Supports constructing Dice Policies on a Dice chains, enabling various ways to specify the constraints. 1. [./src/](https://cs.android.com/android/platform/superproject/main/+/main:system/secretkeeper/dice_policy/src/lib.rs): Supports matching Dice Chains against Dice Policies. ## DICE chain [Open Profile for DICE][open_dice_spec] is designed to be layered. The certificate generated by the next DICE layer can chain to the certificate generated by the previous DICE layer. This chain of certificates has been termed as DICE chain in context of this documentation. Note that the libraries in this directory are implemented to work with DICE chains following tighter constraints of [Android Profile for DICE chains][android_dice_spec], although the concept is applicable to any DICE chain profiles. ## Rollback protection and DICE Each component in a DICE chain receives a secret, the “attestation CDI”, which depends on all of the information in the chain up to that point; this secret is used to protect a signing keypair that the component uses to sign DICE assertions. This secret isn’t useful for protecting component data, since it changes whenever the component or any part of the boot chain is updated. Some DICE implementations provide a “sealing CDI” which depends only on stable information such as component names and the public keys used to sign components. However, this provides no protection against attacks based on version rollback because it doesn't include any version information. To resolve this, we change the sealing operation to take an additional input called a “policy”. Unsealing is only permitted if the DICE chain for the component requesting unsealing complies with the policy given when the message was sealed. A typical policy will assert things like: 1. UDS_Public must have a specific value 1. The DICE chain must be exactly five certificates long 1. authorityHash in the third certificate must have this value 1. securityVersion in the fourth certificate must be an integer greater than 8 At sealing time, the component performing the sealing must compose a policy that meets its needs: specific enough that its secrets are protected from attackers, but general enough that future versions of the component can unseal them. Projects such as [Secretkeeper][sk_project] use policy-based protection; they are the foundation to providing rollback-secure identities and secrets to VMs and Authgraph participants. ## Example DICE policy Below is a highly simplified DICE policy on DICE chains specifying (among other things) that a particular DiceChainEntry need to have auth_hash value exactly equal to specified one and security_version >= 5. ``` DicePolicy { version: 1, node_constraint_list: NodeConstraints [ Constraint { type=ExactMatch, path=[] value="1", }, ] node_constraint_list: NodeConstraints [ Constraint { type=ExactMatch, path=[] value="a50101032704810220062158203e85e5727555e51ee7f335948ebbbd741e1dca499c97397706d3c86e8bd733f9", }, ] node_constraint_list: NodeConstraints [ Constraint { type=ExactMatch, path=[authority_hash] value="04255d605f5c450df29a6e993003b8d6e199711bf844fab531791c37684e1dc0247468f880203e44b143d29cfc129e770ade2924ff2efac710d573d4c6df629f", }, Constraint { type=ExactMatch, path=[mode] value="01", }, Constraint { type=GreaterOrEqual, path=[config_desc,security_version] value="5", }, ] } ``` ## CBOR representation ### Explicit-key DiceCertChain format In the [Android Profile for DICE][android_dice_spec] `DiceCertChain` format specification, the `subjectPublicKey` in a certificate which describes the signing key of the next party in the chain is specified as a `.bstr cbor`: a binary string containing CBOR data. This makes it very easy to define eg “the hash of the public key” or compare two keys for identity. However, this is not true of the first public key in the chain, UDS_Public, derived from the Unique Device Secret (UDS). For example, it means that the DICE chain verifiers have to resort custom look ups look up to converted from COSE_Key form to an algorithm-specific non-COSE format for lookup. The policy comparison code should stay as simple and predictable as possible, algorithm specific lookups should be avoided. So instead we specify a new DICE chain format which is slightly different to the DiceCertChain format and addresses this issue. We don’t anticipate that devices will switch to using this new chain from the moment they boot - that would be a disruptive change. Instead, we anticipate that components will receive their DICE chain in DiceCertChain format, and convert it to “ExplicitKeyDiceCertChain” format before presenting it to any other party in any context where policy comparisons are relevant. This conversion must be deterministic so that the UDS_Public bstr presented on the device never changes, or policy comparisons will fail; CBOR canonicalization can be used to this end. ``` ExplicitKeyDiceCertChain = [ 1, ; version, hopefully will never change DiceCertChainInitialPayload, * DiceChainEntry ] ; Encoded in accordance with Core Deterministic Encoding Requirements [RFC 8949 s4.2.1] DiceCertChainInitialPayload = bstr .cbor PubKeyEd25519 / bstr .cbor PubKeyECDSA256 / bstr .cbor PubKeyECDSA384 ; subjectPublicKey ``` ## DICE policy specification The spec is extracted from [DicePolicy.cddl][dicepolicycddl] ``` dicePolicy = [ 1, ; version, hopefully will never change + nodeConstraintList ] nodeConstraintList = [ * nodeConstraint ] ; We may add a hashConstraint item later nodeConstraint = exactMatchConstraint / geConstraint exactMatchConstraint = [1, keySpec, value] geConstraint = [2, keySpec, int] keySpec = [value+] value = bool / int / tstr / bstr ``` [android_dice_spec]: https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl [dicepolicycddl]: https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/security/authgraph/aidl/android/hardware/security/authgraph/DicePolicy.cddl [open_dice_spec]: https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#Layering-Details [sk_project]: https://android.git.corp.google.com/platform/system/secretkeeper/