Merge "Use shared libutils instead of static for keystore fuzzers"
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
index 9594977..50e0e96 100644
--- a/diced/src/lib.rs
+++ b/diced/src/lib.rs
@@ -100,7 +100,7 @@
Ok(BinderInputValues {
codeHash: [0; dice::HASH_SIZE],
config: BinderConfig {
- desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, true)
+ desc: dice::bcc::format_config_descriptor(Some(&format!("{}", uid)), None, false)
.context("In client_input_values: failed to format config descriptor")?,
},
authorityHash: [0; dice::HASH_SIZE],
diff --git a/keystore/tests/confirmationui_invocation_test.cpp b/keystore/tests/confirmationui_invocation_test.cpp
index 7f8a373..822e6a4 100644
--- a/keystore/tests/confirmationui_invocation_test.cpp
+++ b/keystore/tests/confirmationui_invocation_test.cpp
@@ -55,7 +55,7 @@
std::string locale("en");
std::vector<uint8_t> extraData{0xaa, 0xff, 0x00, 0x55};
- auto listener = std::make_shared<ConfirmationListener>();
+ auto listener = ndk::SharedRefBase::make<ConfirmationListener>();
auto future = listener->get_future();
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 2027af4..e7c2752 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -79,7 +79,10 @@
name: "libkeystore2_test_utils",
crate_name: "keystore2_test_utils",
srcs: ["test_utils/lib.rs"],
+ defaults: ["keymint_use_latest_hal_aidl_rust"],
rustlibs: [
+ "android.system.keystore2-V2-rust",
+ "libbinder_rs",
"libkeystore2_selinux",
"liblog_rust",
"libnix",
@@ -89,14 +92,30 @@
],
}
+rust_library {
+ name: "libkeystore2_with_test_utils",
+ defaults: ["libkeystore2_defaults"],
+ features: [
+ "keystore2_blob_test_utils",
+ ],
+ rustlibs: [
+ "liblibsqlite3_sys",
+ "librusqlite",
+ "libkeystore2_test_utils",
+ ],
+}
+
rust_test {
name: "keystore2_test_utils_test",
srcs: ["test_utils/lib.rs"],
+ defaults: ["keymint_use_latest_hal_aidl_rust"],
test_suites: ["general-tests"],
require_root: true,
auto_gen_config: true,
compile_multilib: "first",
rustlibs: [
+ "android.system.keystore2-V2-rust",
+ "libbinder_rs",
"libkeystore2_selinux",
"liblog_rust",
"libnix",
@@ -119,10 +138,12 @@
"liblibsqlite3_sys",
"libnix",
"librusqlite",
+ "libkeystore2_with_test_utils",
],
// The test should always include watchdog.
features: [
"watchdog",
+ "keystore2_blob_test_utils",
],
}
diff --git a/keystore2/TEST_MAPPING b/keystore2/TEST_MAPPING
index 049adc7..5d0a7dd 100644
--- a/keystore2/TEST_MAPPING
+++ b/keystore2/TEST_MAPPING
@@ -13,6 +13,9 @@
"name": "keystore2_test_utils_test"
},
{
+ "name": "keystore2_legacy_blobs_test"
+ },
+ {
"name": "CtsIdentityTestCases"
},
{
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index 3df5936..6a37c78 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -23,15 +23,10 @@
* user's password.
* @hide
*/
-@SensitiveData
+ @SensitiveData
interface IKeystoreMaintenance {
/**
- * Special value indicating the callers uid.
- */
- const int UID_SELF = -1;
-
- /**
* Allows LockSettingsService to inform keystore about adding a new user.
* Callers require 'AddUser' permission.
*
@@ -120,10 +115,6 @@
* The source may be specified by Domain::APP, Domain::SELINUX, or Domain::KEY_ID. The target
* may be specified by Domain::APP or Domain::SELINUX.
*
- * If Domain::APP is selected in either source or destination, nspace must be set to UID_SELF,
- * implying the caller's UID. If the caller has the MIGRATE_ANY_KEY permission, Domain::APP may
- * be used with other nspace values which then indicates the UID of a different application.
- *
* ## Error conditions:
* `ResponseCode::PERMISSION_DENIED` - If the caller lacks any of the required permissions.
* `ResponseCode::KEY_NOT_FOUND` - If the source did not exist.
@@ -140,22 +131,4 @@
* Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
*/
void deleteAllKeys();
-
- /**
- * List all entries accessible by the caller in the given `domain` and `nspace`.
- *
- * Callers either has to have the `GET_INFO` permission for the requested namespace or `LIST`
- * permission to list all the entries.
- *
- * ## Error conditions
- * `ResponseCode::INVALID_ARGUMENT` if `domain` is other than `Domain::APP` or `Domain::SELINUX`
- * `ResponseCode::PERMISSION_DENIED` if the caller does not have the permission
- *
- * @param domain `Domain::APP` or `Domain::SELINUX`.
- *
- * @param nspace The SELinux keystore2_key namespace.
- *
- * @return List of KeyDescriptors.
- */
- KeyDescriptor[] listEntries(in Domain domain, in long nspace);
}
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index 771d609..9854974 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -107,6 +107,9 @@
use anyhow::{Context, Result};
use rusqlite::types::{Null, ToSql, ToSqlOutput};
use rusqlite::Result as SqlResult;
+use serde::de::Deserializer;
+use serde::ser::Serializer;
+use serde::{Deserialize, Serialize};
/// This trait is used to associate a primitive to any type that can be stored inside a
/// KeyParameterValue, especially the AIDL enum types, e.g., keymint::{Algorithm, Digest, ...}.
@@ -121,7 +124,7 @@
/// there is no wrapped type):
/// `KeyParameterValue::$vname(<$vtype>::from_primitive(row.get(0)))`
trait AssociatePrimitive {
- type Primitive;
+ type Primitive: Into<Primitive> + TryFrom<Primitive>;
fn from_primitive(v: Self::Primitive) -> Self;
fn to_primitive(&self) -> Self::Primitive;
@@ -177,6 +180,7 @@
/// This enum allows passing a primitive value to `KeyParameterValue::new_from_tag_primitive_pair`
/// Usually, it is not necessary to use this type directly because the function uses
/// `Into<Primitive>` as a trait bound.
+#[derive(Deserialize, Serialize)]
pub enum Primitive {
/// Wraps an i64.
I64(i64),
@@ -213,37 +217,57 @@
UnknownTag,
}
-impl TryInto<i64> for Primitive {
+impl TryFrom<Primitive> for i64 {
type Error = PrimitiveError;
- fn try_into(self) -> Result<i64, Self::Error> {
- match self {
- Self::I64(v) => Ok(v),
+ fn try_from(p: Primitive) -> Result<i64, Self::Error> {
+ match p {
+ Primitive::I64(v) => Ok(v),
_ => Err(Self::Error::TypeMismatch),
}
}
}
-impl TryInto<i32> for Primitive {
+impl TryFrom<Primitive> for i32 {
type Error = PrimitiveError;
- fn try_into(self) -> Result<i32, Self::Error> {
- match self {
- Self::I32(v) => Ok(v),
+ fn try_from(p: Primitive) -> Result<i32, Self::Error> {
+ match p {
+ Primitive::I32(v) => Ok(v),
_ => Err(Self::Error::TypeMismatch),
}
}
}
-impl TryInto<Vec<u8>> for Primitive {
+impl TryFrom<Primitive> for Vec<u8> {
type Error = PrimitiveError;
- fn try_into(self) -> Result<Vec<u8>, Self::Error> {
- match self {
- Self::Vec(v) => Ok(v),
+ fn try_from(p: Primitive) -> Result<Vec<u8>, Self::Error> {
+ match p {
+ Primitive::Vec(v) => Ok(v),
_ => Err(Self::Error::TypeMismatch),
}
}
}
+fn serialize_primitive<S, P>(v: &P, serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+ P: AssociatePrimitive,
+{
+ let primitive: Primitive = v.to_primitive().into();
+ primitive.serialize(serializer)
+}
+
+fn deserialize_primitive<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+ D: Deserializer<'de>,
+ T: AssociatePrimitive,
+{
+ let primitive: Primitive = serde::de::Deserialize::deserialize(deserializer)?;
+ Ok(T::from_primitive(
+ primitive.try_into().map_err(|_| serde::de::Error::custom("Type Mismatch"))?,
+ ))
+}
+
/// Expands the list of KeyParameterValue variants as follows:
///
/// Input:
@@ -763,6 +787,14 @@
value: KmKeyParameterValue::$field_name(Default::default())}
),*]
}
+
+ #[cfg(test)]
+ fn make_key_parameter_defaults_vector() -> Vec<KeyParameter> {
+ vec![$(KeyParameter{
+ value: KeyParameterValue::$vname$((<$vtype as Default>::default()))?,
+ security_level: SecurityLevel(100),
+ }),*]
+ }
}
implement_try_from_to_km_parameter!(
@@ -777,27 +809,37 @@
implement_key_parameter_value! {
/// KeyParameterValue holds a value corresponding to one of the Tags defined in
/// the AIDL spec at hardware/interfaces/security/keymint
-#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)]
pub enum KeyParameterValue {
/// Associated with Tag:INVALID
#[key_param(tag = INVALID, field = Invalid)]
Invalid,
/// Set of purposes for which the key may be used
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = PURPOSE, field = KeyPurpose)]
KeyPurpose(KeyPurpose),
/// Cryptographic algorithm with which the key is used
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = ALGORITHM, field = Algorithm)]
Algorithm(Algorithm),
/// Size of the key , in bits
#[key_param(tag = KEY_SIZE, field = Integer)]
KeySize(i32),
/// Block cipher mode(s) with which the key may be used
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = BLOCK_MODE, field = BlockMode)]
BlockMode(BlockMode),
/// Digest algorithms that may be used with the key to perform signing and verification
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = DIGEST, field = Digest)]
Digest(Digest),
/// Padding modes that may be used with the key. Relevant to RSA, AES and 3DES keys.
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = PADDING, field = PaddingMode)]
PaddingMode(PaddingMode),
/// Can the caller provide a nonce for nonce-requiring operations
@@ -807,6 +849,8 @@
#[key_param(tag = MIN_MAC_LENGTH, field = Integer)]
MinMacLength(i32),
/// The elliptic curve
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = EC_CURVE, field = EcCurve)]
EcCurve(EcCurve),
/// Value of the public exponent for an RSA key pair
@@ -856,6 +900,8 @@
#[key_param(tag = NO_AUTH_REQUIRED, field = BoolValue)]
NoAuthRequired,
/// The types of user authenticators that may be used to authorize this key
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = USER_AUTH_TYPE, field = HardwareAuthenticatorType)]
HardwareAuthenticatorType(HardwareAuthenticatorType),
/// The time in seconds for which the key is authorized for use, after user authentication
@@ -886,6 +932,8 @@
#[key_param(tag = CREATION_DATETIME, field = DateTime)]
CreationDateTime(i64),
/// Specifies where the key was created, if known
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
#[key_param(tag = ORIGIN, field = Origin)]
KeyOrigin(KeyOrigin),
/// The key used by verified boot to validate the operating system booted
@@ -981,9 +1029,11 @@
}
/// KeyParameter wraps the KeyParameterValue and the security level at which it is enforced.
-#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct KeyParameter {
value: KeyParameterValue,
+ #[serde(deserialize_with = "deserialize_primitive")]
+ #[serde(serialize_with = "serialize_primitive")]
security_level: SecurityLevel,
}
@@ -1106,6 +1156,18 @@
fn key_parameter_value_field_matches_tag_type() {
check_field_matches_tag_type(&KeyParameterValue::make_field_matches_tag_type_test_vector());
}
+
+ #[test]
+ fn key_parameter_serialization_test() {
+ let params = KeyParameterValue::make_key_parameter_defaults_vector();
+ let mut out_buffer: Vec<u8> = Default::default();
+ serde_cbor::to_writer(&mut out_buffer, ¶ms)
+ .expect("Failed to serialize key parameters.");
+ let deserialized_params: Vec<KeyParameter> =
+ serde_cbor::from_reader(&mut out_buffer.as_slice())
+ .expect("Failed to deserialize key parameters.");
+ assert_eq!(params, deserialized_params);
+ }
}
#[cfg(test)]
diff --git a/keystore2/src/legacy_blob.rs b/keystore2/src/legacy_blob.rs
index cbc680d..d75bfd2 100644
--- a/keystore2/src/legacy_blob.rs
+++ b/keystore2/src/legacy_blob.rs
@@ -1387,25 +1387,24 @@
}
}
-#[cfg(test)]
-mod test {
+/// This module implements utility apis for creating legacy blob files.
+#[cfg(feature = "keystore2_blob_test_utils")]
+pub mod test_utils {
#![allow(dead_code)]
- use super::*;
- use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt};
- use rand::Rng;
- use std::string::FromUtf8Error;
- mod legacy_blob_test_vectors;
+
+ /// test vectors for legacy key blobs
+ pub mod legacy_blob_test_vectors;
+
use crate::legacy_blob::blob_types::{
GENERIC, KEY_CHARACTERISTICS, KEY_CHARACTERISTICS_CACHE, KM_BLOB, SUPER_KEY,
SUPER_KEY_AES256,
};
- use crate::legacy_blob::test::legacy_blob_test_vectors::*;
+ use crate::legacy_blob::*;
use anyhow::{anyhow, Result};
- use keystore2_test_utils::TempDir;
+ use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt};
use std::convert::TryInto;
use std::fs::OpenOptions;
use std::io::Write;
- use std::ops::Deref;
/// This function takes a blob and synchronizes the encrypted/super encrypted flags
/// with the blob type for the pairs Generic/EncryptedGeneric,
@@ -1414,7 +1413,7 @@
/// or flags::ENCRYPTED is set, the payload is encrypted and the corresponding
/// encrypted variant is returned, and vice versa. All other variants remain untouched
/// even if flags and BlobValue variant are inconsistent.
- fn prepare_blob(blob: Blob, key: &[u8]) -> Result<Blob> {
+ pub fn prepare_blob(blob: Blob, key: &[u8]) -> Result<Blob> {
match blob {
Blob { value: BlobValue::Generic(data), flags } if blob.is_encrypted() => {
let (ciphertext, iv, tag) = aes_gcm_encrypt(&data, key).unwrap();
@@ -1453,7 +1452,8 @@
}
}
- struct LegacyBlobHeader {
+ /// Legacy blob header structure.
+ pub struct LegacyBlobHeader {
version: u8,
blob_type: u8,
flags: u8,
@@ -1467,7 +1467,7 @@
/// version 3. Note that the flags field and the values field may be
/// inconsistent and could be sanitized by this function. It is intentionally
/// not done to enable tests to construct malformed blobs.
- fn write_legacy_blob(out: &mut dyn Write, blob: Blob) -> Result<usize> {
+ pub fn write_legacy_blob(out: &mut dyn Write, blob: Blob) -> Result<usize> {
let (header, data, salt) = match blob {
Blob { value: BlobValue::Generic(data), flags } => (
LegacyBlobHeader {
@@ -1581,7 +1581,9 @@
write_legacy_blob_helper(out, &header, &data, salt.as_deref())
}
- fn write_legacy_blob_helper(
+ /// This function takes LegacyBlobHeader, blob payload and writes it to out as a legacy blob file
+ /// version 3.
+ pub fn write_legacy_blob_helper(
out: &mut dyn Write,
header: &LegacyBlobHeader,
data: &[u8],
@@ -1622,10 +1624,51 @@
Ok(40 + data.len() + info.map(|v| v.len()).unwrap_or(0))
}
- fn make_encrypted_characteristics_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
+ /// Create encrypted characteristics file using given key.
+ pub fn make_encrypted_characteristics_file<P: AsRef<Path>>(
+ path: P,
+ key: &[u8],
+ data: &[u8],
+ ) -> Result<()> {
+ let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+ let blob =
+ Blob { value: BlobValue::Characteristics(data.to_vec()), flags: flags::ENCRYPTED };
+ let blob = prepare_blob(blob, key).unwrap();
+ write_legacy_blob(&mut file, blob).unwrap();
+ Ok(())
+ }
+
+ /// Create encrypted user certificate file using given key.
+ pub fn make_encrypted_usr_cert_file<P: AsRef<Path>>(
+ path: P,
+ key: &[u8],
+ data: &[u8],
+ ) -> Result<()> {
+ let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+ let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: flags::ENCRYPTED };
+ let blob = prepare_blob(blob, key).unwrap();
+ write_legacy_blob(&mut file, blob).unwrap();
+ Ok(())
+ }
+
+ /// Create encrypted CA certificate file using given key.
+ pub fn make_encrypted_ca_cert_file<P: AsRef<Path>>(
+ path: P,
+ key: &[u8],
+ data: &[u8],
+ ) -> Result<()> {
+ let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
+ let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: flags::ENCRYPTED };
+ let blob = prepare_blob(blob, key).unwrap();
+ write_legacy_blob(&mut file, blob).unwrap();
+ Ok(())
+ }
+
+ /// Create encrypted user key file using given key.
+ pub fn make_encrypted_key_file<P: AsRef<Path>>(path: P, key: &[u8], data: &[u8]) -> Result<()> {
let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
let blob = Blob {
- value: BlobValue::Characteristics(KEY_PARAMETERS.to_vec()),
+ value: BlobValue::Decrypted(ZVec::try_from(data).unwrap()),
flags: flags::ENCRYPTED,
};
let blob = prepare_blob(blob, key).unwrap();
@@ -1633,27 +1676,29 @@
Ok(())
}
- fn make_encrypted_usr_cert_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
+ /// Create user or ca cert blob file.
+ pub fn make_cert_blob_file<P: AsRef<Path>>(path: P, data: &[u8]) -> Result<()> {
let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
- let blob = Blob {
- value: BlobValue::Generic(LOADED_CERT_AUTHBOUND.to_vec()),
- flags: flags::ENCRYPTED,
- };
- let blob = prepare_blob(blob, key).unwrap();
+ let blob = Blob { value: BlobValue::Generic(data.to_vec()), flags: 0 };
+ let blob = prepare_blob(blob, &[]).unwrap();
write_legacy_blob(&mut file, blob).unwrap();
Ok(())
}
+}
- fn make_encrypted_ca_cert_file<P: AsRef<Path>>(path: P, key: &[u8]) -> Result<()> {
- let mut file = OpenOptions::new().write(true).create_new(true).open(path).unwrap();
- let blob = Blob {
- value: BlobValue::Generic(LOADED_CACERT_AUTHBOUND.to_vec()),
- flags: flags::ENCRYPTED,
- };
- let blob = prepare_blob(blob, key).unwrap();
- write_legacy_blob(&mut file, blob).unwrap();
- 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() {
@@ -1962,6 +2007,7 @@
make_encrypted_characteristics_file(
&*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
&super_key,
+ KEY_PARAMETERS,
)
.unwrap();
std::fs::write(
@@ -2053,11 +2099,13 @@
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();
@@ -2139,11 +2187,13 @@
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();
diff --git a/keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs b/keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
similarity index 98%
rename from keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs
rename to keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
index 2049ac2..3eecee0 100644
--- a/keystore2/src/legacy_blob/test/legacy_blob_test_vectors.rs
+++ b/keystore2/src/legacy_blob/test_utils/legacy_blob_test_vectors.rs
@@ -20,6 +20,7 @@
KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
};
+/// Holds Blob structure.
pub static BLOB: &[u8] = &[
3, // version
1, // type
@@ -31,6 +32,7 @@
0xde, 0xed, 0xbe, 0xef, // payload
];
+/// Creates LegacyKeyCharacteristics with security level KEYSTORE.
pub fn structured_test_params() -> LegacyKeyCharacteristics {
LegacyKeyCharacteristics::File(vec![
KeyParameter::new(KeyParameterValue::KeyPurpose(KeyPurpose::SIGN), SecurityLevel::KEYSTORE),
@@ -61,6 +63,7 @@
])
}
+/// Creates LegacyKeyCharacteristics with security level TRUSTED_ENVIRONMENT.
pub fn structured_test_params_cache() -> LegacyKeyCharacteristics {
LegacyKeyCharacteristics::Cache(vec![
KeyParameter::new(
@@ -117,7 +120,7 @@
])
}
-// One encoded list of key parameters.
+/// One encoded list of key parameters.
pub static KEY_PARAMETERS: &[u8] = &[
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x20,
@@ -130,6 +133,7 @@
0x30, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
];
+/// Real legacy blob.
pub static REAL_LEGACY_BLOB: &[u8] = &[
0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -161,6 +165,7 @@
0xda, 0x40, 0x2b, 0x75, 0xd0, 0xd2, 0x81, 0x7f, 0xe2, 0x2b, 0xef, 0x64,
];
+/// Real legacy blob payload.
pub static REAL_LEGACY_BLOB_PAYLOAD: &[u8] = &[
0x6c, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x72, 0x00, 0x00,
0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00, 0x20, 0x85, 0x42, 0x9e, 0xe9, 0x34, 0x85, 0x2a, 0x00,
@@ -190,11 +195,13 @@
0xe2, 0x2b, 0xef, 0x64,
];
+/// AES key blob.
pub static AES_KEY: &[u8] = &[
0x48, 0xe4, 0xb5, 0xff, 0xcd, 0x9c, 0x41, 0x1e, 0x20, 0x41, 0xf2, 0x65, 0xa0, 0x4f, 0xf6, 0x57,
0xc6, 0x58, 0xca, 0xbf, 0x28, 0xa3, 0x01, 0x98, 0x01, 0x76, 0x10, 0xc0, 0x30, 0x4e, 0x35, 0x6e,
];
+/// AES-GCM encrypted blob.
pub static AES_GCM_ENCRYPTED_BLOB: &[u8] = &[
0x03, 0x04, 0x04, 0x00, 0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9,
@@ -227,6 +234,7 @@
0x2e, 0x0c, 0xc7, 0xbf, 0x29, 0x1e, 0x31, 0xdc, 0x0e, 0x85, 0x96, 0x7b,
];
+/// Decrypted payload.
pub static DECRYPTED_PAYLOAD: &[u8] = &[
0x7c, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x72, 0x00, 0x00,
0x00, 0x06, 0x00, 0x80, 0x00, 0x43, 0x00, 0x20, 0xa4, 0xee, 0xdc, 0x1f, 0x9e, 0xba, 0x42, 0xd6,
@@ -257,6 +265,7 @@
0xf6, 0x0b, 0x81, 0x07,
];
+/// Password blob.
pub static PASSWORD: &[u8] = &[
0x42, 0x39, 0x30, 0x37, 0x44, 0x37, 0x32, 0x37, 0x39, 0x39, 0x43, 0x42, 0x39, 0x41, 0x42, 0x30,
0x34, 0x31, 0x30, 0x38, 0x46, 0x44, 0x33, 0x45, 0x39, 0x42, 0x32, 0x38, 0x36, 0x35, 0x41, 0x36,
@@ -264,6 +273,7 @@
0x32, 0x45, 0x31, 0x35, 0x43, 0x43, 0x46, 0x32, 0x39, 0x36, 0x33, 0x34, 0x31, 0x32, 0x41, 0x39,
];
+/// Super key blob.
pub static SUPERKEY: &[u8] = &[
0x03, 0x07, 0x01, 0x10, 0x9a, 0x81, 0x56, 0x7d, 0xf5, 0x86, 0x7c, 0x62, 0xd7, 0xf9, 0x26, 0x06,
0x00, 0x00, 0x00, 0x00, 0xde, 0x2a, 0xcb, 0xac, 0x98, 0x57, 0x2b, 0xe5, 0x57, 0x18, 0x78, 0x57,
@@ -273,23 +283,28 @@
0x94, 0xb6, 0x67, 0x7b, 0x39, 0x85, 0x28, 0x11,
];
+/// Super key IV.
pub static SUPERKEY_IV: &[u8] = &[
0x9a, 0x81, 0x56, 0x7d, 0xf5, 0x86, 0x7c, 0x62, 0xd7, 0xf9, 0x26, 0x06, 0x00, 0x00, 0x00, 0x00,
];
+/// Super key tag.
pub static SUPERKEY_TAG: &[u8] = &[
0xde, 0x2a, 0xcb, 0xac, 0x98, 0x57, 0x2b, 0xe5, 0x57, 0x18, 0x78, 0x57, 0x6e, 0x10, 0x09, 0x84,
];
+/// Super key salt.
pub static SUPERKEY_SALT: &[u8] = &[
0x04, 0x5b, 0xb4, 0x8a, 0x09, 0x22, 0x13, 0x0c, 0x94, 0xb6, 0x67, 0x7b, 0x39, 0x85, 0x28, 0x11,
];
+/// Super key payload.
pub static SUPERKEY_PAYLOAD: &[u8] = &[
0xac, 0x6d, 0x13, 0xe6, 0xad, 0x2c, 0x89, 0x53, 0x1a, 0x99, 0xa5, 0x6c, 0x88, 0xe9, 0xeb, 0x5c,
0xef, 0x68, 0x5e, 0x5b, 0x53, 0xa8, 0xe7, 0xa2, 0x76, 0x04, 0x2a, 0x48, 0xd1, 0xa7, 0x59, 0xd1,
];
+/// user key blob.
pub static USRPKEY_AUTHBOUND: &[u8] = &[
0x03, 0x04, 0x04, 0x00, 0x1c, 0x34, 0x87, 0x6f, 0xc8, 0x35, 0x0d, 0x34, 0x88, 0x59, 0xbc, 0xf5,
0x00, 0x00, 0x00, 0x00, 0x62, 0xe3, 0x38, 0x2d, 0xd0, 0x58, 0x40, 0xc1, 0xb0, 0xf2, 0x4a, 0xdd,
@@ -330,14 +345,17 @@
0x83, 0x42, 0xdd, 0x4e, 0x6d,
];
+/// Authbound IV.
pub static USRPKEY_AUTHBOUND_IV: &[u8] = &[
0x1c, 0x34, 0x87, 0x6f, 0xc8, 0x35, 0x0d, 0x34, 0x88, 0x59, 0xbc, 0xf5, 0x00, 0x00, 0x00, 0x00,
];
+/// Authbond IV Tag.
pub static USRPKEY_AUTHBOUND_TAG: &[u8] = &[
0x62, 0xe3, 0x38, 0x2d, 0xd0, 0x58, 0x40, 0xc1, 0xb0, 0xf2, 0x4a, 0xdd, 0xf7, 0x81, 0x67, 0x0b,
];
+/// Encrypted use key payload.
pub static USRPKEY_AUTHBOUND_ENC_PAYLOAD: &[u8] = &[
0x05, 0xb2, 0x5a, 0x1d, 0x1b, 0x25, 0x19, 0x48, 0xbf, 0x76, 0x0b, 0x37, 0x8c, 0x60, 0x52, 0xea,
0x30, 0x2a, 0x2c, 0x89, 0x99, 0x95, 0x57, 0x5c, 0xec, 0x62, 0x3c, 0x08, 0x1a, 0xc6, 0x65, 0xf9,
@@ -375,6 +393,7 @@
0x73, 0x08, 0x50, 0xb2, 0x19, 0xe8, 0x23, 0x1b, 0x83, 0x42, 0xdd, 0x4e, 0x6d,
];
+/// User key characterstics blob.
pub static USRPKEY_AUTHBOUND_CHR: &[u8] = &[
0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -390,6 +409,8 @@
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xbd, 0x02, 0x00, 0x60,
0x10, 0x9d, 0x8b, 0x31, 0x76, 0x01, 0x00, 0x00, 0xf5, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
];
+
+/// User certificate blob.
pub static USRCERT_AUTHBOUND: &[u8] = &[
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -436,6 +457,8 @@
0x39, 0x58, 0xe9, 0x89, 0x1a, 0x14, 0x41, 0x8d, 0xe0, 0xdc, 0x3d, 0x88, 0xf4, 0x2c, 0x7c, 0xda,
0xa1, 0x84, 0xfa, 0x7f, 0xf9, 0x07, 0x97, 0xfb, 0xb5, 0xb7, 0x28, 0x28, 0x00, 0x7c, 0xa7,
];
+
+/// CA certificate blob.
pub static CACERT_AUTHBOUND: &[u8] = &[
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -624,6 +647,7 @@
0xab, 0xae, 0x24, 0xe2, 0x44, 0x35, 0x16, 0x8d, 0x55, 0x3c, 0xe4,
];
+/// User non-authbond-key blob.
pub static USRPKEY_NON_AUTHBOUND: &[u8] = &[
0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -663,6 +687,8 @@
0x46, 0xf0, 0xee, 0x50, 0x73, 0x6a, 0x7b, 0xa3, 0xe9, 0xb1, 0x08, 0x81, 0x00, 0xdf, 0x0e, 0xc9,
0xc3, 0x2c, 0x13, 0x64, 0xa1,
];
+
+/// User non-authbond-key characteristics blob.
pub static USRPKEY_NON_AUTHBOUND_CHR: &[u8] = &[
0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -678,6 +704,7 @@
0x60, 0x60, 0x60, 0x8c, 0x31, 0x76, 0x01, 0x00, 0x00, 0xf5, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00,
];
+/// User non-authbond-key certificate blob.
pub static USRCERT_NON_AUTHBOUND: &[u8] = &[
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -725,6 +752,7 @@
0xd8, 0xd5, 0xd1, 0x64, 0x4c, 0x05, 0xdd, 0x13, 0x0e, 0xa4, 0xf3, 0x38, 0xbf, 0x18, 0xd5,
];
+/// User non-authbond-key ca-certs blob.
pub static CACERT_NON_AUTHBOUND: &[u8] = &[
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -913,6 +941,7 @@
0xab, 0xae, 0x24, 0xe2, 0x44, 0x35, 0x16, 0x8d, 0x55, 0x3c, 0xe4,
];
+/// User decrypted authbond-key blob.
pub static _DECRYPTED_USRPKEY_AUTHBOUND: &[u8] = &[
0x44, 0x4b, 0x4d, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xc6, 0x15, 0x3a, 0x08, 0x1e, 0x43, 0xba, 0x7a, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
@@ -950,6 +979,7 @@
0x60, 0x5e, 0xcd, 0xce, 0x3a, 0xd8, 0x09, 0xeb, 0x9d, 0x40, 0xdb, 0x58, 0x53,
];
+/// User loaded authbond certs blob.
pub static LOADED_CERT_AUTHBOUND: &[u8] = &[
0x30, 0x82, 0x02, 0x93, 0x30, 0x82, 0x02, 0x3A, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01,
0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x29, 0x31, 0x19,
@@ -994,6 +1024,8 @@
0xE0, 0xDC, 0x3D, 0x88, 0xF4, 0x2C, 0x7C, 0xDA, 0xA1, 0x84, 0xFA, 0x7F, 0xF9, 0x07, 0x97, 0xFB,
0xB5, 0xB7, 0x28, 0x28, 0x00, 0x7C, 0xA7,
];
+
+/// User loaded authbond ca-certs blob.
pub static LOADED_CACERT_AUTHBOUND: &[u8] = &[
0x30, 0x82, 0x02, 0x26, 0x30, 0x82, 0x01, 0xAB, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0A, 0x05,
0x84, 0x20, 0x26, 0x90, 0x76, 0x23, 0x58, 0x71, 0x77, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48,
@@ -1180,6 +1212,7 @@
0x55, 0x3C, 0xE4,
];
+/// User loaded non-authbond user key blob.
pub static LOADED_USRPKEY_NON_AUTHBOUND: &[u8] = &[
0x44, 0x4b, 0x4d, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x8a, 0xc1, 0x08, 0x13, 0x7c, 0x47, 0xba, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
@@ -1217,6 +1250,7 @@
0xe9, 0xb1, 0x08, 0x81, 0x00, 0xdf, 0x0e, 0xc9, 0xc3, 0x2c, 0x13, 0x64, 0xa1,
];
+/// User loaded non-authbond certificate blob.
pub static LOADED_CERT_NON_AUTHBOUND: &[u8] = &[
0x30, 0x82, 0x02, 0x93, 0x30, 0x82, 0x02, 0x39, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01,
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x29, 0x31, 0x19,
@@ -1262,6 +1296,7 @@
0x0e, 0xa4, 0xf3, 0x38, 0xbf, 0x18, 0xd5,
];
+/// User loaded non-authbond ca-certificates blob.
pub static LOADED_CACERT_NON_AUTHBOUND: &[u8] = &[
0x30, 0x82, 0x02, 0x26, 0x30, 0x82, 0x01, 0xab, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x05,
0x84, 0x20, 0x26, 0x90, 0x76, 0x23, 0x58, 0x71, 0x77, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
diff --git a/keystore2/src/legacy_importer.rs b/keystore2/src/legacy_importer.rs
index 5a64020..93e1735 100644
--- a/keystore2/src/legacy_importer.rs
+++ b/keystore2/src/legacy_importer.rs
@@ -280,116 +280,6 @@
result
}
- /// This function behaves exactly like with_try_import unless the src_key has an encrypted
- /// component (other than the key blob itself [1]) and super_key is None.
- /// In that case the files belonging to the src_key will be renamed to be moved to the
- /// namespace indicated by dst_key. The destination domain must be in Domain::APP.
- ///
- /// [1] Components that cannot be encrypted with the super key in keystore2 include the
- /// characteristics file, which was encrypted before Android Q, and certificate entries
- /// added by KeyChain before Android Q.
- pub fn with_try_import_or_migrate_namespaces<F, T>(
- &self,
- src: (u32, &KeyDescriptor),
- dest: (u32, &KeyDescriptor),
- super_key: Option<Arc<dyn AesGcm + Send + Sync>>,
- has_migrate_any_permission: bool,
- key_accessor: F,
- ) -> Result<Option<T>>
- where
- F: Fn() -> Result<T>,
- {
- let _wp = wd::watch_millis("LegacyImporter::with_try_import_or_migrate_namespaces", 500);
-
- let (src_uid, src_key) = src;
- let (dest_uid, dest_key) = dest;
-
- // Access the key and return on success.
- match key_accessor() {
- Ok(result) => return Ok(Some(result)),
- Err(e) => {
- if e.root_cause().downcast_ref::<Error>()
- != Some(&Error::Rc(ResponseCode::KEY_NOT_FOUND))
- {
- return Err(e);
- }
- }
- }
-
- // Filter inputs. We can only load legacy app domain keys as well
- // as the SELINUX WIFI_NAMESPACE, which will be populated from AID_WIFI.
- let src_uid = match src_key {
- KeyDescriptor { domain: Domain::APP, alias: Some(_), .. } => src_uid,
- KeyDescriptor { domain: Domain::SELINUX, nspace, alias: Some(_), .. } => {
- match *nspace {
- Self::WIFI_NAMESPACE => Self::AID_WIFI,
- _ => {
- return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
- .context(format!("No legacy keys for namespace {}", nspace))
- }
- }
- }
- _ => {
- return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
- .context("No legacy keys for key descriptor.")
- }
- };
-
- let dest_uid = match dest_key {
- KeyDescriptor { domain: Domain::APP, alias: Some(_), .. } => Some(dest_uid),
- KeyDescriptor { domain: Domain::SELINUX, alias: Some(_), .. } => {
- // Domain::SELINUX cannot be migrated in place, but we cannot fail at this point
- // because the import may succeed at which point the actual migration will
- // be performed by the caller.
- None
- }
- _ => {
- return Err(Error::Rc(ResponseCode::KEY_NOT_FOUND))
- .context("No legacy keys for key descriptor.")
- }
- };
-
- let src_key_clone = src_key.clone();
- let dest_key_clone = dest_key.clone();
- let result = self.do_serialized(move |importer_state| {
- let super_key = super_key.map(|sk| -> Arc<dyn AesGcm> { sk });
- match (
- importer_state.check_and_import(src_uid, src_key_clone.clone(), super_key),
- dest_uid,
- ) {
- // The import into the database was successful. Return Ok(true)
- (Ok(()), _) => Ok(true),
- // The import failed because a certificate and/or characteristics
- // file was encrypted and no super_key was available. Migration within the
- // legacy database is attempted and Ok(false) is returned on success.
- (Err(e), Some(dest_uid))
- if has_migrate_any_permission
- && e.root_cause().downcast_ref::<Error>()
- == Some(&Error::Rc(ResponseCode::LOCKED)) =>
- {
- importer_state
- .migrate_namespaces(src_uid, dest_uid, src_key_clone, dest_key_clone)
- .map(|_| false)
- }
- (Err(e), _) => Err(e),
- }
- });
-
- match result {
- None => {
- Err(Error::Rc(ResponseCode::KEY_NOT_FOUND)).context("Legacy database is empty.")
- }
-
- Some(Ok(true)) => {
- // After successful import try again.
- key_accessor().map(|v| Some(v))
- }
- // The entry was successfully migrated within the legacy database.
- Some(Ok(false)) => Ok(None),
- Some(Err(e)) => Err(e),
- }
- }
-
/// Runs the key_accessor function and returns its result. If it returns an error and the
/// root cause was KEY_NOT_FOUND, tries to import a key with the given parameters from
/// the legacy database to the new database and runs the key_accessor function again if
@@ -544,39 +434,6 @@
.context("In list_uid: Trying to list legacy entries.")
}
- fn migrate_namespaces(
- &mut self,
- src_uid: u32,
- dest_uid: u32,
- src_key: KeyDescriptor,
- dest_key: KeyDescriptor,
- ) -> Result<()> {
- let src_alias = src_key.alias.ok_or_else(|| {
- anyhow::anyhow!(Error::sys()).context(
- "In legacy_migrator::migrate_namespace: src_key.alias must be Some because \
- our caller must not have called us otherwise.",
- )
- })?;
-
- if dest_key.domain != Domain::APP {
- return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
- "In legacy_migrator::migrate_namespace: \
- Legacy in-place migration to SELinux namespace is not supported.",
- );
- }
-
- let dest_alias = dest_key.alias.ok_or_else(|| {
- anyhow::anyhow!(Error::sys()).context(concat!(
- "In legacy_migrator::migrate_namespace: dest_key.alias must be Some because ",
- "our caller must not have called us otherwise."
- ))
- })?;
-
- self.legacy_loader
- .move_keystore_entry(src_uid, dest_uid, &src_alias, &dest_alias)
- .context("In legacy_migrator::migrate_namespace: Moving key entry files.")
- }
-
/// Checks if the key can potentially be unlocked. And deletes the key entry otherwise.
/// If the super_key has already been imported, the super key database id is returned.
fn get_super_key_id_check_unlockable_or_delete(
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 0d637d8..1fca5d9 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -23,14 +23,13 @@
use crate::permission::{KeyPerm, KeystorePerm};
use crate::super_key::{SuperKeyManager, UserState};
use crate::utils::{
- check_key_permission, check_keystore_permission, list_key_entries, uid_to_android_user,
- watchdog as wd,
+ check_key_permission, check_keystore_permission, uid_to_android_user, watchdog as wd,
};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
};
use android_security_maintenance::aidl::android::security::maintenance::{
- IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance, UID_SELF},
+ IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
UserState::UserState as AidlUserState,
};
use android_security_maintenance::binder::{
@@ -40,7 +39,6 @@
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{Context, Result};
use keystore2_crypto::Password;
-use keystore2_selinux as selinux;
/// Reexport Domain for the benefit of DeleteListener
pub use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
@@ -225,15 +223,10 @@
}
fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
- let migrate_any_key_permission =
- check_keystore_permission(KeystorePerm::MigrateAnyKey).is_ok();
+ let calling_uid = ThreadState::get_calling_uid();
- let src_uid = match source.domain {
- Domain::SELINUX | Domain::KEY_ID => ThreadState::get_calling_uid(),
- Domain::APP if source.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
- Domain::APP if source.nspace != UID_SELF.into() && migrate_any_key_permission => {
- source.nspace as u32
- }
+ match source.domain {
+ Domain::SELINUX | Domain::KEY_ID | Domain::APP => (),
_ => {
return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
"In migrate_key_namespace: \
@@ -242,12 +235,8 @@
}
};
- let dest_uid = match destination.domain {
- Domain::SELINUX => ThreadState::get_calling_uid(),
- Domain::APP if destination.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
- Domain::APP if destination.nspace != UID_SELF.into() && migrate_any_key_permission => {
- destination.nspace as u32
- }
+ match destination.domain {
+ Domain::SELINUX | Domain::APP => (),
_ => {
return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
"In migrate_key_namespace: \
@@ -256,54 +245,30 @@
}
};
- let user_id = uid_to_android_user(dest_uid);
-
- if user_id != uid_to_android_user(src_uid)
- && (source.domain == Domain::APP || destination.domain == Domain::APP)
- {
- return Err(Error::sys()).context(
- "In migrate_key_namespace: Keys cannot be migrated across android users.",
- );
- }
+ let user_id = uid_to_android_user(calling_uid);
let super_key = SUPER_KEY.read().unwrap().get_per_boot_key_by_user_id(user_id);
DB.with(|db| {
- if let Some((key_id_guard, _)) = LEGACY_IMPORTER
- .with_try_import_or_migrate_namespaces(
- (src_uid, source),
- (dest_uid, destination),
- super_key,
- migrate_any_key_permission,
- || {
- db.borrow_mut().load_key_entry(
- source,
- KeyType::Client,
- KeyEntryLoadBits::NONE,
- src_uid,
- |k, av| {
- if migrate_any_key_permission {
- Ok(())
- } else {
- check_key_permission(KeyPerm::Use, k, &av)?;
- check_key_permission(KeyPerm::Delete, k, &av)?;
- check_key_permission(KeyPerm::Grant, k, &av)
- }
- },
- )
- },
- )
- .context("In migrate_key_namespace: Failed to load key blob.")?
- {
- db.borrow_mut().migrate_key_namespace(key_id_guard, destination, dest_uid, |k| {
- if migrate_any_key_permission {
- Ok(())
- } else {
- check_key_permission(KeyPerm::Rebind, k, &None)
- }
+ let (key_id_guard, _) = LEGACY_IMPORTER
+ .with_try_import(source, calling_uid, super_key, || {
+ db.borrow_mut().load_key_entry(
+ source,
+ KeyType::Client,
+ KeyEntryLoadBits::NONE,
+ calling_uid,
+ |k, av| {
+ check_key_permission(KeyPerm::Use, k, &av)?;
+ check_key_permission(KeyPerm::Delete, k, &av)?;
+ check_key_permission(KeyPerm::Grant, k, &av)
+ },
+ )
})
- } else {
- Ok(())
+ .context("In migrate_key_namespace: Failed to load key blob.")?;
+ {
+ db.borrow_mut().migrate_key_namespace(key_id_guard, destination, calling_uid, |k| {
+ check_key_permission(KeyPerm::Rebind, k, &None)
+ })
}
})
}
@@ -316,30 +281,6 @@
Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys())
}
-
- fn list_entries(domain: Domain, nspace: i64) -> Result<Vec<KeyDescriptor>> {
- let k = match domain {
- Domain::APP | Domain::SELINUX => KeyDescriptor{domain, nspace, ..Default::default()},
- _ => return Err(Error::perm()).context(
- "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
- ),
- };
-
- // The caller has to have either GetInfo for the namespace or List permission
- check_key_permission(KeyPerm::GetInfo, &k, &None)
- .or_else(|e| {
- if Some(&selinux::Error::PermissionDenied)
- == e.root_cause().downcast_ref::<selinux::Error>()
- {
- check_keystore_permission(KeystorePerm::List)
- } else {
- Err(e)
- }
- })
- .context("In list_entries: While checking key and keystore permission.")?;
-
- DB.with(|db| list_key_entries(&mut db.borrow_mut(), domain, nspace))
- }
}
impl Interface for Maintenance {}
@@ -389,11 +330,6 @@
map_or_log_err(Self::migrate_key_namespace(source, destination), Ok)
}
- fn listEntries(&self, domain: Domain, namespace: i64) -> BinderResult<Vec<KeyDescriptor>> {
- let _wp = wd::watch_millis("IKeystoreMaintenance::listEntries", 500);
- map_or_log_err(Self::list_entries(domain, namespace), Ok)
- }
-
fn deleteAllKeys(&self) -> BinderResult<()> {
let _wp = wd::watch_millis("IKeystoreMaintenance::deleteAllKeys", 500);
map_or_log_err(Self::delete_all_keys(), Ok)
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 1e6f10a..22509c4 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -145,10 +145,6 @@
/// Checked when IKeystoreMaintenance::deleteAllKeys is called.
#[selinux(name = delete_all_keys)]
DeleteAllKeys,
- /// Checked when migrating any key from any namespace to any other namespace. It was
- /// introduced for migrating keys when an app leaves a sharedUserId.
- #[selinux(name = migrate_any_key)]
- MigrateAnyKey,
/// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
#[selinux(name = get_attestation_key)]
GetAttestationKey,
diff --git a/keystore2/test_utils/authorizations.rs b/keystore2/test_utils/authorizations.rs
new file mode 100644
index 0000000..4fbe124
--- /dev/null
+++ b/keystore2/test_utils/authorizations.rs
@@ -0,0 +1,88 @@
+// Copyright 2022, 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.
+
+//! This module implements test utils to create Autherizations.
+
+use std::ops::Deref;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, KeyParameter::KeyParameter,
+ KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, Tag::Tag,
+};
+
+/// Helper struct to create set of Authorizations.
+pub struct AuthSetBuilder(Vec<KeyParameter>);
+
+impl Default for AuthSetBuilder {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl AuthSetBuilder {
+ /// Creates new Authorizations list.
+ pub fn new() -> Self {
+ Self(Vec::new())
+ }
+
+ /// Add Purpose.
+ pub fn purpose(mut self, p: KeyPurpose) -> Self {
+ self.0.push(KeyParameter { tag: Tag::PURPOSE, value: KeyParameterValue::KeyPurpose(p) });
+ self
+ }
+
+ /// Add Digest.
+ pub fn digest(mut self, d: Digest) -> Self {
+ self.0.push(KeyParameter { tag: Tag::DIGEST, value: KeyParameterValue::Digest(d) });
+ self
+ }
+
+ /// Add Algorithm.
+ pub fn algorithm(mut self, a: Algorithm) -> Self {
+ self.0.push(KeyParameter { tag: Tag::ALGORITHM, value: KeyParameterValue::Algorithm(a) });
+ self
+ }
+
+ /// Add EC-Curve.
+ pub fn ec_curve(mut self, e: EcCurve) -> Self {
+ self.0.push(KeyParameter { tag: Tag::EC_CURVE, value: KeyParameterValue::EcCurve(e) });
+ self
+ }
+
+ /// Add Attestation-Challenge.
+ pub fn attestation_challenge(mut self, b: Vec<u8>) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::ATTESTATION_CHALLENGE,
+ value: KeyParameterValue::Blob(b),
+ });
+ self
+ }
+
+ /// Add Attestation-ID.
+ pub fn attestation_app_id(mut self, b: Vec<u8>) -> Self {
+ self.0.push(KeyParameter {
+ tag: Tag::ATTESTATION_APPLICATION_ID,
+ value: KeyParameterValue::Blob(b),
+ });
+ self
+ }
+}
+
+impl Deref for AuthSetBuilder {
+ type Target = Vec<KeyParameter>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
new file mode 100644
index 0000000..f49aa9f
--- /dev/null
+++ b/keystore2/test_utils/key_generations.rs
@@ -0,0 +1,68 @@
+// Copyright 2022, 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.
+
+//! This module implements test utils to generate various types of keys.
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, KeyPurpose::KeyPurpose,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+ KeyMetadata::KeyMetadata,
+};
+
+use crate::authorizations::AuthSetBuilder;
+
+const SELINUX_SHELL_NAMESPACE: i64 = 1;
+
+/// Generate attested EC Key blob using given security level with below key parameters -
+/// Purposes: SIGN and VERIFY
+/// Digest: SHA_2_256
+/// Curve: P_256
+pub fn generate_ec_p256_signing_key_with_attestation(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+) -> binder::Result<KeyMetadata> {
+ let att_challenge: &[u8] = b"foo";
+ let att_app_id: &[u8] = b"bar";
+ let gen_params = AuthSetBuilder::new()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256)
+ .ec_curve(EcCurve::P_256)
+ .attestation_challenge(att_challenge.to_vec())
+ .attestation_app_id(att_app_id.to_vec());
+
+ match sec_level.generateKey(
+ &KeyDescriptor {
+ domain: Domain::BLOB,
+ nspace: SELINUX_SHELL_NAMESPACE,
+ alias: None,
+ blob: None,
+ },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ ) {
+ Ok(key_metadata) => {
+ assert!(key_metadata.certificate.is_some());
+ assert!(key_metadata.certificateChain.is_some());
+ assert!(key_metadata.key.blob.is_some());
+
+ Ok(key_metadata)
+ }
+ Err(e) => Err(e),
+ }
+}
diff --git a/keystore2/test_utils/lib.rs b/keystore2/test_utils/lib.rs
index a355544..c63bfac 100644
--- a/keystore2/test_utils/lib.rs
+++ b/keystore2/test_utils/lib.rs
@@ -19,8 +19,14 @@
use std::path::{Path, PathBuf};
use std::{env::temp_dir, ops::Deref};
+use android_system_keystore2::aidl::android::system::keystore2::IKeystoreService::IKeystoreService;
+
+pub mod authorizations;
+pub mod key_generations;
pub mod run_as;
+static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
+
/// Represents the lifecycle of a temporary directory for testing.
#[derive(Debug)]
pub struct TempDir {
@@ -104,3 +110,8 @@
&self.0
}
}
+
+/// Get Keystore2 service.
+pub fn get_keystore_service() -> binder::Strong<dyn IKeystoreService> {
+ binder::get_interface(KS2_SERVICE_NAME).unwrap()
+}
diff --git a/keystore2/tests/legacy_blobs/Android.bp b/keystore2/tests/legacy_blobs/Android.bp
new file mode 100644
index 0000000..2f48d7f
--- /dev/null
+++ b/keystore2/tests/legacy_blobs/Android.bp
@@ -0,0 +1,42 @@
+// Copyright 2022, 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.
+
+rust_test {
+ name: "keystore2_legacy_blobs_test",
+ srcs: ["keystore2_legacy_blob_tests.rs"],
+ test_suites: [
+ "general-tests",
+ ],
+ // auto_gen_config: true,
+ test_config: "AndroidTest.xml",
+
+ rustlibs: [
+ "libkeystore2_with_test_utils",
+ "libkeystore2_crypto_rust",
+ "android.system.keystore2-V2-rust",
+ "android.hardware.security.keymint-V2-rust",
+ "android.security.maintenance-rust",
+ "android.security.authorization-rust",
+ "librustutils",
+ "libkeystore2_test_utils",
+ "libnix",
+ "libanyhow",
+ "libbinder_rs",
+ "liblazy_static",
+ "liblibc",
+ "libserde",
+ "libthiserror",
+ ],
+ require_root: true,
+}
diff --git a/keystore2/tests/legacy_blobs/AndroidTest.xml b/keystore2/tests/legacy_blobs/AndroidTest.xml
new file mode 100644
index 0000000..ea83fbf
--- /dev/null
+++ b/keystore2/tests/legacy_blobs/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<configuration description="Config to run keystore2_legacy_blobs_test device tests.">
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option
+ name="push"
+ value="keystore2_legacy_blobs_test->/data/local/tmp/keystore2_legacy_blobs_test"
+ />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+ <option name="test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="keystore2_legacy_blobs_test" />
+ <option name="native-test-flag" value="--test-threads=1" />
+ </test>
+</configuration>
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
new file mode 100644
index 0000000..6def39e
--- /dev/null
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -0,0 +1,579 @@
+// Copyright 2022, 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.
+
+use nix::unistd::{getuid, Gid, Uid};
+use rustutils::users::AID_USER_OFFSET;
+use serde::{Deserialize, Serialize};
+
+use std::ops::Deref;
+use std::path::PathBuf;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel;
+
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, KeyDescriptor::KeyDescriptor,
+};
+
+use android_security_maintenance::aidl::android::security::maintenance::{
+ IKeystoreMaintenance::IKeystoreMaintenance, UserState::UserState,
+};
+
+use android_security_authorization::aidl::android::security::authorization::{
+ IKeystoreAuthorization::IKeystoreAuthorization, LockScreenEvent::LockScreenEvent,
+};
+
+use keystore2::key_parameter::KeyParameter as KsKeyparameter;
+use keystore2::legacy_blob::test_utils::legacy_blob_test_vectors::*;
+use keystore2::legacy_blob::test_utils::*;
+use keystore2::legacy_blob::LegacyKeyCharacteristics;
+use keystore2::utils::AesGcm;
+use keystore2_crypto::{Password, ZVec};
+
+use keystore2_test_utils::get_keystore_service;
+use keystore2_test_utils::key_generations;
+use keystore2_test_utils::run_as;
+
+static USER_MANAGER_SERVICE_NAME: &str = "android.security.maintenance";
+static AUTH_SERVICE_NAME: &str = "android.security.authorization";
+const SELINUX_SHELL_NAMESPACE: i64 = 1;
+
+fn get_maintenance() -> binder::Strong<dyn IKeystoreMaintenance> {
+ binder::get_interface(USER_MANAGER_SERVICE_NAME).unwrap()
+}
+
+fn get_authorization() -> binder::Strong<dyn IKeystoreAuthorization> {
+ binder::get_interface(AUTH_SERVICE_NAME).unwrap()
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+struct KeygenResult {
+ cert: Vec<u8>,
+ cert_chain: Vec<u8>,
+ key_parameters: Vec<KsKeyparameter>,
+}
+
+struct TestKey(ZVec);
+
+impl keystore2::utils::AesGcmKey for TestKey {
+ fn key(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+impl Deref for TestKey {
+ type Target = [u8];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn keystore2_restart_service() {
+ let output = std::process::Command::new("pidof")
+ .arg("keystore2")
+ .output()
+ .expect("failed to execute pidof keystore2");
+
+ let id = String::from_utf8(output.stdout).unwrap();
+ let id: String = id.chars().filter(|c| c.is_digit(10)).collect();
+
+ let _status = std::process::Command::new("kill").arg("-9").arg(id).status().unwrap();
+
+ // Loop till we find keystore2 service up and running.
+ loop {
+ let output = std::process::Command::new("pidof")
+ .arg("keystore2")
+ .output()
+ .expect("failed to execute pidof keystore2");
+
+ if output.status.code() == Some(0) {
+ break;
+ }
+ }
+}
+
+/// Create legacy blobs file layout for a user with user-id 99 and app-id 10001 with
+/// user-cert, ca-certs and encrypted key-characteristics files and tries to import
+/// these legacy blobs under user context.
+///
+/// Expected File layout for user with user-id "98" and app-id "10001" and key-alias
+/// "authbound":
+/// /data/misc/keystore/user_99/.masterkey
+/// /data/misc/keystore/user_99/9910001_USRPKEY_authbound
+/// /data/misc/keystore/user_99/.9910001_chr_USRPKEY_authbound
+/// /data/misc/keystore/user_99/9910001_USRCERT_authbound
+/// /data/misc/keystore/user_99/9910001_CACERT_authbound
+///
+/// Test performs below tasks -
+/// With su context it performs following tasks -
+/// 1. Remove this user if already exist.
+/// 2. Generate a key-blob, user cert-blob and ca-cert-blob to store it in legacy blobs file
+/// layout.
+/// 3. Prepare file layout using generated key-blob, user cert and ca certs.
+/// 4. Restart the keystore2 service to make it detect the populated legacy blobs.
+/// 5. Inform the keystore2 service about the user and unlock the user.
+/// With user-99 context it performs following tasks -
+/// 6. To load and import the legacy key using its alias.
+/// 7. After successful key import validate the user cert and cert-chain with initially
+/// generated blobs.
+/// 8. Validate imported key perameters. Imported key parameters list should be the combination
+/// of the key-parameters in characteristics file and the characteristics according to
+/// the augmentation rules. There might be duplicate entries with different values for the
+/// parameters like OS_VERSION, OS_VERSION, BOOT_PATCHLEVEL, VENDOR_PATCHLEVEL etc.
+/// 9. Confirm keystore2 service cleanup the legacy blobs after successful import.
+#[test]
+fn keystore2_encrypted_characteristics() -> anyhow::Result<()> {
+ let auid = 99 * AID_USER_OFFSET + 10001;
+ let agid = 99 * AID_USER_OFFSET + 10001;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+ // Cleanup user directory if it exists
+ let path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ if path_buf.as_path().is_dir() {
+ std::fs::remove_dir_all(path_buf.as_path()).unwrap();
+ }
+
+ // Safety: run_as must be called from a single threaded process.
+ // This device test is run as a separate single threaded process.
+ let mut gen_key_result = unsafe {
+ run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+ // Remove user if already exist.
+ let maint_service = get_maintenance();
+ match maint_service.onUserRemoved(99) {
+ Ok(_) => {
+ println!("User was existed, deleted successfully");
+ }
+ Err(e) => {
+ println!("onUserRemoved error: {:#?}", e);
+ }
+ }
+
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2
+ .getSecurityLevel(SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT)
+ .unwrap();
+ // Generate Key BLOB and prepare legacy keystore blob files.
+ let key_metadata =
+ key_generations::generate_ec_p256_signing_key_with_attestation(&sec_level)
+ .expect("Failed to generate key blob");
+
+ // Create keystore file layout for user_99.
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key(Some(SUPERKEY_SALT), 32).unwrap());
+ let super_key =
+ TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ if !path_buf.as_path().is_dir() {
+ std::fs::create_dir(path_buf.as_path()).unwrap();
+ }
+ path_buf.push(".masterkey");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push("9910001_USRPKEY_authbound");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_key_file(
+ path_buf.as_path(),
+ &super_key,
+ &key_metadata.key.blob.unwrap(),
+ )
+ .unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push(".9910001_chr_USRPKEY_authbound");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_characteristics_file(path_buf.as_path(), &super_key, KEY_PARAMETERS)
+ .unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push("9910001_USRCERT_authbound");
+ if !path_buf.as_path().is_file() {
+ make_cert_blob_file(path_buf.as_path(), key_metadata.certificate.as_ref().unwrap())
+ .unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push("9910001_CACERT_authbound");
+ if !path_buf.as_path().is_file() {
+ make_cert_blob_file(
+ path_buf.as_path(),
+ key_metadata.certificateChain.as_ref().unwrap(),
+ )
+ .unwrap();
+ }
+
+ // Keystore2 disables the legacy importer when it finds the legacy database empty.
+ // However, if the device boots with an empty legacy database, the optimization kicks in
+ // and keystore2 never checks the legacy file system layout.
+ // So, restart keystore2 service to detect populated legacy database.
+ keystore2_restart_service();
+
+ let auth_service = get_authorization();
+ match auth_service.onLockScreenEvent(LockScreenEvent::UNLOCK, 99, Some(PASSWORD), None)
+ {
+ Ok(result) => {
+ println!("Unlock Result: {:?}", result);
+ }
+ Err(e) => {
+ panic!("Unlock should have succeeded: {:?}", e);
+ }
+ }
+
+ let maint_service = get_maintenance();
+ assert_eq!(Ok(UserState(1)), maint_service.getState(99));
+
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_metadata.authorizations {
+ let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ KeygenResult {
+ cert: key_metadata.certificate.unwrap(),
+ cert_chain: key_metadata.certificateChain.unwrap(),
+ key_parameters: key_params,
+ }
+ })
+ };
+
+ // Safety: run_as must be called from a single threaded process.
+ // This device test is run as a separate single threaded process.
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
+ println!("UID: {}", getuid());
+ println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9910001));
+ println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9910001));
+
+ let test_alias = "authbound";
+ let keystore2 = get_keystore_service();
+
+ match keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: SELINUX_SHELL_NAMESPACE,
+ alias: Some(test_alias.to_string()),
+ blob: None,
+ }) {
+ Ok(key_entry_response) => {
+ assert_eq!(
+ key_entry_response.metadata.certificate.unwrap(),
+ gen_key_result.cert
+ );
+ assert_eq!(
+ key_entry_response.metadata.certificateChain.unwrap(),
+ gen_key_result.cert_chain
+ );
+ assert_eq!(key_entry_response.metadata.key.domain, Domain::KEY_ID);
+ assert_ne!(key_entry_response.metadata.key.nspace, 0);
+ assert_eq!(
+ key_entry_response.metadata.keySecurityLevel,
+ SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+ );
+
+ // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_entry_response.metadata.authorizations {
+ let key_param =
+ KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ // Combine keyparameters from gen_key_result and keyparameters
+ // from legacy key-char file.
+ let mut legacy_file_key_params: Vec<KsKeyparameter> = Vec::new();
+ match structured_test_params() {
+ LegacyKeyCharacteristics::File(legacy_key_params) => {
+ for param in &legacy_key_params {
+ let mut present_in_gen_params = false;
+ for gen_param in &gen_key_result.key_parameters {
+ if param.get_tag() == gen_param.get_tag() {
+ present_in_gen_params = true;
+ }
+ }
+ if !present_in_gen_params {
+ legacy_file_key_params.push(param.clone());
+ }
+ }
+ }
+ _ => {
+ panic!("Expecting file characteristics");
+ }
+ }
+
+ // Remove Key-Params which have security levels other than TRUSTED_ENVIRONMENT
+ gen_key_result.key_parameters.retain(|in_element| {
+ *in_element.security_level()
+ == SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+ });
+
+ println!("GetKeyEntry response key params: {:#?}", key_params);
+ println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+
+ gen_key_result.key_parameters.append(&mut legacy_file_key_params);
+
+ println!("Combined key params: {:#?}", gen_key_result.key_parameters);
+
+ // Validate all keyparameters present in getKeyEntry response.
+ for param in &key_params {
+ gen_key_result.key_parameters.retain(|in_element| *in_element != *param);
+ }
+
+ println!(
+ "GetKeyEntry response unmatched key params: {:#?}",
+ gen_key_result.key_parameters
+ );
+ assert_eq!(gen_key_result.key_parameters.len(), 0);
+ }
+ Err(s) => {
+ panic!("getKeyEntry should have succeeded. {:?}", s);
+ }
+ };
+ })
+ };
+
+ // Make sure keystore2 clean up imported legacy db.
+ let path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ if path_buf.as_path().is_dir() {
+ panic!("Keystore service should have deleted this dir {:?}", path_buf);
+ }
+ Ok(())
+}
+
+/// Create legacy blobs file layout for a user with user-id 98 and app-id 10001 with encrypted
+/// user-cert and ca-certs files and tries to import these legacy blobs under user context.
+///
+/// Expected File layout for user with user-id "98" and app-id "10001" and key-alias
+/// "authboundcertenc":
+/// /data/misc/keystore/user_98/.masterkey
+/// /data/misc/keystore/user_98/9810001_USRPKEY_authboundcertenc
+/// /data/misc/keystore/user_98/.9810001_chr_USRPKEY_authboundcertenc
+/// /data/misc/keystore/user_98/9810001_USRCERT_authboundcertenc
+/// /data/misc/keystore/user_98/9810001_CACERT_authboundcertenc
+///
+/// Test performs below tasks -
+/// With su context it performs following tasks -
+/// 1. Remove this user if already exist.
+/// 2. Generate a key-blob, user cert-blob and ca-cert-blob to store it in legacy blobs file
+/// layout.
+/// 3. Prepare file layout using generated key-blob, user cert and ca certs.
+/// 4. Restart the keystore2 service to make it detect the populated legacy blobs.
+/// 5. Inform the keystore2 service about the user and unlock the user.
+/// With user-98 context it performs following tasks -
+/// 6. To load and import the legacy key using its alias.
+/// 7. After successful key import validate the user cert and cert-chain with initially
+/// generated blobs.
+/// 8. Validate imported key perameters. Imported key parameters list should be the combination
+/// of the key-parameters in characteristics file and the characteristics according to
+/// the augmentation rules. There might be duplicate entries with different values for the
+/// parameters like OS_VERSION, OS_VERSION, BOOT_PATCHLEVEL, VENDOR_PATCHLEVEL etc.
+/// 9. Confirm keystore2 service cleanup the legacy blobs after successful import.
+#[test]
+fn keystore2_encrypted_certificates() -> anyhow::Result<()> {
+ let auid = 98 * AID_USER_OFFSET + 10001;
+ let agid = 98 * AID_USER_OFFSET + 10001;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+ // Cleanup user directory if it exists
+ let path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ if path_buf.as_path().is_dir() {
+ std::fs::remove_dir_all(path_buf.as_path()).unwrap();
+ }
+
+ // Safety: run_as must be called from a single threaded process.
+ // This device test is run as a separate single threaded process.
+ let gen_key_result = unsafe {
+ run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+ // Remove user if already exist.
+ let maint_service = get_maintenance();
+ match maint_service.onUserRemoved(98) {
+ Ok(_) => {
+ println!("User was existed, deleted successfully");
+ }
+ Err(e) => {
+ println!("onUserRemoved error: {:#?}", e);
+ }
+ }
+
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2
+ .getSecurityLevel(SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT)
+ .unwrap();
+ // Generate Key BLOB and prepare legacy keystore blob files.
+ let key_metadata =
+ key_generations::generate_ec_p256_signing_key_with_attestation(&sec_level)
+ .expect("Failed to generate key blob");
+
+ // Create keystore file layout for user_98.
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key(Some(SUPERKEY_SALT), 32).unwrap());
+ let super_key =
+ TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ if !path_buf.as_path().is_dir() {
+ std::fs::create_dir(path_buf.as_path()).unwrap();
+ }
+ path_buf.push(".masterkey");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push("9810001_USRPKEY_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_key_file(
+ path_buf.as_path(),
+ &super_key,
+ &key_metadata.key.blob.unwrap(),
+ )
+ .unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push(".9810001_chr_USRPKEY_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), USRPKEY_AUTHBOUND_CHR).unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push("9810001_USRCERT_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_usr_cert_file(
+ path_buf.as_path(),
+ &super_key,
+ key_metadata.certificate.as_ref().unwrap(),
+ )
+ .unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push("9810001_CACERT_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_ca_cert_file(
+ path_buf.as_path(),
+ &super_key,
+ key_metadata.certificateChain.as_ref().unwrap(),
+ )
+ .unwrap();
+ }
+
+ // Keystore2 disables the legacy importer when it finds the legacy database empty.
+ // However, if the device boots with an empty legacy database, the optimization kicks in
+ // and keystore2 never checks the legacy file system layout.
+ // So, restart keystore2 service to detect populated legacy database.
+ keystore2_restart_service();
+
+ let auth_service = get_authorization();
+ match auth_service.onLockScreenEvent(LockScreenEvent::UNLOCK, 98, Some(PASSWORD), None)
+ {
+ Ok(result) => {
+ println!("Unlock Result: {:?}", result);
+ }
+ Err(e) => {
+ panic!("Unlock should have succeeded: {:?}", e);
+ }
+ }
+
+ let maint_service = get_maintenance();
+ assert_eq!(Ok(UserState(1)), maint_service.getState(98));
+
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_metadata.authorizations {
+ let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ KeygenResult {
+ cert: key_metadata.certificate.unwrap(),
+ cert_chain: key_metadata.certificateChain.unwrap(),
+ key_parameters: key_params,
+ }
+ })
+ };
+
+ // Safety: run_as must be called from a single threaded process.
+ // This device test is run as a separate single threaded process.
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
+ println!("UID: {}", getuid());
+ println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9810001));
+ println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9810001));
+
+ let test_alias = "authboundcertenc";
+ let keystore2 = get_keystore_service();
+
+ match keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: SELINUX_SHELL_NAMESPACE,
+ alias: Some(test_alias.to_string()),
+ blob: None,
+ }) {
+ Ok(key_entry_response) => {
+ assert_eq!(
+ key_entry_response.metadata.certificate.unwrap(),
+ gen_key_result.cert
+ );
+ assert_eq!(
+ key_entry_response.metadata.certificateChain.unwrap(),
+ gen_key_result.cert_chain
+ );
+
+ // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_entry_response.metadata.authorizations {
+ let key_param =
+ KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ println!("GetKeyEntry response key params: {:#?}", key_params);
+ println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+ match structured_test_params_cache() {
+ LegacyKeyCharacteristics::Cache(legacy_key_params) => {
+ println!("Legacy key-char cache: {:#?}", legacy_key_params);
+ // Validate all keyparameters present in getKeyEntry response.
+ for param in &legacy_key_params {
+ key_params.retain(|in_element| *in_element != *param);
+ }
+
+ println!(
+ "GetKeyEntry response unmatched key params: {:#?}",
+ key_params
+ );
+ assert_eq!(key_params.len(), 0);
+ }
+ _ => {
+ panic!("Expecting file characteristics");
+ }
+ }
+ }
+ Err(s) => {
+ panic!("getKeyEntry should have succeeded. {:?}", s);
+ }
+ };
+ })
+ };
+
+ // Make sure keystore2 clean up imported legacy db.
+ let path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ if path_buf.as_path().is_dir() {
+ panic!("Keystore service should have deleted this dir {:?}", path_buf);
+ }
+ Ok(())
+}