Move legacy_blob tests into separate file
This complies better with the Android Rust style guide, and makes it
easier to navigate the code.
Test: keystore2_test
Change-Id: Ia6ea2b0a31f57bfe1b6114b3ce03181c24760310
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index 2bb7f27..c27a050 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -36,6 +36,9 @@
const SUPPORTED_LEGACY_BLOB_VERSION: u8 = 3;
+#[cfg(test)]
+mod tests;
+
mod flags {
/// This flag is deprecated. It is here to support keys that have been written with this flag
/// set, but we don't create any new keys with this flag.
@@ -1645,675 +1648,3 @@
Ok(())
}
}
-
-#[cfg(test)]
-mod test {
- #![allow(dead_code)]
- use super::*;
- use crate::legacy_blob::test_utils::legacy_blob_test_vectors::*;
- use crate::legacy_blob::test_utils::*;
- use anyhow::{anyhow, Result};
- use keystore2_crypto::aes_gcm_decrypt;
- use keystore2_test_utils::TempDir;
- use rand::Rng;
- use std::convert::TryInto;
- use std::ops::Deref;
- use std::string::FromUtf8Error;
-
- #[test]
- fn decode_encode_alias_test() {
- static ALIAS: &str = "#({}test[])😗";
- static ENCODED_ALIAS: &str = "+S+X{}test[]+Y.`-O-H-G";
- // Second multi byte out of range ------v
- static ENCODED_ALIAS_ERROR1: &str = "+S+{}test[]+Y";
- // Incomplete multi byte ------------------------v
- static ENCODED_ALIAS_ERROR2: &str = "+S+X{}test[]+";
- // Our encoding: ".`-O-H-G"
- // is UTF-8: 0xF0 0x9F 0x98 0x97
- // is UNICODE: U+1F617
- // is 😗
- // But +H below is a valid encoding for 0x18 making this sequence invalid UTF-8.
- static ENCODED_ALIAS_ERROR_UTF8: &str = ".`-O+H-G";
-
- assert_eq!(ENCODED_ALIAS, &LegacyBlobLoader::encode_alias(ALIAS));
- assert_eq!(ALIAS, &LegacyBlobLoader::decode_alias(ENCODED_ALIAS).unwrap());
- assert_eq!(
- Some(&Error::BadEncoding),
- LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR1)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>()
- );
- assert_eq!(
- Some(&Error::BadEncoding),
- LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR2)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>()
- );
- assert!(LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR_UTF8)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<FromUtf8Error>()
- .is_some());
-
- for _i in 0..100 {
- // Any valid UTF-8 string should be en- and decoded without loss.
- let alias_str = rand::thread_rng().gen::<[char; 20]>().iter().collect::<String>();
- let random_alias = alias_str.as_bytes();
- let encoded = LegacyBlobLoader::encode_alias(&alias_str);
- let decoded = match LegacyBlobLoader::decode_alias(&encoded) {
- Ok(d) => d,
- Err(_) => panic!("random_alias: {:x?}\nencoded {}", random_alias, encoded),
- };
- assert_eq!(random_alias.to_vec(), decoded.bytes().collect::<Vec<u8>>());
- }
- }
-
- #[test]
- fn read_golden_key_blob_test() -> anyhow::Result<()> {
- let blob = LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*BLOB, |_, _, _, _, _| {
- Err(anyhow!("should not be called"))
- })
- .unwrap();
- assert!(!blob.is_encrypted());
- assert!(!blob.is_fallback());
- assert!(!blob.is_strongbox());
- assert!(!blob.is_critical_to_device_encryption());
- assert_eq!(blob.value(), &BlobValue::Generic([0xde, 0xed, 0xbe, 0xef].to_vec()));
-
- let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
- &mut &*REAL_LEGACY_BLOB,
- |_, _, _, _, _| Err(anyhow!("should not be called")),
- )
- .unwrap();
- assert!(!blob.is_encrypted());
- assert!(!blob.is_fallback());
- assert!(!blob.is_strongbox());
- assert!(!blob.is_critical_to_device_encryption());
- assert_eq!(
- blob.value(),
- &BlobValue::Decrypted(REAL_LEGACY_BLOB_PAYLOAD.try_into().unwrap())
- );
- Ok(())
- }
-
- #[test]
- fn read_aes_gcm_encrypted_key_blob_test() {
- let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
- &mut &*AES_GCM_ENCRYPTED_BLOB,
- |d, iv, tag, salt, key_size| {
- assert_eq!(salt, None);
- assert_eq!(key_size, None);
- assert_eq!(
- iv,
- &[
- 0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f,
- 0x00, 0x00, 0x00, 0x00,
- ]
- );
- assert_eq!(
- tag,
- &[
- 0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9,
- 0xb9, 0xe0, 0x0b, 0xc3
- ][..]
- );
- aes_gcm_decrypt(d, iv, tag, AES_KEY).context("Trying to decrypt blob.")
- },
- )
- .unwrap();
- assert!(blob.is_encrypted());
- assert!(!blob.is_fallback());
- assert!(!blob.is_strongbox());
- assert!(!blob.is_critical_to_device_encryption());
-
- assert_eq!(blob.value(), &BlobValue::Decrypted(DECRYPTED_PAYLOAD.try_into().unwrap()));
- }
-
- #[test]
- fn read_golden_key_blob_too_short_test() {
- let error =
- LegacyBlobLoader::new_from_stream_decrypt_with(&mut &BLOB[0..15], |_, _, _, _, _| {
- Err(anyhow!("should not be called"))
- })
- .unwrap_err();
- assert_eq!(Some(&Error::BadLen), error.root_cause().downcast_ref::<Error>());
- }
-
- #[test]
- fn test_is_empty() {
- let temp_dir = TempDir::new("test_is_empty").expect("Failed to create temp dir.");
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty."));
-
- let _db = crate::database::KeystoreDB::new(temp_dir.path(), None)
- .expect("Failed to open database.");
-
- assert!(legacy_blob_loader.is_empty().expect("Should succeed and still be empty."));
-
- std::fs::create_dir(&*temp_dir.build().push("user_0")).expect("Failed to create user_0.");
-
- assert!(!legacy_blob_loader.is_empty().expect("Should succeed but not be empty."));
-
- std::fs::create_dir(&*temp_dir.build().push("user_10")).expect("Failed to create user_10.");
-
- assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
-
- std::fs::remove_dir_all(&*temp_dir.build().push("user_0"))
- .expect("Failed to remove user_0.");
-
- assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
-
- std::fs::remove_dir_all(&*temp_dir.build().push("user_10"))
- .expect("Failed to remove user_10.");
-
- assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty again."));
- }
-
- #[test]
- fn test_legacy_blobs() -> anyhow::Result<()> {
- let temp_dir = TempDir::new("legacy_blob_test").unwrap();
- std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
-
- std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
-
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND_CHR,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
- USRCERT_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
- CACERT_AUTHBOUND,
- )
- .unwrap();
-
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRPKEY_non_authbound"),
- USRPKEY_NON_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_non_authbound"),
- USRPKEY_NON_AUTHBOUND_CHR,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRCERT_non_authbound"),
- USRCERT_NON_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_CACERT_non_authbound"),
- CACERT_NON_AUTHBOUND,
- )
- .unwrap();
-
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
- {
- assert_eq!(flags, 4);
- assert_eq!(
- value,
- BlobValue::Encrypted {
- data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
- iv: USRPKEY_AUTHBOUND_IV.to_vec(),
- tag: USRPKEY_AUTHBOUND_TAG.to_vec()
- }
- );
- assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
- assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
- } else {
- panic!("");
- }
-
- if let (Some((Blob { flags, value: _ }, _params)), Some(cert), Some(chain)) =
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
- {
- assert_eq!(flags, 4);
- //assert_eq!(value, BlobValue::Encrypted(..));
- assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
- assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
- } else {
- panic!("");
- }
- if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
- legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
- {
- assert_eq!(flags, 0);
- assert_eq!(value, BlobValue::Decrypted(LOADED_USRPKEY_NON_AUTHBOUND.try_into()?));
- assert_eq!(&cert[..], LOADED_CERT_NON_AUTHBOUND);
- assert_eq!(&chain[..], LOADED_CACERT_NON_AUTHBOUND);
- } else {
- panic!("");
- }
-
- legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
- legacy_blob_loader
- .remove_keystore_entry(10223, "non_authbound")
- .expect("This should succeed.");
-
- assert_eq!(
- (None, None, None),
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
- );
- assert_eq!(
- (None, None, None),
- legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
- );
-
- // The database should not be empty due to the super key.
- assert!(!legacy_blob_loader.is_empty()?);
- assert!(!legacy_blob_loader.is_empty_user(0)?);
-
- // The database should be considered empty for user 1.
- assert!(legacy_blob_loader.is_empty_user(1)?);
-
- legacy_blob_loader.remove_super_key(0);
-
- // Now it should be empty.
- assert!(legacy_blob_loader.is_empty_user(0)?);
- assert!(legacy_blob_loader.is_empty()?);
-
- Ok(())
- }
-
- struct TestKey(ZVec);
-
- impl crate::utils::AesGcmKey for TestKey {
- fn key(&self) -> &[u8] {
- &self.0
- }
- }
-
- impl Deref for TestKey {
- type Target = [u8];
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
-
- #[test]
- fn test_with_encrypted_characteristics() -> anyhow::Result<()> {
- let temp_dir = TempDir::new("test_with_encrypted_characteristics").unwrap();
- std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
-
- let pw: Password = PASSWORD.into();
- let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
- let super_key =
- Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
-
- std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
-
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND,
- )
- .unwrap();
- make_encrypted_characteristics_file(
- &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
- &super_key,
- KEY_PARAMETERS,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
- USRCERT_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
- CACERT_AUTHBOUND,
- )
- .unwrap();
-
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert_eq!(
- legacy_blob_loader
- .load_by_uid_alias(10223, "authbound", &None)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>(),
- Some(&Error::LockedComponent)
- );
-
- assert_eq!(
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
- (
- Some((
- Blob {
- flags: 4,
- value: BlobValue::Encrypted {
- data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
- iv: USRPKEY_AUTHBOUND_IV.to_vec(),
- tag: USRPKEY_AUTHBOUND_TAG.to_vec()
- }
- },
- structured_test_params()
- )),
- Some(LOADED_CERT_AUTHBOUND.to_vec()),
- Some(LOADED_CACERT_AUTHBOUND.to_vec())
- )
- );
-
- legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
-
- assert_eq!(
- (None, None, None),
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
- );
-
- // The database should not be empty due to the super key.
- assert!(!legacy_blob_loader.is_empty().unwrap());
- assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
-
- // The database should be considered empty for user 1.
- assert!(legacy_blob_loader.is_empty_user(1).unwrap());
-
- legacy_blob_loader.remove_super_key(0);
-
- // Now it should be empty.
- assert!(legacy_blob_loader.is_empty_user(0).unwrap());
- assert!(legacy_blob_loader.is_empty().unwrap());
-
- Ok(())
- }
-
- #[test]
- fn test_with_encrypted_certificates() -> anyhow::Result<()> {
- let temp_dir = TempDir::new("test_with_encrypted_certificates").unwrap();
- std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
-
- let pw: Password = PASSWORD.into();
- let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
- let super_key =
- Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
-
- std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
-
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND_CHR,
- )
- .unwrap();
- make_encrypted_usr_cert_file(
- &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
- &super_key,
- LOADED_CERT_AUTHBOUND,
- )
- .unwrap();
- make_encrypted_ca_cert_file(
- &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
- &super_key,
- LOADED_CACERT_AUTHBOUND,
- )
- .unwrap();
-
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert_eq!(
- legacy_blob_loader
- .load_by_uid_alias(10223, "authbound", &None)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>(),
- Some(&Error::LockedComponent)
- );
-
- assert_eq!(
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
- (
- Some((
- Blob {
- flags: 4,
- value: BlobValue::Encrypted {
- data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
- iv: USRPKEY_AUTHBOUND_IV.to_vec(),
- tag: USRPKEY_AUTHBOUND_TAG.to_vec()
- }
- },
- structured_test_params_cache()
- )),
- Some(LOADED_CERT_AUTHBOUND.to_vec()),
- Some(LOADED_CACERT_AUTHBOUND.to_vec())
- )
- );
-
- legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
-
- assert_eq!(
- (None, None, None),
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
- );
-
- // The database should not be empty due to the super key.
- assert!(!legacy_blob_loader.is_empty().unwrap());
- assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
-
- // The database should be considered empty for user 1.
- assert!(legacy_blob_loader.is_empty_user(1).unwrap());
-
- legacy_blob_loader.remove_super_key(0);
-
- // Now it should be empty.
- assert!(legacy_blob_loader.is_empty_user(0).unwrap());
- assert!(legacy_blob_loader.is_empty().unwrap());
-
- Ok(())
- }
-
- #[test]
- fn test_in_place_key_migration() -> anyhow::Result<()> {
- let temp_dir = TempDir::new("test_in_place_key_migration").unwrap();
- std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
-
- let pw: Password = PASSWORD.into();
- let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
- let super_key =
- Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
-
- std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
-
- std::fs::write(
- &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND,
- )
- .unwrap();
- std::fs::write(
- &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
- USRPKEY_AUTHBOUND_CHR,
- )
- .unwrap();
- make_encrypted_usr_cert_file(
- &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
- &super_key,
- LOADED_CERT_AUTHBOUND,
- )
- .unwrap();
- make_encrypted_ca_cert_file(
- &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
- &super_key,
- LOADED_CACERT_AUTHBOUND,
- )
- .unwrap();
-
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert_eq!(
- legacy_blob_loader
- .load_by_uid_alias(10223, "authbound", &None)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>(),
- Some(&Error::LockedComponent)
- );
-
- let super_key: Option<Arc<dyn AesGcm>> = Some(super_key);
-
- assert_eq!(
- legacy_blob_loader.load_by_uid_alias(10223, "authbound", &super_key).unwrap(),
- (
- Some((
- Blob {
- flags: 4,
- value: BlobValue::Encrypted {
- data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
- iv: USRPKEY_AUTHBOUND_IV.to_vec(),
- tag: USRPKEY_AUTHBOUND_TAG.to_vec()
- }
- },
- structured_test_params_cache()
- )),
- Some(LOADED_CERT_AUTHBOUND.to_vec()),
- Some(LOADED_CACERT_AUTHBOUND.to_vec())
- )
- );
-
- legacy_blob_loader.move_keystore_entry(10223, 10224, "authbound", "boundauth").unwrap();
-
- assert_eq!(
- legacy_blob_loader
- .load_by_uid_alias(10224, "boundauth", &None)
- .unwrap_err()
- .root_cause()
- .downcast_ref::<Error>(),
- Some(&Error::LockedComponent)
- );
-
- assert_eq!(
- legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &super_key).unwrap(),
- (
- Some((
- Blob {
- flags: 4,
- value: BlobValue::Encrypted {
- data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
- iv: USRPKEY_AUTHBOUND_IV.to_vec(),
- tag: USRPKEY_AUTHBOUND_TAG.to_vec()
- }
- },
- structured_test_params_cache()
- )),
- Some(LOADED_CERT_AUTHBOUND.to_vec()),
- Some(LOADED_CACERT_AUTHBOUND.to_vec())
- )
- );
-
- legacy_blob_loader.remove_keystore_entry(10224, "boundauth").expect("This should succeed.");
-
- assert_eq!(
- (None, None, None),
- legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &None).unwrap()
- );
-
- // The database should not be empty due to the super key.
- assert!(!legacy_blob_loader.is_empty().unwrap());
- assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
-
- // The database should be considered empty for user 1.
- assert!(legacy_blob_loader.is_empty_user(1).unwrap());
-
- legacy_blob_loader.remove_super_key(0);
-
- // Now it should be empty.
- assert!(legacy_blob_loader.is_empty_user(0).unwrap());
- assert!(legacy_blob_loader.is_empty().unwrap());
-
- Ok(())
- }
-
- #[test]
- fn list_non_existing_user() -> Result<()> {
- let temp_dir = TempDir::new("list_non_existing_user").unwrap();
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert!(legacy_blob_loader.list_user(20)?.is_empty());
-
- Ok(())
- }
-
- #[test]
- fn list_legacy_keystore_entries_on_non_existing_user() -> Result<()> {
- let temp_dir = TempDir::new("list_legacy_keystore_entries_on_non_existing_user").unwrap();
- let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
-
- assert!(legacy_blob_loader.list_legacy_keystore_entries_for_user(20)?.is_empty());
-
- Ok(())
- }
-
- #[test]
- fn test_move_keystore_entry() {
- let temp_dir = TempDir::new("test_move_keystore_entry").unwrap();
- std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
-
- const SOME_CONTENT: &[u8] = b"some content";
- const ANOTHER_CONTENT: &[u8] = b"another content";
- const SOME_FILENAME: &str = "some_file";
- const ANOTHER_FILENAME: &str = "another_file";
-
- std::fs::write(&*temp_dir.build().push("user_0").push(SOME_FILENAME), SOME_CONTENT)
- .unwrap();
-
- std::fs::write(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME), ANOTHER_CONTENT)
- .unwrap();
-
- // Non existent source id silently ignored.
- assert!(LegacyBlobLoader::move_keystore_file_if_exists(
- 1,
- 2,
- "non_existent",
- ANOTHER_FILENAME,
- "ignored",
- |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
- )
- .is_ok());
-
- // Content of another_file has not changed.
- let another_content =
- std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
- assert_eq!(&another_content, ANOTHER_CONTENT);
-
- // Check that some_file still exists.
- assert!(temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
- // Existing target files are silently overwritten.
-
- assert!(LegacyBlobLoader::move_keystore_file_if_exists(
- 1,
- 2,
- SOME_FILENAME,
- ANOTHER_FILENAME,
- "ignored",
- |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
- )
- .is_ok());
-
- // Content of another_file is now "some content".
- let another_content =
- std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
- assert_eq!(&another_content, SOME_CONTENT);
-
- // Check that some_file no longer exists.
- assert!(!temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
- }
-}
diff --git a/keystore2/src/legacy_blob/tests.rs b/keystore2/src/legacy_blob/tests.rs
new file mode 100644
index 0000000..53fe03f
--- /dev/null
+++ b/keystore2/src/legacy_blob/tests.rs
@@ -0,0 +1,676 @@
+// Copyright 2020, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Tests for legacy keyblob processing.
+
+#![allow(dead_code)]
+use super::*;
+use crate::legacy_blob::test_utils::legacy_blob_test_vectors::*;
+use crate::legacy_blob::test_utils::*;
+use anyhow::{anyhow, Result};
+use keystore2_crypto::aes_gcm_decrypt;
+use keystore2_test_utils::TempDir;
+use rand::Rng;
+use std::convert::TryInto;
+use std::ops::Deref;
+use std::string::FromUtf8Error;
+
+#[test]
+fn decode_encode_alias_test() {
+ static ALIAS: &str = "#({}test[])😗";
+ static ENCODED_ALIAS: &str = "+S+X{}test[]+Y.`-O-H-G";
+ // Second multi byte out of range ------v
+ static ENCODED_ALIAS_ERROR1: &str = "+S+{}test[]+Y";
+ // Incomplete multi byte ------------------------v
+ static ENCODED_ALIAS_ERROR2: &str = "+S+X{}test[]+";
+ // Our encoding: ".`-O-H-G"
+ // is UTF-8: 0xF0 0x9F 0x98 0x97
+ // is UNICODE: U+1F617
+ // is 😗
+ // But +H below is a valid encoding for 0x18 making this sequence invalid UTF-8.
+ static ENCODED_ALIAS_ERROR_UTF8: &str = ".`-O+H-G";
+
+ assert_eq!(ENCODED_ALIAS, &LegacyBlobLoader::encode_alias(ALIAS));
+ assert_eq!(ALIAS, &LegacyBlobLoader::decode_alias(ENCODED_ALIAS).unwrap());
+ assert_eq!(
+ Some(&Error::BadEncoding),
+ LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR1)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>()
+ );
+ assert_eq!(
+ Some(&Error::BadEncoding),
+ LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR2)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>()
+ );
+ assert!(LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR_UTF8)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<FromUtf8Error>()
+ .is_some());
+
+ for _i in 0..100 {
+ // Any valid UTF-8 string should be en- and decoded without loss.
+ let alias_str = rand::thread_rng().gen::<[char; 20]>().iter().collect::<String>();
+ let random_alias = alias_str.as_bytes();
+ let encoded = LegacyBlobLoader::encode_alias(&alias_str);
+ let decoded = match LegacyBlobLoader::decode_alias(&encoded) {
+ Ok(d) => d,
+ Err(_) => panic!("random_alias: {:x?}\nencoded {}", random_alias, encoded),
+ };
+ assert_eq!(random_alias.to_vec(), decoded.bytes().collect::<Vec<u8>>());
+ }
+}
+
+#[test]
+fn read_golden_key_blob_test() -> anyhow::Result<()> {
+ let blob = LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*BLOB, |_, _, _, _, _| {
+ Err(anyhow!("should not be called"))
+ })
+ .unwrap();
+ assert!(!blob.is_encrypted());
+ assert!(!blob.is_fallback());
+ assert!(!blob.is_strongbox());
+ assert!(!blob.is_critical_to_device_encryption());
+ assert_eq!(blob.value(), &BlobValue::Generic([0xde, 0xed, 0xbe, 0xef].to_vec()));
+
+ let blob =
+ LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*REAL_LEGACY_BLOB, |_, _, _, _, _| {
+ Err(anyhow!("should not be called"))
+ })
+ .unwrap();
+ assert!(!blob.is_encrypted());
+ assert!(!blob.is_fallback());
+ assert!(!blob.is_strongbox());
+ assert!(!blob.is_critical_to_device_encryption());
+ assert_eq!(blob.value(), &BlobValue::Decrypted(REAL_LEGACY_BLOB_PAYLOAD.try_into().unwrap()));
+ Ok(())
+}
+
+#[test]
+fn read_aes_gcm_encrypted_key_blob_test() {
+ let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
+ &mut &*AES_GCM_ENCRYPTED_BLOB,
+ |d, iv, tag, salt, key_size| {
+ assert_eq!(salt, None);
+ assert_eq!(key_size, None);
+ assert_eq!(
+ iv,
+ &[
+ 0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f, 0x00,
+ 0x00, 0x00, 0x00,
+ ]
+ );
+ assert_eq!(
+ tag,
+ &[
+ 0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9, 0xb9,
+ 0xe0, 0x0b, 0xc3
+ ][..]
+ );
+ aes_gcm_decrypt(d, iv, tag, AES_KEY).context("Trying to decrypt blob.")
+ },
+ )
+ .unwrap();
+ assert!(blob.is_encrypted());
+ assert!(!blob.is_fallback());
+ assert!(!blob.is_strongbox());
+ assert!(!blob.is_critical_to_device_encryption());
+
+ assert_eq!(blob.value(), &BlobValue::Decrypted(DECRYPTED_PAYLOAD.try_into().unwrap()));
+}
+
+#[test]
+fn read_golden_key_blob_too_short_test() {
+ let error =
+ LegacyBlobLoader::new_from_stream_decrypt_with(&mut &BLOB[0..15], |_, _, _, _, _| {
+ Err(anyhow!("should not be called"))
+ })
+ .unwrap_err();
+ assert_eq!(Some(&Error::BadLen), error.root_cause().downcast_ref::<Error>());
+}
+
+#[test]
+fn test_is_empty() {
+ let temp_dir = TempDir::new("test_is_empty").expect("Failed to create temp dir.");
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty."));
+
+ let _db =
+ crate::database::KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database.");
+
+ assert!(legacy_blob_loader.is_empty().expect("Should succeed and still be empty."));
+
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).expect("Failed to create user_0.");
+
+ assert!(!legacy_blob_loader.is_empty().expect("Should succeed but not be empty."));
+
+ std::fs::create_dir(&*temp_dir.build().push("user_10")).expect("Failed to create user_10.");
+
+ assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
+
+ std::fs::remove_dir_all(&*temp_dir.build().push("user_0")).expect("Failed to remove user_0.");
+
+ assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
+
+ std::fs::remove_dir_all(&*temp_dir.build().push("user_10")).expect("Failed to remove user_10.");
+
+ assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty again."));
+}
+
+#[test]
+fn test_legacy_blobs() -> anyhow::Result<()> {
+ let temp_dir = TempDir::new("legacy_blob_test").unwrap();
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
+
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND_CHR,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
+ USRCERT_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
+ CACERT_AUTHBOUND,
+ )
+ .unwrap();
+
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRPKEY_non_authbound"),
+ USRPKEY_NON_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_non_authbound"),
+ USRPKEY_NON_AUTHBOUND_CHR,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRCERT_non_authbound"),
+ USRCERT_NON_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_CACERT_non_authbound"),
+ CACERT_NON_AUTHBOUND,
+ )
+ .unwrap();
+
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
+ {
+ assert_eq!(flags, 4);
+ assert_eq!(
+ value,
+ BlobValue::Encrypted {
+ data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
+ iv: USRPKEY_AUTHBOUND_IV.to_vec(),
+ tag: USRPKEY_AUTHBOUND_TAG.to_vec()
+ }
+ );
+ assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
+ assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
+ } else {
+ panic!("");
+ }
+
+ if let (Some((Blob { flags, value: _ }, _params)), Some(cert), Some(chain)) =
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
+ {
+ assert_eq!(flags, 4);
+ //assert_eq!(value, BlobValue::Encrypted(..));
+ assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
+ assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
+ } else {
+ panic!("");
+ }
+ if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
+ legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
+ {
+ assert_eq!(flags, 0);
+ assert_eq!(value, BlobValue::Decrypted(LOADED_USRPKEY_NON_AUTHBOUND.try_into()?));
+ assert_eq!(&cert[..], LOADED_CERT_NON_AUTHBOUND);
+ assert_eq!(&chain[..], LOADED_CACERT_NON_AUTHBOUND);
+ } else {
+ panic!("");
+ }
+
+ legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
+ legacy_blob_loader.remove_keystore_entry(10223, "non_authbound").expect("This should succeed.");
+
+ assert_eq!(
+ (None, None, None),
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
+ );
+ assert_eq!(
+ (None, None, None),
+ legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
+ );
+
+ // The database should not be empty due to the super key.
+ assert!(!legacy_blob_loader.is_empty()?);
+ assert!(!legacy_blob_loader.is_empty_user(0)?);
+
+ // The database should be considered empty for user 1.
+ assert!(legacy_blob_loader.is_empty_user(1)?);
+
+ legacy_blob_loader.remove_super_key(0);
+
+ // Now it should be empty.
+ assert!(legacy_blob_loader.is_empty_user(0)?);
+ assert!(legacy_blob_loader.is_empty()?);
+
+ Ok(())
+}
+
+struct TestKey(ZVec);
+
+impl crate::utils::AesGcmKey for TestKey {
+ fn key(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+impl Deref for TestKey {
+ type Target = [u8];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+#[test]
+fn test_with_encrypted_characteristics() -> anyhow::Result<()> {
+ let temp_dir = TempDir::new("test_with_encrypted_characteristics").unwrap();
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
+
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+ let super_key =
+ Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
+
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND,
+ )
+ .unwrap();
+ make_encrypted_characteristics_file(
+ &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
+ &super_key,
+ KEY_PARAMETERS,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
+ USRCERT_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
+ CACERT_AUTHBOUND,
+ )
+ .unwrap();
+
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert_eq!(
+ legacy_blob_loader
+ .load_by_uid_alias(10223, "authbound", &None)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>(),
+ Some(&Error::LockedComponent)
+ );
+
+ assert_eq!(
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
+ (
+ Some((
+ Blob {
+ flags: 4,
+ value: BlobValue::Encrypted {
+ data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
+ iv: USRPKEY_AUTHBOUND_IV.to_vec(),
+ tag: USRPKEY_AUTHBOUND_TAG.to_vec()
+ }
+ },
+ structured_test_params()
+ )),
+ Some(LOADED_CERT_AUTHBOUND.to_vec()),
+ Some(LOADED_CACERT_AUTHBOUND.to_vec())
+ )
+ );
+
+ legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
+
+ assert_eq!(
+ (None, None, None),
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
+ );
+
+ // The database should not be empty due to the super key.
+ assert!(!legacy_blob_loader.is_empty().unwrap());
+ assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
+
+ // The database should be considered empty for user 1.
+ assert!(legacy_blob_loader.is_empty_user(1).unwrap());
+
+ legacy_blob_loader.remove_super_key(0);
+
+ // Now it should be empty.
+ assert!(legacy_blob_loader.is_empty_user(0).unwrap());
+ assert!(legacy_blob_loader.is_empty().unwrap());
+
+ Ok(())
+}
+
+#[test]
+fn test_with_encrypted_certificates() -> anyhow::Result<()> {
+ let temp_dir = TempDir::new("test_with_encrypted_certificates").unwrap();
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
+
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+ let super_key =
+ Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
+
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND_CHR,
+ )
+ .unwrap();
+ make_encrypted_usr_cert_file(
+ &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
+ &super_key,
+ LOADED_CERT_AUTHBOUND,
+ )
+ .unwrap();
+ make_encrypted_ca_cert_file(
+ &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
+ &super_key,
+ LOADED_CACERT_AUTHBOUND,
+ )
+ .unwrap();
+
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert_eq!(
+ legacy_blob_loader
+ .load_by_uid_alias(10223, "authbound", &None)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>(),
+ Some(&Error::LockedComponent)
+ );
+
+ assert_eq!(
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
+ (
+ Some((
+ Blob {
+ flags: 4,
+ value: BlobValue::Encrypted {
+ data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
+ iv: USRPKEY_AUTHBOUND_IV.to_vec(),
+ tag: USRPKEY_AUTHBOUND_TAG.to_vec()
+ }
+ },
+ structured_test_params_cache()
+ )),
+ Some(LOADED_CERT_AUTHBOUND.to_vec()),
+ Some(LOADED_CACERT_AUTHBOUND.to_vec())
+ )
+ );
+
+ legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
+
+ assert_eq!(
+ (None, None, None),
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
+ );
+
+ // The database should not be empty due to the super key.
+ assert!(!legacy_blob_loader.is_empty().unwrap());
+ assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
+
+ // The database should be considered empty for user 1.
+ assert!(legacy_blob_loader.is_empty_user(1).unwrap());
+
+ legacy_blob_loader.remove_super_key(0);
+
+ // Now it should be empty.
+ assert!(legacy_blob_loader.is_empty_user(0).unwrap());
+ assert!(legacy_blob_loader.is_empty().unwrap());
+
+ Ok(())
+}
+
+#[test]
+fn test_in_place_key_migration() -> anyhow::Result<()> {
+ let temp_dir = TempDir::new("test_in_place_key_migration").unwrap();
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
+
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+ let super_key =
+ Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
+
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND,
+ )
+ .unwrap();
+ std::fs::write(
+ &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
+ USRPKEY_AUTHBOUND_CHR,
+ )
+ .unwrap();
+ make_encrypted_usr_cert_file(
+ &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
+ &super_key,
+ LOADED_CERT_AUTHBOUND,
+ )
+ .unwrap();
+ make_encrypted_ca_cert_file(
+ &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
+ &super_key,
+ LOADED_CACERT_AUTHBOUND,
+ )
+ .unwrap();
+
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert_eq!(
+ legacy_blob_loader
+ .load_by_uid_alias(10223, "authbound", &None)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>(),
+ Some(&Error::LockedComponent)
+ );
+
+ let super_key: Option<Arc<dyn AesGcm>> = Some(super_key);
+
+ assert_eq!(
+ legacy_blob_loader.load_by_uid_alias(10223, "authbound", &super_key).unwrap(),
+ (
+ Some((
+ Blob {
+ flags: 4,
+ value: BlobValue::Encrypted {
+ data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
+ iv: USRPKEY_AUTHBOUND_IV.to_vec(),
+ tag: USRPKEY_AUTHBOUND_TAG.to_vec()
+ }
+ },
+ structured_test_params_cache()
+ )),
+ Some(LOADED_CERT_AUTHBOUND.to_vec()),
+ Some(LOADED_CACERT_AUTHBOUND.to_vec())
+ )
+ );
+
+ legacy_blob_loader.move_keystore_entry(10223, 10224, "authbound", "boundauth").unwrap();
+
+ assert_eq!(
+ legacy_blob_loader
+ .load_by_uid_alias(10224, "boundauth", &None)
+ .unwrap_err()
+ .root_cause()
+ .downcast_ref::<Error>(),
+ Some(&Error::LockedComponent)
+ );
+
+ assert_eq!(
+ legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &super_key).unwrap(),
+ (
+ Some((
+ Blob {
+ flags: 4,
+ value: BlobValue::Encrypted {
+ data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
+ iv: USRPKEY_AUTHBOUND_IV.to_vec(),
+ tag: USRPKEY_AUTHBOUND_TAG.to_vec()
+ }
+ },
+ structured_test_params_cache()
+ )),
+ Some(LOADED_CERT_AUTHBOUND.to_vec()),
+ Some(LOADED_CACERT_AUTHBOUND.to_vec())
+ )
+ );
+
+ legacy_blob_loader.remove_keystore_entry(10224, "boundauth").expect("This should succeed.");
+
+ assert_eq!(
+ (None, None, None),
+ legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &None).unwrap()
+ );
+
+ // The database should not be empty due to the super key.
+ assert!(!legacy_blob_loader.is_empty().unwrap());
+ assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
+
+ // The database should be considered empty for user 1.
+ assert!(legacy_blob_loader.is_empty_user(1).unwrap());
+
+ legacy_blob_loader.remove_super_key(0);
+
+ // Now it should be empty.
+ assert!(legacy_blob_loader.is_empty_user(0).unwrap());
+ assert!(legacy_blob_loader.is_empty().unwrap());
+
+ Ok(())
+}
+
+#[test]
+fn list_non_existing_user() -> Result<()> {
+ let temp_dir = TempDir::new("list_non_existing_user").unwrap();
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert!(legacy_blob_loader.list_user(20)?.is_empty());
+
+ Ok(())
+}
+
+#[test]
+fn list_legacy_keystore_entries_on_non_existing_user() -> Result<()> {
+ let temp_dir = TempDir::new("list_legacy_keystore_entries_on_non_existing_user").unwrap();
+ let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
+
+ assert!(legacy_blob_loader.list_legacy_keystore_entries_for_user(20)?.is_empty());
+
+ Ok(())
+}
+
+#[test]
+fn test_move_keystore_entry() {
+ let temp_dir = TempDir::new("test_move_keystore_entry").unwrap();
+ std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
+
+ const SOME_CONTENT: &[u8] = b"some content";
+ const ANOTHER_CONTENT: &[u8] = b"another content";
+ const SOME_FILENAME: &str = "some_file";
+ const ANOTHER_FILENAME: &str = "another_file";
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(SOME_FILENAME), SOME_CONTENT).unwrap();
+
+ std::fs::write(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME), ANOTHER_CONTENT)
+ .unwrap();
+
+ // Non existent source id silently ignored.
+ assert!(LegacyBlobLoader::move_keystore_file_if_exists(
+ 1,
+ 2,
+ "non_existent",
+ ANOTHER_FILENAME,
+ "ignored",
+ |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
+ )
+ .is_ok());
+
+ // Content of another_file has not changed.
+ let another_content =
+ std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
+ assert_eq!(&another_content, ANOTHER_CONTENT);
+
+ // Check that some_file still exists.
+ assert!(temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
+ // Existing target files are silently overwritten.
+
+ assert!(LegacyBlobLoader::move_keystore_file_if_exists(
+ 1,
+ 2,
+ SOME_FILENAME,
+ ANOTHER_FILENAME,
+ "ignored",
+ |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
+ )
+ .is_ok());
+
+ // Content of another_file is now "some content".
+ let another_content =
+ std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
+ assert_eq!(&another_content, SOME_CONTENT);
+
+ // Check that some_file no longer exists.
+ assert!(!temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
+}