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