From a75e208d30b3aa7de532d5ebfa221ac99eb3d9cc Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Wed, 7 Oct 2020 16:44:26 -0700 Subject: [PATCH] Keystore 2.0: Add globals.rs and utils.rs These two files add some utility functions and a thread local reference to a database connection. Test: None Change-Id: I34fdf977deb233571b9a0c6d50da20e47593d6a5 --- keystore2/src/globals.rs | 29 ++++++++++ keystore2/src/lib.rs | 2 + keystore2/src/utils.rs | 122 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 keystore2/src/globals.rs create mode 100644 keystore2/src/utils.rs diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs new file mode 100644 index 00000000..0654b29f --- /dev/null +++ b/keystore2/src/globals.rs @@ -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 = + RefCell::new(KeystoreDB::new().expect("Failed to open database.")); +} diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs index b5fef3e5..7439a5b9 100644 --- a/keystore2/src/lib.rs +++ b/keystore2/src/lib.rs @@ -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; diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs new file mode 100644 index 00000000..825b34a6 --- /dev/null +++ b/keystore2/src/utils.rs @@ -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, +) -> 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); + +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(&self) -> anyhow::Result> { + // 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))) + } +}