1use std::collections::BTreeMap;
9
10use anyhow::{Context, Error, anyhow, bail};
11
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum Policy {
14 Null,
15 TeeRequired,
16 TeeTransitional,
17 TeeOpportunistic,
18 Keymint,
19}
20
21impl TryFrom<String> for Policy {
22 type Error = Error;
23
24 fn try_from(value: String) -> Result<Self, Self::Error> {
25 match value.as_ref() {
26 "null" => Ok(Policy::Null),
27 "tee" => Ok(Policy::TeeRequired),
28 "tee-transitional" => Ok(Policy::TeeTransitional),
29 "tee-opportunistic" => Ok(Policy::TeeOpportunistic),
30 "keymint" => Ok(Policy::Keymint),
31 p => bail!("unrecognized key source policy: '{p}'"),
32 }
33 }
34}
35
36impl std::fmt::Display for Policy {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 Self::Null => f.write_str("null"),
40 Self::TeeRequired => f.write_str("tee"),
41 Self::TeeTransitional => f.write_str("tee-transitional"),
42 Self::TeeOpportunistic => f.write_str("tee-opportunistic"),
43 Self::Keymint => f.write_str("keymint"),
44 }
45 }
46}
47
48pub async fn get_policy() -> Result<Policy, Error> {
50 fuchsia_fs::file::read_in_namespace_to_string("/boot/config/zxcrypt").await?.try_into()
51}
52
53#[derive(Clone, Copy, Debug)]
56pub enum KeyConsumer {
57 Fxfs,
62 Zxcrypt,
64}
65
66#[derive(Debug)]
67pub struct NullKeySource;
68
69impl NullKeySource {
70 pub fn get_key(&self, consumer: KeyConsumer) -> Vec<u8> {
71 match consumer {
72 KeyConsumer::Fxfs => {
73 let mut key = b"zxcrypt".to_vec();
74 key.resize(16, 0);
75 key
76 }
77 KeyConsumer::Zxcrypt => vec![0u8; 32],
78 }
79 }
80}
81
82#[derive(Debug)]
83pub struct TeeDerivedKeySource;
84
85impl TeeDerivedKeySource {
86 pub async fn get_key(&self) -> Result<Vec<u8>, Error> {
87 kms_stateless::get_hardware_derived_key(kms_stateless::KeyInfo::new_zxcrypt())
91 .await
92 .context("failed to get hardware key")
93 }
94}
95
96#[derive(Clone, serde::Serialize, serde::Deserialize)]
101pub struct KeymintSealedData {
102 pub sealing_key_info: Vec<u8>,
103 pub sealing_key_blob: Vec<u8>,
104 pub sealed_keys: BTreeMap<String, Vec<u8>>,
105 #[serde(default)]
106 pub old_blob: Option<Vec<u8>>,
107}
108
109impl KeymintSealedData {
110 pub async fn new() -> Result<Self, Error> {
116 let mut sealing_key_info = vec![0u8; 32];
117 zx::cprng_draw(&mut sealing_key_info[..]);
118 let sealing_key_blob = kms_stateless::create_sealing_key(&sealing_key_info[..])
119 .await
120 .context("Failed to create sealing key")?;
121 Ok(Self {
122 sealing_key_info,
123 sealing_key_blob,
124 sealed_keys: BTreeMap::default(),
125 old_blob: None,
126 })
127 }
128
129 pub async fn create_key(&mut self, label: &str) -> Result<Vec<u8>, Error> {
132 let mut key = vec![0u8; 32];
133 zx::cprng_draw(&mut key[..]);
134 let sealed_data =
135 kms_stateless::seal(&self.sealing_key_info[..], &self.sealing_key_blob[..], &key[..])
136 .await
137 .context("Failed to seal keymint key")?;
138 self.sealed_keys.insert(label.to_string(), sealed_data);
139 Ok(key)
140 }
141
142 pub async fn unseal_key(&self, label: &str) -> Result<UnsealResult, Error> {
146 let sealed = self.sealed_keys.get(label).ok_or_else(|| anyhow!("Key not found"))?;
147 match kms_stateless::unseal(
148 &self.sealing_key_info[..],
149 &self.sealing_key_blob[..],
150 &sealed[..],
151 )
152 .await
153 {
154 Ok(key) => Ok(UnsealResult::Success(key)),
155 Err(e) => {
156 if let kms_stateless::SealingKeysError::Unseal(
157 fidl_fuchsia_security_keymint::UnsealError::KeyRequiresUpgrade,
158 ) = e
159 {
160 return Ok(UnsealResult::KeyRequiresUpgrade);
161 }
162 Err(e.into())
163 }
164 }
165 }
166
167 pub async fn upgrade_sealing_blob(&mut self) -> Result<(), Error> {
171 let new_blob = kms_stateless::upgrade_sealing_key(
172 &self.sealing_key_info[..],
173 &self.sealing_key_blob[..],
174 )
175 .await?;
176
177 let old_blob = std::mem::replace(&mut self.sealing_key_blob, new_blob);
178 if self.old_blob.is_some() {
179 tracing::warn!(
180 "Overwriting an existing old_blob during upgrade. A Keymint key has been leaked."
181 );
182 }
183 self.old_blob = Some(old_blob);
184
185 Ok(())
186 }
187}
188
189pub enum UnsealResult {
191 Success(Vec<u8>),
192 KeyRequiresUpgrade,
193}
194
195pub async fn delete_all_keymint_keys() -> Result<(), Error> {
197 Ok(kms_stateless::delete_all_keys().await?)
198}
199
200pub async fn delete_sealing_key(key_blob: &[u8]) -> Result<(), Error> {
202 Ok(kms_stateless::delete_sealing_key(key_blob).await?)
203}
204
205#[derive(Debug)]
206pub enum KeySource {
207 Null(NullKeySource),
209 TeeDerived(TeeDerivedKeySource),
212 KeymintSealed,
216}
217
218pub fn format_sources(policy: Policy) -> Vec<KeySource> {
220 match policy {
221 Policy::Null => vec![KeySource::Null(NullKeySource)],
222 Policy::TeeRequired => vec![KeySource::TeeDerived(TeeDerivedKeySource)],
223 Policy::TeeTransitional => vec![KeySource::TeeDerived(TeeDerivedKeySource)],
224 Policy::TeeOpportunistic => {
225 vec![KeySource::TeeDerived(TeeDerivedKeySource), KeySource::Null(NullKeySource)]
226 }
227 Policy::Keymint => vec![KeySource::KeymintSealed],
228 }
229}
230
231pub fn unseal_sources(policy: Policy) -> Vec<KeySource> {
233 match policy {
234 Policy::Null => vec![KeySource::Null(NullKeySource)],
235 Policy::TeeRequired => vec![KeySource::TeeDerived(TeeDerivedKeySource)],
236 Policy::TeeTransitional => {
237 vec![KeySource::TeeDerived(TeeDerivedKeySource), KeySource::Null(NullKeySource)]
238 }
239 Policy::TeeOpportunistic => {
240 vec![KeySource::TeeDerived(TeeDerivedKeySource), KeySource::Null(NullKeySource)]
241 }
242 Policy::Keymint => vec![KeySource::KeymintSealed],
243 }
244}