blob: 274ddf8cebe81bb112566b78c7d1ae8a6029c848 [file] [log] [blame]
Hasini Gunasinghe3410f792020-09-14 17:55:21 +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
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000015//! This is the Keystore 2.0 Enforcements module.
16// TODO: more description to follow.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080017use crate::error::{map_binder_status, Error, ErrorCode};
18use crate::globals::{get_timestamp_service, ASYNC_TASK, DB, ENFORCEMENTS};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000019use crate::key_parameter::{KeyParameter, KeyParameterValue};
Qi Wub9433b52020-12-01 14:52:46 +080020use crate::{
21 database::{AuthTokenEntry, MonotonicRawTime},
22 gc::Gc,
23};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000024use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000025 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080026 HardwareAuthenticatorType::HardwareAuthenticatorType,
27 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, Tag::Tag,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080028};
29use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080030 ISecureClock::ISecureClock, TimeStampToken::TimeStampToken,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000031};
32use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
33use anyhow::{Context, Result};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000034use std::collections::{HashMap, HashSet};
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080035use std::sync::{
36 mpsc::{channel, Receiver, Sender},
37 Arc, Mutex, Weak,
38};
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000039use std::time::SystemTime;
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000040
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080041#[derive(Debug)]
42enum AuthRequestState {
43 /// An outstanding per operation authorization request.
44 OpAuth,
45 /// An outstanding request for per operation authorization and secure timestamp.
46 TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
47 /// An outstanding request for a timestamp token.
48 TimeStamp(Receiver<Result<TimeStampToken, Error>>),
49}
50
51#[derive(Debug)]
52struct AuthRequest {
53 state: AuthRequestState,
54 /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
55 /// AuthRequestState::TimeStampedOpAuth.
56 hat: Option<HardwareAuthToken>,
57}
58
59impl AuthRequest {
60 fn op_auth() -> Arc<Mutex<Self>> {
61 Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
62 }
63
64 fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
65 Arc::new(Mutex::new(Self {
66 state: AuthRequestState::TimeStampedOpAuth(receiver),
67 hat: None,
68 }))
69 }
70
71 fn timestamp(
72 hat: HardwareAuthToken,
73 receiver: Receiver<Result<TimeStampToken, Error>>,
74 ) -> Arc<Mutex<Self>> {
75 Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
76 }
77
78 fn add_auth_token(&mut self, hat: HardwareAuthToken) {
79 self.hat = Some(hat)
80 }
81
82 fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
83 match (&self.state, self.hat.is_some()) {
84 (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
85 (AuthRequestState::TimeStampedOpAuth(recv), true)
86 | (AuthRequestState::TimeStamp(recv), true) => {
87 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
88 let tst = result.context(concat!(
89 "In get_auth_tokens: Worker responded with error ",
90 "from generating timestamp token."
91 ))?;
92 Ok((self.hat.take().unwrap(), Some(tst)))
93 }
94 (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
95 .context("In get_auth_tokens: No operation auth token received."),
96 }
97 }
98}
99
100/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
101/// updating and finishing an operation.
102#[derive(Debug)]
103enum DeferredAuthState {
104 /// Used when an operation does not require further authorization.
105 NoAuthRequired,
106 /// Indicates that the operation requires an operation specific token. This means we have
107 /// to return an operation challenge to the client which should reward us with an
108 /// operation specific auth token. If it is not provided before the client calls update
109 /// or finish, the operation fails as not authorized.
110 OpAuthRequired,
111 /// Indicates that the operation requires a time stamp token. The auth token was already
112 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
113 /// the target KM with a different clock about the time on the authenticators.
114 TimeStampRequired(HardwareAuthToken),
115 /// Indicates that both an operation bound auth token and a verification token are
116 /// before the operation can commence.
117 TimeStampedOpAuthRequired,
118 /// In this state the auth info is waiting for the deferred authorizations to come in.
119 /// We block on timestamp tokens, because we can always make progress on these requests.
120 /// The per-op auth tokens might never come, which means we fail if the client calls
121 /// update or finish before we got a per-op auth token.
122 Waiting(Arc<Mutex<AuthRequest>>),
123 /// In this state we have gotten all of the required tokens, we just cache them to
124 /// be used when the operation progresses.
125 Token(HardwareAuthToken, Option<TimeStampToken>),
126}
127
128/// Auth info hold all of the authorization related information of an operation. It is stored
129/// in and owned by the operation. It is constructed by authorize_create and stays with the
130/// operation until it completes.
131#[derive(Debug)]
132pub struct AuthInfo {
133 state: DeferredAuthState,
Qi Wub9433b52020-12-01 14:52:46 +0800134 /// An optional key id required to update the usage count if the key usage is limited.
135 key_usage_limited: Option<i64>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800136}
137
138struct TokenReceiverMap {
139 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
140 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
141 /// and the entry is removed from the map. In the case where no HAT is received before the
142 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
143 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
144 /// The cleanup counter is decremented every time a new receiver is added.
145 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
146 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
147}
148
149impl Default for TokenReceiverMap {
150 fn default() -> Self {
151 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
152 }
153}
154
155impl TokenReceiverMap {
156 /// There is a chance that receivers may become stale because their operation is dropped
157 /// without ever being authorized. So occasionally we iterate through the map and throw
158 /// out obsolete entries.
159 /// This is the number of calls to add_receiver between cleanups.
160 const CLEANUP_PERIOD: u8 = 25;
161
162 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
163 let mut map = self.map_and_cleanup_counter.lock().unwrap();
164 let (ref mut map, _) = *map;
165 if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
166 recv.add_auth_token(hat);
167 }
168 }
169
170 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
171 let mut map = self.map_and_cleanup_counter.lock().unwrap();
172 let (ref mut map, ref mut cleanup_counter) = *map;
173 map.insert(challenge, recv);
174
175 *cleanup_counter -= 1;
176 if *cleanup_counter == 0 {
177 map.retain(|_, v| !v.is_obsolete());
178 map.shrink_to_fit();
179 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
180 }
181 }
182}
183
184#[derive(Debug)]
185struct TokenReceiver(Weak<Mutex<AuthRequest>>);
186
187impl TokenReceiver {
188 fn is_obsolete(&self) -> bool {
189 self.0.upgrade().is_none()
190 }
191
192 fn add_auth_token(&self, hat: HardwareAuthToken) {
193 if let Some(state_arc) = self.0.upgrade() {
194 let mut state = state_arc.lock().unwrap();
195 state.add_auth_token(hat);
196 }
197 }
198}
199
200fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
201 let dev: Box<dyn ISecureClock> = get_timestamp_service()
202 .expect(concat!(
203 "Secure Clock service must be present ",
204 "if TimeStampTokens are required."
205 ))
206 .get_interface()
207 .expect("Fatal: Timestamp service does not implement ISecureClock.");
208 map_binder_status(dev.generateTimeStamp(challenge))
209}
210
211fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
212 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
213 log::info!(
214 concat!(
215 "In timestamp_token_request: Operation hung up ",
216 "before timestamp token could be delivered. {:?}"
217 ),
218 e
219 );
220 }
221}
222
223impl AuthInfo {
224 /// This function gets called after an operation was successfully created.
225 /// It makes all the preparations required, so that the operation has all the authentication
226 /// related artifacts to advance on update and finish.
227 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
228 match &self.state {
229 DeferredAuthState::OpAuthRequired => {
230 let auth_request = AuthRequest::op_auth();
231 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
232 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
233
234 self.state = DeferredAuthState::Waiting(auth_request);
235 Some(OperationChallenge { challenge })
236 }
237 DeferredAuthState::TimeStampedOpAuthRequired => {
238 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
239 let auth_request = AuthRequest::timestamped_op_auth(receiver);
240 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
241 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
242
243 ASYNC_TASK.queue_hi(move || timestamp_token_request(challenge, sender));
244 self.state = DeferredAuthState::Waiting(auth_request);
245 Some(OperationChallenge { challenge })
246 }
247 DeferredAuthState::TimeStampRequired(hat) => {
248 let hat = (*hat).clone();
249 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
250 let auth_request = AuthRequest::timestamp(hat, receiver);
251 ASYNC_TASK.queue_hi(move || timestamp_token_request(challenge, sender));
252 self.state = DeferredAuthState::Waiting(auth_request);
253 None
254 }
255 _ => None,
256 }
257 }
258
Qi Wub9433b52020-12-01 14:52:46 +0800259 /// This function is the authorization hook called before operation update.
260 /// It returns the auth tokens required by the operation to commence update.
261 pub fn before_update(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
262 self.get_auth_tokens()
263 }
264
265 /// This function is the authorization hook called before operation finish.
266 /// It returns the auth tokens required by the operation to commence finish.
267 pub fn before_finish(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
268 self.get_auth_tokens()
269 }
270
271 /// This function is the authorization hook called after finish succeeded.
272 /// As of this writing it checks if the key was a limited use key. If so it updates the
273 /// use counter of the key in the database. When the use counter is depleted, the key gets
274 /// marked for deletion and the garbage collector is notified.
275 pub fn after_finish(&self) -> Result<()> {
276 if let Some(key_id) = self.key_usage_limited {
277 // On the last successful use, the key gets deleted. In this case we
278 // have to notify the garbage collector.
279 let need_gc = DB
280 .with(|db| {
281 db.borrow_mut()
282 .check_and_update_key_usage_count(key_id)
283 .context("Trying to update key usage count.")
284 })
285 .context("In after_finish.")?;
286 if need_gc {
287 Gc::notify_gc();
288 }
289 }
290 Ok(())
291 }
292
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800293 /// This function returns the auth tokens as needed by the ongoing operation or fails
294 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
295 /// after a deferred authorization was requested by finalize_create_authorization, this
296 /// function may block on the generation of a time stamp token. It then moves the
297 /// tokens into the DeferredAuthState::Token state for future use.
Qi Wub9433b52020-12-01 14:52:46 +0800298 fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800299 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
300 let mut state = auth_request.lock().unwrap();
301 Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
302 } else {
303 None
304 };
305
306 if let Some((hat, tst)) = deferred_tokens {
307 self.state = DeferredAuthState::Token(hat, tst);
308 }
309
310 match &self.state {
311 DeferredAuthState::NoAuthRequired => Ok((None, None)),
312 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
313 DeferredAuthState::OpAuthRequired
314 | DeferredAuthState::TimeStampedOpAuthRequired
315 | DeferredAuthState::TimeStampRequired(_) => {
316 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
317 "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
318 "This should not happen."
319 ))
320 }
321 // This should not be reachable, because it should have been handled above.
322 DeferredAuthState::Waiting(_) => {
323 Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
324 }
325 }
326 }
327}
328
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000329/// Enforcements data structure
330pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800331 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
332 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000333 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800334 /// This field maps outstanding auth challenges to their operations. When an auth token
335 /// with the right challenge is received it is passed to the map using
336 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
337 /// stale, because the operation gets dropped before an auth token is received, the map
338 /// is cleaned up in regular intervals.
339 op_auth_map: TokenReceiverMap,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000340}
341
342impl Enforcements {
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000343 /// Creates an enforcement object with the two data structures it holds and the sender as None.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000344 pub fn new() -> Self {
345 Enforcements {
346 device_unlocked_set: Mutex::new(HashSet::new()),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800347 op_auth_map: Default::default(),
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000348 }
349 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000350
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000351 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800352 /// It returns an optional immediate auth token which can be presented to begin, and an
353 /// AuthInfo object which stays with the authorized operation and is used to obtain
354 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000355 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800356 ///
357 /// If no key parameters are given (typically when the client is self managed
358 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000359 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800360 /// If the above step is successful, and if requires_timestamp is given, the returned
361 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000362 pub fn authorize_create(
363 &self,
364 purpose: KeyPurpose,
Qi Wub9433b52020-12-01 14:52:46 +0800365 key_properties: Option<&(i64, Vec<KeyParameter>)>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800366 op_params: &[KmKeyParameter],
367 requires_timestamp: bool,
368 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
Qi Wub9433b52020-12-01 14:52:46 +0800369 let (key_id, key_params) = match key_properties {
370 Some((key_id, key_params)) => (*key_id, key_params),
371 None => {
372 return Ok((
373 None,
374 AuthInfo { state: DeferredAuthState::NoAuthRequired, key_usage_limited: None },
375 ))
376 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800377 };
378
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000379 match purpose {
380 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
381 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
382 // Rule out WRAP_KEY purpose
383 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800384 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000385 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
386 }
387 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
388 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
389 // asymmetric keys.
390 for kp in key_params.iter() {
391 match *kp.key_parameter_value() {
392 KeyParameterValue::Algorithm(Algorithm::RSA)
393 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800394 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000395 "In authorize_create: public operations on asymmetric keys are not
396 supported.",
397 );
398 }
399 _ => {}
400 }
401 }
402 }
403 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800404 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000405 .context("In authorize_create: specified purpose is not supported.");
406 }
407 }
408 // The following variables are to record information from key parameters to be used in
409 // enforcements, when two or more such pieces of information are required for enforcements.
410 // There is only one additional variable than what legacy keystore has, but this helps
411 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
412 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000413 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000414 let mut no_auth_required: bool = false;
415 let mut caller_nonce_allowed = false;
416 let mut user_id: i32 = -1;
417 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000418 let mut key_time_out: Option<i64> = None;
419 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000420 let mut unlocked_device_required = false;
Qi Wub9433b52020-12-01 14:52:46 +0800421 let mut key_usage_limited: Option<i64> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000422
423 // iterate through key parameters, recording information we need for authorization
424 // enforcements later, or enforcing authorizations in place, where applicable
425 for key_param in key_params.iter() {
426 match key_param.key_parameter_value() {
427 KeyParameterValue::NoAuthRequired => {
428 no_auth_required = true;
429 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000430 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000431 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000432 }
433 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000434 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000435 }
436 KeyParameterValue::KeyPurpose(p) => {
437 // Note: if there can be multiple KeyPurpose key parameters (TODO: confirm this),
438 // following check has the effect of key_params.contains(purpose)
439 // Also, authorizing purpose can not be completed here, if there can be multiple
440 // key parameters for KeyPurpose
441 if !key_purpose_authorized && *p == purpose {
442 key_purpose_authorized = true;
443 }
444 }
445 KeyParameterValue::CallerNonce => {
446 caller_nonce_allowed = true;
447 }
448 KeyParameterValue::ActiveDateTime(a) => {
449 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800450 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000451 .context("In authorize_create: key is not yet active.");
452 }
453 }
454 KeyParameterValue::OriginationExpireDateTime(o) => {
455 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
456 && Enforcements::is_given_time_passed(*o, false)
457 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800458 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000459 .context("In authorize_create: key is expired.");
460 }
461 }
462 KeyParameterValue::UsageExpireDateTime(u) => {
463 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
464 && Enforcements::is_given_time_passed(*u, false)
465 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800466 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000467 .context("In authorize_create: key is expired.");
468 }
469 }
470 KeyParameterValue::UserSecureID(s) => {
471 user_secure_ids.push(*s);
472 }
473 KeyParameterValue::UserID(u) => {
474 user_id = *u;
475 }
476 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000477 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000478 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000479 KeyParameterValue::AllowWhileOnBody => {
480 allow_while_on_body = true;
481 }
Qi Wub9433b52020-12-01 14:52:46 +0800482 KeyParameterValue::UsageCountLimit(_) => {
483 // We don't examine the limit here because this is enforced on finish.
484 // Instead, we store the key_id so that finish can look up the key
485 // in the database again and check and update the counter.
486 key_usage_limited = Some(key_id);
487 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000488 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
489 // create operation if any non-allowed tags are present, is not done in
490 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800491 // a subset of non-allowed tags are present). Because sanitizing key parameters
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000492 // should have been done during generate/import key, by KeyMint.
493 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
494 }
495 }
496
497 // authorize the purpose
498 if !key_purpose_authorized {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800499 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000500 .context("In authorize_create: the purpose is not authorized.");
501 }
502
503 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
504 if !user_secure_ids.is_empty() && no_auth_required {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800505 return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000506 "In authorize_create: key has both NO_AUTH_REQUIRED
507 and USER_SECURE_ID tags.",
508 );
509 }
510
511 // if either of auth_type or secure_id is present and the other is not present, return error
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000512 if (user_auth_type.is_some() && user_secure_ids.is_empty())
513 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000514 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800515 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000516 "In authorize_create: Auth required, but either auth type or secure ids
517 are not present.",
518 );
519 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800520
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000521 // validate caller nonce for origination purposes
522 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
523 && !caller_nonce_allowed
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800524 && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000525 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800526 return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000527 "In authorize_create, NONCE is present,
528 although CALLER_NONCE is not present",
529 );
530 }
531
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000532 if unlocked_device_required {
533 // check the device locked status. If locked, operations on the key are not
534 // allowed.
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000535 if self.is_device_locked(user_id) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800536 return Err(Error::Km(Ec::DEVICE_LOCKED))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000537 .context("In authorize_create: device is locked.");
538 }
539 }
540
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800541 if !unlocked_device_required && no_auth_required {
Qi Wub9433b52020-12-01 14:52:46 +0800542 return Ok((
543 None,
544 AuthInfo { state: DeferredAuthState::NoAuthRequired, key_usage_limited },
545 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000546 }
547
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800548 let has_sids = !user_secure_ids.is_empty();
549
550 let timeout_bound = key_time_out.is_some() && has_sids;
551
552 let per_op_bound = key_time_out.is_none() && has_sids;
553
554 let need_auth_token = timeout_bound || unlocked_device_required;
555
556 let hat_and_last_off_body = if need_auth_token {
557 let hat_and_last_off_body = Self::find_auth_token(|hat: &AuthTokenEntry| {
558 if let (Some(auth_type), true) = (user_auth_type, has_sids) {
559 hat.satisfies(&user_secure_ids, auth_type)
560 } else {
561 unlocked_device_required
562 }
563 })
564 .context("In authorize_create: Trying to get required auth token.")?;
565 Some(
566 hat_and_last_off_body
567 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
568 .context("In authorize_create: No suitable auth token found.")?,
569 )
570 } else {
571 None
572 };
573
574 // Now check the validity of the auth token if the key is timeout bound.
575 let hat = match (hat_and_last_off_body, key_time_out) {
576 (Some((hat, last_off_body)), Some(key_time_out)) => {
577 let now = MonotonicRawTime::now();
578 let token_age = now
579 .checked_sub(&hat.time_received())
580 .ok_or_else(Error::sys)
581 .context(concat!(
582 "In authorize_create: Overflow while computing Auth token validity. ",
583 "Validity cannot be established."
584 ))?;
585
586 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
587
588 if token_age.seconds() > key_time_out && !on_body_extended {
589 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
590 .context("In authorize_create: matching auth token is expired.");
591 }
592 Some(hat)
593 }
594 (Some((hat, _)), None) => Some(hat),
595 // If timeout_bound is true, above code must have retrieved a HAT or returned with
596 // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
597 (None, Some(_)) => panic!("Logical error."),
598 _ => None,
599 };
600
601 Ok(match (hat, requires_timestamp, per_op_bound) {
602 // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
603 // device required. In addition, this KM instance needs a timestamp token.
604 // So the HAT cannot be presented on create. So on update/finish we present both
605 // an per-op-bound auth token and a timestamp token.
606 (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
607 (Some(hat), true, false) => {
608 (None, DeferredAuthState::TimeStampRequired(hat.take_auth_token()))
609 }
610 (Some(hat), false, true) => {
611 (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
612 }
613 (Some(hat), false, false) => {
614 (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
615 }
616 (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
617 (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
618 })
Qi Wub9433b52020-12-01 14:52:46 +0800619 .map(|(hat, state)| (hat, AuthInfo { state, key_usage_limited }))
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800620 }
621
622 fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
623 where
624 F: Fn(&AuthTokenEntry) -> bool,
625 {
626 DB.with(|db| {
627 let mut db = db.borrow_mut();
628 db.find_auth_token_entry(p).context("Trying to find auth token.")
629 })
630 .context("In find_auth_token.")
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000631 }
632
633 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
634 /// set) the given time (in milliseconds)
635 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
636 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
637
638 let time_since_epoch = match duration_since_epoch {
639 Ok(duration) => duration.as_millis(),
640 Err(_) => return false,
641 };
642
643 if is_given_time_inclusive {
644 time_since_epoch >= (given_time as u128)
645 } else {
646 time_since_epoch > (given_time as u128)
647 }
648 }
649
650 /// Check if the device is locked for the given user. If there's no entry yet for the user,
651 /// we assume that the device is locked
652 fn is_device_locked(&self, user_id: i32) -> bool {
653 // unwrap here because there's no way this mutex guard can be poisoned and
654 // because there's no way to recover, even if it is poisoned.
655 let set = self.device_unlocked_set.lock().unwrap();
656 !set.contains(&user_id)
657 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000658
659 /// Sets the device locked status for the user. This method is called externally.
660 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
661 // unwrap here because there's no way this mutex guard can be poisoned and
662 // because there's no way to recover, even if it is poisoned.
663 let mut set = self.device_unlocked_set.lock().unwrap();
664 if device_locked_status {
665 set.remove(&user_id);
666 } else {
667 set.insert(user_id);
668 }
669 }
670
671 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800672 /// Then present the auth token to the op auth map. If an operation is waiting for this
673 /// auth token this fulfills the request and removes the receiver from the map.
674 pub fn add_auth_token(&self, hat: HardwareAuthToken) -> Result<()> {
675 DB.with(|db| db.borrow_mut().insert_auth_token(&hat)).context("In add_auth_token.")?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000676
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800677 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000678 Ok(())
679 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000680
681 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
682 /// This is to be called by create_operation, once it has received the operation challenge
683 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800684 /// by the DeferredAuthState.
685 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
686 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000687 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000688}
689
690impl Default for Enforcements {
691 fn default() -> Self {
692 Self::new()
693 }
694}
695
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000696// TODO: Add tests to enforcement module (b/175578618).