• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Utilities for handling legacy KeyMaster/KeyMint key blobs.
2 
3 use crate::tag::legacy::{consume_i32, consume_u32, consume_u8, consume_vec};
4 use crate::{
5     crypto, get_opt_tag_value, km_err, try_to_vec, vec_try_with_capacity, Error, FallibleAllocExt,
6 };
7 use alloc::vec::Vec;
8 use core::mem::size_of;
9 use kmr_wire::keymint::KeyParam;
10 
11 #[cfg(test)]
12 mod tests;
13 
14 /// Key blob version.
15 const KEY_BLOB_VERSION: u8 = 0;
16 
17 /// Hard-coded HMAC key used for keyblob authentication.
18 const HMAC_KEY: &[u8] = b"IntegrityAssuredBlob0\0";
19 
20 /// Format of encrypted key blob.
21 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
22 pub enum AuthEncryptedBlobFormat {
23     AesOcb = 0,
24     AesGcmWithSwEnforced = 1,
25     AesGcmWithSecureDeletion = 2,
26     AesGcmWithSwEnforcedVersioned = 3,
27     AesGcmWithSecureDeletionVersioned = 4,
28 }
29 
30 impl AuthEncryptedBlobFormat {
requires_secure_deletion(&self) -> bool31     pub fn requires_secure_deletion(&self) -> bool {
32         matches!(self, Self::AesGcmWithSecureDeletion | Self::AesGcmWithSecureDeletionVersioned)
33     }
is_versioned(&self) -> bool34     pub fn is_versioned(&self) -> bool {
35         matches!(
36             self,
37             Self::AesGcmWithSwEnforcedVersioned | Self::AesGcmWithSecureDeletionVersioned
38         )
39     }
40 }
41 
42 /// Encrypted key blob, including key characteristics.
43 #[derive(Debug, PartialEq, Eq)]
44 pub struct EncryptedKeyBlob {
45     pub format: AuthEncryptedBlobFormat,
46     // IV for encryption.
47     pub nonce: Vec<u8>,
48     // Encrypted key material.
49     pub ciphertext: Vec<u8>,
50     // Authenticated encryption tag.
51     pub tag: Vec<u8>,
52 
53     // The following two fields are preset iff `format.is_versioned()`
54     pub kdf_version: Option<u32>,
55     pub addl_info: Option<i32>,
56 
57     pub hw_enforced: Vec<KeyParam>,
58     pub sw_enforced: Vec<KeyParam>,
59     pub key_slot: Option<u32>,
60 }
61 
62 impl EncryptedKeyBlob {
63     /// Serialize an [`EncryptedKeyBlob`].
serialize(&self) -> Result<Vec<u8>, Error>64     pub fn serialize(&self) -> Result<Vec<u8>, Error> {
65         let hw_enforced_data = crate::tag::legacy::serialize(&self.hw_enforced)?;
66         let sw_enforced_data = crate::tag::legacy::serialize(&self.sw_enforced)?;
67         let mut result = vec_try_with_capacity!(
68             size_of::<u8>()
69                 + size_of::<u32>()
70                 + self.nonce.len()
71                 + size_of::<u32>()
72                 + self.ciphertext.len()
73                 + size_of::<u32>()
74                 + self.tag.len()
75                 + hw_enforced_data.len()
76                 + sw_enforced_data.len()
77                 + size_of::<u32>()
78         )?;
79         result.push(self.format as u8);
80         result.extend_from_slice(&(self.nonce.len() as u32).to_ne_bytes());
81         result.extend_from_slice(&self.nonce);
82         result.extend_from_slice(&(self.ciphertext.len() as u32).to_ne_bytes());
83         result.extend_from_slice(&self.ciphertext);
84         result.extend_from_slice(&(self.tag.len() as u32).to_ne_bytes());
85         result.extend_from_slice(&self.tag);
86         if self.format.is_versioned() {
87             let kdf_version = self.kdf_version.ok_or_else(|| {
88                 km_err!(UnknownError, "keyblob of format {:?} missing kdf_version", self.format)
89             })?;
90             let addl_info = self.addl_info.ok_or_else(|| {
91                 km_err!(UnknownError, "keyblob of format {:?} missing addl_info", self.format)
92             })? as u32;
93             result.extend_from_slice(&kdf_version.to_ne_bytes());
94             result.extend_from_slice(&addl_info.to_ne_bytes());
95         }
96         result.extend_from_slice(&hw_enforced_data);
97         result.extend_from_slice(&sw_enforced_data);
98         if let Some(slot) = self.key_slot {
99             result.extend_from_slice(&slot.to_ne_bytes());
100         }
101         Ok(result)
102     }
103 
104     /// Parse a serialized [`KeyBlob`].
deserialize(mut data: &[u8]) -> Result<Self, Error>105     pub fn deserialize(mut data: &[u8]) -> Result<Self, Error> {
106         let format = match consume_u8(&mut data)? {
107             x if x == AuthEncryptedBlobFormat::AesOcb as u8 => AuthEncryptedBlobFormat::AesOcb,
108             x if x == AuthEncryptedBlobFormat::AesGcmWithSwEnforced as u8 => {
109                 AuthEncryptedBlobFormat::AesGcmWithSwEnforced
110             }
111             x if x == AuthEncryptedBlobFormat::AesGcmWithSecureDeletion as u8 => {
112                 AuthEncryptedBlobFormat::AesGcmWithSecureDeletion
113             }
114             x if x == AuthEncryptedBlobFormat::AesGcmWithSwEnforcedVersioned as u8 => {
115                 AuthEncryptedBlobFormat::AesGcmWithSwEnforcedVersioned
116             }
117             x if x == AuthEncryptedBlobFormat::AesGcmWithSecureDeletionVersioned as u8 => {
118                 AuthEncryptedBlobFormat::AesGcmWithSecureDeletionVersioned
119             }
120             x => return Err(km_err!(InvalidKeyBlob, "unexpected blob format {}", x)),
121         };
122 
123         let nonce = consume_vec(&mut data)?;
124         let ciphertext = consume_vec(&mut data)?;
125         let tag = consume_vec(&mut data)?;
126         let mut kdf_version = None;
127         let mut addl_info = None;
128         if format.is_versioned() {
129             kdf_version = Some(consume_u32(&mut data)?);
130             addl_info = Some(consume_i32(&mut data)?);
131         }
132         let hw_enforced = crate::tag::legacy::deserialize(&mut data)?;
133         let sw_enforced = crate::tag::legacy::deserialize(&mut data)?;
134 
135         let key_slot = match data.len() {
136             0 => None,
137             4 => Some(consume_u32(&mut data)?),
138             _ => return Err(km_err!(InvalidKeyBlob, "unexpected remaining length {}", data.len())),
139         };
140 
141         Ok(EncryptedKeyBlob {
142             format,
143             nonce,
144             ciphertext,
145             tag,
146             kdf_version,
147             addl_info,
148             hw_enforced,
149             sw_enforced,
150             key_slot,
151         })
152     }
153 }
154 
155 /// Plaintext key blob, with key characteristics.
156 #[derive(Debug, PartialEq, Eq)]
157 pub struct KeyBlob {
158     pub key_material: Vec<u8>,
159     pub hw_enforced: Vec<KeyParam>,
160     pub sw_enforced: Vec<KeyParam>,
161 }
162 
163 impl KeyBlob {
164     /// Size (in bytes) of appended MAC.
165     pub const MAC_LEN: usize = 8;
166 
167     /// Serialize a [`KeyBlob`].
serialize<H: crypto::Hmac>( &self, hmac: &H, hidden: &[KeyParam], ) -> Result<Vec<u8>, crate::Error>168     pub fn serialize<H: crypto::Hmac>(
169         &self,
170         hmac: &H,
171         hidden: &[KeyParam],
172     ) -> Result<Vec<u8>, crate::Error> {
173         let hw_enforced_data = crate::tag::legacy::serialize(&self.hw_enforced)?;
174         let sw_enforced_data = crate::tag::legacy::serialize(&self.sw_enforced)?;
175         let mut result = vec_try_with_capacity!(
176             size_of::<u8>()
177                 + size_of::<u32>()
178                 + self.key_material.len()
179                 + hw_enforced_data.len()
180                 + sw_enforced_data.len()
181         )?;
182         result.push(KEY_BLOB_VERSION);
183         result.extend_from_slice(&(self.key_material.len() as u32).to_ne_bytes());
184         result.extend_from_slice(&self.key_material);
185         result.extend_from_slice(&hw_enforced_data);
186         result.extend_from_slice(&sw_enforced_data);
187         let mac = Self::compute_hmac(hmac, &result, hidden)?;
188         result.extend_from_slice(&mac);
189         Ok(result)
190     }
191 
192     /// Parse a serialized [`KeyBlob`].
deserialize<E: crypto::ConstTimeEq, H: crypto::Hmac>( hmac: &H, mut data: &[u8], hidden: &[KeyParam], comparator: E, ) -> Result<Self, Error>193     pub fn deserialize<E: crypto::ConstTimeEq, H: crypto::Hmac>(
194         hmac: &H,
195         mut data: &[u8],
196         hidden: &[KeyParam],
197         comparator: E,
198     ) -> Result<Self, Error> {
199         if data.len() < (Self::MAC_LEN + 4 + 4 + 4) {
200             return Err(km_err!(InvalidKeyBlob, "blob not long enough (len = {})", data.len()));
201         }
202 
203         // Check the HMAC in the last 8 bytes before doing anything else.
204         let mac = &data[data.len() - Self::MAC_LEN..];
205         let computed_mac = Self::compute_hmac(hmac, &data[..data.len() - Self::MAC_LEN], hidden)?;
206         if comparator.ne(mac, &computed_mac) {
207             return Err(km_err!(InvalidKeyBlob, "invalid key blob"));
208         }
209 
210         let version = consume_u8(&mut data)?;
211         if version != KEY_BLOB_VERSION {
212             return Err(km_err!(InvalidKeyBlob, "unexpected blob version {}", version));
213         }
214         let key_material = consume_vec(&mut data)?;
215         let hw_enforced = crate::tag::legacy::deserialize(&mut data)?;
216         let sw_enforced = crate::tag::legacy::deserialize(&mut data)?;
217 
218         // Should just be the (already-checked) MAC left.
219         let rest = &data[Self::MAC_LEN..];
220         if !rest.is_empty() {
221             return Err(km_err!(InvalidKeyBlob, "extra data (len {})", rest.len()));
222         }
223         Ok(KeyBlob { key_material, hw_enforced, sw_enforced })
224     }
225 
226     /// Compute the authentication HMAC for a KeyBlob. This is built as:
227     ///   HMAC-SHA256(HK, data || serialize(hidden))
228     /// with HK = b"IntegrityAssuredBlob0\0".
compute_hmac<H: crypto::Hmac>( hmac: &H, data: &[u8], hidden: &[KeyParam], ) -> Result<Vec<u8>, crate::Error>229     pub fn compute_hmac<H: crypto::Hmac>(
230         hmac: &H,
231         data: &[u8],
232         hidden: &[KeyParam],
233     ) -> Result<Vec<u8>, crate::Error> {
234         let hidden_data = crate::tag::legacy::serialize(hidden)?;
235         let mut op = hmac.begin(
236             crypto::hmac::Key(try_to_vec(HMAC_KEY)?).into(),
237             kmr_wire::keymint::Digest::Sha256,
238         )?;
239         op.update(data)?;
240         op.update(&hidden_data)?;
241         let mut tag = op.finish()?;
242         tag.truncate(Self::MAC_LEN);
243         Ok(tag)
244     }
245 }
246 
247 /// Build the parameters that are used as the hidden input to HMAC calculations:
248 /// - `ApplicationId(data)` if present
249 /// - `ApplicationData(data)` if present
250 /// - (repeated) `RootOfTrust(rot)` where `rot` is a hardcoded root of trust (expected to
251 ///   be the CBOR serialization of a `RootOfTrustInfo` instance).
hidden(params: &[KeyParam], rots: &[&[u8]]) -> Result<Vec<KeyParam>, Error>252 pub fn hidden(params: &[KeyParam], rots: &[&[u8]]) -> Result<Vec<KeyParam>, Error> {
253     let mut results = Vec::new();
254     if let Ok(Some(app_id)) = get_opt_tag_value!(params, ApplicationId) {
255         results.try_push(KeyParam::ApplicationId(try_to_vec(app_id)?))?;
256     }
257     if let Ok(Some(app_data)) = get_opt_tag_value!(params, ApplicationData) {
258         results.try_push(KeyParam::ApplicationData(try_to_vec(app_data)?))?;
259     }
260     for rot in rots {
261         results.try_push(KeyParam::RootOfTrust(try_to_vec(rot)?))?;
262     }
263     Ok(results)
264 }
265