// 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 crate implements the Keystore 2.0 service entry point. use keystore2::entropy; use keystore2::globals::ENFORCEMENTS; use keystore2::maintenance::Maintenance; use keystore2::metrics::Metrics; use keystore2::metrics_store; use keystore2::service::KeystoreService; use keystore2::{apc::ApcManager, shared_secret_negotiation}; use keystore2::{authorization::AuthorizationManager, id_rotation::IdRotationState}; use legacykeystore::LegacyKeystore; use log::{error, info}; use rusqlite::trace as sqlite_trace; use std::{os::raw::c_int, panic, path::Path, sync::mpsc::channel}; static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default"; static APC_SERVICE_NAME: &str = "android.security.apc"; static AUTHORIZATION_SERVICE_NAME: &str = "android.security.authorization"; static METRICS_SERVICE_NAME: &str = "android.security.metrics"; static USER_MANAGER_SERVICE_NAME: &str = "android.security.maintenance"; static LEGACY_KEYSTORE_SERVICE_NAME: &str = "android.security.legacykeystore"; /// Keystore 2.0 takes one argument which is a path indicating its designated working directory. fn main() { // Initialize android logging. android_logger::init_once( android_logger::Config::default() .with_tag("keystore2") .with_min_level(log::Level::Debug) .with_log_id(android_logger::LogId::System) .format(|buf, record| { writeln!( buf, "{}:{} - {}", record.file().unwrap_or("unknown"), record.line().unwrap_or(0), record.args() ) }), ); // Redirect panic messages to logcat. panic::set_hook(Box::new(|panic_info| { error!("{}", panic_info); })); // Saying hi. info!("Keystore2 is starting."); let mut args = std::env::args(); args.next().expect("That's odd. How is there not even a first argument?"); // This must happen early before any other sqlite operations. log::info!("Setting up sqlite logging for keystore2"); fn sqlite_log_handler(err: c_int, message: &str) { log::error!("[SQLITE3] {}: {}", err, message); } // SAFETY: There are no other threads yet, `sqlite_log_handler` is threadsafe, and it doesn't // invoke any SQLite calls. unsafe { sqlite_trace::config_log(Some(sqlite_log_handler)) } .expect("Error setting sqlite log callback."); // Write/update keystore.crash_count system property. metrics_store::update_keystore_crash_sysprop(); // Keystore 2.0 cannot change to the database directory (typically /data/misc/keystore) on // startup as Keystore 1.0 did because Keystore 2.0 is intended to run much earlier than // Keystore 1.0. Instead we set a global variable to the database path. // For the ground truth check the service startup rule for init (typically in keystore2.rc). let id_rotation_state = if let Some(dir) = args.next() { let db_path = Path::new(&dir); *keystore2::globals::DB_PATH.write().expect("Could not lock DB_PATH.") = db_path.to_path_buf(); IdRotationState::new(db_path) } else { panic!("Must specify a database directory."); }; let (confirmation_token_sender, confirmation_token_receiver) = channel(); ENFORCEMENTS.install_confirmation_token_receiver(confirmation_token_receiver); entropy::register_feeder(); shared_secret_negotiation::perform_shared_secret_negotiation(); info!("Starting thread pool now."); binder::ProcessState::start_thread_pool(); let ks_service = KeystoreService::new_native_binder(id_rotation_state).unwrap_or_else(|e| { panic!("Failed to create service {} because of {:?}.", KS2_SERVICE_NAME, e); }); binder::add_service(KS2_SERVICE_NAME, ks_service.as_binder()).unwrap_or_else(|e| { panic!("Failed to register service {} because of {:?}.", KS2_SERVICE_NAME, e); }); let apc_service = ApcManager::new_native_binder(confirmation_token_sender).unwrap_or_else(|e| { panic!("Failed to create service {} because of {:?}.", APC_SERVICE_NAME, e); }); binder::add_service(APC_SERVICE_NAME, apc_service.as_binder()).unwrap_or_else(|e| { panic!("Failed to register service {} because of {:?}.", APC_SERVICE_NAME, e); }); let authorization_service = AuthorizationManager::new_native_binder().unwrap_or_else(|e| { panic!("Failed to create service {} because of {:?}.", AUTHORIZATION_SERVICE_NAME, e); }); binder::add_service(AUTHORIZATION_SERVICE_NAME, authorization_service.as_binder()) .unwrap_or_else(|e| { panic!("Failed to register service {} because of {:?}.", AUTHORIZATION_SERVICE_NAME, e); }); let (delete_listener, legacykeystore) = LegacyKeystore::new_native_binder( &keystore2::globals::DB_PATH.read().expect("Could not get DB_PATH."), ); let maintenance_service = Maintenance::new_native_binder(delete_listener).unwrap_or_else(|e| { panic!("Failed to create service {} because of {:?}.", USER_MANAGER_SERVICE_NAME, e); }); binder::add_service(USER_MANAGER_SERVICE_NAME, maintenance_service.as_binder()).unwrap_or_else( |e| { panic!("Failed to register service {} because of {:?}.", USER_MANAGER_SERVICE_NAME, e); }, ); let metrics_service = Metrics::new_native_binder().unwrap_or_else(|e| { panic!("Failed to create service {} because of {:?}.", METRICS_SERVICE_NAME, e); }); binder::add_service(METRICS_SERVICE_NAME, metrics_service.as_binder()).unwrap_or_else(|e| { panic!("Failed to register service {} because of {:?}.", METRICS_SERVICE_NAME, e); }); binder::add_service(LEGACY_KEYSTORE_SERVICE_NAME, legacykeystore.as_binder()).unwrap_or_else( |e| { panic!( "Failed to register service {} because of {:?}.", LEGACY_KEYSTORE_SERVICE_NAME, e ); }, ); info!("Successfully registered Keystore 2.0 service."); info!("Joining thread pool now."); binder::ProcessState::join_thread_pool(); }