• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020, 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 //! This module implements methods to load legacy keystore key blob files.
16 
17 use crate::{
18     error::{Error as KsError, ResponseCode},
19     key_parameter::{KeyParameter, KeyParameterValue},
20     super_key::SuperKeyManager,
21     utils::uid_to_android_user,
22 };
23 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
24     SecurityLevel::SecurityLevel, Tag::Tag, TagType::TagType,
25 };
26 use anyhow::{Context, Result};
27 use keystore2_crypto::{aes_gcm_decrypt, Password, ZVec};
28 use std::collections::{HashMap, HashSet};
29 use std::{convert::TryInto, fs::File, path::Path, path::PathBuf};
30 use std::{
31     fs,
32     io::{ErrorKind, Read, Result as IoResult},
33 };
34 
35 const SUPPORTED_LEGACY_BLOB_VERSION: u8 = 3;
36 
37 mod flags {
38     /// This flag is deprecated. It is here to support keys that have been written with this flag
39     /// set, but we don't create any new keys with this flag.
40     pub const ENCRYPTED: u8 = 1 << 0;
41     /// This flag is deprecated. It indicates that the blob was generated and thus owned by a
42     /// software fallback Keymaster implementation. Keymaster 1.0 was the last Keymaster version
43     /// that could be accompanied by a software fallback. With the removal of Keymaster 1.0
44     /// support, this flag is obsolete.
45     pub const FALLBACK: u8 = 1 << 1;
46     /// KEYSTORE_FLAG_SUPER_ENCRYPTED is for blobs that are already encrypted by KM but have
47     /// an additional layer of password-based encryption applied. The same encryption scheme is used
48     /// as KEYSTORE_FLAG_ENCRYPTED. The latter is deprecated.
49     pub const SUPER_ENCRYPTED: u8 = 1 << 2;
50     /// KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION is for blobs that are part of device encryption
51     /// flow so it receives special treatment from keystore. For example this blob will not be super
52     /// encrypted, and it will be stored separately under a unique UID instead. This flag should
53     /// only be available to system uid.
54     pub const CRITICAL_TO_DEVICE_ENCRYPTION: u8 = 1 << 3;
55     /// The blob is associated with the security level Strongbox as opposed to TEE.
56     pub const STRONGBOX: u8 = 1 << 4;
57 }
58 
59 /// Lagacy key blob types.
60 mod blob_types {
61     /// A generic blob used for non sensitive unstructured blobs.
62     pub const GENERIC: u8 = 1;
63     /// This key is a super encryption key encrypted with AES128
64     /// and a password derived key.
65     pub const SUPER_KEY: u8 = 2;
66     // Used to be the KEY_PAIR type.
67     const _RESERVED: u8 = 3;
68     /// A KM key blob.
69     pub const KM_BLOB: u8 = 4;
70     /// A legacy key characteristics file. This has only a single list of Authorizations.
71     pub const KEY_CHARACTERISTICS: u8 = 5;
72     /// A key characteristics cache has both a hardware enforced and a software enforced list
73     /// of authorizations.
74     pub const KEY_CHARACTERISTICS_CACHE: u8 = 6;
75     /// Like SUPER_KEY but encrypted with AES256.
76     pub const SUPER_KEY_AES256: u8 = 7;
77 }
78 
79 /// Error codes specific to the legacy blob module.
80 #[derive(thiserror::Error, Debug, Eq, PartialEq)]
81 pub enum Error {
82     /// Returned by the legacy blob module functions if an input stream
83     /// did not have enough bytes to read.
84     #[error("Input stream had insufficient bytes to read.")]
85     BadLen,
86     /// This error code is returned by `Blob::decode_alias` if it encounters
87     /// an invalid alias filename encoding.
88     #[error("Invalid alias filename encoding.")]
89     BadEncoding,
90 }
91 
92 /// The blob payload, optionally with all information required to decrypt it.
93 #[derive(Debug, Eq, PartialEq)]
94 pub enum BlobValue {
95     /// A generic blob used for non sensitive unstructured blobs.
96     Generic(Vec<u8>),
97     /// A legacy key characteristics file. This has only a single list of Authorizations.
98     Characteristics(Vec<u8>),
99     /// A key characteristics cache has both a hardware enforced and a software enforced list
100     /// of authorizations.
101     CharacteristicsCache(Vec<u8>),
102     /// A password encrypted blob. Includes the initialization vector, the aead tag, the
103     /// ciphertext data, a salt, and a key size. The latter two are used for key derivation.
104     PwEncrypted {
105         /// Initialization vector.
106         iv: Vec<u8>,
107         /// Aead tag for integrity verification.
108         tag: Vec<u8>,
109         /// Ciphertext.
110         data: Vec<u8>,
111         /// Salt for key derivation.
112         salt: Vec<u8>,
113         /// Key sise for key derivation. This selects between AES128 GCM and AES256 GCM.
114         key_size: usize,
115     },
116     /// An encrypted blob. Includes the initialization vector, the aead tag, and the
117     /// ciphertext data. The key can be selected from context, i.e., the owner of the key
118     /// blob.
119     Encrypted {
120         /// Initialization vector.
121         iv: Vec<u8>,
122         /// Aead tag for integrity verification.
123         tag: Vec<u8>,
124         /// Ciphertext.
125         data: Vec<u8>,
126     },
127     /// Holds the plaintext key blob either after unwrapping an encrypted blob or when the
128     /// blob was stored in "plaintext" on disk. The "plaintext" of a key blob is not actual
129     /// plaintext because all KeyMint blobs are encrypted with a device bound key. The key
130     /// blob in this Variant is decrypted only with respect to any extra layer of encryption
131     /// that Keystore added.
132     Decrypted(ZVec),
133 }
134 
135 /// Represents a loaded legacy key blob file.
136 #[derive(Debug, Eq, PartialEq)]
137 pub struct Blob {
138     flags: u8,
139     value: BlobValue,
140 }
141 
142 /// This object represents a path that holds a legacy Keystore blob database.
143 pub struct LegacyBlobLoader {
144     path: PathBuf,
145 }
146 
read_bool(stream: &mut dyn Read) -> Result<bool>147 fn read_bool(stream: &mut dyn Read) -> Result<bool> {
148     const SIZE: usize = std::mem::size_of::<bool>();
149     let mut buffer: [u8; SIZE] = [0; SIZE];
150     stream.read_exact(&mut buffer).map(|_| buffer[0] != 0).context("In read_ne_bool.")
151 }
152 
read_ne_u32(stream: &mut dyn Read) -> Result<u32>153 fn read_ne_u32(stream: &mut dyn Read) -> Result<u32> {
154     const SIZE: usize = std::mem::size_of::<u32>();
155     let mut buffer: [u8; SIZE] = [0; SIZE];
156     stream.read_exact(&mut buffer).map(|_| u32::from_ne_bytes(buffer)).context("In read_ne_u32.")
157 }
158 
read_ne_i32(stream: &mut dyn Read) -> Result<i32>159 fn read_ne_i32(stream: &mut dyn Read) -> Result<i32> {
160     const SIZE: usize = std::mem::size_of::<i32>();
161     let mut buffer: [u8; SIZE] = [0; SIZE];
162     stream.read_exact(&mut buffer).map(|_| i32::from_ne_bytes(buffer)).context("In read_ne_i32.")
163 }
164 
read_ne_i64(stream: &mut dyn Read) -> Result<i64>165 fn read_ne_i64(stream: &mut dyn Read) -> Result<i64> {
166     const SIZE: usize = std::mem::size_of::<i64>();
167     let mut buffer: [u8; SIZE] = [0; SIZE];
168     stream.read_exact(&mut buffer).map(|_| i64::from_ne_bytes(buffer)).context("In read_ne_i64.")
169 }
170 
171 impl Blob {
172     /// This blob was generated with a fallback software KM device.
is_fallback(&self) -> bool173     pub fn is_fallback(&self) -> bool {
174         self.flags & flags::FALLBACK != 0
175     }
176 
177     /// This blob is encrypted and needs to be decrypted with the user specific master key
178     /// before use.
is_encrypted(&self) -> bool179     pub fn is_encrypted(&self) -> bool {
180         self.flags & (flags::SUPER_ENCRYPTED | flags::ENCRYPTED) != 0
181     }
182 
183     /// This blob is critical to device encryption. It cannot be encrypted with the super key
184     /// because it is itself part of the key derivation process for the key encrypting the
185     /// super key.
is_critical_to_device_encryption(&self) -> bool186     pub fn is_critical_to_device_encryption(&self) -> bool {
187         self.flags & flags::CRITICAL_TO_DEVICE_ENCRYPTION != 0
188     }
189 
190     /// This blob is associated with the Strongbox security level.
is_strongbox(&self) -> bool191     pub fn is_strongbox(&self) -> bool {
192         self.flags & flags::STRONGBOX != 0
193     }
194 
195     /// Returns the payload data of this blob file.
value(&self) -> &BlobValue196     pub fn value(&self) -> &BlobValue {
197         &self.value
198     }
199 
200     /// Consume this blob structure and extract the payload.
take_value(self) -> BlobValue201     pub fn take_value(self) -> BlobValue {
202         self.value
203     }
204 }
205 
206 impl LegacyBlobLoader {
207     const IV_SIZE: usize = keystore2_crypto::LEGACY_IV_LENGTH;
208     const GCM_TAG_LENGTH: usize = keystore2_crypto::TAG_LENGTH;
209     const SALT_SIZE: usize = keystore2_crypto::SALT_LENGTH;
210 
211     // The common header has the following structure:
212     // version (1 Byte)
213     // blob_type (1 Byte)
214     // flags (1 Byte)
215     // info (1 Byte)
216     // initialization_vector (16 Bytes)
217     // integrity (MD5 digest or gcm tag) (16 Bytes)
218     // length (4 Bytes)
219     const COMMON_HEADER_SIZE: usize = 4 + Self::IV_SIZE + Self::GCM_TAG_LENGTH + 4;
220 
221     const VERSION_OFFSET: usize = 0;
222     const TYPE_OFFSET: usize = 1;
223     const FLAGS_OFFSET: usize = 2;
224     const SALT_SIZE_OFFSET: usize = 3;
225     const LENGTH_OFFSET: usize = 4 + Self::IV_SIZE + Self::GCM_TAG_LENGTH;
226     const IV_OFFSET: usize = 4;
227     const AEAD_TAG_OFFSET: usize = Self::IV_OFFSET + Self::IV_SIZE;
228     const _DIGEST_OFFSET: usize = Self::IV_OFFSET + Self::IV_SIZE;
229 
230     /// Construct a new LegacyBlobLoader with a root path of `path` relative to which it will
231     /// expect legacy key blob files.
new(path: &Path) -> Self232     pub fn new(path: &Path) -> Self {
233         Self { path: path.to_owned() }
234     }
235 
236     /// Encodes an alias string as ascii character sequence in the range
237     /// ['+' .. '.'] and ['0' .. '~'].
238     /// Bytes with values in the range ['0' .. '~'] are represented as they are.
239     /// All other bytes are split into two characters as follows:
240     ///
241     ///      msb a a | b b b b b b
242     ///
243     /// The most significant bits (a) are encoded:
244     ///   a a  character
245     ///   0 0     '+'
246     ///   0 1     ','
247     ///   1 0     '-'
248     ///   1 1     '.'
249     ///
250     /// The 6 lower bits are represented with the range ['0' .. 'o']:
251     ///   b(hex)  character
252     ///   0x00     '0'
253     ///       ...
254     ///   0x3F     'o'
255     ///
256     /// The function cannot fail because we have a representation for each
257     /// of the 256 possible values of each byte.
encode_alias(name: &str) -> String258     pub fn encode_alias(name: &str) -> String {
259         let mut acc = String::new();
260         for c in name.bytes() {
261             match c {
262                 b'0'..=b'~' => {
263                     acc.push(c as char);
264                 }
265                 c => {
266                     acc.push((b'+' + (c as u8 >> 6)) as char);
267                     acc.push((b'0' + (c & 0x3F)) as char);
268                 }
269             };
270         }
271         acc
272     }
273 
274     /// This function reverses the encoding described in `encode_alias`.
275     /// This function can fail, because not all possible character
276     /// sequences are valid code points. And even if the encoding is valid,
277     /// the result may not be a valid UTF-8 sequence.
decode_alias(name: &str) -> Result<String>278     pub fn decode_alias(name: &str) -> Result<String> {
279         let mut multi: Option<u8> = None;
280         let mut s = Vec::<u8>::new();
281         for c in name.bytes() {
282             multi = match (c, multi) {
283                 // m is set, we are processing the second part of a multi byte sequence
284                 (b'0'..=b'o', Some(m)) => {
285                     s.push(m | (c - b'0'));
286                     None
287                 }
288                 (b'+'..=b'.', None) => Some((c - b'+') << 6),
289                 (b'0'..=b'~', None) => {
290                     s.push(c);
291                     None
292                 }
293                 _ => {
294                     return Err(Error::BadEncoding)
295                         .context("In decode_alias: could not decode filename.")
296                 }
297             };
298         }
299         if multi.is_some() {
300             return Err(Error::BadEncoding).context("In decode_alias: could not decode filename.");
301         }
302 
303         String::from_utf8(s).context("In decode_alias: encoded alias was not valid UTF-8.")
304     }
305 
new_from_stream(stream: &mut dyn Read) -> Result<Blob>306     fn new_from_stream(stream: &mut dyn Read) -> Result<Blob> {
307         let mut buffer = Vec::new();
308         stream.read_to_end(&mut buffer).context("In new_from_stream.")?;
309 
310         if buffer.len() < Self::COMMON_HEADER_SIZE {
311             return Err(Error::BadLen).context("In new_from_stream.")?;
312         }
313 
314         let version: u8 = buffer[Self::VERSION_OFFSET];
315 
316         let flags: u8 = buffer[Self::FLAGS_OFFSET];
317         let blob_type: u8 = buffer[Self::TYPE_OFFSET];
318         let is_encrypted = flags & (flags::ENCRYPTED | flags::SUPER_ENCRYPTED) != 0;
319         let salt = match buffer[Self::SALT_SIZE_OFFSET] as usize {
320             Self::SALT_SIZE => Some(&buffer[buffer.len() - Self::SALT_SIZE..buffer.len()]),
321             _ => None,
322         };
323 
324         if version != SUPPORTED_LEGACY_BLOB_VERSION {
325             return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
326                 .context(format!("In new_from_stream: Unknown blob version: {}.", version));
327         }
328 
329         let length = u32::from_be_bytes(
330             buffer[Self::LENGTH_OFFSET..Self::LENGTH_OFFSET + 4].try_into().unwrap(),
331         ) as usize;
332         if buffer.len() < Self::COMMON_HEADER_SIZE + length {
333             return Err(Error::BadLen).context(format!(
334                 "In new_from_stream. Expected: {} got: {}.",
335                 Self::COMMON_HEADER_SIZE + length,
336                 buffer.len()
337             ));
338         }
339         let value = &buffer[Self::COMMON_HEADER_SIZE..Self::COMMON_HEADER_SIZE + length];
340         let iv = &buffer[Self::IV_OFFSET..Self::IV_OFFSET + Self::IV_SIZE];
341         let tag = &buffer[Self::AEAD_TAG_OFFSET..Self::AEAD_TAG_OFFSET + Self::GCM_TAG_LENGTH];
342 
343         match (blob_type, is_encrypted, salt) {
344             (blob_types::GENERIC, _, _) => {
345                 Ok(Blob { flags, value: BlobValue::Generic(value.to_vec()) })
346             }
347             (blob_types::KEY_CHARACTERISTICS, _, _) => {
348                 Ok(Blob { flags, value: BlobValue::Characteristics(value.to_vec()) })
349             }
350             (blob_types::KEY_CHARACTERISTICS_CACHE, _, _) => {
351                 Ok(Blob { flags, value: BlobValue::CharacteristicsCache(value.to_vec()) })
352             }
353             (blob_types::SUPER_KEY, _, Some(salt)) => Ok(Blob {
354                 flags,
355                 value: BlobValue::PwEncrypted {
356                     iv: iv.to_vec(),
357                     tag: tag.to_vec(),
358                     data: value.to_vec(),
359                     key_size: keystore2_crypto::AES_128_KEY_LENGTH,
360                     salt: salt.to_vec(),
361                 },
362             }),
363             (blob_types::SUPER_KEY_AES256, _, Some(salt)) => Ok(Blob {
364                 flags,
365                 value: BlobValue::PwEncrypted {
366                     iv: iv.to_vec(),
367                     tag: tag.to_vec(),
368                     data: value.to_vec(),
369                     key_size: keystore2_crypto::AES_256_KEY_LENGTH,
370                     salt: salt.to_vec(),
371                 },
372             }),
373             (blob_types::KM_BLOB, true, _) => Ok(Blob {
374                 flags,
375                 value: BlobValue::Encrypted {
376                     iv: iv.to_vec(),
377                     tag: tag.to_vec(),
378                     data: value.to_vec(),
379                 },
380             }),
381             (blob_types::KM_BLOB, false, _) => Ok(Blob {
382                 flags,
383                 value: BlobValue::Decrypted(value.try_into().context("In new_from_stream.")?),
384             }),
385             (blob_types::SUPER_KEY, _, None) | (blob_types::SUPER_KEY_AES256, _, None) => {
386                 Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
387                     .context("In new_from_stream: Super key without salt for key derivation.")
388             }
389             _ => Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
390                 "In new_from_stream: Unknown blob type. {} {}",
391                 blob_type, is_encrypted
392             )),
393         }
394     }
395 
396     /// Parses a legacy key blob file read from `stream`. A `decrypt` closure
397     /// must be supplied, that is primed with the appropriate key.
398     /// The callback takes the following arguments:
399     ///  * ciphertext: &[u8] - The to-be-deciphered message.
400     ///  * iv: &[u8] - The initialization vector.
401     ///  * tag: Option<&[u8]> - AEAD tag if AES GCM is selected.
402     ///  * salt: Option<&[u8]> - An optional salt. Used for password key derivation.
403     ///  * key_size: Option<usize> - An optional key size. Used for pw key derivation.
404     ///
405     /// If no super key is available, the callback must return
406     /// `Err(KsError::Rc(ResponseCode::LOCKED))`. The callback is only called
407     /// if the to-be-read blob is encrypted.
new_from_stream_decrypt_with<F>(mut stream: impl Read, decrypt: F) -> Result<Blob> where F: FnOnce(&[u8], &[u8], &[u8], Option<&[u8]>, Option<usize>) -> Result<ZVec>,408     pub fn new_from_stream_decrypt_with<F>(mut stream: impl Read, decrypt: F) -> Result<Blob>
409     where
410         F: FnOnce(&[u8], &[u8], &[u8], Option<&[u8]>, Option<usize>) -> Result<ZVec>,
411     {
412         let blob =
413             Self::new_from_stream(&mut stream).context("In new_from_stream_decrypt_with.")?;
414 
415         match blob.value() {
416             BlobValue::Encrypted { iv, tag, data } => Ok(Blob {
417                 flags: blob.flags,
418                 value: BlobValue::Decrypted(
419                     decrypt(&data, &iv, &tag, None, None)
420                         .context("In new_from_stream_decrypt_with.")?,
421                 ),
422             }),
423             BlobValue::PwEncrypted { iv, tag, data, salt, key_size } => Ok(Blob {
424                 flags: blob.flags,
425                 value: BlobValue::Decrypted(
426                     decrypt(&data, &iv, &tag, Some(salt), Some(*key_size))
427                         .context("In new_from_stream_decrypt_with.")?,
428                 ),
429             }),
430             _ => Ok(blob),
431         }
432     }
433 
tag_type(tag: Tag) -> TagType434     fn tag_type(tag: Tag) -> TagType {
435         TagType((tag.0 as u32 & 0xFF000000u32) as i32)
436     }
437 
438     /// Read legacy key parameter file content.
439     /// Depending on the file type a key characteristics file stores one (TYPE_KEY_CHARACTERISTICS)
440     /// or two (TYPE_KEY_CHARACTERISTICS_CACHE) key parameter lists. The format of the list is as
441     /// follows:
442     ///
443     /// +------------------------------+
444     /// | 32 bit indirect_size         |
445     /// +------------------------------+
446     /// | indirect_size bytes of data  |     This is where the blob data is stored
447     /// +------------------------------+
448     /// | 32 bit element_count         |     Number of key parameter entries.
449     /// | 32 bit elements_size         |     Total bytes used by entries.
450     /// +------------------------------+
451     /// | elements_size bytes of data  |     This is where the elements are stored.
452     /// +------------------------------+
453     ///
454     /// Elements have a 32 bit header holding the tag with a tag type encoded in the
455     /// four most significant bits (see android/hardware/secruity/keymint/TagType.aidl).
456     /// The header is immediately followed by the payload. The payload size depends on
457     /// the encoded tag type in the header:
458     ///      BOOLEAN                          :    1 byte
459     ///      ENUM, ENUM_REP, UINT, UINT_REP   :    4 bytes
460     ///      ULONG, ULONG_REP, DATETIME       :    8 bytes
461     ///      BLOB, BIGNUM                     :    8 bytes see below.
462     ///
463     /// Bignum and blob payload format:
464     /// +------------------------+
465     /// | 32 bit blob_length     |    Length of the indirect payload in bytes.
466     /// | 32 bit indirect_offset |    Offset from the beginning of the indirect section.
467     /// +------------------------+
read_key_parameters(stream: &mut &[u8]) -> Result<Vec<KeyParameterValue>>468     pub fn read_key_parameters(stream: &mut &[u8]) -> Result<Vec<KeyParameterValue>> {
469         let indirect_size =
470             read_ne_u32(stream).context("In read_key_parameters: While reading indirect size.")?;
471 
472         let indirect_buffer = stream
473             .get(0..indirect_size as usize)
474             .ok_or(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
475             .context("In read_key_parameters: While reading indirect buffer.")?;
476 
477         // update the stream position.
478         *stream = &stream[indirect_size as usize..];
479 
480         let element_count =
481             read_ne_u32(stream).context("In read_key_parameters: While reading element count.")?;
482         let element_size =
483             read_ne_u32(stream).context("In read_key_parameters: While reading element size.")?;
484 
485         let mut element_stream = stream
486             .get(0..element_size as usize)
487             .ok_or(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
488             .context("In read_key_parameters: While reading elements buffer.")?;
489 
490         // update the stream position.
491         *stream = &stream[element_size as usize..];
492 
493         let mut params: Vec<KeyParameterValue> = Vec::new();
494         for _ in 0..element_count {
495             let tag = Tag(read_ne_i32(&mut element_stream).context("In read_key_parameters.")?);
496             let param = match Self::tag_type(tag) {
497                 TagType::ENUM | TagType::ENUM_REP | TagType::UINT | TagType::UINT_REP => {
498                     KeyParameterValue::new_from_tag_primitive_pair(
499                         tag,
500                         read_ne_i32(&mut element_stream).context("While reading integer.")?,
501                     )
502                     .context("Trying to construct integer/enum KeyParameterValue.")
503                 }
504                 TagType::ULONG | TagType::ULONG_REP | TagType::DATE => {
505                     KeyParameterValue::new_from_tag_primitive_pair(
506                         tag,
507                         read_ne_i64(&mut element_stream).context("While reading long integer.")?,
508                     )
509                     .context("Trying to construct long KeyParameterValue.")
510                 }
511                 TagType::BOOL => {
512                     if read_bool(&mut element_stream).context("While reading long integer.")? {
513                         KeyParameterValue::new_from_tag_primitive_pair(tag, 1)
514                             .context("Trying to construct boolean KeyParameterValue.")
515                     } else {
516                         Err(anyhow::anyhow!("Invalid."))
517                     }
518                 }
519                 TagType::BYTES | TagType::BIGNUM => {
520                     let blob_size = read_ne_u32(&mut element_stream)
521                         .context("While reading blob size.")?
522                         as usize;
523                     let indirect_offset = read_ne_u32(&mut element_stream)
524                         .context("While reading indirect offset.")?
525                         as usize;
526                     KeyParameterValue::new_from_tag_primitive_pair(
527                         tag,
528                         indirect_buffer
529                             .get(indirect_offset..indirect_offset + blob_size)
530                             .context("While reading blob value.")?
531                             .to_vec(),
532                     )
533                     .context("Trying to construct blob KeyParameterValue.")
534                 }
535                 TagType::INVALID => Err(anyhow::anyhow!("Invalid.")),
536                 _ => {
537                     return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
538                         .context("In read_key_parameters: Encountered bogus tag type.");
539                 }
540             };
541             if let Ok(p) = param {
542                 params.push(p);
543             }
544         }
545 
546         Ok(params)
547     }
548 
read_characteristics_file( &self, uid: u32, prefix: &str, alias: &str, hw_sec_level: SecurityLevel, ) -> Result<Vec<KeyParameter>>549     fn read_characteristics_file(
550         &self,
551         uid: u32,
552         prefix: &str,
553         alias: &str,
554         hw_sec_level: SecurityLevel,
555     ) -> Result<Vec<KeyParameter>> {
556         let blob = Self::read_generic_blob(&self.make_chr_filename(uid, alias, prefix))
557             .context("In read_characteristics_file")?;
558 
559         let blob = match blob {
560             None => return Ok(Vec::new()),
561             Some(blob) => blob,
562         };
563 
564         let mut stream = match blob.value() {
565             BlobValue::Characteristics(data) => &data[..],
566             BlobValue::CharacteristicsCache(data) => &data[..],
567             _ => {
568                 return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(concat!(
569                     "In read_characteristics_file: ",
570                     "Characteristics file does not hold key characteristics."
571                 ))
572             }
573         };
574 
575         let hw_list = match blob.value() {
576             // The characteristics cache file has two lists and the first is
577             // the hardware enforced list.
578             BlobValue::CharacteristicsCache(_) => Some(
579                 Self::read_key_parameters(&mut stream)
580                     .context("In read_characteristics_file.")?
581                     .into_iter()
582                     .map(|value| KeyParameter::new(value, hw_sec_level)),
583             ),
584             _ => None,
585         };
586 
587         let sw_list = Self::read_key_parameters(&mut stream)
588             .context("In read_characteristics_file.")?
589             .into_iter()
590             .map(|value| KeyParameter::new(value, SecurityLevel::KEYSTORE));
591 
592         Ok(hw_list.into_iter().flatten().chain(sw_list).collect())
593     }
594 
595     // This is a list of known prefixes that the Keystore 1.0 SPI used to use.
596     //  * USRPKEY was used for private and secret key material, i.e., KM blobs.
597     //  * USRSKEY was used for secret key material, i.e., KM blobs, before Android P.
598     //  * CACERT  was used for key chains or free standing public certificates.
599     //  * USRCERT was used for public certificates of USRPKEY entries. But KeyChain also
600     //            used this for user installed certificates without private key material.
601 
602     const KNOWN_KEYSTORE_PREFIXES: &'static [&'static str] =
603         &["USRPKEY_", "USRSKEY_", "USRCERT_", "CACERT_"];
604 
is_keystore_alias(encoded_alias: &str) -> bool605     fn is_keystore_alias(encoded_alias: &str) -> bool {
606         // We can check the encoded alias because the prefixes we are interested
607         // in are all in the printable range that don't get mangled.
608         Self::KNOWN_KEYSTORE_PREFIXES.iter().any(|prefix| encoded_alias.starts_with(prefix))
609     }
610 
read_km_blob_file(&self, uid: u32, alias: &str) -> Result<Option<(Blob, String)>>611     fn read_km_blob_file(&self, uid: u32, alias: &str) -> Result<Option<(Blob, String)>> {
612         let mut iter = ["USRPKEY", "USRSKEY"].iter();
613 
614         let (blob, prefix) = loop {
615             if let Some(prefix) = iter.next() {
616                 if let Some(blob) =
617                     Self::read_generic_blob(&self.make_blob_filename(uid, alias, prefix))
618                         .context("In read_km_blob_file.")?
619                 {
620                     break (blob, prefix);
621                 }
622             } else {
623                 return Ok(None);
624             }
625         };
626 
627         Ok(Some((blob, prefix.to_string())))
628     }
629 
read_generic_blob(path: &Path) -> Result<Option<Blob>>630     fn read_generic_blob(path: &Path) -> Result<Option<Blob>> {
631         let mut file = match Self::with_retry_interrupted(|| File::open(path)) {
632             Ok(file) => file,
633             Err(e) => match e.kind() {
634                 ErrorKind::NotFound => return Ok(None),
635                 _ => return Err(e).context("In read_generic_blob."),
636             },
637         };
638 
639         Ok(Some(Self::new_from_stream(&mut file).context("In read_generic_blob.")?))
640     }
641 
642     /// Read a legacy keystore entry blob.
read_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<Option<Vec<u8>>>643     pub fn read_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<Option<Vec<u8>>> {
644         let path = match self.make_legacy_keystore_entry_filename(uid, alias) {
645             Some(path) => path,
646             None => return Ok(None),
647         };
648 
649         let blob = Self::read_generic_blob(&path)
650             .context("In read_legacy_keystore_entry: Failed to read blob.")?;
651 
652         Ok(blob.and_then(|blob| match blob.value {
653             BlobValue::Generic(blob) => Some(blob),
654             _ => {
655                 log::info!("Unexpected legacy keystore entry blob type. Ignoring");
656                 None
657             }
658         }))
659     }
660 
661     /// Remove a legacy keystore entry by the name alias with owner uid.
remove_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<()>662     pub fn remove_legacy_keystore_entry(&self, uid: u32, alias: &str) -> Result<()> {
663         let path = match self.make_legacy_keystore_entry_filename(uid, alias) {
664             Some(path) => path,
665             None => return Ok(()),
666         };
667 
668         if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
669             match e.kind() {
670                 ErrorKind::NotFound => return Ok(()),
671                 _ => return Err(e).context("In remove_legacy_keystore_entry."),
672             }
673         }
674 
675         let user_id = uid_to_android_user(uid);
676         self.remove_user_dir_if_empty(user_id)
677             .context("In remove_legacy_keystore_entry: Trying to remove empty user dir.")
678     }
679 
680     /// List all entries belonging to the given uid.
list_legacy_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>>681     pub fn list_legacy_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>> {
682         let mut path = self.path.clone();
683         let user_id = uid_to_android_user(uid);
684         path.push(format!("user_{}", user_id));
685         let uid_str = uid.to_string();
686         let dir = match Self::with_retry_interrupted(|| fs::read_dir(path.as_path())) {
687             Ok(dir) => dir,
688             Err(e) => match e.kind() {
689                 ErrorKind::NotFound => return Ok(Default::default()),
690                 _ => {
691                     return Err(e).context(format!(
692                         concat!(
693                             "In list_legacy_keystore_entries_for_uid: ,",
694                             "Failed to open legacy blob database: {:?}"
695                         ),
696                         path
697                     ))
698                 }
699             },
700         };
701         let mut result: Vec<String> = Vec::new();
702         for entry in dir {
703             let file_name = entry
704                 .context("In list_legacy_keystore_entries_for_uid: Trying to access dir entry")?
705                 .file_name();
706             if let Some(f) = file_name.to_str() {
707                 let encoded_alias = &f[uid_str.len() + 1..];
708                 if f.starts_with(&uid_str) && !Self::is_keystore_alias(encoded_alias) {
709                     result.push(Self::decode_alias(encoded_alias).context(
710                         "In list_legacy_keystore_entries_for_uid: Trying to decode alias.",
711                     )?)
712                 }
713             }
714         }
715         Ok(result)
716     }
717 
extract_legacy_alias(encoded_alias: &str) -> Option<String>718     fn extract_legacy_alias(encoded_alias: &str) -> Option<String> {
719         if !Self::is_keystore_alias(encoded_alias) {
720             Self::decode_alias(encoded_alias).ok()
721         } else {
722             None
723         }
724     }
725 
726     /// Lists all keystore entries belonging to the given user. Returns a map of UIDs
727     /// to sets of decoded aliases. Only returns entries that do not begin with
728     /// KNOWN_KEYSTORE_PREFIXES.
list_legacy_keystore_entries_for_user( &self, user_id: u32, ) -> Result<HashMap<u32, HashSet<String>>>729     pub fn list_legacy_keystore_entries_for_user(
730         &self,
731         user_id: u32,
732     ) -> Result<HashMap<u32, HashSet<String>>> {
733         let user_entries = self
734             .list_user(user_id)
735             .context("In list_legacy_keystore_entries_for_user: Trying to list user.")?;
736 
737         let result =
738             user_entries.into_iter().fold(HashMap::<u32, HashSet<String>>::new(), |mut acc, v| {
739                 if let Some(sep_pos) = v.find('_') {
740                     if let Ok(uid) = v[0..sep_pos].parse::<u32>() {
741                         if let Some(alias) = Self::extract_legacy_alias(&v[sep_pos + 1..]) {
742                             let entry = acc.entry(uid).or_default();
743                             entry.insert(alias);
744                         }
745                     }
746                 }
747                 acc
748             });
749         Ok(result)
750     }
751 
752     /// This function constructs the legacy blob file name which has the form:
753     /// user_<android user id>/<uid>_<alias>. Legacy blob file names must not use
754     /// known keystore prefixes.
make_legacy_keystore_entry_filename(&self, uid: u32, alias: &str) -> Option<PathBuf>755     fn make_legacy_keystore_entry_filename(&self, uid: u32, alias: &str) -> Option<PathBuf> {
756         // Legacy entries must not use known keystore prefixes.
757         if Self::is_keystore_alias(alias) {
758             log::warn!(
759                 "Known keystore prefixes cannot be used with legacy keystore -> ignoring request."
760             );
761             return None;
762         }
763 
764         let mut path = self.path.clone();
765         let user_id = uid_to_android_user(uid);
766         let encoded_alias = Self::encode_alias(alias);
767         path.push(format!("user_{}", user_id));
768         path.push(format!("{}_{}", uid, encoded_alias));
769         Some(path)
770     }
771 
772     /// This function constructs the blob file name which has the form:
773     /// user_<android user id>/<uid>_<prefix>_<alias>.
make_blob_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf774     fn make_blob_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf {
775         let user_id = uid_to_android_user(uid);
776         let encoded_alias = Self::encode_alias(&format!("{}_{}", prefix, alias));
777         let mut path = self.make_user_path_name(user_id);
778         path.push(format!("{}_{}", uid, encoded_alias));
779         path
780     }
781 
782     /// This function constructs the characteristics file name which has the form:
783     /// user_<android user id>/.<uid>_chr_<prefix>_<alias>.
make_chr_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf784     fn make_chr_filename(&self, uid: u32, alias: &str, prefix: &str) -> PathBuf {
785         let user_id = uid_to_android_user(uid);
786         let encoded_alias = Self::encode_alias(&format!("{}_{}", prefix, alias));
787         let mut path = self.make_user_path_name(user_id);
788         path.push(format!(".{}_chr_{}", uid, encoded_alias));
789         path
790     }
791 
make_super_key_filename(&self, user_id: u32) -> PathBuf792     fn make_super_key_filename(&self, user_id: u32) -> PathBuf {
793         let mut path = self.make_user_path_name(user_id);
794         path.push(".masterkey");
795         path
796     }
797 
make_user_path_name(&self, user_id: u32) -> PathBuf798     fn make_user_path_name(&self, user_id: u32) -> PathBuf {
799         let mut path = self.path.clone();
800         path.push(&format!("user_{}", user_id));
801         path
802     }
803 
804     /// Returns if the legacy blob database is empty, i.e., there are no entries matching "user_*"
805     /// in the database dir.
is_empty(&self) -> Result<bool>806     pub fn is_empty(&self) -> Result<bool> {
807         let dir = Self::with_retry_interrupted(|| fs::read_dir(self.path.as_path()))
808             .context("In is_empty: Failed to open legacy blob database.")?;
809         for entry in dir {
810             if (*entry.context("In is_empty: Trying to access dir entry")?.file_name())
811                 .to_str()
812                 .map_or(false, |f| f.starts_with("user_"))
813             {
814                 return Ok(false);
815             }
816         }
817         Ok(true)
818     }
819 
820     /// Returns if the legacy blob database is empty for a given user, i.e., there are no entries
821     /// matching "user_*" in the database dir.
is_empty_user(&self, user_id: u32) -> Result<bool>822     pub fn is_empty_user(&self, user_id: u32) -> Result<bool> {
823         let mut user_path = self.path.clone();
824         user_path.push(format!("user_{}", user_id));
825         if !user_path.as_path().is_dir() {
826             return Ok(true);
827         }
828         Ok(Self::with_retry_interrupted(|| user_path.read_dir())
829             .context("In is_empty_user: Failed to open legacy user dir.")?
830             .next()
831             .is_none())
832     }
833 
extract_keystore_alias(encoded_alias: &str) -> Option<String>834     fn extract_keystore_alias(encoded_alias: &str) -> Option<String> {
835         // We can check the encoded alias because the prefixes we are interested
836         // in are all in the printable range that don't get mangled.
837         for prefix in Self::KNOWN_KEYSTORE_PREFIXES {
838             if let Some(alias) = encoded_alias.strip_prefix(prefix) {
839                 return Self::decode_alias(&alias).ok();
840             }
841         }
842         None
843     }
844 
845     /// List all entries for a given user. The strings are unchanged file names, i.e.,
846     /// encoded with UID prefix.
list_user(&self, user_id: u32) -> Result<Vec<String>>847     fn list_user(&self, user_id: u32) -> Result<Vec<String>> {
848         let path = self.make_user_path_name(user_id);
849         let dir = match Self::with_retry_interrupted(|| fs::read_dir(path.as_path())) {
850             Ok(dir) => dir,
851             Err(e) => match e.kind() {
852                 ErrorKind::NotFound => return Ok(Default::default()),
853                 _ => {
854                     return Err(e).context(format!(
855                         "In list_user: Failed to open legacy blob database. {:?}",
856                         path
857                     ))
858                 }
859             },
860         };
861         let mut result: Vec<String> = Vec::new();
862         for entry in dir {
863             let file_name = entry.context("In list_user: Trying to access dir entry")?.file_name();
864             if let Some(f) = file_name.to_str() {
865                 result.push(f.to_string())
866             }
867         }
868         Ok(result)
869     }
870 
871     /// List all keystore entries belonging to the given user. Returns a map of UIDs
872     /// to sets of decoded aliases.
list_keystore_entries_for_user( &self, user_id: u32, ) -> Result<HashMap<u32, HashSet<String>>>873     pub fn list_keystore_entries_for_user(
874         &self,
875         user_id: u32,
876     ) -> Result<HashMap<u32, HashSet<String>>> {
877         let user_entries = self
878             .list_user(user_id)
879             .context("In list_keystore_entries_for_user: Trying to list user.")?;
880 
881         let result =
882             user_entries.into_iter().fold(HashMap::<u32, HashSet<String>>::new(), |mut acc, v| {
883                 if let Some(sep_pos) = v.find('_') {
884                     if let Ok(uid) = v[0..sep_pos].parse::<u32>() {
885                         if let Some(alias) = Self::extract_keystore_alias(&v[sep_pos + 1..]) {
886                             let entry = acc.entry(uid).or_default();
887                             entry.insert(alias);
888                         }
889                     }
890                 }
891                 acc
892             });
893         Ok(result)
894     }
895 
896     /// List all keystore entries belonging to the given uid.
list_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>>897     pub fn list_keystore_entries_for_uid(&self, uid: u32) -> Result<Vec<String>> {
898         let user_id = uid_to_android_user(uid);
899 
900         let user_entries = self
901             .list_user(user_id)
902             .context("In list_keystore_entries_for_uid: Trying to list user.")?;
903 
904         let uid_str = format!("{}_", uid);
905 
906         let mut result: Vec<String> = user_entries
907             .into_iter()
908             .filter_map(|v| {
909                 if !v.starts_with(&uid_str) {
910                     return None;
911                 }
912                 let encoded_alias = &v[uid_str.len()..];
913                 Self::extract_keystore_alias(encoded_alias)
914             })
915             .collect();
916 
917         result.sort_unstable();
918         result.dedup();
919         Ok(result)
920     }
921 
with_retry_interrupted<F, T>(f: F) -> IoResult<T> where F: Fn() -> IoResult<T>,922     fn with_retry_interrupted<F, T>(f: F) -> IoResult<T>
923     where
924         F: Fn() -> IoResult<T>,
925     {
926         loop {
927             match f() {
928                 Ok(v) => return Ok(v),
929                 Err(e) => match e.kind() {
930                     ErrorKind::Interrupted => continue,
931                     _ => return Err(e),
932                 },
933             }
934         }
935     }
936 
937     /// Deletes a keystore entry. Also removes the user_<uid> directory on the
938     /// last migration.
remove_keystore_entry(&self, uid: u32, alias: &str) -> Result<bool>939     pub fn remove_keystore_entry(&self, uid: u32, alias: &str) -> Result<bool> {
940         let mut something_was_deleted = false;
941         let prefixes = ["USRPKEY", "USRSKEY"];
942         for prefix in &prefixes {
943             let path = self.make_blob_filename(uid, alias, prefix);
944             if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
945                 match e.kind() {
946                     // Only a subset of keys are expected.
947                     ErrorKind::NotFound => continue,
948                     // Log error but ignore.
949                     _ => log::error!("Error while deleting key blob entries. {:?}", e),
950                 }
951             }
952             let path = self.make_chr_filename(uid, alias, prefix);
953             if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
954                 match e.kind() {
955                     ErrorKind::NotFound => {
956                         log::info!("No characteristics file found for legacy key blob.")
957                     }
958                     // Log error but ignore.
959                     _ => log::error!("Error while deleting key blob entries. {:?}", e),
960                 }
961             }
962             something_was_deleted = true;
963             // Only one of USRPKEY and USRSKEY can be present. So we can end the loop
964             // if we reach this point.
965             break;
966         }
967 
968         let prefixes = ["USRCERT", "CACERT"];
969         for prefix in &prefixes {
970             let path = self.make_blob_filename(uid, alias, prefix);
971             if let Err(e) = Self::with_retry_interrupted(|| fs::remove_file(path.as_path())) {
972                 match e.kind() {
973                     // USRCERT and CACERT are optional either or both may or may not be present.
974                     ErrorKind::NotFound => continue,
975                     // Log error but ignore.
976                     _ => log::error!("Error while deleting key blob entries. {:?}", e),
977                 }
978                 something_was_deleted = true;
979             }
980         }
981 
982         if something_was_deleted {
983             let user_id = uid_to_android_user(uid);
984             self.remove_user_dir_if_empty(user_id)
985                 .context("In remove_keystore_entry: Trying to remove empty user dir.")?;
986         }
987 
988         Ok(something_was_deleted)
989     }
990 
remove_user_dir_if_empty(&self, user_id: u32) -> Result<()>991     fn remove_user_dir_if_empty(&self, user_id: u32) -> Result<()> {
992         if self
993             .is_empty_user(user_id)
994             .context("In remove_user_dir_if_empty: Trying to check for empty user dir.")?
995         {
996             let user_path = self.make_user_path_name(user_id);
997             Self::with_retry_interrupted(|| fs::remove_dir(user_path.as_path())).ok();
998         }
999         Ok(())
1000     }
1001 
1002     /// Load a legacy key blob entry by uid and alias.
load_by_uid_alias( &self, uid: u32, alias: &str, key_manager: Option<&SuperKeyManager>, ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<Vec<u8>>, Option<Vec<u8>>)>1003     pub fn load_by_uid_alias(
1004         &self,
1005         uid: u32,
1006         alias: &str,
1007         key_manager: Option<&SuperKeyManager>,
1008     ) -> Result<(Option<(Blob, Vec<KeyParameter>)>, Option<Vec<u8>>, Option<Vec<u8>>)> {
1009         let km_blob = self.read_km_blob_file(uid, alias).context("In load_by_uid_alias.")?;
1010 
1011         let km_blob = match km_blob {
1012             Some((km_blob, prefix)) => {
1013                 let km_blob = match km_blob {
1014                     Blob { flags: _, value: BlobValue::Decrypted(_) } => km_blob,
1015                     // Unwrap the key blob if required and if we have key_manager.
1016                     Blob { flags, value: BlobValue::Encrypted { ref iv, ref tag, ref data } } => {
1017                         if let Some(key_manager) = key_manager {
1018                             let decrypted = match key_manager
1019                                 .get_per_boot_key_by_user_id(uid_to_android_user(uid))
1020                             {
1021                                 Some(key) => key.aes_gcm_decrypt(data, iv, tag).context(
1022                                     "In load_by_uid_alias: while trying to decrypt legacy blob.",
1023                                 )?,
1024                                 None => {
1025                                     return Err(KsError::Rc(ResponseCode::LOCKED)).context(format!(
1026                                         concat!(
1027                                             "In load_by_uid_alias: ",
1028                                             "User {} has not unlocked the keystore yet.",
1029                                         ),
1030                                         uid_to_android_user(uid)
1031                                     ))
1032                                 }
1033                             };
1034                             Blob { flags, value: BlobValue::Decrypted(decrypted) }
1035                         } else {
1036                             km_blob
1037                         }
1038                     }
1039                     _ => {
1040                         return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
1041                             "In load_by_uid_alias: Found wrong blob type in legacy key blob file.",
1042                         )
1043                     }
1044                 };
1045 
1046                 let hw_sec_level = match km_blob.is_strongbox() {
1047                     true => SecurityLevel::STRONGBOX,
1048                     false => SecurityLevel::TRUSTED_ENVIRONMENT,
1049                 };
1050                 let key_parameters = self
1051                     .read_characteristics_file(uid, &prefix, alias, hw_sec_level)
1052                     .context("In load_by_uid_alias.")?;
1053                 Some((km_blob, key_parameters))
1054             }
1055             None => None,
1056         };
1057 
1058         let user_cert =
1059             match Self::read_generic_blob(&self.make_blob_filename(uid, alias, "USRCERT"))
1060                 .context("In load_by_uid_alias: While loading user cert.")?
1061             {
1062                 Some(Blob { value: BlobValue::Generic(data), .. }) => Some(data),
1063                 None => None,
1064                 _ => {
1065                     return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
1066                         "In load_by_uid_alias: Found unexpected blob type in USRCERT file",
1067                     )
1068                 }
1069             };
1070 
1071         let ca_cert = match Self::read_generic_blob(&self.make_blob_filename(uid, alias, "CACERT"))
1072             .context("In load_by_uid_alias: While loading ca cert.")?
1073         {
1074             Some(Blob { value: BlobValue::Generic(data), .. }) => Some(data),
1075             None => None,
1076             _ => {
1077                 return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED))
1078                     .context("In load_by_uid_alias: Found unexpected blob type in CACERT file")
1079             }
1080         };
1081 
1082         Ok((km_blob, user_cert, ca_cert))
1083     }
1084 
1085     /// Returns true if the given user has a super key.
has_super_key(&self, user_id: u32) -> bool1086     pub fn has_super_key(&self, user_id: u32) -> bool {
1087         self.make_super_key_filename(user_id).is_file()
1088     }
1089 
1090     /// Load and decrypt legacy super key blob.
load_super_key(&self, user_id: u32, pw: &Password) -> Result<Option<ZVec>>1091     pub fn load_super_key(&self, user_id: u32, pw: &Password) -> Result<Option<ZVec>> {
1092         let path = self.make_super_key_filename(user_id);
1093         let blob = Self::read_generic_blob(&path)
1094             .context("In load_super_key: While loading super key.")?;
1095 
1096         let blob = match blob {
1097             Some(blob) => match blob {
1098                 Blob { flags, value: BlobValue::PwEncrypted { iv, tag, data, salt, key_size } } => {
1099                     if (flags & flags::ENCRYPTED) != 0 {
1100                         let key = pw
1101                             .derive_key(Some(&salt), key_size)
1102                             .context("In load_super_key: Failed to derive key from password.")?;
1103                         let blob = aes_gcm_decrypt(&data, &iv, &tag, &key).context(
1104                             "In load_super_key: while trying to decrypt legacy super key blob.",
1105                         )?;
1106                         Some(blob)
1107                     } else {
1108                         // In 2019 we had some unencrypted super keys due to b/141955555.
1109                         Some(
1110                             data.try_into()
1111                                 .context("In load_super_key: Trying to convert key into ZVec")?,
1112                         )
1113                     }
1114                 }
1115                 _ => {
1116                     return Err(KsError::Rc(ResponseCode::VALUE_CORRUPTED)).context(
1117                         "In load_super_key: Found wrong blob type in legacy super key blob file.",
1118                     )
1119                 }
1120             },
1121             None => None,
1122         };
1123 
1124         Ok(blob)
1125     }
1126 
1127     /// Removes the super key for the given user from the legacy database.
1128     /// If this was the last entry in the user's database, this function removes
1129     /// the user_<uid> directory as well.
remove_super_key(&self, user_id: u32)1130     pub fn remove_super_key(&self, user_id: u32) {
1131         let path = self.make_super_key_filename(user_id);
1132         Self::with_retry_interrupted(|| fs::remove_file(path.as_path())).ok();
1133         if self.is_empty_user(user_id).ok().unwrap_or(false) {
1134             let path = self.make_user_path_name(user_id);
1135             Self::with_retry_interrupted(|| fs::remove_dir(path.as_path())).ok();
1136         }
1137     }
1138 }
1139 
1140 #[cfg(test)]
1141 mod test {
1142     use super::*;
1143     use anyhow::anyhow;
1144     use keystore2_crypto::aes_gcm_decrypt;
1145     use rand::Rng;
1146     use std::string::FromUtf8Error;
1147     mod legacy_blob_test_vectors;
1148     use crate::error;
1149     use crate::legacy_blob::test::legacy_blob_test_vectors::*;
1150     use keystore2_test_utils::TempDir;
1151 
1152     #[test]
decode_encode_alias_test()1153     fn decode_encode_alias_test() {
1154         static ALIAS: &str = "#({}test[])��";
1155         static ENCODED_ALIAS: &str = "+S+X{}test[]+Y.`-O-H-G";
1156         // Second multi byte out of range ------v
1157         static ENCODED_ALIAS_ERROR1: &str = "+S+{}test[]+Y";
1158         // Incomplete multi byte ------------------------v
1159         static ENCODED_ALIAS_ERROR2: &str = "+S+X{}test[]+";
1160         // Our encoding: ".`-O-H-G"
1161         // is UTF-8: 0xF0 0x9F 0x98 0x97
1162         // is UNICODE: U+1F617
1163         // is ��
1164         // But +H below is a valid encoding for 0x18 making this sequence invalid UTF-8.
1165         static ENCODED_ALIAS_ERROR_UTF8: &str = ".`-O+H-G";
1166 
1167         assert_eq!(ENCODED_ALIAS, &LegacyBlobLoader::encode_alias(ALIAS));
1168         assert_eq!(ALIAS, &LegacyBlobLoader::decode_alias(ENCODED_ALIAS).unwrap());
1169         assert_eq!(
1170             Some(&Error::BadEncoding),
1171             LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR1)
1172                 .unwrap_err()
1173                 .root_cause()
1174                 .downcast_ref::<Error>()
1175         );
1176         assert_eq!(
1177             Some(&Error::BadEncoding),
1178             LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR2)
1179                 .unwrap_err()
1180                 .root_cause()
1181                 .downcast_ref::<Error>()
1182         );
1183         assert!(LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR_UTF8)
1184             .unwrap_err()
1185             .root_cause()
1186             .downcast_ref::<FromUtf8Error>()
1187             .is_some());
1188 
1189         for _i in 0..100 {
1190             // Any valid UTF-8 string should be en- and decoded without loss.
1191             let alias_str = rand::thread_rng().gen::<[char; 20]>().iter().collect::<String>();
1192             let random_alias = alias_str.as_bytes();
1193             let encoded = LegacyBlobLoader::encode_alias(&alias_str);
1194             let decoded = match LegacyBlobLoader::decode_alias(&encoded) {
1195                 Ok(d) => d,
1196                 Err(_) => panic!("random_alias: {:x?}\nencoded {}", random_alias, encoded),
1197             };
1198             assert_eq!(random_alias.to_vec(), decoded.bytes().collect::<Vec<u8>>());
1199         }
1200     }
1201 
1202     #[test]
read_golden_key_blob_test() -> anyhow::Result<()>1203     fn read_golden_key_blob_test() -> anyhow::Result<()> {
1204         let blob = LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*BLOB, |_, _, _, _, _| {
1205             Err(anyhow!("should not be called"))
1206         })?;
1207         assert!(!blob.is_encrypted());
1208         assert!(!blob.is_fallback());
1209         assert!(!blob.is_strongbox());
1210         assert!(!blob.is_critical_to_device_encryption());
1211         assert_eq!(blob.value(), &BlobValue::Generic([0xde, 0xed, 0xbe, 0xef].to_vec()));
1212 
1213         let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
1214             &mut &*REAL_LEGACY_BLOB,
1215             |_, _, _, _, _| Err(anyhow!("should not be called")),
1216         )?;
1217         assert!(!blob.is_encrypted());
1218         assert!(!blob.is_fallback());
1219         assert!(!blob.is_strongbox());
1220         assert!(!blob.is_critical_to_device_encryption());
1221         assert_eq!(
1222             blob.value(),
1223             &BlobValue::Decrypted(REAL_LEGACY_BLOB_PAYLOAD.try_into().unwrap())
1224         );
1225         Ok(())
1226     }
1227 
1228     #[test]
read_aes_gcm_encrypted_key_blob_test()1229     fn read_aes_gcm_encrypted_key_blob_test() {
1230         let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
1231             &mut &*AES_GCM_ENCRYPTED_BLOB,
1232             |d, iv, tag, salt, key_size| {
1233                 assert_eq!(salt, None);
1234                 assert_eq!(key_size, None);
1235                 assert_eq!(
1236                     iv,
1237                     &[
1238                         0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f,
1239                         0x00, 0x00, 0x00, 0x00,
1240                     ]
1241                 );
1242                 assert_eq!(
1243                     tag,
1244                     &[
1245                         0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9,
1246                         0xb9, 0xe0, 0x0b, 0xc3
1247                     ][..]
1248                 );
1249                 aes_gcm_decrypt(d, iv, tag, AES_KEY).context("Trying to decrypt blob.")
1250             },
1251         )
1252         .unwrap();
1253         assert!(blob.is_encrypted());
1254         assert!(!blob.is_fallback());
1255         assert!(!blob.is_strongbox());
1256         assert!(!blob.is_critical_to_device_encryption());
1257 
1258         assert_eq!(blob.value(), &BlobValue::Decrypted(DECRYPTED_PAYLOAD.try_into().unwrap()));
1259     }
1260 
1261     #[test]
read_golden_key_blob_too_short_test()1262     fn read_golden_key_blob_too_short_test() {
1263         let error =
1264             LegacyBlobLoader::new_from_stream_decrypt_with(&mut &BLOB[0..15], |_, _, _, _, _| {
1265                 Err(anyhow!("should not be called"))
1266             })
1267             .unwrap_err();
1268         assert_eq!(Some(&Error::BadLen), error.root_cause().downcast_ref::<Error>());
1269     }
1270 
1271     #[test]
test_is_empty()1272     fn test_is_empty() {
1273         let temp_dir = TempDir::new("test_is_empty").expect("Failed to create temp dir.");
1274         let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
1275 
1276         assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty."));
1277 
1278         let _db = crate::database::KeystoreDB::new(temp_dir.path(), None)
1279             .expect("Failed to open database.");
1280 
1281         assert!(legacy_blob_loader.is_empty().expect("Should succeed and still be empty."));
1282 
1283         std::fs::create_dir(&*temp_dir.build().push("user_0")).expect("Failed to create user_0.");
1284 
1285         assert!(!legacy_blob_loader.is_empty().expect("Should succeed but not be empty."));
1286 
1287         std::fs::create_dir(&*temp_dir.build().push("user_10")).expect("Failed to create user_10.");
1288 
1289         assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
1290 
1291         std::fs::remove_dir_all(&*temp_dir.build().push("user_0"))
1292             .expect("Failed to remove user_0.");
1293 
1294         assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
1295 
1296         std::fs::remove_dir_all(&*temp_dir.build().push("user_10"))
1297             .expect("Failed to remove user_10.");
1298 
1299         assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty again."));
1300     }
1301 
1302     #[test]
test_legacy_blobs() -> anyhow::Result<()>1303     fn test_legacy_blobs() -> anyhow::Result<()> {
1304         let temp_dir = TempDir::new("legacy_blob_test")?;
1305         std::fs::create_dir(&*temp_dir.build().push("user_0"))?;
1306 
1307         std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY)?;
1308 
1309         std::fs::write(
1310             &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
1311             USRPKEY_AUTHBOUND,
1312         )?;
1313         std::fs::write(
1314             &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
1315             USRPKEY_AUTHBOUND_CHR,
1316         )?;
1317         std::fs::write(
1318             &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
1319             USRCERT_AUTHBOUND,
1320         )?;
1321         std::fs::write(
1322             &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
1323             CACERT_AUTHBOUND,
1324         )?;
1325 
1326         std::fs::write(
1327             &*temp_dir.build().push("user_0").push("10223_USRPKEY_non_authbound"),
1328             USRPKEY_NON_AUTHBOUND,
1329         )?;
1330         std::fs::write(
1331             &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_non_authbound"),
1332             USRPKEY_NON_AUTHBOUND_CHR,
1333         )?;
1334         std::fs::write(
1335             &*temp_dir.build().push("user_0").push("10223_USRCERT_non_authbound"),
1336             USRCERT_NON_AUTHBOUND,
1337         )?;
1338         std::fs::write(
1339             &*temp_dir.build().push("user_0").push("10223_CACERT_non_authbound"),
1340             CACERT_NON_AUTHBOUND,
1341         )?;
1342 
1343         let key_manager: SuperKeyManager = Default::default();
1344         let mut db = crate::database::KeystoreDB::new(temp_dir.path(), None)?;
1345         let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
1346 
1347         assert_eq!(
1348             legacy_blob_loader
1349                 .load_by_uid_alias(10223, "authbound", Some(&key_manager))
1350                 .unwrap_err()
1351                 .root_cause()
1352                 .downcast_ref::<error::Error>(),
1353             Some(&error::Error::Rc(ResponseCode::LOCKED))
1354         );
1355 
1356         key_manager.unlock_user_key(&mut db, 0, &(PASSWORD.into()), &legacy_blob_loader)?;
1357 
1358         if let (Some((Blob { flags, value: _ }, _params)), Some(cert), Some(chain)) =
1359             legacy_blob_loader.load_by_uid_alias(10223, "authbound", Some(&key_manager))?
1360         {
1361             assert_eq!(flags, 4);
1362             //assert_eq!(value, BlobValue::Encrypted(..));
1363             assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
1364             assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
1365         } else {
1366             panic!("");
1367         }
1368         if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
1369             legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", Some(&key_manager))?
1370         {
1371             assert_eq!(flags, 0);
1372             assert_eq!(value, BlobValue::Decrypted(LOADED_USRPKEY_NON_AUTHBOUND.try_into()?));
1373             assert_eq!(&cert[..], LOADED_CERT_NON_AUTHBOUND);
1374             assert_eq!(&chain[..], LOADED_CACERT_NON_AUTHBOUND);
1375         } else {
1376             panic!("");
1377         }
1378 
1379         legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
1380         legacy_blob_loader
1381             .remove_keystore_entry(10223, "non_authbound")
1382             .expect("This should succeed.");
1383 
1384         assert_eq!(
1385             (None, None, None),
1386             legacy_blob_loader.load_by_uid_alias(10223, "authbound", Some(&key_manager))?
1387         );
1388         assert_eq!(
1389             (None, None, None),
1390             legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", Some(&key_manager))?
1391         );
1392 
1393         // The database should not be empty due to the super key.
1394         assert!(!legacy_blob_loader.is_empty()?);
1395         assert!(!legacy_blob_loader.is_empty_user(0)?);
1396 
1397         // The database should be considered empty for user 1.
1398         assert!(legacy_blob_loader.is_empty_user(1)?);
1399 
1400         legacy_blob_loader.remove_super_key(0);
1401 
1402         // Now it should be empty.
1403         assert!(legacy_blob_loader.is_empty_user(0)?);
1404         assert!(legacy_blob_loader.is_empty()?);
1405 
1406         Ok(())
1407     }
1408 
1409     #[test]
list_non_existing_user() -> Result<()>1410     fn list_non_existing_user() -> Result<()> {
1411         let temp_dir = TempDir::new("list_non_existing_user")?;
1412         let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
1413 
1414         assert!(legacy_blob_loader.list_user(20)?.is_empty());
1415 
1416         Ok(())
1417     }
1418 
1419     #[test]
list_legacy_keystore_entries_on_non_existing_user() -> Result<()>1420     fn list_legacy_keystore_entries_on_non_existing_user() -> Result<()> {
1421         let temp_dir = TempDir::new("list_legacy_keystore_entries_on_non_existing_user")?;
1422         let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
1423 
1424         assert!(legacy_blob_loader.list_legacy_keystore_entries_for_user(20)?.is_empty());
1425 
1426         Ok(())
1427     }
1428 }
1429