crypt_policy/
lib.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! crypt_policy contains all the key policy logic for the different operations that can be done
6//! with hardware keys.  Keeping the policy logic in one place makes it easier to audit.
7
8use anyhow::{bail, Context, Error};
9
10#[derive(Clone, Copy, PartialEq)]
11pub enum Policy {
12    Null,
13    TeeRequired,
14    TeeTransitional,
15    TeeOpportunistic,
16}
17
18impl TryFrom<String> for Policy {
19    type Error = Error;
20
21    fn try_from(value: String) -> Result<Self, Self::Error> {
22        match value.as_ref() {
23            "null" => Ok(Policy::Null),
24            "tee" => Ok(Policy::TeeRequired),
25            "tee-transitional" => Ok(Policy::TeeTransitional),
26            "tee-opportunistic" => Ok(Policy::TeeOpportunistic),
27            p => bail!("unrecognized key source policy: '{p}'"),
28        }
29    }
30}
31
32/// Reads the policy from well-known locations in `/boot`.
33pub async fn get_policy() -> Result<Policy, Error> {
34    fuchsia_fs::file::read_in_namespace_to_string("/boot/config/zxcrypt").await?.try_into()
35}
36
37#[derive(Debug)]
38pub enum KeySource {
39    Null,
40    Tee,
41}
42
43/// Fxfs and zxcrypt have different null keys, so operations have to indicate which is ultimately
44/// going to consume the key we produce.
45pub enum KeyConsumer {
46    /// The null key for fxfs is a 128-bit key with the bytes "zxcrypt" at the beginning and then
47    /// padded with zeros. This is for legacy reasons - earlier versions of this code picked this
48    /// key, so we need to continue to use it to avoid wiping everyone's null-key-encrypted fxfs
49    /// data partitions.
50    Fxfs,
51    /// The null key for zxcrypt is a 256-bit key containing all zeros.
52    Zxcrypt,
53}
54
55impl KeySource {
56    pub async fn get_key(&self, consumer: KeyConsumer) -> Result<Vec<u8>, Error> {
57        match self {
58            KeySource::Null => match consumer {
59                KeyConsumer::Fxfs => {
60                    let mut key = b"zxcrypt".to_vec();
61                    key.resize(16, 0);
62                    Ok(key)
63                }
64                KeyConsumer::Zxcrypt => Ok(vec![0u8; 32]),
65            },
66            KeySource::Tee => {
67                // Regardless of the consumer of this key, the key we retrieve with kms is always
68                // named "zxcrypt". This is so that old recovery images that might not be aware of
69                // fxfs can still wipe the data keys during a factory reset.
70                kms_stateless::get_hardware_derived_key(kms_stateless::KeyInfo::new_zxcrypt())
71                    .await
72                    .context("failed to get hardware key")
73            }
74        }
75    }
76}
77
78/// Returns all valid key sources when formatting a volume, based on `policy`.
79pub fn format_sources(policy: Policy) -> Vec<KeySource> {
80    match policy {
81        Policy::Null => vec![KeySource::Null],
82        Policy::TeeRequired => vec![KeySource::Tee],
83        Policy::TeeTransitional => vec![KeySource::Tee],
84        Policy::TeeOpportunistic => vec![KeySource::Tee, KeySource::Null],
85    }
86}
87
88/// Returns all valid key sources when unsealing a volume, based on `policy`.
89pub fn unseal_sources(policy: Policy) -> Vec<KeySource> {
90    match policy {
91        Policy::Null => vec![KeySource::Null],
92        Policy::TeeRequired => vec![KeySource::Tee],
93        Policy::TeeTransitional => vec![KeySource::Tee, KeySource::Null],
94        Policy::TeeOpportunistic => vec![KeySource::Tee, KeySource::Null],
95    }
96}