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:
Treehugger Robot 2020-10-08 17:41:00 +00:00 committed by Gerrit Code Review
commit c79a95510f
10 changed files with 1076 additions and 2005 deletions

View file

@ -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

View file

@ -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)

View file

@ -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
View 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."));
}

View file

@ -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()

View file

@ -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;

View file

@ -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
View 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)))
}
}