blob: 3f003be29428123b61d2ae74c8c9ab1ecfa60a82 [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 Danisevskis7e8b4622021-02-13 10:01:59 -080017use crate::database::{AuthTokenEntry, MonotonicRawTime};
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080018use 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};
Paul Crowley7a658392021-03-18 17:08:20 -070021use crate::{authorization::Error as AuthzError, super_key::SuperEncryptionType};
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000022use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000023 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080024 HardwareAuthenticatorType::HardwareAuthenticatorType,
25 KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, Tag::Tag,
Janis Danisevskisc3a496b2021-01-05 10:37:22 -080026};
27use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080028 ISecureClock::ISecureClock, TimeStampToken::TimeStampToken,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000029};
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +000030use android_security_authorization::aidl::android::security::authorization::ResponseCode::ResponseCode as AuthzResponseCode;
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000031use android_system_keystore2::aidl::android::system::keystore2::{
Paul Crowley7a658392021-03-18 17:08:20 -070032 Domain::Domain, IKeystoreSecurityLevel::KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING,
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000033 OperationChallenge::OperationChallenge,
34};
Stephen Crane221bbb52020-12-16 15:52:10 -080035use android_system_keystore2::binder::Strong;
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000036use anyhow::{Context, Result};
Paul Crowley7c57bf12021-02-02 16:26:57 -080037use keystore2_system_property::PropertyWatcher;
Janis Danisevskisb1673db2021-02-08 18:11:57 -080038use std::{
39 collections::{HashMap, HashSet},
Paul Crowley7c57bf12021-02-02 16:26:57 -080040 sync::{
41 atomic::{AtomicI32, Ordering},
42 mpsc::{channel, Receiver, Sender, TryRecvError},
43 Arc, Mutex, Weak,
44 },
45 time::SystemTime,
Janis Danisevskisb1673db2021-02-08 18:11:57 -080046};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000047
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080048#[derive(Debug)]
49enum AuthRequestState {
50 /// An outstanding per operation authorization request.
51 OpAuth,
52 /// An outstanding request for per operation authorization and secure timestamp.
53 TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
54 /// An outstanding request for a timestamp token.
55 TimeStamp(Receiver<Result<TimeStampToken, Error>>),
56}
57
58#[derive(Debug)]
59struct AuthRequest {
60 state: AuthRequestState,
61 /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
62 /// AuthRequestState::TimeStampedOpAuth.
63 hat: Option<HardwareAuthToken>,
64}
65
66impl AuthRequest {
67 fn op_auth() -> Arc<Mutex<Self>> {
68 Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
69 }
70
71 fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
72 Arc::new(Mutex::new(Self {
73 state: AuthRequestState::TimeStampedOpAuth(receiver),
74 hat: None,
75 }))
76 }
77
78 fn timestamp(
79 hat: HardwareAuthToken,
80 receiver: Receiver<Result<TimeStampToken, Error>>,
81 ) -> Arc<Mutex<Self>> {
82 Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
83 }
84
85 fn add_auth_token(&mut self, hat: HardwareAuthToken) {
86 self.hat = Some(hat)
87 }
88
89 fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
90 match (&self.state, self.hat.is_some()) {
91 (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
92 (AuthRequestState::TimeStampedOpAuth(recv), true)
93 | (AuthRequestState::TimeStamp(recv), true) => {
94 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
95 let tst = result.context(concat!(
96 "In get_auth_tokens: Worker responded with error ",
97 "from generating timestamp token."
98 ))?;
99 Ok((self.hat.take().unwrap(), Some(tst)))
100 }
101 (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
102 .context("In get_auth_tokens: No operation auth token received."),
103 }
104 }
105}
106
107/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
108/// updating and finishing an operation.
109#[derive(Debug)]
110enum DeferredAuthState {
111 /// Used when an operation does not require further authorization.
112 NoAuthRequired,
113 /// Indicates that the operation requires an operation specific token. This means we have
114 /// to return an operation challenge to the client which should reward us with an
115 /// operation specific auth token. If it is not provided before the client calls update
116 /// or finish, the operation fails as not authorized.
117 OpAuthRequired,
118 /// Indicates that the operation requires a time stamp token. The auth token was already
119 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
120 /// the target KM with a different clock about the time on the authenticators.
121 TimeStampRequired(HardwareAuthToken),
122 /// Indicates that both an operation bound auth token and a verification token are
123 /// before the operation can commence.
124 TimeStampedOpAuthRequired,
125 /// In this state the auth info is waiting for the deferred authorizations to come in.
126 /// We block on timestamp tokens, because we can always make progress on these requests.
127 /// The per-op auth tokens might never come, which means we fail if the client calls
128 /// update or finish before we got a per-op auth token.
129 Waiting(Arc<Mutex<AuthRequest>>),
130 /// In this state we have gotten all of the required tokens, we just cache them to
131 /// be used when the operation progresses.
132 Token(HardwareAuthToken, Option<TimeStampToken>),
133}
134
135/// Auth info hold all of the authorization related information of an operation. It is stored
136/// in and owned by the operation. It is constructed by authorize_create and stays with the
137/// operation until it completes.
138#[derive(Debug)]
139pub struct AuthInfo {
140 state: DeferredAuthState,
Qi Wub9433b52020-12-01 14:52:46 +0800141 /// An optional key id required to update the usage count if the key usage is limited.
142 key_usage_limited: Option<i64>,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800143 confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800144}
145
146struct TokenReceiverMap {
147 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
148 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
149 /// and the entry is removed from the map. In the case where no HAT is received before the
150 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
151 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
152 /// The cleanup counter is decremented every time a new receiver is added.
153 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
154 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
155}
156
157impl Default for TokenReceiverMap {
158 fn default() -> Self {
159 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
160 }
161}
162
163impl TokenReceiverMap {
164 /// There is a chance that receivers may become stale because their operation is dropped
165 /// without ever being authorized. So occasionally we iterate through the map and throw
166 /// out obsolete entries.
167 /// This is the number of calls to add_receiver between cleanups.
168 const CLEANUP_PERIOD: u8 = 25;
169
170 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
171 let mut map = self.map_and_cleanup_counter.lock().unwrap();
172 let (ref mut map, _) = *map;
173 if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
174 recv.add_auth_token(hat);
175 }
176 }
177
178 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
179 let mut map = self.map_and_cleanup_counter.lock().unwrap();
180 let (ref mut map, ref mut cleanup_counter) = *map;
181 map.insert(challenge, recv);
182
183 *cleanup_counter -= 1;
184 if *cleanup_counter == 0 {
185 map.retain(|_, v| !v.is_obsolete());
186 map.shrink_to_fit();
187 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
188 }
189 }
190}
191
192#[derive(Debug)]
193struct TokenReceiver(Weak<Mutex<AuthRequest>>);
194
195impl TokenReceiver {
196 fn is_obsolete(&self) -> bool {
197 self.0.upgrade().is_none()
198 }
199
200 fn add_auth_token(&self, hat: HardwareAuthToken) {
201 if let Some(state_arc) = self.0.upgrade() {
202 let mut state = state_arc.lock().unwrap();
203 state.add_auth_token(hat);
204 }
205 }
206}
207
208fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
Stephen Crane221bbb52020-12-16 15:52:10 -0800209 let dev: Strong<dyn ISecureClock> = get_timestamp_service()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800210 .expect(concat!(
211 "Secure Clock service must be present ",
212 "if TimeStampTokens are required."
213 ))
214 .get_interface()
215 .expect("Fatal: Timestamp service does not implement ISecureClock.");
216 map_binder_status(dev.generateTimeStamp(challenge))
217}
218
219fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
220 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
221 log::info!(
222 concat!(
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000223 "In timestamp_token_request: Receiver hung up ",
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800224 "before timestamp token could be delivered. {:?}"
225 ),
226 e
227 );
228 }
229}
230
231impl AuthInfo {
232 /// This function gets called after an operation was successfully created.
233 /// It makes all the preparations required, so that the operation has all the authentication
234 /// related artifacts to advance on update and finish.
235 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
236 match &self.state {
237 DeferredAuthState::OpAuthRequired => {
238 let auth_request = AuthRequest::op_auth();
239 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
240 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
241
242 self.state = DeferredAuthState::Waiting(auth_request);
243 Some(OperationChallenge { challenge })
244 }
245 DeferredAuthState::TimeStampedOpAuthRequired => {
246 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
247 let auth_request = AuthRequest::timestamped_op_auth(receiver);
248 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
249 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
250
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800251 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800252 self.state = DeferredAuthState::Waiting(auth_request);
253 Some(OperationChallenge { challenge })
254 }
255 DeferredAuthState::TimeStampRequired(hat) => {
256 let hat = (*hat).clone();
257 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
258 let auth_request = AuthRequest::timestamp(hat, receiver);
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800259 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800260 self.state = DeferredAuthState::Waiting(auth_request);
261 None
262 }
263 _ => None,
264 }
265 }
266
Qi Wub9433b52020-12-01 14:52:46 +0800267 /// This function is the authorization hook called before operation update.
268 /// It returns the auth tokens required by the operation to commence update.
269 pub fn before_update(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
270 self.get_auth_tokens()
271 }
272
273 /// This function is the authorization hook called before operation finish.
274 /// It returns the auth tokens required by the operation to commence finish.
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800275 /// The third token is a confirmation token.
276 pub fn before_finish(
277 &mut self,
278 ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>, Option<Vec<u8>>)> {
279 let mut confirmation_token: Option<Vec<u8>> = None;
280 if let Some(ref confirmation_token_receiver) = self.confirmation_token_receiver {
281 let locked_receiver = confirmation_token_receiver.lock().unwrap();
282 if let Some(ref receiver) = *locked_receiver {
283 loop {
284 match receiver.try_recv() {
285 // As long as we get tokens we loop and discard all but the most
286 // recent one.
287 Ok(t) => confirmation_token = Some(t),
288 Err(TryRecvError::Empty) => break,
289 Err(TryRecvError::Disconnected) => {
290 log::error!(concat!(
291 "We got disconnected from the APC service, ",
292 "this should never happen."
293 ));
294 break;
295 }
296 }
297 }
298 }
299 }
300 self.get_auth_tokens().map(|(hat, tst)| (hat, tst, confirmation_token))
Qi Wub9433b52020-12-01 14:52:46 +0800301 }
302
303 /// This function is the authorization hook called after finish succeeded.
304 /// As of this writing it checks if the key was a limited use key. If so it updates the
305 /// use counter of the key in the database. When the use counter is depleted, the key gets
306 /// marked for deletion and the garbage collector is notified.
307 pub fn after_finish(&self) -> Result<()> {
308 if let Some(key_id) = self.key_usage_limited {
309 // On the last successful use, the key gets deleted. In this case we
310 // have to notify the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800311 DB.with(|db| {
312 db.borrow_mut()
313 .check_and_update_key_usage_count(key_id)
314 .context("Trying to update key usage count.")
315 })
316 .context("In after_finish.")?;
Qi Wub9433b52020-12-01 14:52:46 +0800317 }
318 Ok(())
319 }
320
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800321 /// This function returns the auth tokens as needed by the ongoing operation or fails
322 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
323 /// after a deferred authorization was requested by finalize_create_authorization, this
324 /// function may block on the generation of a time stamp token. It then moves the
325 /// tokens into the DeferredAuthState::Token state for future use.
Qi Wub9433b52020-12-01 14:52:46 +0800326 fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800327 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
328 let mut state = auth_request.lock().unwrap();
329 Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
330 } else {
331 None
332 };
333
334 if let Some((hat, tst)) = deferred_tokens {
335 self.state = DeferredAuthState::Token(hat, tst);
336 }
337
338 match &self.state {
339 DeferredAuthState::NoAuthRequired => Ok((None, None)),
340 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
341 DeferredAuthState::OpAuthRequired
342 | DeferredAuthState::TimeStampedOpAuthRequired
343 | DeferredAuthState::TimeStampRequired(_) => {
344 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
345 "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
346 "This should not happen."
347 ))
348 }
349 // This should not be reachable, because it should have been handled above.
350 DeferredAuthState::Waiting(_) => {
351 Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
352 }
353 }
354 }
355}
356
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000357/// Enforcements data structure
Paul Crowley7c57bf12021-02-02 16:26:57 -0800358#[derive(Default)]
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000359pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800360 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
361 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000362 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800363 /// This field maps outstanding auth challenges to their operations. When an auth token
364 /// with the right challenge is received it is passed to the map using
365 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
366 /// stale, because the operation gets dropped before an auth token is received, the map
367 /// is cleaned up in regular intervals.
368 op_auth_map: TokenReceiverMap,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800369 /// The enforcement module will try to get a confirmation token from this channel whenever
370 /// an operation that requires confirmation finishes.
371 confirmation_token_receiver: Arc<Mutex<Option<Receiver<Vec<u8>>>>>,
Paul Crowley7c57bf12021-02-02 16:26:57 -0800372 /// Highest boot level seen in keystore.boot_level; used to enforce MAX_BOOT_LEVEL tag.
373 boot_level: AtomicI32,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000374}
375
376impl Enforcements {
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800377 /// Install the confirmation token receiver. The enforcement module will try to get a
378 /// confirmation token from this channel whenever an operation that requires confirmation
379 /// finishes.
380 pub fn install_confirmation_token_receiver(
381 &self,
382 confirmation_token_receiver: Receiver<Vec<u8>>,
383 ) {
384 *self.confirmation_token_receiver.lock().unwrap() = Some(confirmation_token_receiver);
385 }
386
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000387 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800388 /// It returns an optional immediate auth token which can be presented to begin, and an
389 /// AuthInfo object which stays with the authorized operation and is used to obtain
390 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000391 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800392 ///
393 /// If no key parameters are given (typically when the client is self managed
394 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000395 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800396 /// If the above step is successful, and if requires_timestamp is given, the returned
397 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000398 pub fn authorize_create(
399 &self,
400 purpose: KeyPurpose,
Qi Wub9433b52020-12-01 14:52:46 +0800401 key_properties: Option<&(i64, Vec<KeyParameter>)>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800402 op_params: &[KmKeyParameter],
403 requires_timestamp: bool,
404 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
Qi Wub9433b52020-12-01 14:52:46 +0800405 let (key_id, key_params) = match key_properties {
406 Some((key_id, key_params)) => (*key_id, key_params),
407 None => {
408 return Ok((
409 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800410 AuthInfo {
411 state: DeferredAuthState::NoAuthRequired,
412 key_usage_limited: None,
413 confirmation_token_receiver: None,
414 },
Qi Wub9433b52020-12-01 14:52:46 +0800415 ))
416 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800417 };
418
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000419 match purpose {
420 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
421 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
422 // Rule out WRAP_KEY purpose
423 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800424 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000425 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
426 }
Bram Bonnéa6b83822021-01-20 11:10:05 +0100427 // Allow AGREE_KEY for EC keys only.
428 KeyPurpose::AGREE_KEY => {
429 for kp in key_params.iter() {
430 if kp.get_tag() == Tag::ALGORITHM
431 && *kp.key_parameter_value() != KeyParameterValue::Algorithm(Algorithm::EC)
432 {
433 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
434 "In authorize_create: key agreement is only supported for EC keys.",
435 );
436 }
437 }
438 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000439 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
440 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
441 // asymmetric keys.
442 for kp in key_params.iter() {
443 match *kp.key_parameter_value() {
444 KeyParameterValue::Algorithm(Algorithm::RSA)
445 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800446 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000447 "In authorize_create: public operations on asymmetric keys are not
448 supported.",
449 );
450 }
451 _ => {}
452 }
453 }
454 }
455 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800456 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000457 .context("In authorize_create: specified purpose is not supported.");
458 }
459 }
460 // The following variables are to record information from key parameters to be used in
461 // enforcements, when two or more such pieces of information are required for enforcements.
462 // There is only one additional variable than what legacy keystore has, but this helps
463 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
464 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000465 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000466 let mut no_auth_required: bool = false;
467 let mut caller_nonce_allowed = false;
468 let mut user_id: i32 = -1;
469 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000470 let mut key_time_out: Option<i64> = None;
471 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000472 let mut unlocked_device_required = false;
Qi Wub9433b52020-12-01 14:52:46 +0800473 let mut key_usage_limited: Option<i64> = None;
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800474 let mut confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>> = None;
Paul Crowley7c57bf12021-02-02 16:26:57 -0800475 let mut max_boot_level: Option<i32> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000476
477 // iterate through key parameters, recording information we need for authorization
478 // enforcements later, or enforcing authorizations in place, where applicable
479 for key_param in key_params.iter() {
480 match key_param.key_parameter_value() {
481 KeyParameterValue::NoAuthRequired => {
482 no_auth_required = true;
483 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000484 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000485 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000486 }
487 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000488 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000489 }
490 KeyParameterValue::KeyPurpose(p) => {
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800491 // The following check has the effect of key_params.contains(purpose)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000492 // Also, authorizing purpose can not be completed here, if there can be multiple
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800493 // key parameters for KeyPurpose.
494 key_purpose_authorized = key_purpose_authorized || *p == purpose;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000495 }
496 KeyParameterValue::CallerNonce => {
497 caller_nonce_allowed = true;
498 }
499 KeyParameterValue::ActiveDateTime(a) => {
500 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800501 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000502 .context("In authorize_create: key is not yet active.");
503 }
504 }
505 KeyParameterValue::OriginationExpireDateTime(o) => {
506 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
507 && Enforcements::is_given_time_passed(*o, false)
508 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800509 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000510 .context("In authorize_create: key is expired.");
511 }
512 }
513 KeyParameterValue::UsageExpireDateTime(u) => {
514 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
515 && Enforcements::is_given_time_passed(*u, false)
516 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800517 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000518 .context("In authorize_create: key is expired.");
519 }
520 }
521 KeyParameterValue::UserSecureID(s) => {
522 user_secure_ids.push(*s);
523 }
524 KeyParameterValue::UserID(u) => {
525 user_id = *u;
526 }
527 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000528 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000529 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000530 KeyParameterValue::AllowWhileOnBody => {
531 allow_while_on_body = true;
532 }
Qi Wub9433b52020-12-01 14:52:46 +0800533 KeyParameterValue::UsageCountLimit(_) => {
534 // We don't examine the limit here because this is enforced on finish.
535 // Instead, we store the key_id so that finish can look up the key
536 // in the database again and check and update the counter.
537 key_usage_limited = Some(key_id);
538 }
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800539 KeyParameterValue::TrustedConfirmationRequired => {
540 confirmation_token_receiver = Some(self.confirmation_token_receiver.clone());
541 }
Paul Crowley7c57bf12021-02-02 16:26:57 -0800542 KeyParameterValue::MaxBootLevel(level) => {
543 max_boot_level = Some(*level);
544 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000545 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
546 // create operation if any non-allowed tags are present, is not done in
547 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800548 // a subset of non-allowed tags are present). Because sanitizing key parameters
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000549 // should have been done during generate/import key, by KeyMint.
550 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
551 }
552 }
553
554 // authorize the purpose
555 if !key_purpose_authorized {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800556 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000557 .context("In authorize_create: the purpose is not authorized.");
558 }
559
560 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
561 if !user_secure_ids.is_empty() && no_auth_required {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800562 return Err(Error::Km(Ec::INVALID_KEY_BLOB)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000563 "In authorize_create: key has both NO_AUTH_REQUIRED
564 and USER_SECURE_ID tags.",
565 );
566 }
567
568 // 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 +0000569 if (user_auth_type.is_some() && user_secure_ids.is_empty())
570 || (user_auth_type.is_none() && !user_secure_ids.is_empty())
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000571 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800572 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000573 "In authorize_create: Auth required, but either auth type or secure ids
574 are not present.",
575 );
576 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800577
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000578 // validate caller nonce for origination purposes
579 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
580 && !caller_nonce_allowed
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800581 && op_params.iter().any(|kp| kp.tag == Tag::NONCE)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000582 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800583 return Err(Error::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000584 "In authorize_create, NONCE is present,
585 although CALLER_NONCE is not present",
586 );
587 }
588
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000589 if unlocked_device_required {
590 // check the device locked status. If locked, operations on the key are not
591 // allowed.
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000592 if self.is_device_locked(user_id) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800593 return Err(Error::Km(Ec::DEVICE_LOCKED))
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000594 .context("In authorize_create: device is locked.");
595 }
596 }
597
Paul Crowley7c57bf12021-02-02 16:26:57 -0800598 if let Some(level) = max_boot_level {
599 if level < self.boot_level.load(Ordering::SeqCst) {
600 return Err(Error::Km(Ec::BOOT_LEVEL_EXCEEDED))
601 .context("In authorize_create: boot level is too late.");
602 }
603 }
604
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800605 if !unlocked_device_required && no_auth_required {
Qi Wub9433b52020-12-01 14:52:46 +0800606 return Ok((
607 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800608 AuthInfo {
609 state: DeferredAuthState::NoAuthRequired,
610 key_usage_limited,
611 confirmation_token_receiver,
612 },
Qi Wub9433b52020-12-01 14:52:46 +0800613 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000614 }
615
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800616 let has_sids = !user_secure_ids.is_empty();
617
618 let timeout_bound = key_time_out.is_some() && has_sids;
619
620 let per_op_bound = key_time_out.is_none() && has_sids;
621
622 let need_auth_token = timeout_bound || unlocked_device_required;
623
624 let hat_and_last_off_body = if need_auth_token {
625 let hat_and_last_off_body = Self::find_auth_token(|hat: &AuthTokenEntry| {
626 if let (Some(auth_type), true) = (user_auth_type, has_sids) {
627 hat.satisfies(&user_secure_ids, auth_type)
628 } else {
629 unlocked_device_required
630 }
631 })
632 .context("In authorize_create: Trying to get required auth token.")?;
633 Some(
634 hat_and_last_off_body
635 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
636 .context("In authorize_create: No suitable auth token found.")?,
637 )
638 } else {
639 None
640 };
641
642 // Now check the validity of the auth token if the key is timeout bound.
643 let hat = match (hat_and_last_off_body, key_time_out) {
644 (Some((hat, last_off_body)), Some(key_time_out)) => {
645 let now = MonotonicRawTime::now();
646 let token_age = now
647 .checked_sub(&hat.time_received())
648 .ok_or_else(Error::sys)
649 .context(concat!(
650 "In authorize_create: Overflow while computing Auth token validity. ",
651 "Validity cannot be established."
652 ))?;
653
654 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
655
656 if token_age.seconds() > key_time_out && !on_body_extended {
657 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
658 .context("In authorize_create: matching auth token is expired.");
659 }
660 Some(hat)
661 }
662 (Some((hat, _)), None) => Some(hat),
663 // If timeout_bound is true, above code must have retrieved a HAT or returned with
664 // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
665 (None, Some(_)) => panic!("Logical error."),
666 _ => None,
667 };
668
669 Ok(match (hat, requires_timestamp, per_op_bound) {
670 // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
671 // device required. In addition, this KM instance needs a timestamp token.
672 // So the HAT cannot be presented on create. So on update/finish we present both
673 // an per-op-bound auth token and a timestamp token.
674 (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
675 (Some(hat), true, false) => {
676 (None, DeferredAuthState::TimeStampRequired(hat.take_auth_token()))
677 }
678 (Some(hat), false, true) => {
679 (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
680 }
681 (Some(hat), false, false) => {
682 (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
683 }
684 (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
685 (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
686 })
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800687 .map(|(hat, state)| {
688 (hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver })
689 })
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800690 }
691
692 fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
693 where
694 F: Fn(&AuthTokenEntry) -> bool,
695 {
696 DB.with(|db| {
697 let mut db = db.borrow_mut();
698 db.find_auth_token_entry(p).context("Trying to find auth token.")
699 })
700 .context("In find_auth_token.")
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000701 }
702
703 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
704 /// set) the given time (in milliseconds)
705 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
706 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
707
708 let time_since_epoch = match duration_since_epoch {
709 Ok(duration) => duration.as_millis(),
710 Err(_) => return false,
711 };
712
713 if is_given_time_inclusive {
714 time_since_epoch >= (given_time as u128)
715 } else {
716 time_since_epoch > (given_time as u128)
717 }
718 }
719
720 /// Check if the device is locked for the given user. If there's no entry yet for the user,
721 /// we assume that the device is locked
722 fn is_device_locked(&self, user_id: i32) -> bool {
723 // unwrap here because there's no way this mutex guard can be poisoned and
724 // because there's no way to recover, even if it is poisoned.
725 let set = self.device_unlocked_set.lock().unwrap();
726 !set.contains(&user_id)
727 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000728
729 /// Sets the device locked status for the user. This method is called externally.
730 pub fn set_device_locked(&self, user_id: i32, device_locked_status: bool) {
731 // unwrap here because there's no way this mutex guard can be poisoned and
732 // because there's no way to recover, even if it is poisoned.
733 let mut set = self.device_unlocked_set.lock().unwrap();
734 if device_locked_status {
735 set.remove(&user_id);
736 } else {
737 set.insert(user_id);
738 }
739 }
740
741 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800742 /// Then present the auth token to the op auth map. If an operation is waiting for this
743 /// auth token this fulfills the request and removes the receiver from the map.
744 pub fn add_auth_token(&self, hat: HardwareAuthToken) -> Result<()> {
745 DB.with(|db| db.borrow_mut().insert_auth_token(&hat)).context("In add_auth_token.")?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000746
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800747 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000748 Ok(())
749 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000750
751 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
752 /// This is to be called by create_operation, once it has received the operation challenge
753 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800754 /// by the DeferredAuthState.
755 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
756 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000757 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000758
759 /// Given the set of key parameters and flags, check if super encryption is required.
Paul Crowley7a658392021-03-18 17:08:20 -0700760 pub fn super_encryption_required(
761 domain: &Domain,
762 key_parameters: &[KeyParameter],
763 flags: Option<i32>,
764 ) -> SuperEncryptionType {
765 if *domain != Domain::APP {
766 return SuperEncryptionType::None;
767 }
768 if let Some(flags) = flags {
769 if (flags & KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING) != 0 {
770 return SuperEncryptionType::None;
771 }
772 }
773 if key_parameters
774 .iter()
775 .any(|kp| matches!(kp.key_parameter_value(), KeyParameterValue::UnlockedDeviceRequired))
776 {
777 return SuperEncryptionType::ScreenLockBound;
778 }
779 if key_parameters
780 .iter()
781 .any(|kp| matches!(kp.key_parameter_value(), KeyParameterValue::UserSecureID(_)))
782 {
783 return SuperEncryptionType::LskfBound;
784 }
785 SuperEncryptionType::None
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000786 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000787
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000788 /// Finds a matching auth token along with a timestamp token.
789 /// This method looks through auth-tokens cached by keystore which satisfy the given
790 /// authentication information (i.e. |secureUserId|).
791 /// The most recent matching auth token which has a |challenge| field which matches
792 /// the passed-in |challenge| parameter is returned.
793 /// In this case the |authTokenMaxAgeMillis| parameter is not used.
794 ///
795 /// Otherwise, the most recent matching auth token which is younger than |authTokenMaxAgeMillis|
796 /// is returned.
797 pub fn get_auth_tokens(
798 &self,
799 challenge: i64,
800 secure_user_id: i64,
801 auth_token_max_age_millis: i64,
802 ) -> Result<(HardwareAuthToken, TimeStampToken)> {
803 let auth_type = HardwareAuthenticatorType::ANY;
804 let sids: Vec<i64> = vec![secure_user_id];
805 // Filter the matching auth tokens by challenge
806 let result = Self::find_auth_token(|hat: &AuthTokenEntry| {
807 (challenge == hat.challenge()) && hat.satisfies(&sids, auth_type)
808 })
809 .context(
810 "In get_auth_tokens: Failed to get a matching auth token filtered by challenge.",
811 )?;
812
813 let auth_token = if let Some((auth_token_entry, _)) = result {
814 auth_token_entry.take_auth_token()
815 } else {
816 // Filter the matching auth tokens by age.
817 if auth_token_max_age_millis != 0 {
818 let now_in_millis = MonotonicRawTime::now().milli_seconds();
819 let result = Self::find_auth_token(|auth_token_entry: &AuthTokenEntry| {
820 let token_valid = now_in_millis
821 .checked_sub(auth_token_entry.time_received().milli_seconds())
822 .map_or(false, |token_age_in_millis| {
Hasini Gunasinghe971dbb62021-03-23 14:57:34 +0000823 auth_token_max_age_millis > token_age_in_millis
Hasini Gunasingheb3715fb2021-02-26 20:34:45 +0000824 });
825 token_valid && auth_token_entry.satisfies(&sids, auth_type)
826 })
827 .context(
828 "In get_auth_tokens: Failed to get a matching auth token filtered by age.",
829 )?;
830
831 if let Some((auth_token_entry, _)) = result {
832 auth_token_entry.take_auth_token()
833 } else {
834 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
835 .context("In get_auth_tokens: No auth token found.");
836 }
837 } else {
838 return Err(AuthzError::Rc(AuthzResponseCode::NO_AUTH_TOKEN_FOUND))
839 .context("In get_auth_tokens: Passed-in auth token max age is zero.");
840 }
841 };
842 // Wait and obtain the timestamp token from secure clock service.
843 let tst = get_timestamp_token(challenge)
844 .context("In get_auth_tokens. Error in getting timestamp token.")?;
845 Ok((auth_token, tst))
846 }
847
Paul Crowley7c57bf12021-02-02 16:26:57 -0800848 /// Watch the `keystore.boot_level` system property, and keep self.boot_level up to date.
849 /// Blocks waiting for system property changes, so must be run in its own thread.
850 pub fn watch_boot_level(&self) -> Result<()> {
851 let mut w = PropertyWatcher::new("keystore.boot_level")?;
852 loop {
853 fn parse_value(_name: &str, value: &str) -> Result<Option<i32>> {
854 Ok(if value == "end" { None } else { Some(value.parse::<i32>()?) })
855 }
856 match w.read(parse_value)? {
857 Some(level) => {
858 let old = self.boot_level.fetch_max(level, Ordering::SeqCst);
859 log::info!(
860 "Read keystore.boot_level: {}; boot level {} -> {}",
861 level,
862 old,
863 std::cmp::max(old, level)
864 );
865 }
866 None => {
867 log::info!("keystore.boot_level is `end`, finishing.");
868 self.boot_level.fetch_max(i32::MAX, Ordering::SeqCst);
869 break;
870 }
871 }
872 w.wait()?;
873 }
874 Ok(())
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000875 }
876}
877
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000878// TODO: Add tests to enforcement module (b/175578618).