blob: 387604ef538f1d5f9c22d56544d24e7b97340603 [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::database::{AuthTokenEntry, MonotonicRawTime};
18use crate::error::{map_binder_status, Error, ErrorCode};
19use crate::globals::{get_timestamp_service, ASYNC_TASK, DB, ENFORCEMENTS};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000020use crate::key_parameter::{KeyParameter, KeyParameterValue};
21use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000022 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080023 HardwareAuthenticatorType::HardwareAuthenticatorType,
24 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, Tag::Tag,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080025};
26use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080027 ISecureClock::ISecureClock, TimeStampToken::TimeStampToken,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000028};
29use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
30use anyhow::{Context, Result};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000031use std::collections::{HashMap, HashSet};
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080032use std::sync::{
33 mpsc::{channel, Receiver, Sender},
34 Arc, Mutex, Weak,
35};
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000036use std::time::SystemTime;
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000037
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080038#[derive(Debug)]
39enum AuthRequestState {
40 /// An outstanding per operation authorization request.
41 OpAuth,
42 /// An outstanding request for per operation authorization and secure timestamp.
43 TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
44 /// An outstanding request for a timestamp token.
45 TimeStamp(Receiver<Result<TimeStampToken, Error>>),
46}
47
48#[derive(Debug)]
49struct AuthRequest {
50 state: AuthRequestState,
51 /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
52 /// AuthRequestState::TimeStampedOpAuth.
53 hat: Option<HardwareAuthToken>,
54}
55
56impl AuthRequest {
57 fn op_auth() -> Arc<Mutex<Self>> {
58 Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
59 }
60
61 fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
62 Arc::new(Mutex::new(Self {
63 state: AuthRequestState::TimeStampedOpAuth(receiver),
64 hat: None,
65 }))
66 }
67
68 fn timestamp(
69 hat: HardwareAuthToken,
70 receiver: Receiver<Result<TimeStampToken, Error>>,
71 ) -> Arc<Mutex<Self>> {
72 Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
73 }
74
75 fn add_auth_token(&mut self, hat: HardwareAuthToken) {
76 self.hat = Some(hat)
77 }
78
79 fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
80 match (&self.state, self.hat.is_some()) {
81 (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
82 (AuthRequestState::TimeStampedOpAuth(recv), true)
83 | (AuthRequestState::TimeStamp(recv), true) => {
84 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
85 let tst = result.context(concat!(
86 "In get_auth_tokens: Worker responded with error ",
87 "from generating timestamp token."
88 ))?;
89 Ok((self.hat.take().unwrap(), Some(tst)))
90 }
91 (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
92 .context("In get_auth_tokens: No operation auth token received."),
93 }
94 }
95}
96
97/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
98/// updating and finishing an operation.
99#[derive(Debug)]
100enum DeferredAuthState {
101 /// Used when an operation does not require further authorization.
102 NoAuthRequired,
103 /// Indicates that the operation requires an operation specific token. This means we have
104 /// to return an operation challenge to the client which should reward us with an
105 /// operation specific auth token. If it is not provided before the client calls update
106 /// or finish, the operation fails as not authorized.
107 OpAuthRequired,
108 /// Indicates that the operation requires a time stamp token. The auth token was already
109 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
110 /// the target KM with a different clock about the time on the authenticators.
111 TimeStampRequired(HardwareAuthToken),
112 /// Indicates that both an operation bound auth token and a verification token are
113 /// before the operation can commence.
114 TimeStampedOpAuthRequired,
115 /// In this state the auth info is waiting for the deferred authorizations to come in.
116 /// We block on timestamp tokens, because we can always make progress on these requests.
117 /// The per-op auth tokens might never come, which means we fail if the client calls
118 /// update or finish before we got a per-op auth token.
119 Waiting(Arc<Mutex<AuthRequest>>),
120 /// In this state we have gotten all of the required tokens, we just cache them to
121 /// be used when the operation progresses.
122 Token(HardwareAuthToken, Option<TimeStampToken>),
123}
124
125/// Auth info hold all of the authorization related information of an operation. It is stored
126/// in and owned by the operation. It is constructed by authorize_create and stays with the
127/// operation until it completes.
128#[derive(Debug)]
129pub struct AuthInfo {
130 state: DeferredAuthState,
131}
132
133struct TokenReceiverMap {
134 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
135 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
136 /// and the entry is removed from the map. In the case where no HAT is received before the
137 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
138 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
139 /// The cleanup counter is decremented every time a new receiver is added.
140 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
141 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
142}
143
144impl Default for TokenReceiverMap {
145 fn default() -> Self {
146 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
147 }
148}
149
150impl TokenReceiverMap {
151 /// There is a chance that receivers may become stale because their operation is dropped
152 /// without ever being authorized. So occasionally we iterate through the map and throw
153 /// out obsolete entries.
154 /// This is the number of calls to add_receiver between cleanups.
155 const CLEANUP_PERIOD: u8 = 25;
156
157 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
158 let mut map = self.map_and_cleanup_counter.lock().unwrap();
159 let (ref mut map, _) = *map;
160 if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
161 recv.add_auth_token(hat);
162 }
163 }
164
165 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
166 let mut map = self.map_and_cleanup_counter.lock().unwrap();
167 let (ref mut map, ref mut cleanup_counter) = *map;
168 map.insert(challenge, recv);
169
170 *cleanup_counter -= 1;
171 if *cleanup_counter == 0 {
172 map.retain(|_, v| !v.is_obsolete());
173 map.shrink_to_fit();
174 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
175 }
176 }
177}
178
179#[derive(Debug)]
180struct TokenReceiver(Weak<Mutex<AuthRequest>>);
181
182impl TokenReceiver {
183 fn is_obsolete(&self) -> bool {
184 self.0.upgrade().is_none()
185 }
186
187 fn add_auth_token(&self, hat: HardwareAuthToken) {
188 if let Some(state_arc) = self.0.upgrade() {
189 let mut state = state_arc.lock().unwrap();
190 state.add_auth_token(hat);
191 }
192 }
193}
194
195fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
196 let dev: Box<dyn ISecureClock> = get_timestamp_service()
197 .expect(concat!(
198 "Secure Clock service must be present ",
199 "if TimeStampTokens are required."
200 ))
201 .get_interface()
202 .expect("Fatal: Timestamp service does not implement ISecureClock.");
203 map_binder_status(dev.generateTimeStamp(challenge))
204}
205
206fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
207 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
208 log::info!(
209 concat!(
210 "In timestamp_token_request: Operation hung up ",
211 "before timestamp token could be delivered. {:?}"
212 ),
213 e
214 );
215 }
216}
217
218impl AuthInfo {
219 /// This function gets called after an operation was successfully created.
220 /// It makes all the preparations required, so that the operation has all the authentication
221 /// related artifacts to advance on update and finish.
222 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
223 match &self.state {
224 DeferredAuthState::OpAuthRequired => {
225 let auth_request = AuthRequest::op_auth();
226 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
227 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
228
229 self.state = DeferredAuthState::Waiting(auth_request);
230 Some(OperationChallenge { challenge })
231 }
232 DeferredAuthState::TimeStampedOpAuthRequired => {
233 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
234 let auth_request = AuthRequest::timestamped_op_auth(receiver);
235 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
236 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
237
238 ASYNC_TASK.queue_hi(move || timestamp_token_request(challenge, sender));
239 self.state = DeferredAuthState::Waiting(auth_request);
240 Some(OperationChallenge { challenge })
241 }
242 DeferredAuthState::TimeStampRequired(hat) => {
243 let hat = (*hat).clone();
244 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
245 let auth_request = AuthRequest::timestamp(hat, receiver);
246 ASYNC_TASK.queue_hi(move || timestamp_token_request(challenge, sender));
247 self.state = DeferredAuthState::Waiting(auth_request);
248 None
249 }
250 _ => None,
251 }
252 }
253
254 /// This function returns the auth tokens as needed by the ongoing operation or fails
255 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
256 /// after a deferred authorization was requested by finalize_create_authorization, this
257 /// function may block on the generation of a time stamp token. It then moves the
258 /// tokens into the DeferredAuthState::Token state for future use.
259 pub fn get_auth_tokens(
260 &mut self,
261 ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
262 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
263 let mut state = auth_request.lock().unwrap();
264 Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
265 } else {
266 None
267 };
268
269 if let Some((hat, tst)) = deferred_tokens {
270 self.state = DeferredAuthState::Token(hat, tst);
271 }
272
273 match &self.state {
274 DeferredAuthState::NoAuthRequired => Ok((None, None)),
275 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
276 DeferredAuthState::OpAuthRequired
277 | DeferredAuthState::TimeStampedOpAuthRequired
278 | DeferredAuthState::TimeStampRequired(_) => {
279 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
280 "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
281 "This should not happen."
282 ))
283 }
284 // This should not be reachable, because it should have been handled above.
285 DeferredAuthState::Waiting(_) => {
286 Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
287 }
288 }
289 }
290}
291
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000292/// Enforcements data structure
293pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800294 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
295 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000296 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800297 /// This field maps outstanding auth challenges to their operations. When an auth token
298 /// with the right challenge is received it is passed to the map using
299 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
300 /// stale, because the operation gets dropped before an auth token is received, the map
301 /// is cleaned up in regular intervals.
302 op_auth_map: TokenReceiverMap,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000303}
304
305impl Enforcements {
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000306 /// Creates an enforcement object with the two data structures it holds and the sender as None.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000307 pub fn new() -> Self {
308 Enforcements {
309 device_unlocked_set: Mutex::new(HashSet::new()),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800310 op_auth_map: Default::default(),
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000311 }
312 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000313
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000314 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800315 /// It returns an optional immediate auth token which can be presented to begin, and an
316 /// AuthInfo object which stays with the authorized operation and is used to obtain
317 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000318 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800319 ///
320 /// If no key parameters are given (typically when the client is self managed
321 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000322 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800323 /// If the above step is successful, and if requires_timestamp is given, the returned
324 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000325 pub fn authorize_create(
326 &self,
327 purpose: KeyPurpose,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800328 key_params: Option<&[KeyParameter]>,
329 op_params: &[KmKeyParameter],
330 requires_timestamp: bool,
331 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
332 let key_params = if let Some(k) = key_params {
333 k
334 } else {
335 return Ok((None, AuthInfo { state: DeferredAuthState::NoAuthRequired }));
336 };
337
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000338 match purpose {
339 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
340 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
341 // Rule out WRAP_KEY purpose
342 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800343 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000344 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
345 }
346 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
347 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
348 // asymmetric keys.
349 for kp in key_params.iter() {
350 match *kp.key_parameter_value() {
351 KeyParameterValue::Algorithm(Algorithm::RSA)
352 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800353 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000354 "In authorize_create: public operations on asymmetric keys are not
355 supported.",
356 );
357 }
358 _ => {}
359 }
360 }
361 }
362 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800363 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000364 .context("In authorize_create: specified purpose is not supported.");
365 }
366 }
367 // The following variables are to record information from key parameters to be used in
368 // enforcements, when two or more such pieces of information are required for enforcements.
369 // There is only one additional variable than what legacy keystore has, but this helps
370 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
371 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000372 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000373 let mut no_auth_required: bool = false;
374 let mut caller_nonce_allowed = false;
375 let mut user_id: i32 = -1;
376 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000377 let mut key_time_out: Option<i64> = None;
378 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000379 let mut unlocked_device_required = false;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000380
381 // iterate through key parameters, recording information we need for authorization
382 // enforcements later, or enforcing authorizations in place, where applicable
383 for key_param in key_params.iter() {
384 match key_param.key_parameter_value() {
385 KeyParameterValue::NoAuthRequired => {
386 no_auth_required = true;
387 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000388 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000389 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000390 }
391 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000392 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000393 }
394 KeyParameterValue::KeyPurpose(p) => {
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800395 // The following check has the effect of key_params.contains(purpose)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000396 // Also, authorizing purpose can not be completed here, if there can be multiple
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800397 // key parameters for KeyPurpose.
398 key_purpose_authorized = key_purpose_authorized || *p == purpose;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000399 }
400 KeyParameterValue::CallerNonce => {
401 caller_nonce_allowed = true;
402 }
403 KeyParameterValue::ActiveDateTime(a) => {
404 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800405 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000406 .context("In authorize_create: key is not yet active.");
407 }
408 }
409 KeyParameterValue::OriginationExpireDateTime(o) => {
410 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
411 && Enforcements::is_given_time_passed(*o, false)
412 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800413 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000414 .context("In authorize_create: key is expired.");
415 }
416 }
417 KeyParameterValue::UsageExpireDateTime(u) => {
418 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
419 && Enforcements::is_given_time_passed(*u, false)
420 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800421 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000422 .context("In authorize_create: key is expired.");
423 }
424 }
425 KeyParameterValue::UserSecureID(s) => {
426 user_secure_ids.push(*s);
427 }
428 KeyParameterValue::UserID(u) => {
429 user_id = *u;
430 }
431 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000432 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000433 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000434 KeyParameterValue::AllowWhileOnBody => {
435 allow_while_on_body = true;
436 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000437 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
438 // create operation if any non-allowed tags are present, is not done in
439 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800440 // a subset of non-allowed tags are present). Because sanitizing key parameters
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000441 // should have been done during generate/import key, by KeyMint.
442 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
443 }
444 }
445
446 // authorize the purpose
447 if !key_purpose_authorized {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800448 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000449 .context("In authorize_create: the purpose is not authorized.");
450 }
451
452 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
453 if !user_secure_ids.is_empty() && no_auth_required {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800454 return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000455 "In authorize_create: key has both NO_AUTH_REQUIRED
456 and USER_SECURE_ID tags.",
457 );
458 }
459
460 // 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 +0000461 if (user_auth_type.is_some() && user_secure_ids.is_empty())
462 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000463 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800464 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000465 "In authorize_create: Auth required, but either auth type or secure ids
466 are not present.",
467 );
468 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800469
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000470 // validate caller nonce for origination purposes
471 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
472 && !caller_nonce_allowed
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800473 && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000474 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800475 return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000476 "In authorize_create, NONCE is present,
477 although CALLER_NONCE is not present",
478 );
479 }
480
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000481 if unlocked_device_required {
482 // check the device locked status. If locked, operations on the key are not
483 // allowed.
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000484 if self.is_device_locked(user_id) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800485 return Err(Error::Km(Ec::DEVICE_LOCKED))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000486 .context("In authorize_create: device is locked.");
487 }
488 }
489
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800490 if !unlocked_device_required && no_auth_required {
491 return Ok((None, AuthInfo { state: DeferredAuthState::NoAuthRequired }));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000492 }
493
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800494 let has_sids = !user_secure_ids.is_empty();
495
496 let timeout_bound = key_time_out.is_some() && has_sids;
497
498 let per_op_bound = key_time_out.is_none() && has_sids;
499
500 let need_auth_token = timeout_bound || unlocked_device_required;
501
502 let hat_and_last_off_body = if need_auth_token {
503 let hat_and_last_off_body = Self::find_auth_token(|hat: &AuthTokenEntry| {
504 if let (Some(auth_type), true) = (user_auth_type, has_sids) {
505 hat.satisfies(&user_secure_ids, auth_type)
506 } else {
507 unlocked_device_required
508 }
509 })
510 .context("In authorize_create: Trying to get required auth token.")?;
511 Some(
512 hat_and_last_off_body
513 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
514 .context("In authorize_create: No suitable auth token found.")?,
515 )
516 } else {
517 None
518 };
519
520 // Now check the validity of the auth token if the key is timeout bound.
521 let hat = match (hat_and_last_off_body, key_time_out) {
522 (Some((hat, last_off_body)), Some(key_time_out)) => {
523 let now = MonotonicRawTime::now();
524 let token_age = now
525 .checked_sub(&hat.time_received())
526 .ok_or_else(Error::sys)
527 .context(concat!(
528 "In authorize_create: Overflow while computing Auth token validity. ",
529 "Validity cannot be established."
530 ))?;
531
532 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
533
534 if token_age.seconds() > key_time_out && !on_body_extended {
535 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
536 .context("In authorize_create: matching auth token is expired.");
537 }
538 Some(hat)
539 }
540 (Some((hat, _)), None) => Some(hat),
541 // If timeout_bound is true, above code must have retrieved a HAT or returned with
542 // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
543 (None, Some(_)) => panic!("Logical error."),
544 _ => None,
545 };
546
547 Ok(match (hat, requires_timestamp, per_op_bound) {
548 // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
549 // device required. In addition, this KM instance needs a timestamp token.
550 // So the HAT cannot be presented on create. So on update/finish we present both
551 // an per-op-bound auth token and a timestamp token.
552 (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
553 (Some(hat), true, false) => {
554 (None, DeferredAuthState::TimeStampRequired(hat.take_auth_token()))
555 }
556 (Some(hat), false, true) => {
557 (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
558 }
559 (Some(hat), false, false) => {
560 (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
561 }
562 (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
563 (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
564 })
565 .map(|(hat, state)| (hat, AuthInfo { state }))
566 }
567
568 fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
569 where
570 F: Fn(&AuthTokenEntry) -> bool,
571 {
572 DB.with(|db| {
573 let mut db = db.borrow_mut();
574 db.find_auth_token_entry(p).context("Trying to find auth token.")
575 })
576 .context("In find_auth_token.")
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000577 }
578
579 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
580 /// set) the given time (in milliseconds)
581 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
582 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
583
584 let time_since_epoch = match duration_since_epoch {
585 Ok(duration) => duration.as_millis(),
586 Err(_) => return false,
587 };
588
589 if is_given_time_inclusive {
590 time_since_epoch >= (given_time as u128)
591 } else {
592 time_since_epoch > (given_time as u128)
593 }
594 }
595
596 /// Check if the device is locked for the given user. If there's no entry yet for the user,
597 /// we assume that the device is locked
598 fn is_device_locked(&self, user_id: i32) -> bool {
599 // unwrap here because there's no way this mutex guard can be poisoned and
600 // because there's no way to recover, even if it is poisoned.
601 let set = self.device_unlocked_set.lock().unwrap();
602 !set.contains(&user_id)
603 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000604
605 /// Sets the device locked status for the user. This method is called externally.
606 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
607 // unwrap here because there's no way this mutex guard can be poisoned and
608 // because there's no way to recover, even if it is poisoned.
609 let mut set = self.device_unlocked_set.lock().unwrap();
610 if device_locked_status {
611 set.remove(&user_id);
612 } else {
613 set.insert(user_id);
614 }
615 }
616
617 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800618 /// Then present the auth token to the op auth map. If an operation is waiting for this
619 /// auth token this fulfills the request and removes the receiver from the map.
620 pub fn add_auth_token(&self, hat: HardwareAuthToken) -> Result<()> {
621 DB.with(|db| db.borrow_mut().insert_auth_token(&hat)).context("In add_auth_token.")?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000622
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800623 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000624 Ok(())
625 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000626
627 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
628 /// This is to be called by create_operation, once it has received the operation challenge
629 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800630 /// by the DeferredAuthState.
631 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
632 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000633 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000634}
635
636impl Default for Enforcements {
637 fn default() -> Self {
638 Self::new()
639 }
640}
641
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000642// TODO: Add tests to enforcement module (b/175578618).