Merge changes from topic "ks2_aidl_autogen"
* changes: Keystore 2.0: Add globals.rs and utils.rs Update prebuilt keymint interface. Keystore 2.0: Adopt associated const enum variants. Keystore 2.0: Switch to autogenerated AIDL bindings.
This commit is contained in:
commit
c79a95510f
10 changed files with 1076 additions and 2005 deletions
|
@ -18,8 +18,8 @@ rust_library {
|
|||
srcs: ["src/lib.rs"],
|
||||
|
||||
rustlibs: [
|
||||
"android.system.keystore2-rust",
|
||||
"libandroid_hardware_keymint",
|
||||
"libandroid_security_keystore2",
|
||||
"libanyhow",
|
||||
"libbinder_rs",
|
||||
"libkeystore2_selinux",
|
||||
|
@ -39,9 +39,9 @@ rust_test {
|
|||
test_suites: ["general-tests"],
|
||||
auto_gen_config: true,
|
||||
rustlibs: [
|
||||
"android.system.keystore2-rust",
|
||||
"libandroid_logger",
|
||||
"libandroid_hardware_keymint",
|
||||
"libandroid_security_keystore2",
|
||||
"libanyhow",
|
||||
"libbinder_rs",
|
||||
"libkeystore2_selinux",
|
||||
|
@ -66,18 +66,3 @@ rust_library {
|
|||
"liblazy_static",
|
||||
],
|
||||
}
|
||||
|
||||
// This is a placeholder for the libraries that will be generated from the AIDL specs
|
||||
// eventually.
|
||||
rust_library {
|
||||
name: "libandroid_security_keystore2",
|
||||
crate_name: "android_security_keystore2",
|
||||
|
||||
srcs: ["src/android_security_keystore2.rs"],
|
||||
|
||||
rustlibs: [
|
||||
"libandroid_hardware_keymint",
|
||||
"libbinder_rs",
|
||||
"liblazy_static",
|
||||
],
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -41,14 +41,13 @@
|
|||
//! from the database module these functions take permission check
|
||||
//! callbacks.
|
||||
|
||||
use crate::error::Error as KsError;
|
||||
use crate::key_parameter::{KeyParameter, SqlField, TagType};
|
||||
use crate::{error, permission::KeyPermSet};
|
||||
use crate::error::{Error as KsError, ResponseCode};
|
||||
use crate::key_parameter::{KeyParameter, SqlField, Tag};
|
||||
use crate::permission::KeyPermSet;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
|
||||
use android_hardware_keymint::aidl::android::hardware::keymint::SecurityLevel::SecurityLevel as SecurityLevelType;
|
||||
use android_security_keystore2::aidl::android::security::keystore2::{
|
||||
Domain, Domain::Domain as DomainType, KeyDescriptor::KeyDescriptor,
|
||||
use android_system_keystore2::aidl::android::system::keystore2::{
|
||||
Domain::Domain, KeyDescriptor::KeyDescriptor, SecurityLevel::SecurityLevel,
|
||||
};
|
||||
|
||||
#[cfg(not(test))]
|
||||
|
@ -99,7 +98,7 @@ pub struct KeyEntry {
|
|||
km_blob: Option<Vec<u8>>,
|
||||
cert: Option<Vec<u8>>,
|
||||
cert_chain: Option<Vec<u8>>,
|
||||
sec_level: SecurityLevelType,
|
||||
sec_level: SecurityLevel,
|
||||
parameters: Vec<KeyParameter>,
|
||||
}
|
||||
|
||||
|
@ -133,7 +132,7 @@ impl KeyEntry {
|
|||
self.cert_chain.take()
|
||||
}
|
||||
/// Returns the security level of the key entry.
|
||||
pub fn sec_level(&self) -> SecurityLevelType {
|
||||
pub fn sec_level(&self) -> SecurityLevel {
|
||||
self.sec_level
|
||||
}
|
||||
}
|
||||
|
@ -261,9 +260,9 @@ impl KeystoreDB {
|
|||
/// key artifacts, i.e., blobs and parameters have been associated with the new
|
||||
/// key id. Finalizing with `rebind_alias` makes the creation of a new key entry
|
||||
/// atomic even if key generation is not.
|
||||
pub fn create_key_entry(&self, domain: DomainType, namespace: i64) -> Result<i64> {
|
||||
pub fn create_key_entry(&self, domain: Domain, namespace: i64) -> Result<i64> {
|
||||
match domain {
|
||||
Domain::App | Domain::SELinux => {}
|
||||
Domain::APP | Domain::SELINUX => {}
|
||||
_ => {
|
||||
return Err(KsError::sys())
|
||||
.context(format!("Domain {:?} must be either App or SELinux.", domain));
|
||||
|
@ -273,7 +272,7 @@ impl KeystoreDB {
|
|||
self.conn.execute(
|
||||
"INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
|
||||
VALUES(?, datetime('now'), ?, ?, NULL);",
|
||||
params![id, domain as i64, namespace],
|
||||
params![id, domain.0 as u32, namespace],
|
||||
)
|
||||
})
|
||||
.context("In create_key_entry")
|
||||
|
@ -290,13 +289,13 @@ impl KeystoreDB {
|
|||
key_id: i64,
|
||||
sc_type: SubComponentType,
|
||||
blob: &[u8],
|
||||
sec_level: SecurityLevelType,
|
||||
sec_level: SecurityLevel,
|
||||
) -> Result<()> {
|
||||
self.conn
|
||||
.execute(
|
||||
"INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
|
||||
VALUES (?, ?, ?, ?);",
|
||||
params![sc_type, key_id, blob, sec_level],
|
||||
params![sc_type, key_id, blob, sec_level.0],
|
||||
)
|
||||
.context("Failed to insert blob.")?;
|
||||
Ok(())
|
||||
|
@ -319,8 +318,13 @@ impl KeystoreDB {
|
|||
|
||||
let iter = params.into_iter();
|
||||
for p in iter {
|
||||
stmt.insert(params![key_id, p.get_tag(), p.key_parameter_value(), p.security_level()])
|
||||
.with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
|
||||
stmt.insert(params![
|
||||
key_id,
|
||||
p.get_tag().0,
|
||||
p.key_parameter_value(),
|
||||
p.security_level().0
|
||||
])
|
||||
.with_context(|| format!("In insert_keyparameter: Failed to insert {:?}", p))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -332,11 +336,11 @@ impl KeystoreDB {
|
|||
&mut self,
|
||||
newid: i64,
|
||||
alias: &str,
|
||||
domain: DomainType,
|
||||
domain: Domain,
|
||||
namespace: i64,
|
||||
) -> Result<()> {
|
||||
match domain {
|
||||
Domain::App | Domain::SELinux => {}
|
||||
Domain::APP | Domain::SELINUX => {}
|
||||
_ => {
|
||||
return Err(KsError::sys()).context(format!(
|
||||
"In rebind_alias: Domain {:?} must be either App or SELinux.",
|
||||
|
@ -352,7 +356,7 @@ impl KeystoreDB {
|
|||
"UPDATE persistent.keyentry
|
||||
SET alias = NULL, domain = NULL, namespace = NULL
|
||||
WHERE alias = ? AND domain = ? AND namespace = ?;",
|
||||
params![alias, domain as i64, namespace],
|
||||
params![alias, domain.0 as u32, namespace],
|
||||
)
|
||||
.context("In rebind_alias: Failed to rebind existing entry.")?;
|
||||
let result = tx
|
||||
|
@ -360,7 +364,7 @@ impl KeystoreDB {
|
|||
"UPDATE persistent.keyentry
|
||||
SET alias = ?
|
||||
WHERE id = ? AND domain = ? AND namespace = ?;",
|
||||
params![alias, newid, domain as i64, namespace],
|
||||
params![alias, newid, domain.0 as u32, namespace],
|
||||
)
|
||||
.context("In rebind_alias: Failed to set alias.")?;
|
||||
if result != 1 {
|
||||
|
@ -395,10 +399,10 @@ impl KeystoreDB {
|
|||
)
|
||||
.context("In load_key_entry_id: Failed to select from keyentry table.")?;
|
||||
let mut rows = stmt
|
||||
.query(params![key.domain, key.namespace_, alias])
|
||||
.query(params![key.domain.0 as u32, key.nspace, alias])
|
||||
.context("In load_key_entry_id: Failed to read from keyentry table.")?;
|
||||
Self::with_rows_extract_one(&mut rows, |row| {
|
||||
row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?
|
||||
row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
|
||||
.get(0)
|
||||
.context("Failed to unpack id.")
|
||||
})
|
||||
|
@ -408,13 +412,13 @@ impl KeystoreDB {
|
|||
/// This helper function completes the access tuple of a key, which is required
|
||||
/// to perform access control. The strategy depends on the `domain` field in the
|
||||
/// key descriptor.
|
||||
/// * Domain::SELinux: The access tuple is complete and this function only loads
|
||||
/// * Domain::SELINUX: The access tuple is complete and this function only loads
|
||||
/// the key_id for further processing.
|
||||
/// * Domain::App: Like Domain::SELinux, but the tuple is completed by `caller_uid`
|
||||
/// * Domain::APP: Like Domain::SELINUX, but the tuple is completed by `caller_uid`
|
||||
/// which serves as the namespace.
|
||||
/// * Domain::Grant: The grant table is queried for the `key_id` and the
|
||||
/// * Domain::GRANT: The grant table is queried for the `key_id` and the
|
||||
/// `access_vector`.
|
||||
/// * Domain::KeyId: The keyentry table is queried for the owning `domain` and
|
||||
/// * Domain::KEY_ID: The keyentry table is queried for the owning `domain` and
|
||||
/// `namespace`.
|
||||
/// In each case the information returned is sufficient to perform the access
|
||||
/// check and the key id can be used to load further key artifacts.
|
||||
|
@ -429,67 +433,69 @@ impl KeystoreDB {
|
|||
// We already have the full access tuple to perform access control.
|
||||
// The only distinction is that we use the caller_uid instead
|
||||
// of the caller supplied namespace if the domain field is
|
||||
// Domain::App.
|
||||
Domain::App | Domain::SELinux => {
|
||||
// Domain::APP.
|
||||
Domain::APP | Domain::SELINUX => {
|
||||
let mut access_key = key;
|
||||
if access_key.domain == Domain::App {
|
||||
access_key.namespace_ = caller_uid as i64;
|
||||
if access_key.domain == Domain::APP {
|
||||
access_key.nspace = caller_uid as i64;
|
||||
}
|
||||
let key_id = Self::load_key_entry_id(&access_key, &tx)
|
||||
.with_context(|| format!("With key.domain = {}.", access_key.domain))?;
|
||||
.with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
|
||||
|
||||
Ok((key_id, access_key, None))
|
||||
}
|
||||
|
||||
// Domain::Grant. In this case we load the key_id and the access_vector
|
||||
// Domain::GRANT. In this case we load the key_id and the access_vector
|
||||
// from the grant table.
|
||||
Domain::Grant => {
|
||||
Domain::GRANT => {
|
||||
let mut stmt = tx
|
||||
.prepare(
|
||||
"SELECT keyentryid, access_vector FROM perboot.grant
|
||||
WHERE grantee = ? AND id = ?;",
|
||||
)
|
||||
.context("Domain::Grant prepare statement failed")?;
|
||||
.context("Domain::GRANT prepare statement failed")?;
|
||||
let mut rows = stmt
|
||||
.query(params![caller_uid as i64, key.namespace_])
|
||||
.query(params![caller_uid as i64, key.nspace])
|
||||
.context("Domain:Grant: query failed.")?;
|
||||
let (key_id, access_vector): (i64, i32) =
|
||||
Self::with_rows_extract_one(&mut rows, |row| {
|
||||
let r = row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?;
|
||||
let r =
|
||||
row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
|
||||
Ok((
|
||||
r.get(0).context("Failed to unpack key_id.")?,
|
||||
r.get(1).context("Failed to unpack access_vector.")?,
|
||||
))
|
||||
})
|
||||
.context("Domain::Grant.")?;
|
||||
.context("Domain::GRANT.")?;
|
||||
Ok((key_id, key, Some(access_vector.into())))
|
||||
}
|
||||
|
||||
// Domain::KeyId. In this case we load the domain and namespace from the
|
||||
// Domain::KEY_ID. In this case we load the domain and namespace from the
|
||||
// keyentry database because we need them for access control.
|
||||
Domain::KeyId => {
|
||||
Domain::KEY_ID => {
|
||||
let mut stmt = tx
|
||||
.prepare(
|
||||
"SELECT domain, namespace FROM persistent.keyentry
|
||||
WHERE
|
||||
id = ?;",
|
||||
)
|
||||
.context("Domain::KeyId: prepare statement failed")?;
|
||||
.context("Domain::KEY_ID: prepare statement failed")?;
|
||||
let mut rows =
|
||||
stmt.query(params![key.namespace_]).context("Domain::KeyId: query failed.")?;
|
||||
let (domain, namespace): (DomainType, i64) =
|
||||
stmt.query(params![key.nspace]).context("Domain::KEY_ID: query failed.")?;
|
||||
let (domain, namespace): (Domain, i64) =
|
||||
Self::with_rows_extract_one(&mut rows, |row| {
|
||||
let r = row.map_or_else(|| Err(KsError::Rc(error::Rc::KeyNotFound)), Ok)?;
|
||||
let r =
|
||||
row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?;
|
||||
Ok((
|
||||
r.get(0).context("Failed to unpack domain.")?,
|
||||
Domain(r.get(0).context("Failed to unpack domain.")?),
|
||||
r.get(1).context("Failed to unpack namespace.")?,
|
||||
))
|
||||
})
|
||||
.context("Domain::KeyId.")?;
|
||||
let key_id = key.namespace_;
|
||||
.context("Domain::KEY_ID.")?;
|
||||
let key_id = key.nspace;
|
||||
let mut access_key = key;
|
||||
access_key.domain = domain;
|
||||
access_key.namespace_ = namespace;
|
||||
access_key.nspace = namespace;
|
||||
|
||||
Ok((key_id, access_key, None))
|
||||
}
|
||||
|
@ -501,7 +507,7 @@ impl KeystoreDB {
|
|||
key_id: i64,
|
||||
load_bits: KeyEntryLoadBits,
|
||||
tx: &Transaction,
|
||||
) -> Result<(SecurityLevelType, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
|
||||
) -> Result<(SecurityLevel, Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<u8>>)> {
|
||||
let mut stmt = tx
|
||||
.prepare(
|
||||
"SELECT MAX(id), sec_level, subcomponent_type, blob FROM persistent.blobentry
|
||||
|
@ -512,7 +518,7 @@ impl KeystoreDB {
|
|||
let mut rows =
|
||||
stmt.query(params![key_id]).context("In load_blob_components: query failed.")?;
|
||||
|
||||
let mut sec_level: SecurityLevelType = Default::default();
|
||||
let mut sec_level: SecurityLevel = Default::default();
|
||||
let mut km_blob: Option<Vec<u8>> = None;
|
||||
let mut cert_blob: Option<Vec<u8>> = None;
|
||||
let mut cert_chain_blob: Option<Vec<u8>> = None;
|
||||
|
@ -521,7 +527,8 @@ impl KeystoreDB {
|
|||
row.get(2).context("Failed to extract subcomponent_type.")?;
|
||||
match (sub_type, load_bits.load_public()) {
|
||||
(SubComponentType::KM_BLOB, _) => {
|
||||
sec_level = row.get(1).context("Failed to extract security level.")?;
|
||||
sec_level =
|
||||
SecurityLevel(row.get(1).context("Failed to extract security level.")?);
|
||||
if load_bits.load_km() {
|
||||
km_blob = Some(row.get(3).context("Failed to extract KM blob.")?);
|
||||
}
|
||||
|
@ -557,8 +564,8 @@ impl KeystoreDB {
|
|||
let mut rows =
|
||||
stmt.query(params![key_id]).context("In load_key_parameters: query failed.")?;
|
||||
Self::with_rows_extract_all(&mut rows, |row| {
|
||||
let tag: TagType = row.get(0).context("Failed to read tag.")?;
|
||||
let sec_level: SecurityLevelType = row.get(2).context("Failed to read sec_level.")?;
|
||||
let tag = Tag(row.get(0).context("Failed to read tag.")?);
|
||||
let sec_level = SecurityLevel(row.get(2).context("Failed to read sec_level.")?);
|
||||
parameters.push(
|
||||
KeyParameter::new_from_sql(tag, &SqlField::new(1, &row), sec_level)
|
||||
.context("Failed to read KeyParameter.")?,
|
||||
|
@ -634,10 +641,10 @@ impl KeystoreDB {
|
|||
// Load the key_id and complete the access control tuple.
|
||||
// We ignore the access vector here because grants cannot be granted.
|
||||
// The access vector returned here expresses the permissions the
|
||||
// grantee has if key.domain == Domain::Grant. But this vector
|
||||
// grantee has if key.domain == Domain::GRANT. But this vector
|
||||
// cannot include the grant permission by design, so there is no way the
|
||||
// subsequent permission check can pass.
|
||||
// We could check key.domain == Domain::Grant and fail early.
|
||||
// We could check key.domain == Domain::GRANT and fail early.
|
||||
// But even if we load the access tuple by grant here, the permission
|
||||
// check denies the attempt to create a grant by grant descriptor.
|
||||
let (key_id, access_key_descriptor, _) =
|
||||
|
@ -681,7 +688,7 @@ impl KeystoreDB {
|
|||
};
|
||||
tx.commit().context("In grant: failed to commit transaction.")?;
|
||||
|
||||
Ok(KeyDescriptor { domain: Domain::Grant, namespace_: grant_id, alias: None, blob: None })
|
||||
Ok(KeyDescriptor { domain: Domain::GRANT, nspace: grant_id, alias: None, blob: None })
|
||||
}
|
||||
|
||||
/// This function checks permissions like `grant` and `load_key_entry`
|
||||
|
@ -849,7 +856,7 @@ mod tests {
|
|||
fn test_no_persistence_for_tests() -> Result<()> {
|
||||
let db = new_test_db()?;
|
||||
|
||||
db.create_key_entry(Domain::App, 100)?;
|
||||
db.create_key_entry(Domain::APP, 100)?;
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 1);
|
||||
let db = new_test_db()?;
|
||||
|
@ -865,7 +872,7 @@ mod tests {
|
|||
let _file_guard_perboot = TempFile { filename: PERBOOT_TEST_SQL };
|
||||
let db = new_test_db_with_persistent_file()?;
|
||||
|
||||
db.create_key_entry(Domain::App, 100)?;
|
||||
db.create_key_entry(Domain::APP, 100)?;
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 1);
|
||||
let db = new_test_db_with_persistent_file()?;
|
||||
|
@ -877,32 +884,32 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_key_entry() -> Result<()> {
|
||||
fn extractor(ke: &KeyEntryRow) -> (DomainType, i64, Option<&str>) {
|
||||
fn extractor(ke: &KeyEntryRow) -> (Domain, i64, Option<&str>) {
|
||||
(ke.domain.unwrap(), ke.namespace.unwrap(), ke.alias.as_deref())
|
||||
}
|
||||
|
||||
let db = new_test_db()?;
|
||||
|
||||
db.create_key_entry(Domain::App, 100)?;
|
||||
db.create_key_entry(Domain::SELinux, 101)?;
|
||||
db.create_key_entry(Domain::APP, 100)?;
|
||||
db.create_key_entry(Domain::SELINUX, 101)?;
|
||||
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(extractor(&entries[0]), (Domain::App, 100, None));
|
||||
assert_eq!(extractor(&entries[1]), (Domain::SELinux, 101, None));
|
||||
assert_eq!(extractor(&entries[0]), (Domain::APP, 100, None));
|
||||
assert_eq!(extractor(&entries[1]), (Domain::SELINUX, 101, None));
|
||||
|
||||
// Test that we must pass in a valid Domain.
|
||||
check_result_is_error_containing_string(
|
||||
db.create_key_entry(Domain::Grant, 102),
|
||||
"Domain 1 must be either App or SELinux.",
|
||||
db.create_key_entry(Domain::GRANT, 102),
|
||||
"Domain Domain(1) must be either App or SELinux.",
|
||||
);
|
||||
check_result_is_error_containing_string(
|
||||
db.create_key_entry(Domain::Blob, 103),
|
||||
"Domain 3 must be either App or SELinux.",
|
||||
db.create_key_entry(Domain::BLOB, 103),
|
||||
"Domain Domain(3) must be either App or SELinux.",
|
||||
);
|
||||
check_result_is_error_containing_string(
|
||||
db.create_key_entry(Domain::KeyId, 104),
|
||||
"Domain 4 must be either App or SELinux.",
|
||||
db.create_key_entry(Domain::KEY_ID, 104),
|
||||
"Domain Domain(4) must be either App or SELinux.",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -910,56 +917,56 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_rebind_alias() -> Result<()> {
|
||||
fn extractor(ke: &KeyEntryRow) -> (Option<DomainType>, Option<i64>, Option<&str>) {
|
||||
fn extractor(ke: &KeyEntryRow) -> (Option<Domain>, Option<i64>, Option<&str>) {
|
||||
(ke.domain, ke.namespace, ke.alias.as_deref())
|
||||
}
|
||||
|
||||
let mut db = new_test_db()?;
|
||||
db.create_key_entry(Domain::App, 42)?;
|
||||
db.create_key_entry(Domain::App, 42)?;
|
||||
db.create_key_entry(Domain::APP, 42)?;
|
||||
db.create_key_entry(Domain::APP, 42)?;
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), None));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
|
||||
assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), None));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
|
||||
|
||||
// Test that the first call to rebind_alias sets the alias.
|
||||
db.rebind_alias(entries[0].id, "foo", Domain::App, 42)?;
|
||||
db.rebind_alias(entries[0].id, "foo", Domain::APP, 42)?;
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(extractor(&entries[0]), (Some(Domain::App), Some(42), Some("foo")));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), None));
|
||||
assert_eq!(extractor(&entries[0]), (Some(Domain::APP), Some(42), Some("foo")));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), None));
|
||||
|
||||
// Test that the second call to rebind_alias also empties the old one.
|
||||
db.rebind_alias(entries[1].id, "foo", Domain::App, 42)?;
|
||||
db.rebind_alias(entries[1].id, "foo", Domain::APP, 42)?;
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(extractor(&entries[0]), (None, None, None));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
|
||||
|
||||
// Test that we must pass in a valid Domain.
|
||||
check_result_is_error_containing_string(
|
||||
db.rebind_alias(0, "foo", Domain::Grant, 42),
|
||||
"Domain 1 must be either App or SELinux.",
|
||||
db.rebind_alias(0, "foo", Domain::GRANT, 42),
|
||||
"Domain Domain(1) must be either App or SELinux.",
|
||||
);
|
||||
check_result_is_error_containing_string(
|
||||
db.rebind_alias(0, "foo", Domain::Blob, 42),
|
||||
"Domain 3 must be either App or SELinux.",
|
||||
db.rebind_alias(0, "foo", Domain::BLOB, 42),
|
||||
"Domain Domain(3) must be either App or SELinux.",
|
||||
);
|
||||
check_result_is_error_containing_string(
|
||||
db.rebind_alias(0, "foo", Domain::KeyId, 42),
|
||||
"Domain 4 must be either App or SELinux.",
|
||||
db.rebind_alias(0, "foo", Domain::KEY_ID, 42),
|
||||
"Domain Domain(4) must be either App or SELinux.",
|
||||
);
|
||||
|
||||
// Test that we correctly handle setting an alias for something that does not exist.
|
||||
check_result_is_error_containing_string(
|
||||
db.rebind_alias(0, "foo", Domain::SELinux, 42),
|
||||
db.rebind_alias(0, "foo", Domain::SELINUX, 42),
|
||||
"Expected to update a single entry but instead updated 0",
|
||||
);
|
||||
// Test that we correctly abort the transaction in this case.
|
||||
let entries = get_keyentry(&db)?;
|
||||
assert_eq!(entries.len(), 2);
|
||||
assert_eq!(extractor(&entries[0]), (None, None, None));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::App), Some(42), Some("foo")));
|
||||
assert_eq!(extractor(&entries[1]), (Some(Domain::APP), Some(42), Some("foo")));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -977,8 +984,8 @@ mod tests {
|
|||
NO_PARAMS,
|
||||
)?;
|
||||
let app_key = KeyDescriptor {
|
||||
domain: super::Domain::App,
|
||||
namespace_: 0,
|
||||
domain: super::Domain::APP,
|
||||
nspace: 0,
|
||||
alias: Some("key".to_string()),
|
||||
blob: None,
|
||||
};
|
||||
|
@ -996,9 +1003,9 @@ mod tests {
|
|||
assert_eq!(
|
||||
*k,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::App,
|
||||
domain: super::Domain::APP,
|
||||
// namespace must be set to the caller_uid.
|
||||
namespace_: CALLER_UID as i64,
|
||||
nspace: CALLER_UID as i64,
|
||||
alias: Some("key".to_string()),
|
||||
blob: None,
|
||||
}
|
||||
|
@ -1009,17 +1016,17 @@ mod tests {
|
|||
assert_eq!(
|
||||
app_granted_key,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::Grant,
|
||||
domain: super::Domain::GRANT,
|
||||
// The grantid is next_random due to the mock random number generator.
|
||||
namespace_: next_random,
|
||||
nspace: next_random,
|
||||
alias: None,
|
||||
blob: None,
|
||||
}
|
||||
);
|
||||
|
||||
let selinux_key = KeyDescriptor {
|
||||
domain: super::Domain::SELinux,
|
||||
namespace_: SELINUX_NAMESPACE,
|
||||
domain: super::Domain::SELINUX,
|
||||
nspace: SELINUX_NAMESPACE,
|
||||
alias: Some("yek".to_string()),
|
||||
blob: None,
|
||||
};
|
||||
|
@ -1030,10 +1037,10 @@ mod tests {
|
|||
assert_eq!(
|
||||
*k,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::SELinux,
|
||||
domain: super::Domain::SELINUX,
|
||||
// namespace must be the supplied SELinux
|
||||
// namespace.
|
||||
namespace_: SELINUX_NAMESPACE,
|
||||
nspace: SELINUX_NAMESPACE,
|
||||
alias: Some("yek".to_string()),
|
||||
blob: None,
|
||||
}
|
||||
|
@ -1044,9 +1051,9 @@ mod tests {
|
|||
assert_eq!(
|
||||
selinux_granted_key,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::Grant,
|
||||
domain: super::Domain::GRANT,
|
||||
// The grantid is next_random + 1 due to the mock random number generator.
|
||||
namespace_: next_random + 1,
|
||||
nspace: next_random + 1,
|
||||
alias: None,
|
||||
blob: None,
|
||||
}
|
||||
|
@ -1059,10 +1066,10 @@ mod tests {
|
|||
assert_eq!(
|
||||
*k,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::SELinux,
|
||||
domain: super::Domain::SELINUX,
|
||||
// namespace must be the supplied SELinux
|
||||
// namespace.
|
||||
namespace_: SELINUX_NAMESPACE,
|
||||
nspace: SELINUX_NAMESPACE,
|
||||
alias: Some("yek".to_string()),
|
||||
blob: None,
|
||||
}
|
||||
|
@ -1073,9 +1080,9 @@ mod tests {
|
|||
assert_eq!(
|
||||
selinux_granted_key,
|
||||
KeyDescriptor {
|
||||
domain: super::Domain::Grant,
|
||||
domain: super::Domain::GRANT,
|
||||
// Same grant id as before. The entry was only updated.
|
||||
namespace_: next_random + 1,
|
||||
nspace: next_random + 1,
|
||||
alias: None,
|
||||
blob: None,
|
||||
}
|
||||
|
@ -1120,9 +1127,19 @@ mod tests {
|
|||
#[test]
|
||||
fn test_insert_blob() -> Result<()> {
|
||||
let mut db = new_test_db()?;
|
||||
db.insert_blob(1, SubComponentType::KM_BLOB, TEST_KM_BLOB, 1)?;
|
||||
db.insert_blob(1, SubComponentType::CERT, TEST_CERT_BLOB, 2)?;
|
||||
db.insert_blob(1, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB, 3)?;
|
||||
db.insert_blob(1, SubComponentType::KM_BLOB, TEST_KM_BLOB, SecurityLevel::SOFTWARE)?;
|
||||
db.insert_blob(
|
||||
1,
|
||||
SubComponentType::CERT,
|
||||
TEST_CERT_BLOB,
|
||||
SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
)?;
|
||||
db.insert_blob(
|
||||
1,
|
||||
SubComponentType::CERT_CHAIN,
|
||||
TEST_CERT_CHAIN_BLOB,
|
||||
SecurityLevel::STRONGBOX,
|
||||
)?;
|
||||
|
||||
let mut stmt = db.conn.prepare(
|
||||
"SELECT subcomponent_type, keyentryid, blob, sec_level FROM persistent.blobentry
|
||||
|
@ -1133,11 +1150,11 @@ mod tests {
|
|||
Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
|
||||
})?;
|
||||
let r = rows.next().unwrap().unwrap();
|
||||
assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 1));
|
||||
assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
|
||||
let r = rows.next().unwrap().unwrap();
|
||||
assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 2));
|
||||
assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
|
||||
let r = rows.next().unwrap().unwrap();
|
||||
assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 3));
|
||||
assert_eq!(r, (SubComponentType::CERT_CHAIN, 1, TEST_CERT_CHAIN_BLOB.to_vec(), 2));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1147,12 +1164,12 @@ mod tests {
|
|||
#[test]
|
||||
fn test_insert_and_load_full_keyentry_domain_app() -> Result<()> {
|
||||
let mut db = new_test_db()?;
|
||||
let key_id = make_test_key_entry(&mut db, Domain::App, 1, TEST_ALIAS)
|
||||
let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
|
||||
.context("test_insert_and_load_full_keyentry_domain_app")?;
|
||||
let key_entry = db.load_key_entry(
|
||||
KeyDescriptor {
|
||||
domain: Domain::App,
|
||||
namespace_: 0,
|
||||
domain: Domain::APP,
|
||||
nspace: 0,
|
||||
alias: Some(TEST_ALIAS.to_string()),
|
||||
blob: None,
|
||||
},
|
||||
|
@ -1167,7 +1184,7 @@ mod tests {
|
|||
km_blob: Some(TEST_KM_BLOB.to_vec()),
|
||||
cert: Some(TEST_CERT_BLOB.to_vec()),
|
||||
cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
|
||||
sec_level: 1,
|
||||
sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
parameters: make_test_params()
|
||||
}
|
||||
);
|
||||
|
@ -1177,12 +1194,12 @@ mod tests {
|
|||
#[test]
|
||||
fn test_insert_and_load_full_keyentry_domain_selinux() -> Result<()> {
|
||||
let mut db = new_test_db()?;
|
||||
let key_id = make_test_key_entry(&mut db, Domain::SELinux, 1, TEST_ALIAS)
|
||||
let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
|
||||
.context("test_insert_and_load_full_keyentry_domain_selinux")?;
|
||||
let key_entry = db.load_key_entry(
|
||||
KeyDescriptor {
|
||||
domain: Domain::SELinux,
|
||||
namespace_: 1,
|
||||
domain: Domain::SELINUX,
|
||||
nspace: 1,
|
||||
alias: Some(TEST_ALIAS.to_string()),
|
||||
blob: None,
|
||||
},
|
||||
|
@ -1197,7 +1214,7 @@ mod tests {
|
|||
km_blob: Some(TEST_KM_BLOB.to_vec()),
|
||||
cert: Some(TEST_CERT_BLOB.to_vec()),
|
||||
cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
|
||||
sec_level: 1,
|
||||
sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
parameters: make_test_params()
|
||||
}
|
||||
);
|
||||
|
@ -1207,10 +1224,10 @@ mod tests {
|
|||
#[test]
|
||||
fn test_insert_and_load_full_keyentry_domain_key_id() -> Result<()> {
|
||||
let mut db = new_test_db()?;
|
||||
let key_id = make_test_key_entry(&mut db, Domain::SELinux, 1, TEST_ALIAS)
|
||||
let key_id = make_test_key_entry(&mut db, Domain::SELINUX, 1, TEST_ALIAS)
|
||||
.context("test_insert_and_load_full_keyentry_domain_key_id")?;
|
||||
let key_entry = db.load_key_entry(
|
||||
KeyDescriptor { domain: Domain::KeyId, namespace_: key_id, alias: None, blob: None },
|
||||
KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
|
||||
KeyEntryLoadBits::BOTH,
|
||||
1,
|
||||
|_k, _av| Ok(()),
|
||||
|
@ -1222,7 +1239,7 @@ mod tests {
|
|||
km_blob: Some(TEST_KM_BLOB.to_vec()),
|
||||
cert: Some(TEST_CERT_BLOB.to_vec()),
|
||||
cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
|
||||
sec_level: 1,
|
||||
sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
parameters: make_test_params()
|
||||
}
|
||||
);
|
||||
|
@ -1233,13 +1250,13 @@ mod tests {
|
|||
#[test]
|
||||
fn test_insert_and_load_full_keyentry_from_grant() -> Result<()> {
|
||||
let mut db = new_test_db()?;
|
||||
let key_id = make_test_key_entry(&mut db, Domain::App, 1, TEST_ALIAS)
|
||||
let key_id = make_test_key_entry(&mut db, Domain::APP, 1, TEST_ALIAS)
|
||||
.context("test_insert_and_load_full_keyentry_from_grant")?;
|
||||
|
||||
let granted_key = db.grant(
|
||||
KeyDescriptor {
|
||||
domain: Domain::App,
|
||||
namespace_: 0,
|
||||
domain: Domain::APP,
|
||||
nspace: 0,
|
||||
alias: Some(TEST_ALIAS.to_string()),
|
||||
blob: None,
|
||||
},
|
||||
|
@ -1252,7 +1269,7 @@ mod tests {
|
|||
debug_dump_grant_table(&mut db)?;
|
||||
|
||||
let key_entry = db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
|
||||
assert_eq!(Domain::Grant, k.domain);
|
||||
assert_eq!(Domain::GRANT, k.domain);
|
||||
assert!(av.unwrap().includes(KeyPerm::use_()));
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -1264,7 +1281,7 @@ mod tests {
|
|||
km_blob: Some(TEST_KM_BLOB.to_vec()),
|
||||
cert: Some(TEST_CERT_BLOB.to_vec()),
|
||||
cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
|
||||
sec_level: 1,
|
||||
sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
parameters: make_test_params()
|
||||
}
|
||||
);
|
||||
|
@ -1292,7 +1309,7 @@ mod tests {
|
|||
struct KeyEntryRow {
|
||||
id: i64,
|
||||
creation_date: String,
|
||||
domain: Option<DomainType>,
|
||||
domain: Option<Domain>,
|
||||
namespace: Option<i64>,
|
||||
alias: Option<String>,
|
||||
}
|
||||
|
@ -1304,7 +1321,10 @@ mod tests {
|
|||
Ok(KeyEntryRow {
|
||||
id: row.get(0)?,
|
||||
creation_date: row.get(1)?,
|
||||
domain: row.get(2)?,
|
||||
domain: match row.get(2)? {
|
||||
Some(i) => Some(Domain(i)),
|
||||
None => None,
|
||||
},
|
||||
namespace: row.get(3)?,
|
||||
alias: row.get(4)?,
|
||||
})
|
||||
|
@ -1537,14 +1557,29 @@ mod tests {
|
|||
|
||||
fn make_test_key_entry(
|
||||
db: &mut KeystoreDB,
|
||||
domain: DomainType,
|
||||
domain: Domain,
|
||||
namespace: i64,
|
||||
alias: &str,
|
||||
) -> Result<i64> {
|
||||
let key_id = db.create_key_entry(domain, namespace)?;
|
||||
db.insert_blob(key_id, SubComponentType::KM_BLOB, TEST_KM_BLOB, 1)?;
|
||||
db.insert_blob(key_id, SubComponentType::CERT, TEST_CERT_BLOB, 1)?;
|
||||
db.insert_blob(key_id, SubComponentType::CERT_CHAIN, TEST_CERT_CHAIN_BLOB, 1)?;
|
||||
db.insert_blob(
|
||||
key_id,
|
||||
SubComponentType::KM_BLOB,
|
||||
TEST_KM_BLOB,
|
||||
SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
)?;
|
||||
db.insert_blob(
|
||||
key_id,
|
||||
SubComponentType::CERT,
|
||||
TEST_CERT_BLOB,
|
||||
SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
)?;
|
||||
db.insert_blob(
|
||||
key_id,
|
||||
SubComponentType::CERT_CHAIN,
|
||||
TEST_CERT_CHAIN_BLOB,
|
||||
SecurityLevel::TRUSTED_ENVIRONMENT,
|
||||
)?;
|
||||
db.insert_keyparameter(key_id, &make_test_params())?;
|
||||
db.rebind_alias(key_id, alias, domain, namespace)?;
|
||||
Ok(key_id)
|
||||
|
|
|
@ -25,22 +25,19 @@
|
|||
//! This crate provides the convenience method `map_or_log_err` to convert `anyhow::Error`
|
||||
//! into this wire type. In addition to handling the conversion of `Error`
|
||||
//! to the `Result` wire type it handles any other error by mapping it to
|
||||
//! `ResponseCode::SystemError` and logs any error condition.
|
||||
//! `ResponseCode::SYSTEM_ERROR` and logs any error condition.
|
||||
//!
|
||||
//! Keystore functions should use `anyhow::Result` to return error conditions, and
|
||||
//! context should be added every time an error is forwarded.
|
||||
|
||||
use std::cmp::PartialEq;
|
||||
|
||||
pub use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode as Ec;
|
||||
pub use android_security_keystore2::aidl::android::security::keystore2::ResponseCode as Rc;
|
||||
|
||||
use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode::ErrorCode;
|
||||
use android_security_keystore2::aidl::android::security::keystore2::ResponseCode::ResponseCode;
|
||||
pub use android_hardware_keymint::aidl::android::hardware::keymint::ErrorCode::ErrorCode;
|
||||
pub use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
|
||||
|
||||
use keystore2_selinux as selinux;
|
||||
|
||||
use android_security_keystore2::binder::{
|
||||
use android_system_keystore2::binder::{
|
||||
ExceptionCode, Result as BinderResult, Status as BinderStatus,
|
||||
};
|
||||
|
||||
|
@ -60,14 +57,14 @@ pub enum Error {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
/// Short hand for `Error::Rc(ResponseCode::SystemError)`
|
||||
/// Short hand for `Error::Rc(ResponseCode::SYSTEM_ERROR)`
|
||||
pub fn sys() -> Self {
|
||||
Error::Rc(Rc::SystemError)
|
||||
Error::Rc(ResponseCode::SYSTEM_ERROR)
|
||||
}
|
||||
|
||||
/// Short hand for `Error::Rc(ResponseCode::PermissionDenied`
|
||||
/// Short hand for `Error::Rc(ResponseCode::PERMISSION_DENIED`
|
||||
pub fn perm() -> Self {
|
||||
Error::Rc(Rc::PermissionDenied)
|
||||
Error::Rc(ResponseCode::PERMISSION_DENIED)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +80,7 @@ pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
|
|||
let se = s.service_specific_error();
|
||||
if se < 0 {
|
||||
// Negative service specific errors are KM error codes.
|
||||
Error::Km(s.service_specific_error())
|
||||
Error::Km(ErrorCode(s.service_specific_error()))
|
||||
} else {
|
||||
// Non negative error codes cannot be KM error codes.
|
||||
// So we create an `Error::Binder` variant to preserve
|
||||
|
@ -102,16 +99,16 @@ pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
|
|||
}
|
||||
|
||||
/// This function should be used by Keystore service calls to translate error conditions
|
||||
/// into `android.security.keystore2.Result` which is imported here as `aidl::Result`
|
||||
/// into `android.system.keystore2.Result` which is imported here as `aidl::Result`
|
||||
/// and newtyped as AidlResult.
|
||||
/// All error conditions get logged by this function.
|
||||
/// All `Error::Rc(x)` variants get mapped onto `aidl::Result{x, 0}`.
|
||||
/// All `Error::Km(x)` variants get mapped onto
|
||||
/// `aidl::Result{aidl::ResponseCode::KeymintErrorCode, x}`.
|
||||
/// `selinux::Error::perm()` is mapped on `aidl::Result{aidl::ResponseCode::PermissionDenied, 0}`.
|
||||
/// `selinux::Error::perm()` is mapped on `aidl::Result{aidl::ResponseCode::PERMISSION_DENIED, 0}`.
|
||||
///
|
||||
/// All non `Error` error conditions get mapped onto
|
||||
/// `aidl::Result{aidl::ResponseCode::SystemError}`.
|
||||
/// `aidl::Result{aidl::ResponseCode::SYSTEM_ERROR}`.
|
||||
///
|
||||
/// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
|
||||
/// as argument to `handle_ok`. `handle_ok` must generate an `AidlResult`, typically
|
||||
|
@ -125,7 +122,7 @@ pub fn map_km_error<T>(r: BinderResult<T>) -> Result<T, Error> {
|
|||
/// if (good_but_auth_required) {
|
||||
/// Ok(aidl::ResponseCode::OpAuthRequired)
|
||||
/// } else {
|
||||
/// Err(anyhow!(Error::Rc(aidl::ResponseCode::KeyNotFound)))
|
||||
/// Err(anyhow!(Error::Rc(aidl::ResponseCode::KEY_NOT_FOUND)))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
@ -140,15 +137,15 @@ where
|
|||
log::error!("{:?}", e);
|
||||
let root_cause = e.root_cause();
|
||||
let rc = match root_cause.downcast_ref::<Error>() {
|
||||
Some(Error::Rc(rcode)) => *rcode,
|
||||
Some(Error::Km(ec)) => *ec,
|
||||
Some(Error::Rc(rcode)) => rcode.0,
|
||||
Some(Error::Km(ec)) => ec.0,
|
||||
// If an Error::Binder reaches this stage we report a system error.
|
||||
// The exception code and possible service specific error will be
|
||||
// printed in the error log above.
|
||||
Some(Error::Binder(_, _)) => Rc::SystemError,
|
||||
Some(Error::Binder(_, _)) => ResponseCode::SYSTEM_ERROR.0,
|
||||
None => match root_cause.downcast_ref::<selinux::Error>() {
|
||||
Some(selinux::Error::PermissionDenied) => Rc::PermissionDenied,
|
||||
_ => Rc::SystemError,
|
||||
Some(selinux::Error::PermissionDenied) => ResponseCode::PERMISSION_DENIED.0,
|
||||
_ => ResponseCode::SYSTEM_ERROR.0,
|
||||
},
|
||||
};
|
||||
Err(BinderStatus::new_service_specific_error(rc, None))
|
||||
|
@ -161,7 +158,7 @@ where
|
|||
pub mod tests {
|
||||
|
||||
use super::*;
|
||||
use android_security_keystore2::binder::{
|
||||
use android_system_keystore2::binder::{
|
||||
ExceptionCode, Result as BinderResult, Status as BinderStatus,
|
||||
};
|
||||
use anyhow::{anyhow, Context};
|
||||
|
@ -229,27 +226,27 @@ pub mod tests {
|
|||
);
|
||||
// All Error::Rc(x) get mapped on a service specific error
|
||||
// code of x.
|
||||
for rc in Rc::Ok..Rc::BackendBusy {
|
||||
for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(rc),
|
||||
map_or_log_err(nested_rc(rc), |_| Err(BinderStatus::ok()))
|
||||
map_or_log_err(nested_rc(ResponseCode(rc)), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
}
|
||||
|
||||
// All Keystore Error::Km(x) get mapped on a service
|
||||
// specific error of x.
|
||||
for ec in Ec::UNKNOWN_ERROR..Ec::ROOT_OF_TRUST_ALREADY_SET {
|
||||
for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(ec),
|
||||
map_or_log_err(nested_ec(ec), |_| Err(BinderStatus::ok()))
|
||||
map_or_log_err(nested_ec(ErrorCode(ec)), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
);
|
||||
}
|
||||
|
||||
// All Keymint errors x received through a Binder Result get mapped on
|
||||
// a service specific error of x.
|
||||
for ec in Ec::UNKNOWN_ERROR..Ec::ROOT_OF_TRUST_ALREADY_SET {
|
||||
for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(ec),
|
||||
map_or_log_err(
|
||||
|
@ -266,44 +263,47 @@ pub mod tests {
|
|||
// service specific error.
|
||||
let sse = map_km_error(binder_sse_error(1));
|
||||
assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
|
||||
// map_or_log_err then maps it on a service specific error of Rc::SystemError.
|
||||
// map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(Rc::SystemError),
|
||||
Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
|
||||
map_or_log_err(sse.context("Non negative service specific error."), |_| Err(
|
||||
BinderStatus::ok()
|
||||
))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
.map_err(|s| ResponseCode(s.service_specific_error()))
|
||||
);
|
||||
|
||||
// map_km_error creates a Error::Binder variant storing the given exception code.
|
||||
let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
|
||||
assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
|
||||
// map_or_log_err then maps it on a service specific error of Rc::SystemError.
|
||||
// map_or_log_err then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(Rc::SystemError),
|
||||
Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
|
||||
map_or_log_err(binder_exception.context("Binder Exception."), |_| Err(
|
||||
BinderStatus::ok()
|
||||
))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
.map_err(|s| ResponseCode(s.service_specific_error()))
|
||||
);
|
||||
|
||||
// selinux::Error::Perm() needs to be mapped to Rc::PermissionDenied
|
||||
// selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(Rc::PermissionDenied),
|
||||
Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
|
||||
map_or_log_err(nested_selinux_perm(), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
.map_err(|s| ResponseCode(s.service_specific_error()))
|
||||
);
|
||||
|
||||
// All other errors get mapped on System Error.
|
||||
assert_eq!(
|
||||
Result::<(), i32>::Err(Rc::SystemError),
|
||||
Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
|
||||
map_or_log_err(nested_other_error(), |_| Err(BinderStatus::ok()))
|
||||
.map_err(|s| s.service_specific_error())
|
||||
.map_err(|s| ResponseCode(s.service_specific_error()))
|
||||
);
|
||||
|
||||
// Result::Ok variants get passed to the ok handler.
|
||||
assert_eq!(Ok(Rc::OpAuthNeeded), map_or_log_err(nested_ok(Rc::OpAuthNeeded), Ok));
|
||||
assert_eq!(Ok(Rc::Ok), map_or_log_err(nested_ok(Rc::Ok), Ok));
|
||||
assert_eq!(Ok(ResponseCode::LOCKED), map_or_log_err(nested_ok(ResponseCode::LOCKED), Ok));
|
||||
assert_eq!(
|
||||
Ok(ResponseCode::SYSTEM_ERROR),
|
||||
map_or_log_err(nested_ok(ResponseCode::SYSTEM_ERROR), Ok)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
29
keystore2/src/globals.rs
Normal file
29
keystore2/src/globals.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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.
|
||||
|
||||
//! This module holds global state of Keystore such as the thread local
|
||||
//! database connections and connections to services that Keystore needs
|
||||
//! to talk to.
|
||||
|
||||
use crate::database::KeystoreDB;
|
||||
use std::cell::RefCell;
|
||||
|
||||
thread_local! {
|
||||
/// Database connections are not thread safe, but connecting to the
|
||||
/// same database multiple times is safe as long as each connection is
|
||||
/// used by only one thread. So we store one database connection per
|
||||
/// thread in this thread local key.
|
||||
pub static DB: RefCell<KeystoreDB> =
|
||||
RefCell::new(KeystoreDB::new().expect("Failed to open database."));
|
||||
}
|
|
@ -17,18 +17,15 @@
|
|||
//! and the methods to work with KeyParameter.
|
||||
|
||||
use crate::error::Error as KeystoreError;
|
||||
use crate::error::Rc;
|
||||
use crate::error::ResponseCode;
|
||||
|
||||
pub use android_hardware_keymint::aidl::android::hardware::keymint::{
|
||||
Algorithm, Algorithm::Algorithm as AlgorithmType, BlockMode,
|
||||
BlockMode::BlockMode as BlockModeType, Digest, Digest::Digest as DigestType, EcCurve,
|
||||
EcCurve::EcCurve as EcCurveType, HardwareAuthenticatorType,
|
||||
HardwareAuthenticatorType::HardwareAuthenticatorType as HardwareAuthenticatorTypeType,
|
||||
KeyOrigin, KeyOrigin::KeyOrigin as KeyOriginType,
|
||||
KeyParameter::KeyParameter as AidlKeyParameter, KeyPurpose,
|
||||
KeyPurpose::KeyPurpose as KeyPurposeType, PaddingMode,
|
||||
PaddingMode::PaddingMode as PaddingModeType, SecurityLevel,
|
||||
SecurityLevel::SecurityLevel as SecurityLevelType, Tag, Tag::Tag as TagType,
|
||||
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
|
||||
HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
|
||||
KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
|
||||
Tag::Tag,
|
||||
};
|
||||
pub use android_system_keystore2::aidl::android::system::keystore2::SecurityLevel::SecurityLevel;
|
||||
use anyhow::{Context, Result};
|
||||
use rusqlite::types::{FromSql, Null, ToSql, ToSqlOutput};
|
||||
use rusqlite::{Result as SqlResult, Row};
|
||||
|
@ -37,7 +34,7 @@ use rusqlite::{Result as SqlResult, Row};
|
|||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct KeyParameter {
|
||||
key_parameter_value: KeyParameterValue,
|
||||
security_level: SecurityLevelType,
|
||||
security_level: SecurityLevel,
|
||||
}
|
||||
|
||||
/// KeyParameterValue holds a value corresponding to one of the Tags defined in
|
||||
|
@ -47,23 +44,23 @@ pub enum KeyParameterValue {
|
|||
/// Associated with Tag:INVALID
|
||||
Invalid,
|
||||
/// Set of purposes for which the key may be used
|
||||
KeyPurpose(KeyPurposeType),
|
||||
KeyPurpose(KeyPurpose),
|
||||
/// Cryptographic algorithm with which the key is used
|
||||
Algorithm(AlgorithmType),
|
||||
Algorithm(Algorithm),
|
||||
/// Size of the key , in bits
|
||||
KeySize(i32),
|
||||
/// Block cipher mode(s) with which the key may be used
|
||||
BlockMode(BlockModeType),
|
||||
BlockMode(BlockMode),
|
||||
/// Digest algorithms that may be used with the key to perform signing and verification
|
||||
Digest(DigestType),
|
||||
Digest(Digest),
|
||||
/// Padding modes that may be used with the key. Relevant to RSA, AES and 3DES keys.
|
||||
PaddingMode(PaddingModeType),
|
||||
PaddingMode(PaddingMode),
|
||||
/// Can the caller provide a nonce for nonce-requiring operations
|
||||
CallerNonce,
|
||||
/// Minimum length of MAC for HMAC keys and AES keys that support GCM mode
|
||||
MinMacLength(i32),
|
||||
/// The elliptic curve
|
||||
EcCurve(EcCurveType),
|
||||
EcCurve(EcCurve),
|
||||
/// Value of the public exponent for an RSA key pair
|
||||
RSAPublicExponent(i64),
|
||||
/// An attestation certificate for the generated key should contain an application-scoped
|
||||
|
@ -93,7 +90,7 @@ pub enum KeyParameterValue {
|
|||
/// No authentication is required to use this key
|
||||
NoAuthRequired,
|
||||
/// The types of user authenticators that may be used to authorize this key
|
||||
HardwareAuthenticatorType(HardwareAuthenticatorTypeType),
|
||||
HardwareAuthenticatorType(HardwareAuthenticatorType),
|
||||
/// The time in seconds for which the key is authorized for use, after user authentication
|
||||
AuthTimeout(i32),
|
||||
/// The key may be used after authentication timeout if device is still on-body
|
||||
|
@ -114,7 +111,7 @@ pub enum KeyParameterValue {
|
|||
/// Specifies the date and time the key was created
|
||||
CreationDateTime(i64),
|
||||
/// Specifies where the key was created, if known
|
||||
KeyOrigin(KeyOriginType),
|
||||
KeyOrigin(KeyOrigin),
|
||||
/// The key used by verified boot to validate the operating system booted
|
||||
RootOfTrust(Vec<u8>),
|
||||
/// System OS version with which the key may be used
|
||||
|
@ -164,12 +161,12 @@ pub enum KeyParameterValue {
|
|||
|
||||
impl KeyParameter {
|
||||
/// Create an instance of KeyParameter, given the value and the security level.
|
||||
pub fn new(key_parameter_value: KeyParameterValue, security_level: SecurityLevelType) -> Self {
|
||||
pub fn new(key_parameter_value: KeyParameterValue, security_level: SecurityLevel) -> Self {
|
||||
KeyParameter { key_parameter_value, security_level }
|
||||
}
|
||||
|
||||
/// Returns the tag given the KeyParameter instance.
|
||||
pub fn get_tag(&self) -> TagType {
|
||||
pub fn get_tag(&self) -> Tag {
|
||||
match self.key_parameter_value {
|
||||
KeyParameterValue::Invalid => Tag::INVALID,
|
||||
KeyParameterValue::KeyPurpose(_) => Tag::PURPOSE,
|
||||
|
@ -233,7 +230,7 @@ impl KeyParameter {
|
|||
}
|
||||
|
||||
/// Returns the security level of a KeyParameter.
|
||||
pub fn security_level(&self) -> &SecurityLevelType {
|
||||
pub fn security_level(&self) -> &SecurityLevel {
|
||||
&self.security_level
|
||||
}
|
||||
}
|
||||
|
@ -264,15 +261,15 @@ impl ToSql for KeyParameterValue {
|
|||
fn to_sql(&self) -> SqlResult<ToSqlOutput> {
|
||||
match self {
|
||||
KeyParameterValue::Invalid => Ok(ToSqlOutput::from(Null)),
|
||||
KeyParameterValue::KeyPurpose(k) => Ok(ToSqlOutput::from(*k as u32)),
|
||||
KeyParameterValue::Algorithm(a) => Ok(ToSqlOutput::from(*a as u32)),
|
||||
KeyParameterValue::KeyPurpose(k) => Ok(ToSqlOutput::from(k.0 as u32)),
|
||||
KeyParameterValue::Algorithm(a) => Ok(ToSqlOutput::from(a.0 as u32)),
|
||||
KeyParameterValue::KeySize(k) => Ok(ToSqlOutput::from(*k)),
|
||||
KeyParameterValue::BlockMode(b) => Ok(ToSqlOutput::from(*b as u32)),
|
||||
KeyParameterValue::Digest(d) => Ok(ToSqlOutput::from(*d as u32)),
|
||||
KeyParameterValue::PaddingMode(p) => Ok(ToSqlOutput::from(*p as u32)),
|
||||
KeyParameterValue::BlockMode(b) => Ok(ToSqlOutput::from(b.0 as u32)),
|
||||
KeyParameterValue::Digest(d) => Ok(ToSqlOutput::from(d.0 as u32)),
|
||||
KeyParameterValue::PaddingMode(p) => Ok(ToSqlOutput::from(p.0 as u32)),
|
||||
KeyParameterValue::CallerNonce => Ok(ToSqlOutput::from(Null)),
|
||||
KeyParameterValue::MinMacLength(m) => Ok(ToSqlOutput::from(*m)),
|
||||
KeyParameterValue::EcCurve(e) => Ok(ToSqlOutput::from(*e as u32)),
|
||||
KeyParameterValue::EcCurve(e) => Ok(ToSqlOutput::from(e.0 as u32)),
|
||||
KeyParameterValue::RSAPublicExponent(r) => Ok(ToSqlOutput::from(*r as i64)),
|
||||
KeyParameterValue::IncludeUniqueID => Ok(ToSqlOutput::from(Null)),
|
||||
KeyParameterValue::BootLoaderOnly => Ok(ToSqlOutput::from(Null)),
|
||||
|
@ -285,7 +282,7 @@ impl ToSql for KeyParameterValue {
|
|||
KeyParameterValue::UserID(u) => Ok(ToSqlOutput::from(*u)),
|
||||
KeyParameterValue::UserSecureID(u) => Ok(ToSqlOutput::from(*u as i64)),
|
||||
KeyParameterValue::NoAuthRequired => Ok(ToSqlOutput::from(Null)),
|
||||
KeyParameterValue::HardwareAuthenticatorType(h) => Ok(ToSqlOutput::from(*h as u32)),
|
||||
KeyParameterValue::HardwareAuthenticatorType(h) => Ok(ToSqlOutput::from(h.0 as u32)),
|
||||
KeyParameterValue::AuthTimeout(m) => Ok(ToSqlOutput::from(*m)),
|
||||
KeyParameterValue::AllowWhileOnBody => Ok(ToSqlOutput::from(Null)),
|
||||
KeyParameterValue::TrustedUserPresenceRequired => Ok(ToSqlOutput::from(Null)),
|
||||
|
@ -294,7 +291,7 @@ impl ToSql for KeyParameterValue {
|
|||
KeyParameterValue::ApplicationID(a) => Ok(ToSqlOutput::from(a.to_vec())),
|
||||
KeyParameterValue::ApplicationData(a) => Ok(ToSqlOutput::from(a.to_vec())),
|
||||
KeyParameterValue::CreationDateTime(c) => Ok(ToSqlOutput::from(*c as i64)),
|
||||
KeyParameterValue::KeyOrigin(k) => Ok(ToSqlOutput::from(*k as u32)),
|
||||
KeyParameterValue::KeyOrigin(k) => Ok(ToSqlOutput::from(k.0 as u32)),
|
||||
KeyParameterValue::RootOfTrust(r) => Ok(ToSqlOutput::from(r.to_vec())),
|
||||
KeyParameterValue::OSVersion(o) => Ok(ToSqlOutput::from(*o)),
|
||||
KeyParameterValue::OSPatchLevel(o) => Ok(ToSqlOutput::from(*o)),
|
||||
|
@ -328,25 +325,25 @@ impl KeyParameter {
|
|||
/// This filtering is enforced at a higher level and here we support conversion for all the
|
||||
/// variants.
|
||||
pub fn new_from_sql(
|
||||
tag_val: TagType,
|
||||
tag_val: Tag,
|
||||
data: &SqlField,
|
||||
security_level_val: SecurityLevelType,
|
||||
security_level_val: SecurityLevel,
|
||||
) -> Result<Self> {
|
||||
let key_param_value = match tag_val {
|
||||
Tag::INVALID => KeyParameterValue::Invalid,
|
||||
Tag::PURPOSE => {
|
||||
let key_purpose: KeyPurposeType = data
|
||||
let key_purpose: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: PURPOSE.")?;
|
||||
KeyParameterValue::KeyPurpose(key_purpose)
|
||||
KeyParameterValue::KeyPurpose(KeyPurpose(key_purpose))
|
||||
}
|
||||
Tag::ALGORITHM => {
|
||||
let algorithm: AlgorithmType = data
|
||||
let algorithm: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: ALGORITHM.")?;
|
||||
KeyParameterValue::Algorithm(algorithm)
|
||||
KeyParameterValue::Algorithm(Algorithm(algorithm))
|
||||
}
|
||||
Tag::KEY_SIZE => {
|
||||
let key_size: i32 =
|
||||
|
@ -354,25 +351,25 @@ impl KeyParameter {
|
|||
KeyParameterValue::KeySize(key_size)
|
||||
}
|
||||
Tag::BLOCK_MODE => {
|
||||
let block_mode: BlockModeType = data
|
||||
let block_mode: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: BLOCK_MODE.")?;
|
||||
KeyParameterValue::BlockMode(block_mode)
|
||||
KeyParameterValue::BlockMode(BlockMode(block_mode))
|
||||
}
|
||||
Tag::DIGEST => {
|
||||
let digest: DigestType = data
|
||||
let digest: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: DIGEST.")?;
|
||||
KeyParameterValue::Digest(digest)
|
||||
KeyParameterValue::Digest(Digest(digest))
|
||||
}
|
||||
Tag::PADDING => {
|
||||
let padding: PaddingModeType = data
|
||||
let padding: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: PADDING.")?;
|
||||
KeyParameterValue::PaddingMode(padding)
|
||||
KeyParameterValue::PaddingMode(PaddingMode(padding))
|
||||
}
|
||||
Tag::CALLER_NONCE => KeyParameterValue::CallerNonce,
|
||||
Tag::MIN_MAC_LENGTH => {
|
||||
|
@ -381,11 +378,11 @@ impl KeyParameter {
|
|||
KeyParameterValue::MinMacLength(min_mac_length)
|
||||
}
|
||||
Tag::EC_CURVE => {
|
||||
let ec_curve: EcCurveType = data
|
||||
let ec_curve: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: EC_CURVE.")?;
|
||||
KeyParameterValue::EcCurve(ec_curve)
|
||||
KeyParameterValue::EcCurve(EcCurve(ec_curve))
|
||||
}
|
||||
Tag::RSA_PUBLIC_EXPONENT => {
|
||||
let rsa_pub_exponent: i64 =
|
||||
|
@ -436,11 +433,13 @@ impl KeyParameter {
|
|||
}
|
||||
Tag::NO_AUTH_REQUIRED => KeyParameterValue::NoAuthRequired,
|
||||
Tag::USER_AUTH_TYPE => {
|
||||
let user_auth_type: HardwareAuthenticatorTypeType = data
|
||||
let user_auth_type: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: USER_AUTH_TYPE.")?;
|
||||
KeyParameterValue::HardwareAuthenticatorType(user_auth_type)
|
||||
KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType(
|
||||
user_auth_type,
|
||||
))
|
||||
}
|
||||
Tag::AUTH_TIMEOUT => {
|
||||
let auth_timeout: i32 =
|
||||
|
@ -467,11 +466,11 @@ impl KeyParameter {
|
|||
KeyParameterValue::CreationDateTime(creation_datetime)
|
||||
}
|
||||
Tag::ORIGIN => {
|
||||
let origin: KeyOriginType = data
|
||||
let origin: i32 = data
|
||||
.get()
|
||||
.map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to read sql data for tag: ORIGIN.")?;
|
||||
KeyParameterValue::KeyOrigin(origin)
|
||||
KeyParameterValue::KeyOrigin(KeyOrigin(origin))
|
||||
}
|
||||
Tag::ROOT_OF_TRUST => {
|
||||
let root_of_trust: Vec<u8> =
|
||||
|
@ -581,7 +580,7 @@ impl KeyParameter {
|
|||
KeyParameterValue::ConfirmationToken(confirmation_token)
|
||||
}
|
||||
_ => {
|
||||
return Err(KeystoreError::Rc(Rc::ValueCorrupted))
|
||||
return Err(KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
|
||||
.context("Failed to decode Tag enum from value.")?
|
||||
}
|
||||
};
|
||||
|
@ -590,19 +589,20 @@ impl KeyParameter {
|
|||
}
|
||||
|
||||
/// Macro rules for converting key parameter to/from wire type.
|
||||
/// This macro takes three different pieces of information about each of the KeyParameterValue
|
||||
/// variants.
|
||||
/// 1. variant name
|
||||
/// 2. tag name corresponding to the variant
|
||||
/// 3. the field name in the AidlKeyParameter struct, in which information about this variant is
|
||||
/// stored when converted
|
||||
/// This macro takes between three and four different pieces of information about each
|
||||
/// of the KeyParameterValue variants:
|
||||
/// 1. The KeyParameterValue variant name,
|
||||
/// 2. the tag name corresponding to the variant,
|
||||
/// 3. the field name in the KmKeyParameter struct, in which information about this variant is
|
||||
/// stored when converted, and
|
||||
/// 4. an optional enum type name when the nested value is of enum type.
|
||||
/// The macro takes a set of lines corresponding to each KeyParameterValue variant and generates
|
||||
/// the two conversion methods: convert_to_wire() and convert_from_wire().
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// implement_key_parameter_conversion_to_from_wire! {
|
||||
/// Invalid, INVALID, na;
|
||||
/// KeyPurpose, PURPOSE, integer;
|
||||
/// KeyPurpose, PURPOSE, integer, KeyPurpose;
|
||||
/// CallerNonce, CALLER_NONCE, boolValue;
|
||||
/// UserSecureID, USER_SECURE_ID, longInteger;
|
||||
/// ApplicationID, APPLICATION_ID, blob;
|
||||
|
@ -611,33 +611,33 @@ impl KeyParameter {
|
|||
/// ```
|
||||
/// expands to:
|
||||
/// ```
|
||||
/// pub fn convert_to_wire(self) -> AidlKeyParameter {
|
||||
/// pub fn convert_to_wire(self) -> KmKeyParameter {
|
||||
/// match self {
|
||||
/// KeyParameterValue::Invalid => AidlKeyParameter {
|
||||
/// KeyParameterValue::Invalid => KmKeyParameter {
|
||||
/// tag: Tag::INVALID,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// KeyParameterValue::KeyPurpose(v) => AidlKeyParameter {
|
||||
/// KeyParameterValue::KeyPurpose(v) => KmKeyParameter {
|
||||
/// tag: Tag::PURPOSE,
|
||||
/// integer: v,
|
||||
/// integer: v.0,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// KeyParameterValue::CallerNonce => AidlKeyParameter {
|
||||
/// KeyParameterValue::CallerNonce => KmKeyParameter {
|
||||
/// tag: Tag::CALLER_NONCE,
|
||||
/// boolValue: true,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// KeyParameterValue::UserSecureID(v) => AidlKeyParameter {
|
||||
/// KeyParameterValue::UserSecureID(v) => KmKeyParameter {
|
||||
/// tag: Tag::USER_SECURE_ID,
|
||||
/// longInteger: v,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// KeyParameterValue::ApplicationID(v) => AidlKeyParameter {
|
||||
/// KeyParameterValue::ApplicationID(v) => KmKeyParameter {
|
||||
/// tag: Tag::APPLICATION_ID,
|
||||
/// blob: v,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// KeyParameterValue::ActiveDateTime(v) => AidlKeyParameter {
|
||||
/// KeyParameterValue::ActiveDateTime(v) => KmKeyParameter {
|
||||
/// tag: Tag::ACTIVE_DATETIME,
|
||||
/// dateTime: v,
|
||||
/// ..Default::default()
|
||||
|
@ -647,33 +647,33 @@ impl KeyParameter {
|
|||
/// ```
|
||||
/// and
|
||||
/// ```
|
||||
/// pub fn convert_from_wire(aidl_kp: AidlKeyParameter) -> KeyParameterValue {
|
||||
/// pub fn convert_from_wire(aidl_kp: KmKeyParameter) -> KeyParameterValue {
|
||||
/// match aidl_kp {
|
||||
/// AidlKeyParameter {
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::INVALID,
|
||||
/// ..
|
||||
/// } => KeyParameterValue::Invalid,
|
||||
/// AidlKeyParameter {
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::PURPOSE,
|
||||
/// integer: v,
|
||||
/// ..
|
||||
/// } => KeyParameterValue::KeyPurpose(v),
|
||||
/// AidlKeyParameter {
|
||||
/// } => KeyParameterValue::KeyPurpose(KeyPurpose(v)),
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::CALLER_NONCE,
|
||||
/// boolValue: true,
|
||||
/// ..
|
||||
/// } => KeyParameterValue::CallerNonce,
|
||||
/// AidlKeyParameter {
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::USER_SECURE_ID,
|
||||
/// longInteger: v,
|
||||
/// ..
|
||||
/// } => KeyParameterValue::UserSecureID(v),
|
||||
/// AidlKeyParameter {
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::APPLICATION_ID,
|
||||
/// blob: v,
|
||||
/// ..
|
||||
/// } => KeyParameterValue::ApplicationID(v),
|
||||
/// AidlKeyParameter {
|
||||
/// KmKeyParameter {
|
||||
/// tag: Tag::ACTIVE_DATETIME,
|
||||
/// dateTime: v,
|
||||
/// ..
|
||||
|
@ -683,190 +683,227 @@ impl KeyParameter {
|
|||
/// }
|
||||
///
|
||||
macro_rules! implement_key_parameter_conversion_to_from_wire {
|
||||
// There are three groups of rules in this macro.
|
||||
// 1. The first group contains the rule which acts as the public interface. It takes the input
|
||||
// given to this macro and prepares it to be given as input to the two groups of rules
|
||||
// mentioned below.
|
||||
// 2. The second group starts with the prefix @to and generates convert_to_wire() method.
|
||||
// 3. The third group starts with the prefix @from and generates convert_from_wire() method.
|
||||
//
|
||||
// Input to this macro is first handled by the first macro rule (belonging to the first
|
||||
// group above), which pre-processes the input such that rules in the other two groups
|
||||
// generate the code for the two methods, when called recursively.
|
||||
// Each of convert_to_wire() and convert_from_wire() methods are generated using a set of
|
||||
// four macro rules in the second two groups. These four rules intend to do the following
|
||||
// tasks respectively:
|
||||
// i) generates match arms related to Invalid KeyParameterValue variant.
|
||||
// ii) generates match arms related to boolValue field in AidlKeyParameter struct.
|
||||
// iii) generates match arms related to all the other fields in AidlKeyParameter struct.
|
||||
// iv) generates the method definition including the match arms generated from the above
|
||||
// three recursive macro rules.
|
||||
// There are three groups of rules in this macro.
|
||||
// 1. The first group contains the rule which acts as the public interface. It takes the input
|
||||
// given to this macro and prepares it to be given as input to the two groups of rules
|
||||
// mentioned below.
|
||||
// 2. The second group starts with the prefix @to and generates convert_to_wire() method.
|
||||
// 3. The third group starts with the prefix @from and generates convert_from_wire() method.
|
||||
//
|
||||
// Input to this macro is first handled by the first macro rule (belonging to the first
|
||||
// group above), which pre-processes the input such that rules in the other two groups
|
||||
// generate the code for the two methods, when called recursively.
|
||||
// Each of convert_to_wire() and convert_from_wire() methods are generated using a set of
|
||||
// four macro rules in the second two groups. These four rules intend to do the following
|
||||
// tasks respectively:
|
||||
// i) generates match arms related to Invalid KeyParameterValue variant.
|
||||
// ii) generates match arms related to boolValue field in KmKeyParameter struct.
|
||||
// iii) generates match arms related to all the other fields in KmKeyParameter struct.
|
||||
// iv) generates the method definition including the match arms generated from the above
|
||||
// three recursive macro rules.
|
||||
|
||||
// This rule is applied on the input given to the macro invocations from outside the macro.
|
||||
($($variant:ident, $tag_name:ident, $field_name:ident;)*) => {
|
||||
// pre-processes input to target the rules that generate convert_to_wire() method.
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[], $($variant, $tag_name, $field_name;)*
|
||||
}
|
||||
// pre-processes input to target the rules that generate convert_from_wire() method.
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[], $($variant, $tag_name, $field_name;)*
|
||||
}
|
||||
};
|
||||
// This rule is applied on the input given to the macro invocations from outside the macro.
|
||||
($($variant:ident, $tag_name:ident, $field_name:ident $(,$enum_type:ident)?;)*) => {
|
||||
// pre-processes input to target the rules that generate convert_to_wire() method.
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[], $($variant, $tag_name, $field_name $(,$enum_type)?;)*
|
||||
}
|
||||
// pre-processes input to target the rules that generate convert_from_wire() method.
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[], $($variant, $tag_name, $field_name $(,$enum_type)?;)*
|
||||
}
|
||||
};
|
||||
|
||||
// Following four rules (belonging to the aforementioned second group) generate
|
||||
// convert_to_wire() conversion method.
|
||||
// -----------------------------------------------------------------------
|
||||
// This rule handles Invalid variant.
|
||||
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
|
||||
// KeyParameterValue::Invalid => AidlKeyParameter {
|
||||
// tag: Tag::INVALID,
|
||||
// ..Default::default()
|
||||
// },
|
||||
(@to [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::Invalid => AidlKeyParameter {
|
||||
tag: Tag::INVALID,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that correspond to bool values.
|
||||
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates
|
||||
// a match arm like:
|
||||
// KeyParameterValue::CallerNonce => AidlKeyParameter {
|
||||
// tag: Tag::CALLER_NONCE,
|
||||
// boolValue: true,
|
||||
// ..Default::default()
|
||||
// },
|
||||
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::$variant => AidlKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
boolValue: true,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that are neither invalid nor bool values
|
||||
// (i.e. all variants which correspond to integer, longInteger, dateTime and blob fields in
|
||||
// AidlKeyParameter).
|
||||
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
|
||||
// like: KeyParameterValue::ConfirmationToken(v) => AidlKeyParameter {
|
||||
// tag: Tag::CONFIRMATION_TOKEN,
|
||||
// blob: v,
|
||||
// ..Default::default(),
|
||||
// }
|
||||
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::$variant(v) => AidlKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// After all the match arms are generated by the above three rules, this rule combines them
|
||||
// into the convert_to_wire() method.
|
||||
(@to [$($out:tt)*], ) => {
|
||||
/// Conversion of key parameter to wire type
|
||||
pub fn convert_to_wire(self) -> AidlKeyParameter {
|
||||
match self {
|
||||
$($out)*
|
||||
}
|
||||
}
|
||||
};
|
||||
// Following four rules (belonging to the aforementioned second group) generate
|
||||
// convert_to_wire() conversion method.
|
||||
// -----------------------------------------------------------------------
|
||||
// This rule handles Invalid variant.
|
||||
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
|
||||
// KeyParameterValue::Invalid => KmKeyParameter {
|
||||
// tag: Tag::INVALID,
|
||||
// ..Default::default()
|
||||
// },
|
||||
(@to [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::Invalid => KmKeyParameter {
|
||||
tag: Tag::INVALID,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that correspond to bool values.
|
||||
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates
|
||||
// a match arm like:
|
||||
// KeyParameterValue::CallerNonce => KmKeyParameter {
|
||||
// tag: Tag::CALLER_NONCE,
|
||||
// boolValue: true,
|
||||
// ..Default::default()
|
||||
// },
|
||||
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::$variant => KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
boolValue: true,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all enum variants.
|
||||
// On an input like: 'KeyPurpose, PURPOSE, integer, KeyPurpose;' it generates a match arm
|
||||
// like: KeyParameterValue::KeyPurpose(v) => KmKeyParameter {
|
||||
// tag: Tag::PURPOSE,
|
||||
// integer: v.0,
|
||||
// ..Default::default(),
|
||||
// },
|
||||
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident, $enum_type:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::$variant(v) => KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v.0,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that are neither invalid nor bool values nor enums
|
||||
// (i.e. all variants which correspond to integer, longInteger, dateTime and blob fields in
|
||||
// KmKeyParameter).
|
||||
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
|
||||
// like: KeyParameterValue::ConfirmationToken(v) => KmKeyParameter {
|
||||
// tag: Tag::CONFIRMATION_TOKEN,
|
||||
// blob: v,
|
||||
// ..Default::default(),
|
||||
// },
|
||||
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@to
|
||||
[$($out)*
|
||||
KeyParameterValue::$variant(v) => KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v,
|
||||
..Default::default()
|
||||
},
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// After all the match arms are generated by the above three rules, this rule combines them
|
||||
// into the convert_to_wire() method.
|
||||
(@to [$($out:tt)*], ) => {
|
||||
/// Conversion of key parameter to wire type
|
||||
pub fn convert_to_wire(self) -> KmKeyParameter {
|
||||
match self {
|
||||
$($out)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Following four rules (belonging to the aforementioned third group) generate
|
||||
// convert_from_wire() conversion method.
|
||||
// ------------------------------------------------------------------------
|
||||
// This rule handles Invalid variant.
|
||||
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
|
||||
// AidlKeyParameter { tag: Tag::INVALID, .. } => KeyParameterValue::Invalid,
|
||||
(@from [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
AidlKeyParameter {
|
||||
tag: Tag::INVALID,
|
||||
..
|
||||
} => KeyParameterValue::Invalid,
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that correspond to bool values.
|
||||
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates a match arm like:
|
||||
// AidlKeyParameter {
|
||||
// tag: Tag::CALLER_NONCE,
|
||||
// boolValue: true,
|
||||
// ..
|
||||
// } => KeyParameterValue::CallerNonce,
|
||||
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
AidlKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
boolValue: true,
|
||||
..
|
||||
} => KeyParameterValue::$variant,
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that are neither invalid nor bool values
|
||||
// (i.e. all variants which correspond to integer, longInteger, dateTime and blob fields in
|
||||
// AidlKeyParameter).
|
||||
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
|
||||
// like:
|
||||
// AidlKeyParameter {
|
||||
// tag: Tag::CONFIRMATION_TOKEN,
|
||||
// blob: v,
|
||||
// ..,
|
||||
// } => KeyParameterValue::ConfirmationToken(v),
|
||||
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
AidlKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v,
|
||||
..
|
||||
} => KeyParameterValue::$variant(v),
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// After all the match arms are generated by the above three rules, this rule combines them
|
||||
// into the convert_from_wire() method.
|
||||
(@from [$($out:tt)*], ) => {
|
||||
/// Conversion of key parameter from wire type
|
||||
pub fn convert_from_wire(aidl_kp: AidlKeyParameter) -> KeyParameterValue {
|
||||
match aidl_kp {
|
||||
$($out)*
|
||||
_ => KeyParameterValue::Invalid,
|
||||
}
|
||||
}
|
||||
};
|
||||
// Following four rules (belonging to the aforementioned third group) generate
|
||||
// convert_from_wire() conversion method.
|
||||
// ------------------------------------------------------------------------
|
||||
// This rule handles Invalid variant.
|
||||
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
|
||||
// KmKeyParameter { tag: Tag::INVALID, .. } => KeyParameterValue::Invalid,
|
||||
(@from [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
KmKeyParameter {
|
||||
tag: Tag::INVALID,
|
||||
..
|
||||
} => KeyParameterValue::Invalid,
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that correspond to bool values.
|
||||
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates a match arm like:
|
||||
// KmKeyParameter {
|
||||
// tag: Tag::CALLER_NONCE,
|
||||
// boolValue: true,
|
||||
// ..
|
||||
// } => KeyParameterValue::CallerNonce,
|
||||
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
boolValue: true,
|
||||
..
|
||||
} => KeyParameterValue::$variant,
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all enum variants.
|
||||
// On an input like: 'KeyPurpose, PURPOSE, integer, KeyPurpose;' it generates a match arm
|
||||
// like:
|
||||
// KmKeyParameter {
|
||||
// tag: Tag::PURPOSE,
|
||||
// integer: v,
|
||||
// ..,
|
||||
// } => KeyParameterValue::KeyPurpose(KeyPurpose(v)),
|
||||
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident, $enum_type:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v,
|
||||
..
|
||||
} => KeyParameterValue::$variant($enum_type(v)),
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// This rule handles all variants that are neither invalid nor bool values nor enums
|
||||
// (i.e. all variants which correspond to integer, longInteger, dateTime and blob fields in
|
||||
// KmKeyParameter).
|
||||
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
|
||||
// like:
|
||||
// KmKeyParameter {
|
||||
// tag: Tag::CONFIRMATION_TOKEN,
|
||||
// blob: v,
|
||||
// ..,
|
||||
// } => KeyParameterValue::ConfirmationToken(v),
|
||||
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
|
||||
implement_key_parameter_conversion_to_from_wire! {@from
|
||||
[$($out)*
|
||||
KmKeyParameter {
|
||||
tag: Tag::$tag_val,
|
||||
$field: v,
|
||||
..
|
||||
} => KeyParameterValue::$variant(v),
|
||||
], $($in)*
|
||||
}
|
||||
};
|
||||
// After all the match arms are generated by the above three rules, this rule combines them
|
||||
// into the convert_from_wire() method.
|
||||
(@from [$($out:tt)*], ) => {
|
||||
/// Conversion of key parameter from wire type
|
||||
pub fn convert_from_wire(aidl_kp: KmKeyParameter) -> KeyParameterValue {
|
||||
match aidl_kp {
|
||||
$($out)*
|
||||
_ => KeyParameterValue::Invalid,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl KeyParameterValue {
|
||||
// Invoke the macro that generates the code for key parameter conversion to/from wire type
|
||||
// with all possible variants of KeyParameterValue. Each line corresponding to a variant
|
||||
// contains: variant identifier, tag value, and the related field name (i.e.
|
||||
// boolValue/integer/longInteger/dateTime/blob) in the AidlKeyParameter.
|
||||
// boolValue/integer/longInteger/dateTime/blob) in the KmKeyParameter.
|
||||
implement_key_parameter_conversion_to_from_wire! {
|
||||
Invalid, INVALID, na;
|
||||
KeyPurpose, PURPOSE, integer;
|
||||
Algorithm, ALGORITHM, integer;
|
||||
KeyPurpose, PURPOSE, integer, KeyPurpose;
|
||||
Algorithm, ALGORITHM, integer, Algorithm;
|
||||
KeySize, KEY_SIZE, integer;
|
||||
BlockMode, BLOCK_MODE, integer;
|
||||
Digest, DIGEST, integer;
|
||||
PaddingMode, PADDING, integer;
|
||||
BlockMode, BLOCK_MODE, integer, BlockMode;
|
||||
Digest, DIGEST, integer, Digest;
|
||||
PaddingMode, PADDING, integer, PaddingMode;
|
||||
CallerNonce, CALLER_NONCE, boolValue;
|
||||
MinMacLength, MIN_MAC_LENGTH, integer;
|
||||
EcCurve, EC_CURVE, integer;
|
||||
EcCurve, EC_CURVE, integer, EcCurve;
|
||||
RSAPublicExponent, RSA_PUBLIC_EXPONENT, longInteger;
|
||||
IncludeUniqueID, INCLUDE_UNIQUE_ID, boolValue;
|
||||
BootLoaderOnly, BOOTLOADER_ONLY, boolValue;
|
||||
|
@ -879,7 +916,7 @@ impl KeyParameterValue {
|
|||
UserID, USER_ID, integer;
|
||||
UserSecureID, USER_SECURE_ID, longInteger;
|
||||
NoAuthRequired, NO_AUTH_REQUIRED, boolValue;
|
||||
HardwareAuthenticatorType, USER_AUTH_TYPE, integer;
|
||||
HardwareAuthenticatorType, USER_AUTH_TYPE, integer, HardwareAuthenticatorType;
|
||||
AuthTimeout, AUTH_TIMEOUT, integer;
|
||||
AllowWhileOnBody, ALLOW_WHILE_ON_BODY, boolValue;
|
||||
TrustedUserPresenceRequired, TRUSTED_USER_PRESENCE_REQUIRED, boolValue;
|
||||
|
@ -888,7 +925,7 @@ impl KeyParameterValue {
|
|||
ApplicationID, APPLICATION_ID, blob;
|
||||
ApplicationData, APPLICATION_DATA, blob;
|
||||
CreationDateTime, CREATION_DATETIME, dateTime;
|
||||
KeyOrigin, ORIGIN, integer;
|
||||
KeyOrigin, ORIGIN, integer, KeyOrigin;
|
||||
RootOfTrust, ROOT_OF_TRUST, blob;
|
||||
OSVersion, OS_VERSION, integer;
|
||||
OSPatchLevel, OS_PATCHLEVEL, integer;
|
||||
|
@ -960,9 +997,9 @@ mod storage_tests {
|
|||
insert_into_keyparameter(
|
||||
&db,
|
||||
1,
|
||||
Tag::ALGORITHM,
|
||||
&Algorithm::RSA,
|
||||
SecurityLevel::STRONGBOX,
|
||||
Tag::ALGORITHM.0,
|
||||
&Algorithm::RSA.0,
|
||||
SecurityLevel::STRONGBOX.0,
|
||||
)?;
|
||||
let key_param = query_from_keyparameter(&db)?;
|
||||
assert_eq!(Tag::ALGORITHM, key_param.get_tag());
|
||||
|
@ -976,7 +1013,7 @@ mod storage_tests {
|
|||
#[test]
|
||||
fn test_new_from_sql_i32() -> Result<()> {
|
||||
let db = init_db()?;
|
||||
insert_into_keyparameter(&db, 1, Tag::KEY_SIZE, &1024, SecurityLevel::STRONGBOX)?;
|
||||
insert_into_keyparameter(&db, 1, Tag::KEY_SIZE.0, &1024, SecurityLevel::STRONGBOX.0)?;
|
||||
let key_param = query_from_keyparameter(&db)?;
|
||||
assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
|
||||
assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
|
||||
|
@ -992,9 +1029,9 @@ mod storage_tests {
|
|||
insert_into_keyparameter(
|
||||
&db,
|
||||
1,
|
||||
Tag::RSA_PUBLIC_EXPONENT,
|
||||
Tag::RSA_PUBLIC_EXPONENT.0,
|
||||
&(i64::MAX),
|
||||
SecurityLevel::STRONGBOX,
|
||||
SecurityLevel::STRONGBOX.0,
|
||||
)?;
|
||||
let key_param = query_from_keyparameter(&db)?;
|
||||
assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
|
||||
|
@ -1010,7 +1047,7 @@ mod storage_tests {
|
|||
#[test]
|
||||
fn test_new_from_sql_bool() -> Result<()> {
|
||||
let db = init_db()?;
|
||||
insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE, &Null, SecurityLevel::STRONGBOX)?;
|
||||
insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE.0, &Null, SecurityLevel::STRONGBOX.0)?;
|
||||
let key_param = query_from_keyparameter(&db)?;
|
||||
assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
|
||||
assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
|
||||
|
@ -1027,9 +1064,9 @@ mod storage_tests {
|
|||
insert_into_keyparameter(
|
||||
&db,
|
||||
1,
|
||||
Tag::APPLICATION_ID,
|
||||
Tag::APPLICATION_ID.0,
|
||||
&app_id_bytes,
|
||||
SecurityLevel::STRONGBOX,
|
||||
SecurityLevel::STRONGBOX.0,
|
||||
)?;
|
||||
let key_param = query_from_keyparameter(&db)?;
|
||||
assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
|
||||
|
@ -1140,7 +1177,7 @@ mod storage_tests {
|
|||
#[test]
|
||||
fn test_invalid_conversion_from_sql() -> Result<()> {
|
||||
let db = init_db()?;
|
||||
insert_into_keyparameter(&db, 1, Tag::ALGORITHM, &Null, 1)?;
|
||||
insert_into_keyparameter(&db, 1, Tag::ALGORITHM.0, &Null, 1)?;
|
||||
tests::check_result_contains_error_string(
|
||||
query_from_keyparameter(&db),
|
||||
"Failed to read sql data for tag: ALGORITHM.",
|
||||
|
@ -1175,7 +1212,7 @@ mod storage_tests {
|
|||
) -> Result<()> {
|
||||
db.execute(
|
||||
"INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
|
||||
VALUES(?, ?, ?, ?);",
|
||||
VALUES(?, ?, ?, ?);",
|
||||
params![key_id, tag, *value, security_level],
|
||||
)?;
|
||||
Ok(())
|
||||
|
@ -1185,26 +1222,28 @@ VALUES(?, ?, ?, ?);",
|
|||
fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
|
||||
db.execute(
|
||||
"INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
|
||||
VALUES(?, ?, ?, ?);",
|
||||
params![key_id, kp.get_tag(), kp.key_parameter_value(), kp.security_level()],
|
||||
VALUES(?, ?, ?, ?);",
|
||||
params![key_id, kp.get_tag().0, kp.key_parameter_value(), kp.security_level().0],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper method to query a row from keyparameter table
|
||||
fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
|
||||
let mut stmt = db.prepare(
|
||||
"SELECT tag, data, security_level FROM
|
||||
persistent.keyparameter",
|
||||
)?;
|
||||
let mut stmt =
|
||||
db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
|
||||
let mut rows = stmt.query(NO_PARAMS)?;
|
||||
let row = rows.next()?.unwrap();
|
||||
Ok(KeyParameter::new_from_sql(row.get(0)?, &SqlField(1, row), row.get(2)?)?)
|
||||
Ok(KeyParameter::new_from_sql(
|
||||
Tag(row.get(0)?),
|
||||
&SqlField(1, row),
|
||||
SecurityLevel(row.get(2)?),
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
/// The wire_tests module tests the 'convert_to_wire' and 'convert_from_wire' methods for
|
||||
/// KeyParameter, for the five different types used in AidlKeyParameter, in addition to Invalid
|
||||
/// KeyParameter, for the five different types used in KmKeyParameter, in addition to Invalid
|
||||
/// key parameter.
|
||||
/// i) bool
|
||||
/// ii) integer
|
||||
|
@ -1236,7 +1275,7 @@ mod wire_tests {
|
|||
);
|
||||
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
|
||||
assert_eq!(Tag::PURPOSE, actual.tag);
|
||||
assert_eq!(KeyPurpose::ENCRYPT, actual.integer);
|
||||
assert_eq!(KeyPurpose::ENCRYPT.0, actual.integer);
|
||||
}
|
||||
#[test]
|
||||
fn test_convert_to_wire_long_integer() {
|
||||
|
@ -1270,22 +1309,22 @@ mod wire_tests {
|
|||
/// unit tests for from conversion
|
||||
#[test]
|
||||
fn test_convert_from_wire_invalid() {
|
||||
let aidl_kp = AidlKeyParameter { tag: Tag::INVALID, ..Default::default() };
|
||||
let aidl_kp = KmKeyParameter { tag: Tag::INVALID, ..Default::default() };
|
||||
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
|
||||
assert_eq!(KeyParameterValue::Invalid, actual);
|
||||
}
|
||||
#[test]
|
||||
fn test_convert_from_wire_bool() {
|
||||
let aidl_kp =
|
||||
AidlKeyParameter { tag: Tag::CALLER_NONCE, boolValue: true, ..Default::default() };
|
||||
KmKeyParameter { tag: Tag::CALLER_NONCE, boolValue: true, ..Default::default() };
|
||||
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
|
||||
assert_eq!(KeyParameterValue::CallerNonce, actual);
|
||||
}
|
||||
#[test]
|
||||
fn test_convert_from_wire_integer() {
|
||||
let aidl_kp = AidlKeyParameter {
|
||||
let aidl_kp = KmKeyParameter {
|
||||
tag: Tag::PURPOSE,
|
||||
integer: KeyPurpose::ENCRYPT,
|
||||
integer: KeyPurpose::ENCRYPT.0,
|
||||
..Default::default()
|
||||
};
|
||||
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
|
||||
|
@ -1293,7 +1332,7 @@ mod wire_tests {
|
|||
}
|
||||
#[test]
|
||||
fn test_convert_from_wire_long_integer() {
|
||||
let aidl_kp = AidlKeyParameter {
|
||||
let aidl_kp = KmKeyParameter {
|
||||
tag: Tag::USER_SECURE_ID,
|
||||
longInteger: i64::MAX,
|
||||
..Default::default()
|
||||
|
@ -1303,17 +1342,14 @@ mod wire_tests {
|
|||
}
|
||||
#[test]
|
||||
fn test_convert_from_wire_date_time() {
|
||||
let aidl_kp = AidlKeyParameter {
|
||||
tag: Tag::ACTIVE_DATETIME,
|
||||
dateTime: i64::MAX,
|
||||
..Default::default()
|
||||
};
|
||||
let aidl_kp =
|
||||
KmKeyParameter { tag: Tag::ACTIVE_DATETIME, dateTime: i64::MAX, ..Default::default() };
|
||||
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
|
||||
assert_eq!(KeyParameterValue::ActiveDateTime(i64::MAX), actual);
|
||||
}
|
||||
#[test]
|
||||
fn test_convert_from_wire_blob() {
|
||||
let aidl_kp = AidlKeyParameter {
|
||||
let aidl_kp = KmKeyParameter {
|
||||
tag: Tag::CONFIRMATION_TOKEN,
|
||||
blob: String::from("ConfirmationToken").into_bytes(),
|
||||
..Default::default()
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
pub mod database;
|
||||
pub mod error;
|
||||
pub mod globals;
|
||||
/// Internal Representation of Key Parameter and convenience functions.
|
||||
pub mod key_parameter;
|
||||
pub mod permission;
|
||||
pub mod utils;
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
//! It also provides KeystorePerm and KeyPerm as convenience wrappers for the SELinux permission
|
||||
//! defined by keystore2 and keystore2_key respectively.
|
||||
|
||||
use android_security_keystore2::aidl::android::security::keystore2::KeyPermission;
|
||||
|
||||
use android_security_keystore2::aidl::android::security::keystore2::KeyDescriptor::KeyDescriptor;
|
||||
use android_system_keystore2::aidl::android::system::keystore2::{
|
||||
Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
|
||||
};
|
||||
|
||||
use std::cmp::PartialEq;
|
||||
use std::convert::From;
|
||||
|
@ -137,10 +137,10 @@ macro_rules! implement_permission_aidl {
|
|||
=>
|
||||
{
|
||||
$(#[$m])*
|
||||
pub struct $name(pub $aidl_name::$aidl_name);
|
||||
pub struct $name(pub $aidl_name);
|
||||
|
||||
impl From<$aidl_name::$aidl_name> for $name {
|
||||
fn from (p: $aidl_name::$aidl_name) -> Self {
|
||||
impl From<$aidl_name> for $name {
|
||||
fn from (p: $aidl_name) -> Self {
|
||||
match p {
|
||||
$aidl_name::$def_name => Self($aidl_name::$def_name),
|
||||
$($aidl_name::$element_name => Self($aidl_name::$element_name),)*
|
||||
|
@ -149,8 +149,8 @@ macro_rules! implement_permission_aidl {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<$aidl_name::$aidl_name> for $name {
|
||||
fn into(self) -> $aidl_name::$aidl_name {
|
||||
impl Into<$aidl_name> for $name {
|
||||
fn into(self) -> $aidl_name {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
@ -192,17 +192,17 @@ implement_permission_aidl!(
|
|||
/// KeyPerm::get_info().to_selinux());
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
KeyPerm from KeyPermission with default (None, none) {
|
||||
Delete, selinux name: delete;
|
||||
GenUniqueId, selinux name: gen_unique_id;
|
||||
GetInfo, selinux name: get_info;
|
||||
Grant, selinux name: grant;
|
||||
ManageBlob, selinux name: manage_blob;
|
||||
Rebind, selinux name: rebind;
|
||||
ReqForcedOp, selinux name: req_forced_op;
|
||||
Update, selinux name: update;
|
||||
Use, selinux name: use;
|
||||
UseDevId, selinux name: use_dev_id;
|
||||
KeyPerm from KeyPermission with default (NONE, none) {
|
||||
DELETE, selinux name: delete;
|
||||
GEN_UNIQUE_ID, selinux name: gen_unique_id;
|
||||
GET_INFO, selinux name: get_info;
|
||||
GRANT, selinux name: grant;
|
||||
MANAGE_BLOB, selinux name: manage_blob;
|
||||
REBIND, selinux name: rebind;
|
||||
REQ_FORCED_OP, selinux name: req_forced_op;
|
||||
UPDATE, selinux name: update;
|
||||
USE, selinux name: use;
|
||||
USE_DEV_ID, selinux name: use_dev_id;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -356,7 +356,7 @@ mod perm {
|
|||
let p = self.vec.0 & (1 << self.pos);
|
||||
self.pos += 1;
|
||||
if p != 0 {
|
||||
return Some(KeyPerm::from(p));
|
||||
return Some(KeyPerm::from(KeyPermission(p)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +365,7 @@ mod perm {
|
|||
|
||||
impl From<KeyPerm> for KeyPermSet {
|
||||
fn from(p: KeyPerm) -> Self {
|
||||
Self(p.0 as i32)
|
||||
Self((p.0).0 as i32)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,7 +400,7 @@ impl KeyPermSet {
|
|||
macro_rules! key_perm_set {
|
||||
() => { KeyPermSet(0) };
|
||||
($head:expr $(, $tail:expr)* $(,)?) => {
|
||||
KeyPermSet($head.0 as i32 $(| $tail.0 as i32)*)
|
||||
KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -429,8 +429,8 @@ pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyho
|
|||
/// Attempts to grant the grant permission are always denied.
|
||||
///
|
||||
/// The only viable target domains are
|
||||
/// * `Domain::App` in which case u:r:keystore:s0 is used as target context and
|
||||
/// * `Domain::SELinux` in which case the `key.namespace_` parameter is looked up in
|
||||
/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
|
||||
/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
|
||||
/// SELinux keystore key backend, and the result is used
|
||||
/// as target context.
|
||||
pub fn check_grant_permission(
|
||||
|
@ -438,12 +438,10 @@ pub fn check_grant_permission(
|
|||
access_vec: KeyPermSet,
|
||||
key: &KeyDescriptor,
|
||||
) -> anyhow::Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
|
||||
let target_context = match key.domain {
|
||||
Domain::App => getcon().context("check_grant_permission: getcon failed.")?,
|
||||
Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
|
||||
.context("check_grant_permission: Domain::SELinux: Failed to lookup namespace.")?,
|
||||
Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
|
||||
Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
|
||||
.context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
|
||||
_ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
|
||||
};
|
||||
|
||||
|
@ -469,19 +467,19 @@ pub fn check_grant_permission(
|
|||
/// descriptor `key` in the security class `keystore2_key`.
|
||||
///
|
||||
/// The behavior differs slightly depending on the selected target domain:
|
||||
/// * `Domain::App` u:r:keystore:s0 is used as target context.
|
||||
/// * `Domain::SELinux` `key.namespace_` parameter is looked up in the SELinux keystore key
|
||||
/// * `Domain::APP` u:r:keystore:s0 is used as target context.
|
||||
/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
|
||||
/// backend, and the result is used as target context.
|
||||
/// * `Domain::Blob` Same as SELinux but the "manage_blob" permission is always checked additionally
|
||||
/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
|
||||
/// to the one supplied in `perm`.
|
||||
/// * `Domain::Grant` Does not use selinux::check_access. Instead the `access_vector`
|
||||
/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
|
||||
/// parameter is queried for permission, which must be supplied in this case.
|
||||
///
|
||||
/// ## Return values.
|
||||
/// * Ok(()) If the requested permissions were granted.
|
||||
/// * Err(selinux::Error::perm()) If the requested permissions were denied.
|
||||
/// * Err(KsError::sys()) This error is produced if `Domain::Grant` is selected but no `access_vec`
|
||||
/// was supplied. It is also produced if `Domain::KeyId` was selected, and
|
||||
/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
|
||||
/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
|
||||
/// on various unexpected backend failures.
|
||||
pub fn check_key_permission(
|
||||
caller_ctx: &CStr,
|
||||
|
@ -489,14 +487,12 @@ pub fn check_key_permission(
|
|||
key: &KeyDescriptor,
|
||||
access_vector: &Option<KeyPermSet>,
|
||||
) -> anyhow::Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
|
||||
let target_context = match key.domain {
|
||||
// apps get the default keystore context
|
||||
Domain::App => getcon().context("check_key_permission: getcon failed.")?,
|
||||
Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
|
||||
.context("check_key_permission: Domain::SELinux: Failed to lookup namespace.")?,
|
||||
Domain::Grant => {
|
||||
Domain::APP => getcon().context("check_key_permission: getcon failed.")?,
|
||||
Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
|
||||
.context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
|
||||
Domain::GRANT => {
|
||||
match access_vector {
|
||||
Some(pv) => {
|
||||
if pv.includes(perm) {
|
||||
|
@ -509,20 +505,20 @@ pub fn check_key_permission(
|
|||
None => {
|
||||
// If DOMAIN_GRANT was selected an access vector must be supplied.
|
||||
return Err(KsError::sys()).context(
|
||||
"Cannot check permission for Domain::Grant without access vector.",
|
||||
"Cannot check permission for Domain::GRANT without access vector.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Domain::KeyId => {
|
||||
// We should never be called with `Domain::KeyId. The database
|
||||
// lookup should have converted this into one of `Domain::App`
|
||||
// or `Domain::SELinux`.
|
||||
return Err(KsError::sys()).context("Cannot check permission for Domain::KeyId.");
|
||||
Domain::KEY_ID => {
|
||||
// We should never be called with `Domain::KEY_ID. The database
|
||||
// lookup should have converted this into one of `Domain::APP`
|
||||
// or `Domain::SELINUX`.
|
||||
return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
|
||||
}
|
||||
Domain::Blob => {
|
||||
let tctx = lookup_keystore2_key_context(key.namespace_)
|
||||
.context("Domain::Blob: Failed to lookup namespace.")?;
|
||||
Domain::BLOB => {
|
||||
let tctx = lookup_keystore2_key_context(key.nspace)
|
||||
.context("Domain::BLOB: Failed to lookup namespace.")?;
|
||||
// If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
|
||||
// permission in addition to the requested permission.
|
||||
selinux::check_access(
|
||||
|
@ -536,7 +532,7 @@ pub fn check_key_permission(
|
|||
}
|
||||
_ => {
|
||||
return Err(KsError::sys())
|
||||
.context(format!("Unknown domain value: \"{}\".", key.domain))
|
||||
.context(format!("Unknown domain value: \"{:?}\".", key.domain))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -650,8 +646,7 @@ mod tests {
|
|||
fn check_grant_permission_app() -> Result<()> {
|
||||
let system_server_ctx = Context::new("u:r:system_server:s0")?;
|
||||
let shell_ctx = Context::new("u:r:shell:s0")?;
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
|
||||
let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
|
||||
assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
|
||||
// attempts to grant the grant permission must always fail even when privileged.
|
||||
|
||||
|
@ -667,11 +662,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn check_grant_permission_selinux() -> Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let (sctx, namespace, is_su) = check_context()?;
|
||||
let key = KeyDescriptor {
|
||||
domain: Domain::SELinux,
|
||||
namespace_: namespace as i64,
|
||||
domain: Domain::SELINUX,
|
||||
nspace: namespace as i64,
|
||||
alias: None,
|
||||
blob: None,
|
||||
};
|
||||
|
@ -688,8 +682,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn check_key_permission_domain_grant() -> Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let key = KeyDescriptor { domain: Domain::Grant, namespace_: 0, alias: None, blob: None };
|
||||
let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
|
||||
|
||||
assert_perm_failed!(check_key_permission(
|
||||
&selinux::Context::new("ignored").unwrap(),
|
||||
|
@ -711,9 +704,8 @@ mod tests {
|
|||
let system_server_ctx = Context::new("u:r:system_server:s0")?;
|
||||
let shell_ctx = Context::new("u:r:shell:s0")?;
|
||||
let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
|
||||
let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
|
||||
let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
|
||||
|
||||
assert!(check_key_permission(&system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
|
||||
assert!(check_key_permission(&system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
|
||||
|
@ -752,11 +744,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn check_key_permission_domain_selinux() -> Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let (sctx, namespace, is_su) = check_context()?;
|
||||
let key = KeyDescriptor {
|
||||
domain: Domain::SELinux,
|
||||
namespace_: namespace as i64,
|
||||
domain: Domain::SELINUX,
|
||||
nspace: namespace as i64,
|
||||
alias: None,
|
||||
blob: None,
|
||||
};
|
||||
|
@ -789,11 +780,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn check_key_permission_domain_blob() -> Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let (sctx, namespace, is_su) = check_context()?;
|
||||
let key = KeyDescriptor {
|
||||
domain: Domain::Blob,
|
||||
namespace_: namespace as i64,
|
||||
domain: Domain::BLOB,
|
||||
nspace: namespace as i64,
|
||||
alias: None,
|
||||
blob: None,
|
||||
};
|
||||
|
@ -808,8 +798,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn check_key_permission_domain_key_id() -> Result<()> {
|
||||
use android_security_keystore2::aidl::android::security::keystore2::Domain;
|
||||
let key = KeyDescriptor { domain: Domain::KeyId, namespace_: 0, alias: None, blob: None };
|
||||
let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
|
||||
|
||||
assert_eq!(
|
||||
Some(&KsError::sys()),
|
||||
|
|
122
keystore2/src/utils.rs
Normal file
122
keystore2/src/utils.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
// 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.
|
||||
|
||||
//! This module implements utility functions used by the Keystore 2.0 service
|
||||
//! implementation.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::permission;
|
||||
use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
|
||||
use android_hardware_keymint::aidl::android::hardware::keymint::{
|
||||
KeyParameter::KeyParameter as KmParam, Tag::Tag,
|
||||
};
|
||||
use android_system_keystore2::aidl::android::system::keystore2::{
|
||||
KeyDescriptor::KeyDescriptor, KeyParameter::KeyParameter,
|
||||
};
|
||||
use anyhow::{anyhow, Context};
|
||||
use binder::{FromIBinder, SpIBinder, ThreadState};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// This function uses its namesake in the permission module and in
|
||||
/// combination with with_calling_sid from the binder crate to check
|
||||
/// if the caller has the given keystore permission.
|
||||
pub fn check_keystore_permission(perm: KeystorePerm) -> anyhow::Result<()> {
|
||||
ThreadState::with_calling_sid(|calling_sid| {
|
||||
permission::check_keystore_permission(
|
||||
&calling_sid.ok_or_else(Error::sys).context(
|
||||
"In check_keystore_permission: Cannot check permission without calling_sid.",
|
||||
)?,
|
||||
perm,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// This function uses its namesake in the permission module and in
|
||||
/// combination with with_calling_sid from the binder crate to check
|
||||
/// if the caller has the given grant permission.
|
||||
pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
|
||||
ThreadState::with_calling_sid(|calling_sid| {
|
||||
permission::check_grant_permission(
|
||||
&calling_sid.ok_or_else(Error::sys).context(
|
||||
"In check_grant_permission: Cannot check permission without calling_sid.",
|
||||
)?,
|
||||
access_vec,
|
||||
key,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// This function uses its namesake in the permission module and in
|
||||
/// combination with with_calling_sid from the binder crate to check
|
||||
/// if the caller has the given key permission.
|
||||
pub fn check_key_permission(
|
||||
perm: KeyPerm,
|
||||
key: &KeyDescriptor,
|
||||
access_vector: &Option<KeyPermSet>,
|
||||
) -> anyhow::Result<()> {
|
||||
ThreadState::with_calling_sid(|calling_sid| {
|
||||
permission::check_key_permission(
|
||||
&calling_sid
|
||||
.ok_or_else(Error::sys)
|
||||
.context("In check_key_permission: Cannot check permission without calling_sid.")?,
|
||||
perm,
|
||||
key,
|
||||
access_vector,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// This function converts a `KeyParameter` from the keystore2 AIDL
|
||||
/// bindings into a `KeyParameter` from the keymint AIDL bindings.
|
||||
/// TODO This is a temporary workaround until the keymint AIDL spec
|
||||
/// lands.
|
||||
pub fn keyparam_ks_to_km(p: &KeyParameter) -> KmParam {
|
||||
KmParam {
|
||||
tag: Tag(p.tag),
|
||||
boolValue: p.boolValue,
|
||||
integer: p.integer,
|
||||
longInteger: p.longInteger,
|
||||
dateTime: p.dateTime,
|
||||
blob: match &p.blob {
|
||||
Some(b) => b.clone(),
|
||||
None => vec![],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Thread safe wrapper around SpIBinder. It is safe to have SpIBinder smart pointers to the
|
||||
/// same object in multiple threads, but cloning a SpIBinder is not thread safe.
|
||||
/// Keystore frequently hands out binder tokens to the security level interface. If this
|
||||
/// is to happen from a multi threaded thread pool, the SpIBinder needs to be protected by a
|
||||
/// Mutex.
|
||||
#[derive(Debug)]
|
||||
pub struct Asp(Mutex<SpIBinder>);
|
||||
|
||||
impl Asp {
|
||||
/// Creates a new instance owning a SpIBinder wrapped in a Mutex.
|
||||
pub fn new(i: SpIBinder) -> Self {
|
||||
Self(Mutex::new(i))
|
||||
}
|
||||
|
||||
/// Clones the owned SpIBinder and attempts to convert it into the requested interface.
|
||||
pub fn get_interface<T: FromIBinder + ?Sized>(&self) -> anyhow::Result<Box<T>> {
|
||||
// We can use unwrap here because we never panic when locked, so the mutex
|
||||
// can never be poisoned.
|
||||
let lock = self.0.lock().unwrap();
|
||||
(*lock)
|
||||
.clone()
|
||||
.into_interface()
|
||||
.map_err(|e| anyhow!(format!("get_interface failed with error code {:?}", e)))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue