blob: fbb67780d27920c0527bde0570151e7e6971e8c8 [file] [log] [blame]
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +00001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module implements the handling of background tasks such as obtaining timestamp tokens from
16//! the timestamp service (or TEE KeyMint in legacy devices), via a separate thread.
17
18use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
19 HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::IKeyMintDevice,
20 SecurityLevel::SecurityLevel, VerificationToken::VerificationToken,
21};
22use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
23use anyhow::Result;
24use log::error;
25use std::sync::mpsc::{Receiver, Sender};
26use std::sync::Mutex;
27use std::thread::{spawn, JoinHandle};
28/// This is the struct encapsulating the thread which handles background tasks such as
29/// obtaining verification tokens.
30pub struct BackgroundTaskHandler {
31 task_handler: Mutex<Option<JoinHandle<()>>>,
32}
33/// This enum defines the two variants of a message that can be passed down to the
34/// BackgroundTaskHandler via the channel.
35pub enum Message {
36 ///This variant represents a message sent down the channel when requesting a timestamp token.
37 Inputs((HardwareAuthToken, OperationChallenge, Sender<(HardwareAuthToken, VerificationToken)>)),
38 ///This variant represents a message sent down the channel when signalling the thread to stop.
39 Shutdown,
40}
41
42impl BackgroundTaskHandler {
43 /// Initialize the BackgroundTaskHandler with the task_handler field set to None.
44 /// The thread is not started during initialization, as it needs the receiver end of a channel
45 /// to function.
46 pub fn new() -> Self {
47 BackgroundTaskHandler { task_handler: Mutex::new(None) }
48 }
49
50 /// Start the background task handler (bth) by passing in the receiver end of a channel, through
51 /// which the enforcement module can send messages to the bth thread.
52 pub fn start_bth(&self, receiver: Receiver<Message>) -> Result<()> {
53 let task_handler = Self::start_thread(receiver)?;
54 // it is ok to unwrap here because there is no way that this lock can get poisoned.
55 let mut thread_guard = self.task_handler.lock().unwrap();
56 *thread_guard = Some(task_handler);
57 Ok(())
58 }
59
60 fn start_thread(receiver: Receiver<Message>) -> Result<JoinHandle<()>> {
61 // TODO: initialize timestamp service/keymint instances.
62 // First lookup timestamp token service, if this is not a legacy device.
63 // Otherwise, lookup keymaster 4.1 or 4.0 (previous ones are not relevant, because strongbox
64 // was introduced with keymaster 4.0).
65 // If either a timestamp service or a keymint instance is expected to be found and neither
66 // is found, an error is returned.
67 // If neither is expected to be found, make timestamp_service field None, and in the thread,
68 // send a default verification token down the channel to the operation.
69 // Until timestamp service is available and proper probing of legacy keymaster devices are
70 // done, the keymint service is initialized here as it is done in security_level module.
71 Ok(spawn(move || {
72 while let Message::Inputs((auth_token, op_challenge, op_sender)) = receiver
73 .recv()
74 .expect(
75 "In background task handler thread. Failed to receive message over the channel.",
76 ) {
77 // TODO: call the timestamp service/old TEE keymaster to get
78 // timestamp/verification tokens and pass it down the sender that is
79 // coupled with a particular operation's receiver.
80 // If none of the services are available, pass the authtoken and a default
81 // verification token down the channel.
82 let km_dev: Box<dyn IKeyMintDevice> =
83 crate::globals::get_keymint_device(SecurityLevel::TRUSTED_ENVIRONMENT)
84 .expect("A TEE Keymint must be present.")
85 .get_interface()
86 .expect("Fatal: The keymint device does not implement IKeyMintDevice.");
87 let result = km_dev.verifyAuthorization(op_challenge.challenge, &auth_token);
88 match result {
89 Ok(verification_token) => {
90 // this can fail if the operation is dropped and hence the channel
91 // is hung up.
92 op_sender.send((auth_token, verification_token)).unwrap_or_else(|e| {
93 error!(
94 "In background task handler thread. Failed to send
95 verification token to operation {} due to error {:?}.",
96 op_challenge.challenge, e
97 )
98 });
99 }
100 Err(e) => {
101 // log error
102 error!(
103 "In background task handler thread. Failed to receive
104 verification token for operation {} due to error {:?}.",
105 op_challenge.challenge, e
106 );
107 // send default verification token
108 // this can fail if the operation is dropped and the channel is
109 // hung up.
110 op_sender.send((auth_token, VerificationToken::default())).unwrap_or_else(
111 |e| {
112 error!(
113 "In background task handler thread. Failed to send default
114 verification token to operation {} due to error {:?}.",
115 op_challenge.challenge, e
116 )
117 },
118 );
119 }
120 }
121 }
122 }))
123 }
124}
125
126impl Default for BackgroundTaskHandler {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132// TODO: Verify if we want the thread to finish the requests they are working on, during drop.
133impl Drop for BackgroundTaskHandler {
134 fn drop(&mut self) {
135 // it is ok to unwrap here as there is no way this lock can get poisoned.
136 let mut thread_guard = self.task_handler.lock().unwrap();
137 if let Some(thread) = (*thread_guard).take() {
138 // TODO: Verify how best to handle the error in this case.
139 thread.join().unwrap_or_else(|e| {
140 panic!("Failed to join the background task handling thread because of {:?}.", e);
141 });
142 }
143 }
144}