blob: 8574da08a8dde85e7adb272bfb2c20940b9199f2 [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};
Paul Crowley7a658392021-03-18 17:08:20 -070020use crate::{authorization::Error as AuthzError, super_key::SuperEncryptionType};
Paul Crowley9f7f48b2021-03-31 09:17:47 -070021use crate::{
22 database::{AuthTokenEntry, MonotonicRawTime},
23 globals::SUPER_KEY,
24};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000025use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000026 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080027 HardwareAuthenticatorType::HardwareAuthenticatorType,
28 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, Tag::Tag,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080029};
30use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080031 ISecureClock::ISecureClock, TimeStampToken::TimeStampToken,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000032};
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000033use android_security_authorization::aidl::android::security::authorization::ResponseCode::ResponseCode as AuthzResponseCode;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000034use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowley7a658392021-03-18 17:08:20 -070035 Domain::Domain, IKeystoreSecurityLevel::KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000036 OperationChallenge::OperationChallenge,
37};
Stephen Crane221bbb52020-12-16 15:52:10 -080038use android_system_keystore2::binder::Strong;
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000039use anyhow::{Context, Result};
Janis Danisevskisb1673db2021-02-08 18:11:57 -080040use std::{
41 collections::{HashMap, HashSet},
Paul Crowley7c57bf12021-02-02 16:26:57 -080042 sync::{
Paul Crowley7c57bf12021-02-02 16:26:57 -080043 mpsc::{channel, Receiver, Sender, TryRecvError},
44 Arc, Mutex, Weak,
45 },
46 time::SystemTime,
Janis Danisevskisb1673db2021-02-08 18:11:57 -080047};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000048
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080049#[derive(Debug)]
50enum AuthRequestState {
51 /// An outstanding per operation authorization request.
52 OpAuth,
53 /// An outstanding request for per operation authorization and secure timestamp.
54 TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
55 /// An outstanding request for a timestamp token.
56 TimeStamp(Receiver<Result<TimeStampToken, Error>>),
57}
58
59#[derive(Debug)]
60struct AuthRequest {
61 state: AuthRequestState,
62 /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
63 /// AuthRequestState::TimeStampedOpAuth.
64 hat: Option<HardwareAuthToken>,
65}
66
67impl AuthRequest {
68 fn op_auth() -> Arc<Mutex<Self>> {
69 Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
70 }
71
72 fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
73 Arc::new(Mutex::new(Self {
74 state: AuthRequestState::TimeStampedOpAuth(receiver),
75 hat: None,
76 }))
77 }
78
79 fn timestamp(
80 hat: HardwareAuthToken,
81 receiver: Receiver<Result<TimeStampToken, Error>>,
82 ) -> Arc<Mutex<Self>> {
83 Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
84 }
85
86 fn add_auth_token(&mut self, hat: HardwareAuthToken) {
87 self.hat = Some(hat)
88 }
89
90 fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
91 match (&self.state, self.hat.is_some()) {
92 (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
93 (AuthRequestState::TimeStampedOpAuth(recv), true)
94 | (AuthRequestState::TimeStamp(recv), true) => {
95 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
96 let tst = result.context(concat!(
97 "In get_auth_tokens: Worker responded with error ",
98 "from generating timestamp token."
99 ))?;
100 Ok((self.hat.take().unwrap(), Some(tst)))
101 }
102 (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
103 .context("In get_auth_tokens: No operation auth token received."),
104 }
105 }
106}
107
108/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
109/// updating and finishing an operation.
110#[derive(Debug)]
111enum DeferredAuthState {
112 /// Used when an operation does not require further authorization.
113 NoAuthRequired,
114 /// Indicates that the operation requires an operation specific token. This means we have
115 /// to return an operation challenge to the client which should reward us with an
116 /// operation specific auth token. If it is not provided before the client calls update
117 /// or finish, the operation fails as not authorized.
118 OpAuthRequired,
119 /// Indicates that the operation requires a time stamp token. The auth token was already
120 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
121 /// the target KM with a different clock about the time on the authenticators.
122 TimeStampRequired(HardwareAuthToken),
123 /// Indicates that both an operation bound auth token and a verification token are
124 /// before the operation can commence.
125 TimeStampedOpAuthRequired,
126 /// In this state the auth info is waiting for the deferred authorizations to come in.
127 /// We block on timestamp tokens, because we can always make progress on these requests.
128 /// The per-op auth tokens might never come, which means we fail if the client calls
129 /// update or finish before we got a per-op auth token.
130 Waiting(Arc<Mutex<AuthRequest>>),
131 /// In this state we have gotten all of the required tokens, we just cache them to
132 /// be used when the operation progresses.
133 Token(HardwareAuthToken, Option<TimeStampToken>),
134}
135
136/// Auth info hold all of the authorization related information of an operation. It is stored
137/// in and owned by the operation. It is constructed by authorize_create and stays with the
138/// operation until it completes.
139#[derive(Debug)]
140pub struct AuthInfo {
141 state: DeferredAuthState,
Qi Wub9433b52020-12-01 14:52:46 +0800142 /// An optional key id required to update the usage count if the key usage is limited.
143 key_usage_limited: Option<i64>,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800144 confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800145}
146
147struct TokenReceiverMap {
148 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
149 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
150 /// and the entry is removed from the map. In the case where no HAT is received before the
151 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
152 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
153 /// The cleanup counter is decremented every time a new receiver is added.
154 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
155 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
156}
157
158impl Default for TokenReceiverMap {
159 fn default() -> Self {
160 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
161 }
162}
163
164impl TokenReceiverMap {
165 /// There is a chance that receivers may become stale because their operation is dropped
166 /// without ever being authorized. So occasionally we iterate through the map and throw
167 /// out obsolete entries.
168 /// This is the number of calls to add_receiver between cleanups.
169 const CLEANUP_PERIOD: u8 = 25;
170
171 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
172 let mut map = self.map_and_cleanup_counter.lock().unwrap();
173 let (ref mut map, _) = *map;
174 if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
175 recv.add_auth_token(hat);
176 }
177 }
178
179 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
180 let mut map = self.map_and_cleanup_counter.lock().unwrap();
181 let (ref mut map, ref mut cleanup_counter) = *map;
182 map.insert(challenge, recv);
183
184 *cleanup_counter -= 1;
185 if *cleanup_counter == 0 {
186 map.retain(|_, v| !v.is_obsolete());
187 map.shrink_to_fit();
188 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
189 }
190 }
191}
192
193#[derive(Debug)]
194struct TokenReceiver(Weak<Mutex<AuthRequest>>);
195
196impl TokenReceiver {
197 fn is_obsolete(&self) -> bool {
198 self.0.upgrade().is_none()
199 }
200
201 fn add_auth_token(&self, hat: HardwareAuthToken) {
202 if let Some(state_arc) = self.0.upgrade() {
203 let mut state = state_arc.lock().unwrap();
204 state.add_auth_token(hat);
205 }
206 }
207}
208
209fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
Stephen Crane221bbb52020-12-16 15:52:10 -0800210 let dev: Strong<dyn ISecureClock> = get_timestamp_service()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800211 .expect(concat!(
212 "Secure Clock service must be present ",
213 "if TimeStampTokens are required."
214 ))
215 .get_interface()
216 .expect("Fatal: Timestamp service does not implement ISecureClock.");
217 map_binder_status(dev.generateTimeStamp(challenge))
218}
219
220fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
221 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
222 log::info!(
223 concat!(
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000224 "In timestamp_token_request: Receiver hung up ",
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800225 "before timestamp token could be delivered. {:?}"
226 ),
227 e
228 );
229 }
230}
231
232impl AuthInfo {
233 /// This function gets called after an operation was successfully created.
234 /// It makes all the preparations required, so that the operation has all the authentication
235 /// related artifacts to advance on update and finish.
236 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
237 match &self.state {
238 DeferredAuthState::OpAuthRequired => {
239 let auth_request = AuthRequest::op_auth();
240 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
241 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
242
243 self.state = DeferredAuthState::Waiting(auth_request);
244 Some(OperationChallenge { challenge })
245 }
246 DeferredAuthState::TimeStampedOpAuthRequired => {
247 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
248 let auth_request = AuthRequest::timestamped_op_auth(receiver);
249 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
250 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
251
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800252 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800253 self.state = DeferredAuthState::Waiting(auth_request);
254 Some(OperationChallenge { challenge })
255 }
256 DeferredAuthState::TimeStampRequired(hat) => {
257 let hat = (*hat).clone();
258 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
259 let auth_request = AuthRequest::timestamp(hat, receiver);
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800260 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800261 self.state = DeferredAuthState::Waiting(auth_request);
262 None
263 }
264 _ => None,
265 }
266 }
267
Qi Wub9433b52020-12-01 14:52:46 +0800268 /// This function is the authorization hook called before operation update.
269 /// It returns the auth tokens required by the operation to commence update.
270 pub fn before_update(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
271 self.get_auth_tokens()
272 }
273
274 /// This function is the authorization hook called before operation finish.
275 /// It returns the auth tokens required by the operation to commence finish.
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800276 /// The third token is a confirmation token.
277 pub fn before_finish(
278 &mut self,
279 ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>, Option<Vec<u8>>)> {
280 let mut confirmation_token: Option<Vec<u8>> = None;
281 if let Some(ref confirmation_token_receiver) = self.confirmation_token_receiver {
282 let locked_receiver = confirmation_token_receiver.lock().unwrap();
283 if let Some(ref receiver) = *locked_receiver {
284 loop {
285 match receiver.try_recv() {
286 // As long as we get tokens we loop and discard all but the most
287 // recent one.
288 Ok(t) => confirmation_token = Some(t),
289 Err(TryRecvError::Empty) => break,
290 Err(TryRecvError::Disconnected) => {
291 log::error!(concat!(
292 "We got disconnected from the APC service, ",
293 "this should never happen."
294 ));
295 break;
296 }
297 }
298 }
299 }
300 }
301 self.get_auth_tokens().map(|(hat, tst)| (hat, tst, confirmation_token))
Qi Wub9433b52020-12-01 14:52:46 +0800302 }
303
304 /// This function is the authorization hook called after finish succeeded.
305 /// As of this writing it checks if the key was a limited use key. If so it updates the
306 /// use counter of the key in the database. When the use counter is depleted, the key gets
307 /// marked for deletion and the garbage collector is notified.
308 pub fn after_finish(&self) -> Result<()> {
309 if let Some(key_id) = self.key_usage_limited {
310 // On the last successful use, the key gets deleted. In this case we
311 // have to notify the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800312 DB.with(|db| {
313 db.borrow_mut()
314 .check_and_update_key_usage_count(key_id)
315 .context("Trying to update key usage count.")
316 })
317 .context("In after_finish.")?;
Qi Wub9433b52020-12-01 14:52:46 +0800318 }
319 Ok(())
320 }
321
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800322 /// This function returns the auth tokens as needed by the ongoing operation or fails
323 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
324 /// after a deferred authorization was requested by finalize_create_authorization, this
325 /// function may block on the generation of a time stamp token. It then moves the
326 /// tokens into the DeferredAuthState::Token state for future use.
Qi Wub9433b52020-12-01 14:52:46 +0800327 fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800328 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
329 let mut state = auth_request.lock().unwrap();
330 Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
331 } else {
332 None
333 };
334
335 if let Some((hat, tst)) = deferred_tokens {
336 self.state = DeferredAuthState::Token(hat, tst);
337 }
338
339 match &self.state {
340 DeferredAuthState::NoAuthRequired => Ok((None, None)),
341 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
342 DeferredAuthState::OpAuthRequired
343 | DeferredAuthState::TimeStampedOpAuthRequired
344 | DeferredAuthState::TimeStampRequired(_) => {
345 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
346 "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
347 "This should not happen."
348 ))
349 }
350 // This should not be reachable, because it should have been handled above.
351 DeferredAuthState::Waiting(_) => {
352 Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
353 }
354 }
355 }
356}
357
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000358/// Enforcements data structure
Paul Crowley7c57bf12021-02-02 16:26:57 -0800359#[derive(Default)]
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000360pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800361 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
362 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000363 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800364 /// This field maps outstanding auth challenges to their operations. When an auth token
365 /// with the right challenge is received it is passed to the map using
366 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
367 /// stale, because the operation gets dropped before an auth token is received, the map
368 /// is cleaned up in regular intervals.
369 op_auth_map: TokenReceiverMap,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800370 /// The enforcement module will try to get a confirmation token from this channel whenever
371 /// an operation that requires confirmation finishes.
372 confirmation_token_receiver: Arc<Mutex<Option<Receiver<Vec<u8>>>>>,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000373}
374
375impl Enforcements {
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800376 /// Install the confirmation token receiver. The enforcement module will try to get a
377 /// confirmation token from this channel whenever an operation that requires confirmation
378 /// finishes.
379 pub fn install_confirmation_token_receiver(
380 &self,
381 confirmation_token_receiver: Receiver<Vec<u8>>,
382 ) {
383 *self.confirmation_token_receiver.lock().unwrap() = Some(confirmation_token_receiver);
384 }
385
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000386 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800387 /// It returns an optional immediate auth token which can be presented to begin, and an
388 /// AuthInfo object which stays with the authorized operation and is used to obtain
389 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000390 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800391 ///
392 /// If no key parameters are given (typically when the client is self managed
393 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000394 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800395 /// If the above step is successful, and if requires_timestamp is given, the returned
396 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000397 pub fn authorize_create(
398 &self,
399 purpose: KeyPurpose,
Qi Wub9433b52020-12-01 14:52:46 +0800400 key_properties: Option<&(i64, Vec<KeyParameter>)>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800401 op_params: &[KmKeyParameter],
402 requires_timestamp: bool,
403 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
Qi Wub9433b52020-12-01 14:52:46 +0800404 let (key_id, key_params) = match key_properties {
405 Some((key_id, key_params)) => (*key_id, key_params),
406 None => {
407 return Ok((
408 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800409 AuthInfo {
410 state: DeferredAuthState::NoAuthRequired,
411 key_usage_limited: None,
412 confirmation_token_receiver: None,
413 },
Qi Wub9433b52020-12-01 14:52:46 +0800414 ))
415 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800416 };
417
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000418 match purpose {
419 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
420 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
421 // Rule out WRAP_KEY purpose
422 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800423 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000424 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
425 }
Bram Bonnéa6b83822021-01-20 11:10:05 +0100426 // Allow AGREE_KEY for EC keys only.
427 KeyPurpose::AGREE_KEY => {
428 for kp in key_params.iter() {
429 if kp.get_tag() == Tag::ALGORITHM
430 && *kp.key_parameter_value() != KeyParameterValue::Algorithm(Algorithm::EC)
431 {
432 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
433 "In authorize_create: key agreement is only supported for EC keys.",
434 );
435 }
436 }
437 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000438 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
439 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
440 // asymmetric keys.
441 for kp in key_params.iter() {
442 match *kp.key_parameter_value() {
443 KeyParameterValue::Algorithm(Algorithm::RSA)
444 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800445 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000446 "In authorize_create: public operations on asymmetric keys are not
447 supported.",
448 );
449 }
450 _ => {}
451 }
452 }
453 }
454 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800455 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000456 .context("In authorize_create: specified purpose is not supported.");
457 }
458 }
459 // The following variables are to record information from key parameters to be used in
460 // enforcements, when two or more such pieces of information are required for enforcements.
461 // There is only one additional variable than what legacy keystore has, but this helps
462 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
463 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000464 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000465 let mut no_auth_required: bool = false;
466 let mut caller_nonce_allowed = false;
467 let mut user_id: i32 = -1;
468 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000469 let mut key_time_out: Option<i64> = None;
470 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000471 let mut unlocked_device_required = false;
Qi Wub9433b52020-12-01 14:52:46 +0800472 let mut key_usage_limited: Option<i64> = None;
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800473 let mut confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>> = None;
Paul Crowley7c57bf12021-02-02 16:26:57 -0800474 let mut max_boot_level: Option<i32> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000475
476 // iterate through key parameters, recording information we need for authorization
477 // enforcements later, or enforcing authorizations in place, where applicable
478 for key_param in key_params.iter() {
479 match key_param.key_parameter_value() {
480 KeyParameterValue::NoAuthRequired => {
481 no_auth_required = true;
482 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000483 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000484 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000485 }
486 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000487 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000488 }
489 KeyParameterValue::KeyPurpose(p) => {
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800490 // The following check has the effect of key_params.contains(purpose)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000491 // Also, authorizing purpose can not be completed here, if there can be multiple
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800492 // key parameters for KeyPurpose.
493 key_purpose_authorized = key_purpose_authorized || *p == purpose;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000494 }
495 KeyParameterValue::CallerNonce => {
496 caller_nonce_allowed = true;
497 }
498 KeyParameterValue::ActiveDateTime(a) => {
499 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800500 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000501 .context("In authorize_create: key is not yet active.");
502 }
503 }
504 KeyParameterValue::OriginationExpireDateTime(o) => {
505 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
506 && Enforcements::is_given_time_passed(*o, false)
507 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800508 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000509 .context("In authorize_create: key is expired.");
510 }
511 }
512 KeyParameterValue::UsageExpireDateTime(u) => {
513 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
514 && Enforcements::is_given_time_passed(*u, false)
515 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800516 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000517 .context("In authorize_create: key is expired.");
518 }
519 }
520 KeyParameterValue::UserSecureID(s) => {
521 user_secure_ids.push(*s);
522 }
523 KeyParameterValue::UserID(u) => {
524 user_id = *u;
525 }
526 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000527 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000528 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000529 KeyParameterValue::AllowWhileOnBody => {
530 allow_while_on_body = true;
531 }
Qi Wub9433b52020-12-01 14:52:46 +0800532 KeyParameterValue::UsageCountLimit(_) => {
533 // We don't examine the limit here because this is enforced on finish.
534 // Instead, we store the key_id so that finish can look up the key
535 // in the database again and check and update the counter.
536 key_usage_limited = Some(key_id);
537 }
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800538 KeyParameterValue::TrustedConfirmationRequired => {
539 confirmation_token_receiver = Some(self.confirmation_token_receiver.clone());
540 }
Paul Crowley7c57bf12021-02-02 16:26:57 -0800541 KeyParameterValue::MaxBootLevel(level) => {
542 max_boot_level = Some(*level);
543 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000544 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
545 // create operation if any non-allowed tags are present, is not done in
546 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800547 // a subset of non-allowed tags are present). Because sanitizing key parameters
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000548 // should have been done during generate/import key, by KeyMint.
549 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
550 }
551 }
552
553 // authorize the purpose
554 if !key_purpose_authorized {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800555 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000556 .context("In authorize_create: the purpose is not authorized.");
557 }
558
559 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
560 if !user_secure_ids.is_empty() && no_auth_required {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800561 return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000562 "In authorize_create: key has both NO_AUTH_REQUIRED
563 and USER_SECURE_ID tags.",
564 );
565 }
566
567 // 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 +0000568 if (user_auth_type.is_some() && user_secure_ids.is_empty())
569 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000570 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800571 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000572 "In authorize_create: Auth required, but either auth type or secure ids
573 are not present.",
574 );
575 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800576
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000577 // validate caller nonce for origination purposes
578 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
579 && !caller_nonce_allowed
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800580 && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000581 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800582 return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000583 "In authorize_create, NONCE is present,
584 although CALLER_NONCE is not present",
585 );
586 }
587
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000588 if unlocked_device_required {
589 // check the device locked status. If locked, operations on the key are not
590 // allowed.
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000591 if self.is_device_locked(user_id) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800592 return Err(Error::Km(Ec::DEVICE_LOCKED))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000593 .context("In authorize_create: device is locked.");
594 }
595 }
596
Paul Crowley7c57bf12021-02-02 16:26:57 -0800597 if let Some(level) = max_boot_level {
Paul Crowley9f7f48b2021-03-31 09:17:47 -0700598 if !SUPER_KEY.level_accessible(level) {
Paul Crowley7c57bf12021-02-02 16:26:57 -0800599 return Err(Error::Km(Ec::BOOT_LEVEL_EXCEEDED))
600 .context("In authorize_create: boot level is too late.");
601 }
602 }
603
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800604 if !unlocked_device_required && no_auth_required {
Qi Wub9433b52020-12-01 14:52:46 +0800605 return Ok((
606 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800607 AuthInfo {
608 state: DeferredAuthState::NoAuthRequired,
609 key_usage_limited,
610 confirmation_token_receiver,
611 },
Qi Wub9433b52020-12-01 14:52:46 +0800612 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000613 }
614
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800615 let has_sids = !user_secure_ids.is_empty();
616
617 let timeout_bound = key_time_out.is_some() && has_sids;
618
619 let per_op_bound = key_time_out.is_none() && has_sids;
620
621 let need_auth_token = timeout_bound || unlocked_device_required;
622
623 let hat_and_last_off_body = if need_auth_token {
624 let hat_and_last_off_body = Self::find_auth_token(|hat: &AuthTokenEntry| {
625 if let (Some(auth_type), true) = (user_auth_type, has_sids) {
626 hat.satisfies(&user_secure_ids, auth_type)
627 } else {
628 unlocked_device_required
629 }
630 })
631 .context("In authorize_create: Trying to get required auth token.")?;
632 Some(
633 hat_and_last_off_body
634 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
635 .context("In authorize_create: No suitable auth token found.")?,
636 )
637 } else {
638 None
639 };
640
641 // Now check the validity of the auth token if the key is timeout bound.
642 let hat = match (hat_and_last_off_body, key_time_out) {
643 (Some((hat, last_off_body)), Some(key_time_out)) => {
644 let now = MonotonicRawTime::now();
645 let token_age = now
646 .checked_sub(&hat.time_received())
647 .ok_or_else(Error::sys)
648 .context(concat!(
649 "In authorize_create: Overflow while computing Auth token validity. ",
650 "Validity cannot be established."
651 ))?;
652
653 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
654
655 if token_age.seconds() > key_time_out && !on_body_extended {
656 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
657 .context("In authorize_create: matching auth token is expired.");
658 }
659 Some(hat)
660 }
661 (Some((hat, _)), None) => Some(hat),
662 // If timeout_bound is true, above code must have retrieved a HAT or returned with
663 // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
664 (None, Some(_)) => panic!("Logical error."),
665 _ => None,
666 };
667
668 Ok(match (hat, requires_timestamp, per_op_bound) {
669 // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
670 // device required. In addition, this KM instance needs a timestamp token.
671 // So the HAT cannot be presented on create. So on update/finish we present both
672 // an per-op-bound auth token and a timestamp token.
673 (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
674 (Some(hat), true, false) => {
675 (None, DeferredAuthState::TimeStampRequired(hat.take_auth_token()))
676 }
677 (Some(hat), false, true) => {
678 (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
679 }
680 (Some(hat), false, false) => {
681 (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
682 }
683 (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
684 (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
685 })
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800686 .map(|(hat, state)| {
687 (hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver })
688 })
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800689 }
690
691 fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
692 where
693 F: Fn(&AuthTokenEntry) -> bool,
694 {
695 DB.with(|db| {
696 let mut db = db.borrow_mut();
697 db.find_auth_token_entry(p).context("Trying to find auth token.")
698 })
699 .context("In find_auth_token.")
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000700 }
701
702 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
703 /// set) the given time (in milliseconds)
704 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
705 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
706
707 let time_since_epoch = match duration_since_epoch {
708 Ok(duration) => duration.as_millis(),
709 Err(_) => return false,
710 };
711
712 if is_given_time_inclusive {
713 time_since_epoch >= (given_time as u128)
714 } else {
715 time_since_epoch > (given_time as u128)
716 }
717 }
718
719 /// Check if the device is locked for the given user. If there's no entry yet for the user,
720 /// we assume that the device is locked
721 fn is_device_locked(&self, user_id: i32) -> bool {
722 // unwrap here because there's no way this mutex guard can be poisoned and
723 // because there's no way to recover, even if it is poisoned.
724 let set = self.device_unlocked_set.lock().unwrap();
725 !set.contains(&user_id)
726 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000727
728 /// Sets the device locked status for the user. This method is called externally.
729 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
730 // unwrap here because there's no way this mutex guard can be poisoned and
731 // because there's no way to recover, even if it is poisoned.
732 let mut set = self.device_unlocked_set.lock().unwrap();
733 if device_locked_status {
734 set.remove(&user_id);
735 } else {
736 set.insert(user_id);
737 }
738 }
739
740 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800741 /// Then present the auth token to the op auth map. If an operation is waiting for this
742 /// auth token this fulfills the request and removes the receiver from the map.
743 pub fn add_auth_token(&self, hat: HardwareAuthToken) -> Result<()> {
744 DB.with(|db| db.borrow_mut().insert_auth_token(&hat)).context("In add_auth_token.")?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000745
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800746 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000747 Ok(())
748 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000749
750 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
751 /// This is to be called by create_operation, once it has received the operation challenge
752 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800753 /// by the DeferredAuthState.
754 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
755 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000756 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000757
758 /// Given the set of key parameters and flags, check if super encryption is required.
Paul Crowley7a658392021-03-18 17:08:20 -0700759 pub fn super_encryption_required(
760 domain: &Domain,
761 key_parameters: &[KeyParameter],
762 flags: Option<i32>,
763 ) -> SuperEncryptionType {
Paul Crowley7a658392021-03-18 17:08:20 -0700764 if let Some(flags) = flags {
765 if (flags & KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING) != 0 {
766 return SuperEncryptionType::None;
767 }
768 }
Paul Crowley9f7f48b2021-03-31 09:17:47 -0700769 // Each answer has a priority, numerically largest priority wins.
770 struct Candidate {
771 priority: u32,
772 enc_type: SuperEncryptionType,
773 };
774 let mut result = Candidate { priority: 0, enc_type: SuperEncryptionType::None };
775 for kp in key_parameters {
776 let t = match kp.key_parameter_value() {
777 KeyParameterValue::MaxBootLevel(level) => {
778 Candidate { priority: 3, enc_type: SuperEncryptionType::BootLevel(*level) }
779 }
780 KeyParameterValue::UnlockedDeviceRequired if *domain == Domain::APP => {
781 Candidate { priority: 2, enc_type: SuperEncryptionType::ScreenLockBound }
782 }
783 KeyParameterValue::UserSecureID(_) if *domain == Domain::APP => {
784 Candidate { priority: 1, enc_type: SuperEncryptionType::LskfBound }
785 }
786 _ => Candidate { priority: 0, enc_type: SuperEncryptionType::None },
787 };
788 if t.priority > result.priority {
789 result = t;
790 }
Paul Crowley7a658392021-03-18 17:08:20 -0700791 }
Paul Crowley9f7f48b2021-03-31 09:17:47 -0700792 result.enc_type
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000793 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000794
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000795 /// Finds a matching auth token along with a timestamp token.
796 /// This method looks through auth-tokens cached by keystore which satisfy the given
797 /// authentication information (i.e. |secureUserId|).
798 /// The most recent matching auth token which has a |challenge| field which matches
799 /// the passed-in |challenge| parameter is returned.
800 /// In this case the |authTokenMaxAgeMillis| parameter is not used.
801 ///
802 /// Otherwise, the most recent matching auth token which is younger than |authTokenMaxAgeMillis|
803 /// is returned.
804 pub fn get_auth_tokens(
805 &self,
806 challenge: i64,
807 secure_user_id: i64,
808 auth_token_max_age_millis: i64,
809 ) -> Result<(HardwareAuthToken, TimeStampToken)> {
810 let auth_type = HardwareAuthenticatorType::ANY;
811 let sids: Vec<i64> = vec![secure_user_id];
812 // Filter the matching auth tokens by challenge
813 let result = Self::find_auth_token(|hat: &AuthTokenEntry| {
814 (challenge == hat.challenge()) && hat.satisfies(&sids, auth_type)
815 })
816 .context(
817 "In get_auth_tokens: Failed to get a matching auth token filtered by challenge.",
818 )?;
819
820 let auth_token = if let Some((auth_token_entry, _)) = result {
821 auth_token_entry.take_auth_token()
822 } else {
823 // Filter the matching auth tokens by age.
824 if auth_token_max_age_millis != 0 {
825 let now_in_millis = MonotonicRawTime::now().milli_seconds();
826 let result = Self::find_auth_token(|auth_token_entry: &AuthTokenEntry| {
827 let token_valid = now_in_millis
828 .checked_sub(auth_token_entry.time_received().milli_seconds())
829 .map_or(false, |token_age_in_millis| {
Hasini Gunasinghe971dbb62021-03-23 14:57:34 +0000830 auth_token_max_age_millis > token_age_in_millis
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000831 });
832 token_valid && auth_token_entry.satisfies(&sids, auth_type)
833 })
834 .context(
835 "In get_auth_tokens: Failed to get a matching auth token filtered by age.",
836 )?;
837
838 if let Some((auth_token_entry, _)) = result {
839 auth_token_entry.take_auth_token()
840 } else {
841 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
842 .context("In get_auth_tokens: No auth token found.");
843 }
844 } else {
845 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
846 .context("In get_auth_tokens: Passed-in auth token max age is zero.");
847 }
848 };
849 // Wait and obtain the timestamp token from secure clock service.
850 let tst = get_timestamp_token(challenge)
851 .context("In get_auth_tokens. Error in getting timestamp token.")?;
852 Ok((auth_token, tst))
853 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000854}
855
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000856// TODO: Add tests to enforcement module (b/175578618).