blob: cc59c32fea71298813a1cd82dd1878d9b5f014d1 [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};
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};
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +000029use android_system_keystore2::aidl::android::system::keystore2::{
30 IKeystoreSecurityLevel::KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING,
31 OperationChallenge::OperationChallenge,
32};
Stephen Crane221bbb52020-12-16 15:52:10 -080033use android_system_keystore2::binder::Strong;
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000034use anyhow::{Context, Result};
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080035use std::sync::{
36 mpsc::{channel, Receiver, Sender},
37 Arc, Mutex, Weak,
38};
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000039use std::time::SystemTime;
Janis Danisevskisb1673db2021-02-08 18:11:57 -080040use std::{
41 collections::{HashMap, HashSet},
42 sync::mpsc::TryRecvError,
43};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000044
Janis Danisevskis5ed8c532021-01-11 14:19:42 -080045#[derive(Debug)]
46enum AuthRequestState {
47 /// An outstanding per operation authorization request.
48 OpAuth,
49 /// An outstanding request for per operation authorization and secure timestamp.
50 TimeStampedOpAuth(Receiver<Result<TimeStampToken, Error>>),
51 /// An outstanding request for a timestamp token.
52 TimeStamp(Receiver<Result<TimeStampToken, Error>>),
53}
54
55#[derive(Debug)]
56struct AuthRequest {
57 state: AuthRequestState,
58 /// This need to be set to Some to fulfill a AuthRequestState::OpAuth or
59 /// AuthRequestState::TimeStampedOpAuth.
60 hat: Option<HardwareAuthToken>,
61}
62
63impl AuthRequest {
64 fn op_auth() -> Arc<Mutex<Self>> {
65 Arc::new(Mutex::new(Self { state: AuthRequestState::OpAuth, hat: None }))
66 }
67
68 fn timestamped_op_auth(receiver: Receiver<Result<TimeStampToken, Error>>) -> Arc<Mutex<Self>> {
69 Arc::new(Mutex::new(Self {
70 state: AuthRequestState::TimeStampedOpAuth(receiver),
71 hat: None,
72 }))
73 }
74
75 fn timestamp(
76 hat: HardwareAuthToken,
77 receiver: Receiver<Result<TimeStampToken, Error>>,
78 ) -> Arc<Mutex<Self>> {
79 Arc::new(Mutex::new(Self { state: AuthRequestState::TimeStamp(receiver), hat: Some(hat) }))
80 }
81
82 fn add_auth_token(&mut self, hat: HardwareAuthToken) {
83 self.hat = Some(hat)
84 }
85
86 fn get_auth_tokens(&mut self) -> Result<(HardwareAuthToken, Option<TimeStampToken>)> {
87 match (&self.state, self.hat.is_some()) {
88 (AuthRequestState::OpAuth, true) => Ok((self.hat.take().unwrap(), None)),
89 (AuthRequestState::TimeStampedOpAuth(recv), true)
90 | (AuthRequestState::TimeStamp(recv), true) => {
91 let result = recv.recv().context("In get_auth_tokens: Sender disconnected.")?;
92 let tst = result.context(concat!(
93 "In get_auth_tokens: Worker responded with error ",
94 "from generating timestamp token."
95 ))?;
96 Ok((self.hat.take().unwrap(), Some(tst)))
97 }
98 (_, false) => Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED))
99 .context("In get_auth_tokens: No operation auth token received."),
100 }
101 }
102}
103
104/// DeferredAuthState describes how auth tokens and timestamp tokens need to be provided when
105/// updating and finishing an operation.
106#[derive(Debug)]
107enum DeferredAuthState {
108 /// Used when an operation does not require further authorization.
109 NoAuthRequired,
110 /// Indicates that the operation requires an operation specific token. This means we have
111 /// to return an operation challenge to the client which should reward us with an
112 /// operation specific auth token. If it is not provided before the client calls update
113 /// or finish, the operation fails as not authorized.
114 OpAuthRequired,
115 /// Indicates that the operation requires a time stamp token. The auth token was already
116 /// loaded from the database, but it has to be accompanied by a time stamp token to inform
117 /// the target KM with a different clock about the time on the authenticators.
118 TimeStampRequired(HardwareAuthToken),
119 /// Indicates that both an operation bound auth token and a verification token are
120 /// before the operation can commence.
121 TimeStampedOpAuthRequired,
122 /// In this state the auth info is waiting for the deferred authorizations to come in.
123 /// We block on timestamp tokens, because we can always make progress on these requests.
124 /// The per-op auth tokens might never come, which means we fail if the client calls
125 /// update or finish before we got a per-op auth token.
126 Waiting(Arc<Mutex<AuthRequest>>),
127 /// In this state we have gotten all of the required tokens, we just cache them to
128 /// be used when the operation progresses.
129 Token(HardwareAuthToken, Option<TimeStampToken>),
130}
131
132/// Auth info hold all of the authorization related information of an operation. It is stored
133/// in and owned by the operation. It is constructed by authorize_create and stays with the
134/// operation until it completes.
135#[derive(Debug)]
136pub struct AuthInfo {
137 state: DeferredAuthState,
Qi Wub9433b52020-12-01 14:52:46 +0800138 /// An optional key id required to update the usage count if the key usage is limited.
139 key_usage_limited: Option<i64>,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800140 confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800141}
142
143struct TokenReceiverMap {
144 /// The map maps an outstanding challenge to a TokenReceiver. If an incoming Hardware Auth
145 /// Token (HAT) has the map key in its challenge field, it gets passed to the TokenReceiver
146 /// and the entry is removed from the map. In the case where no HAT is received before the
147 /// corresponding operation gets dropped, the entry goes stale. So every time the cleanup
148 /// counter (second field in the tuple) turns 0, the map is cleaned from stale entries.
149 /// The cleanup counter is decremented every time a new receiver is added.
150 /// and reset to TokenReceiverMap::CLEANUP_PERIOD + 1 after each cleanup.
151 map_and_cleanup_counter: Mutex<(HashMap<i64, TokenReceiver>, u8)>,
152}
153
154impl Default for TokenReceiverMap {
155 fn default() -> Self {
156 Self { map_and_cleanup_counter: Mutex::new((HashMap::new(), Self::CLEANUP_PERIOD + 1)) }
157 }
158}
159
160impl TokenReceiverMap {
161 /// There is a chance that receivers may become stale because their operation is dropped
162 /// without ever being authorized. So occasionally we iterate through the map and throw
163 /// out obsolete entries.
164 /// This is the number of calls to add_receiver between cleanups.
165 const CLEANUP_PERIOD: u8 = 25;
166
167 pub fn add_auth_token(&self, hat: HardwareAuthToken) {
168 let mut map = self.map_and_cleanup_counter.lock().unwrap();
169 let (ref mut map, _) = *map;
170 if let Some((_, recv)) = map.remove_entry(&hat.challenge) {
171 recv.add_auth_token(hat);
172 }
173 }
174
175 pub fn add_receiver(&self, challenge: i64, recv: TokenReceiver) {
176 let mut map = self.map_and_cleanup_counter.lock().unwrap();
177 let (ref mut map, ref mut cleanup_counter) = *map;
178 map.insert(challenge, recv);
179
180 *cleanup_counter -= 1;
181 if *cleanup_counter == 0 {
182 map.retain(|_, v| !v.is_obsolete());
183 map.shrink_to_fit();
184 *cleanup_counter = Self::CLEANUP_PERIOD + 1;
185 }
186 }
187}
188
189#[derive(Debug)]
190struct TokenReceiver(Weak<Mutex<AuthRequest>>);
191
192impl TokenReceiver {
193 fn is_obsolete(&self) -> bool {
194 self.0.upgrade().is_none()
195 }
196
197 fn add_auth_token(&self, hat: HardwareAuthToken) {
198 if let Some(state_arc) = self.0.upgrade() {
199 let mut state = state_arc.lock().unwrap();
200 state.add_auth_token(hat);
201 }
202 }
203}
204
205fn get_timestamp_token(challenge: i64) -> Result<TimeStampToken, Error> {
Stephen Crane221bbb52020-12-16 15:52:10 -0800206 let dev: Strong<dyn ISecureClock> = get_timestamp_service()
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800207 .expect(concat!(
208 "Secure Clock service must be present ",
209 "if TimeStampTokens are required."
210 ))
211 .get_interface()
212 .expect("Fatal: Timestamp service does not implement ISecureClock.");
213 map_binder_status(dev.generateTimeStamp(challenge))
214}
215
216fn timestamp_token_request(challenge: i64, sender: Sender<Result<TimeStampToken, Error>>) {
217 if let Err(e) = sender.send(get_timestamp_token(challenge)) {
218 log::info!(
219 concat!(
220 "In timestamp_token_request: Operation hung up ",
221 "before timestamp token could be delivered. {:?}"
222 ),
223 e
224 );
225 }
226}
227
228impl AuthInfo {
229 /// This function gets called after an operation was successfully created.
230 /// It makes all the preparations required, so that the operation has all the authentication
231 /// related artifacts to advance on update and finish.
232 pub fn finalize_create_authorization(&mut self, challenge: i64) -> Option<OperationChallenge> {
233 match &self.state {
234 DeferredAuthState::OpAuthRequired => {
235 let auth_request = AuthRequest::op_auth();
236 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
237 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
238
239 self.state = DeferredAuthState::Waiting(auth_request);
240 Some(OperationChallenge { challenge })
241 }
242 DeferredAuthState::TimeStampedOpAuthRequired => {
243 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
244 let auth_request = AuthRequest::timestamped_op_auth(receiver);
245 let token_receiver = TokenReceiver(Arc::downgrade(&auth_request));
246 ENFORCEMENTS.register_op_auth_receiver(challenge, token_receiver);
247
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800248 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800249 self.state = DeferredAuthState::Waiting(auth_request);
250 Some(OperationChallenge { challenge })
251 }
252 DeferredAuthState::TimeStampRequired(hat) => {
253 let hat = (*hat).clone();
254 let (sender, receiver) = channel::<Result<TimeStampToken, Error>>();
255 let auth_request = AuthRequest::timestamp(hat, receiver);
Janis Danisevskis40f0e6b2021-02-10 15:48:44 -0800256 ASYNC_TASK.queue_hi(move |_| timestamp_token_request(challenge, sender));
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800257 self.state = DeferredAuthState::Waiting(auth_request);
258 None
259 }
260 _ => None,
261 }
262 }
263
Qi Wub9433b52020-12-01 14:52:46 +0800264 /// This function is the authorization hook called before operation update.
265 /// It returns the auth tokens required by the operation to commence update.
266 pub fn before_update(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
267 self.get_auth_tokens()
268 }
269
270 /// This function is the authorization hook called before operation finish.
271 /// It returns the auth tokens required by the operation to commence finish.
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800272 /// The third token is a confirmation token.
273 pub fn before_finish(
274 &mut self,
275 ) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>, Option<Vec<u8>>)> {
276 let mut confirmation_token: Option<Vec<u8>> = None;
277 if let Some(ref confirmation_token_receiver) = self.confirmation_token_receiver {
278 let locked_receiver = confirmation_token_receiver.lock().unwrap();
279 if let Some(ref receiver) = *locked_receiver {
280 loop {
281 match receiver.try_recv() {
282 // As long as we get tokens we loop and discard all but the most
283 // recent one.
284 Ok(t) => confirmation_token = Some(t),
285 Err(TryRecvError::Empty) => break,
286 Err(TryRecvError::Disconnected) => {
287 log::error!(concat!(
288 "We got disconnected from the APC service, ",
289 "this should never happen."
290 ));
291 break;
292 }
293 }
294 }
295 }
296 }
297 self.get_auth_tokens().map(|(hat, tst)| (hat, tst, confirmation_token))
Qi Wub9433b52020-12-01 14:52:46 +0800298 }
299
300 /// This function is the authorization hook called after finish succeeded.
301 /// As of this writing it checks if the key was a limited use key. If so it updates the
302 /// use counter of the key in the database. When the use counter is depleted, the key gets
303 /// marked for deletion and the garbage collector is notified.
304 pub fn after_finish(&self) -> Result<()> {
305 if let Some(key_id) = self.key_usage_limited {
306 // On the last successful use, the key gets deleted. In this case we
307 // have to notify the garbage collector.
Janis Danisevskis7e8b4622021-02-13 10:01:59 -0800308 DB.with(|db| {
309 db.borrow_mut()
310 .check_and_update_key_usage_count(key_id)
311 .context("Trying to update key usage count.")
312 })
313 .context("In after_finish.")?;
Qi Wub9433b52020-12-01 14:52:46 +0800314 }
315 Ok(())
316 }
317
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800318 /// This function returns the auth tokens as needed by the ongoing operation or fails
319 /// with ErrorCode::KEY_USER_NOT_AUTHENTICATED. If this was called for the first time
320 /// after a deferred authorization was requested by finalize_create_authorization, this
321 /// function may block on the generation of a time stamp token. It then moves the
322 /// tokens into the DeferredAuthState::Token state for future use.
Qi Wub9433b52020-12-01 14:52:46 +0800323 fn get_auth_tokens(&mut self) -> Result<(Option<HardwareAuthToken>, Option<TimeStampToken>)> {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800324 let deferred_tokens = if let DeferredAuthState::Waiting(ref auth_request) = self.state {
325 let mut state = auth_request.lock().unwrap();
326 Some(state.get_auth_tokens().context("In AuthInfo::get_auth_tokens.")?)
327 } else {
328 None
329 };
330
331 if let Some((hat, tst)) = deferred_tokens {
332 self.state = DeferredAuthState::Token(hat, tst);
333 }
334
335 match &self.state {
336 DeferredAuthState::NoAuthRequired => Ok((None, None)),
337 DeferredAuthState::Token(hat, tst) => Ok((Some((*hat).clone()), (*tst).clone())),
338 DeferredAuthState::OpAuthRequired
339 | DeferredAuthState::TimeStampedOpAuthRequired
340 | DeferredAuthState::TimeStampRequired(_) => {
341 Err(Error::Km(ErrorCode::KEY_USER_NOT_AUTHENTICATED)).context(concat!(
342 "In AuthInfo::get_auth_tokens: No operation auth token requested??? ",
343 "This should not happen."
344 ))
345 }
346 // This should not be reachable, because it should have been handled above.
347 DeferredAuthState::Waiting(_) => {
348 Err(Error::sys()).context("In AuthInfo::get_auth_tokens: Cannot be reached.")
349 }
350 }
351 }
352}
353
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000354/// Enforcements data structure
355pub struct Enforcements {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800356 /// This hash set contains the user ids for whom the device is currently unlocked. If a user id
357 /// is not in the set, it implies that the device is locked for the user.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000358 device_unlocked_set: Mutex<HashSet<i32>>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800359 /// This field maps outstanding auth challenges to their operations. When an auth token
360 /// with the right challenge is received it is passed to the map using
361 /// TokenReceiverMap::add_auth_token() which removes the entry from the map. If an entry goes
362 /// stale, because the operation gets dropped before an auth token is received, the map
363 /// is cleaned up in regular intervals.
364 op_auth_map: TokenReceiverMap,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800365 /// The enforcement module will try to get a confirmation token from this channel whenever
366 /// an operation that requires confirmation finishes.
367 confirmation_token_receiver: Arc<Mutex<Option<Receiver<Vec<u8>>>>>,
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000368}
369
370impl Enforcements {
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000371 /// Creates an enforcement object with the two data structures it holds and the sender as None.
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000372 pub fn new() -> Self {
373 Enforcements {
374 device_unlocked_set: Mutex::new(HashSet::new()),
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800375 op_auth_map: Default::default(),
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800376 confirmation_token_receiver: Default::default(),
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000377 }
378 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000379
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800380 /// Install the confirmation token receiver. The enforcement module will try to get a
381 /// confirmation token from this channel whenever an operation that requires confirmation
382 /// finishes.
383 pub fn install_confirmation_token_receiver(
384 &self,
385 confirmation_token_receiver: Receiver<Vec<u8>>,
386 ) {
387 *self.confirmation_token_receiver.lock().unwrap() = Some(confirmation_token_receiver);
388 }
389
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000390 /// Checks if a create call is authorized, given key parameters and operation parameters.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800391 /// It returns an optional immediate auth token which can be presented to begin, and an
392 /// AuthInfo object which stays with the authorized operation and is used to obtain
393 /// auth tokens and timestamp tokens as required by the operation.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000394 /// With regard to auth tokens, the following steps are taken:
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800395 ///
396 /// If no key parameters are given (typically when the client is self managed
397 /// (see Domain.Blob)) nothing is enforced.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000398 /// If the key is time-bound, find a matching auth token from the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800399 /// If the above step is successful, and if requires_timestamp is given, the returned
400 /// AuthInfo will provide a Timestamp token as appropriate.
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000401 pub fn authorize_create(
402 &self,
403 purpose: KeyPurpose,
Qi Wub9433b52020-12-01 14:52:46 +0800404 key_properties: Option<&(i64, Vec<KeyParameter>)>,
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800405 op_params: &[KmKeyParameter],
406 requires_timestamp: bool,
407 ) -> Result<(Option<HardwareAuthToken>, AuthInfo)> {
Qi Wub9433b52020-12-01 14:52:46 +0800408 let (key_id, key_params) = match key_properties {
409 Some((key_id, key_params)) => (*key_id, key_params),
410 None => {
411 return Ok((
412 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800413 AuthInfo {
414 state: DeferredAuthState::NoAuthRequired,
415 key_usage_limited: None,
416 confirmation_token_receiver: None,
417 },
Qi Wub9433b52020-12-01 14:52:46 +0800418 ))
419 }
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800420 };
421
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000422 match purpose {
423 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
424 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
425 // Rule out WRAP_KEY purpose
426 KeyPurpose::WRAP_KEY => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800427 return Err(Error::Km(Ec::INCOMPATIBLE_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000428 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
429 }
Bram Bonnéa6b83822021-01-20 11:10:05 +0100430 // Allow AGREE_KEY for EC keys only.
431 KeyPurpose::AGREE_KEY => {
432 for kp in key_params.iter() {
433 if kp.get_tag() == Tag::ALGORITHM
434 && *kp.key_parameter_value() != KeyParameterValue::Algorithm(Algorithm::EC)
435 {
436 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
437 "In authorize_create: key agreement is only supported for EC keys.",
438 );
439 }
440 }
441 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000442 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
443 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
444 // asymmetric keys.
445 for kp in key_params.iter() {
446 match *kp.key_parameter_value() {
447 KeyParameterValue::Algorithm(Algorithm::RSA)
448 | KeyParameterValue::Algorithm(Algorithm::EC) => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800449 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE)).context(
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000450 "In authorize_create: public operations on asymmetric keys are not
451 supported.",
452 );
453 }
454 _ => {}
455 }
456 }
457 }
458 _ => {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800459 return Err(Error::Km(Ec::UNSUPPORTED_PURPOSE))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000460 .context("In authorize_create: specified purpose is not supported.");
461 }
462 }
463 // The following variables are to record information from key parameters to be used in
464 // enforcements, when two or more such pieces of information are required for enforcements.
465 // There is only one additional variable than what legacy keystore has, but this helps
466 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
467 let mut key_purpose_authorized: bool = false;
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000468 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000469 let mut no_auth_required: bool = false;
470 let mut caller_nonce_allowed = false;
471 let mut user_id: i32 = -1;
472 let mut user_secure_ids = Vec::<i64>::new();
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000473 let mut key_time_out: Option<i64> = None;
474 let mut allow_while_on_body = false;
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000475 let mut unlocked_device_required = false;
Qi Wub9433b52020-12-01 14:52:46 +0800476 let mut key_usage_limited: Option<i64> = None;
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800477 let mut confirmation_token_receiver: Option<Arc<Mutex<Option<Receiver<Vec<u8>>>>>> = None;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000478
479 // iterate through key parameters, recording information we need for authorization
480 // enforcements later, or enforcing authorizations in place, where applicable
481 for key_param in key_params.iter() {
482 match key_param.key_parameter_value() {
483 KeyParameterValue::NoAuthRequired => {
484 no_auth_required = true;
485 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000486 KeyParameterValue::AuthTimeout(t) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000487 key_time_out = Some(*t as i64);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000488 }
489 KeyParameterValue::HardwareAuthenticatorType(a) => {
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000490 user_auth_type = Some(*a);
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000491 }
492 KeyParameterValue::KeyPurpose(p) => {
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800493 // The following check has the effect of key_params.contains(purpose)
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000494 // Also, authorizing purpose can not be completed here, if there can be multiple
Janis Danisevskis104d8e42021-01-14 22:49:27 -0800495 // key parameters for KeyPurpose.
496 key_purpose_authorized = key_purpose_authorized || *p == purpose;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000497 }
498 KeyParameterValue::CallerNonce => {
499 caller_nonce_allowed = true;
500 }
501 KeyParameterValue::ActiveDateTime(a) => {
502 if !Enforcements::is_given_time_passed(*a, true) {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800503 return Err(Error::Km(Ec::KEY_NOT_YET_VALID))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000504 .context("In authorize_create: key is not yet active.");
505 }
506 }
507 KeyParameterValue::OriginationExpireDateTime(o) => {
508 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
509 && Enforcements::is_given_time_passed(*o, false)
510 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800511 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000512 .context("In authorize_create: key is expired.");
513 }
514 }
515 KeyParameterValue::UsageExpireDateTime(u) => {
516 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
517 && Enforcements::is_given_time_passed(*u, false)
518 {
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800519 return Err(Error::Km(Ec::KEY_EXPIRED))
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000520 .context("In authorize_create: key is expired.");
521 }
522 }
523 KeyParameterValue::UserSecureID(s) => {
524 user_secure_ids.push(*s);
525 }
526 KeyParameterValue::UserID(u) => {
527 user_id = *u;
528 }
529 KeyParameterValue::UnlockedDeviceRequired => {
Hasini Gunasinghea020b532021-01-07 21:42:35 +0000530 unlocked_device_required = true;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000531 }
Hasini Gunasinghef70cf8e2020-11-11 01:02:41 +0000532 KeyParameterValue::AllowWhileOnBody => {
533 allow_while_on_body = true;
534 }
Qi Wub9433b52020-12-01 14:52:46 +0800535 KeyParameterValue::UsageCountLimit(_) => {
536 // We don't examine the limit here because this is enforced on finish.
537 // Instead, we store the key_id so that finish can look up the key
538 // in the database again and check and update the counter.
539 key_usage_limited = Some(key_id);
540 }
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800541 KeyParameterValue::TrustedConfirmationRequired => {
542 confirmation_token_receiver = Some(self.confirmation_token_receiver.clone());
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
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800597 if !unlocked_device_required && no_auth_required {
Qi Wub9433b52020-12-01 14:52:46 +0800598 return Ok((
599 None,
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800600 AuthInfo {
601 state: DeferredAuthState::NoAuthRequired,
602 key_usage_limited,
603 confirmation_token_receiver,
604 },
Qi Wub9433b52020-12-01 14:52:46 +0800605 ));
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000606 }
607
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800608 let has_sids = !user_secure_ids.is_empty();
609
610 let timeout_bound = key_time_out.is_some() && has_sids;
611
612 let per_op_bound = key_time_out.is_none() && has_sids;
613
614 let need_auth_token = timeout_bound || unlocked_device_required;
615
616 let hat_and_last_off_body = if need_auth_token {
617 let hat_and_last_off_body = Self::find_auth_token(|hat: &AuthTokenEntry| {
618 if let (Some(auth_type), true) = (user_auth_type, has_sids) {
619 hat.satisfies(&user_secure_ids, auth_type)
620 } else {
621 unlocked_device_required
622 }
623 })
624 .context("In authorize_create: Trying to get required auth token.")?;
625 Some(
626 hat_and_last_off_body
627 .ok_or(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
628 .context("In authorize_create: No suitable auth token found.")?,
629 )
630 } else {
631 None
632 };
633
634 // Now check the validity of the auth token if the key is timeout bound.
635 let hat = match (hat_and_last_off_body, key_time_out) {
636 (Some((hat, last_off_body)), Some(key_time_out)) => {
637 let now = MonotonicRawTime::now();
638 let token_age = now
639 .checked_sub(&hat.time_received())
640 .ok_or_else(Error::sys)
641 .context(concat!(
642 "In authorize_create: Overflow while computing Auth token validity. ",
643 "Validity cannot be established."
644 ))?;
645
646 let on_body_extended = allow_while_on_body && last_off_body < hat.time_received();
647
648 if token_age.seconds() > key_time_out && !on_body_extended {
649 return Err(Error::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
650 .context("In authorize_create: matching auth token is expired.");
651 }
652 Some(hat)
653 }
654 (Some((hat, _)), None) => Some(hat),
655 // If timeout_bound is true, above code must have retrieved a HAT or returned with
656 // KEY_USER_NOT_AUTHENTICATED. This arm should not be reachable.
657 (None, Some(_)) => panic!("Logical error."),
658 _ => None,
659 };
660
661 Ok(match (hat, requires_timestamp, per_op_bound) {
662 // Per-op-bound and Some(hat) can only happen if we are both per-op bound and unlocked
663 // device required. In addition, this KM instance needs a timestamp token.
664 // So the HAT cannot be presented on create. So on update/finish we present both
665 // an per-op-bound auth token and a timestamp token.
666 (Some(_), true, true) => (None, DeferredAuthState::TimeStampedOpAuthRequired),
667 (Some(hat), true, false) => {
668 (None, DeferredAuthState::TimeStampRequired(hat.take_auth_token()))
669 }
670 (Some(hat), false, true) => {
671 (Some(hat.take_auth_token()), DeferredAuthState::OpAuthRequired)
672 }
673 (Some(hat), false, false) => {
674 (Some(hat.take_auth_token()), DeferredAuthState::NoAuthRequired)
675 }
676 (None, _, true) => (None, DeferredAuthState::OpAuthRequired),
677 (None, _, false) => (None, DeferredAuthState::NoAuthRequired),
678 })
Janis Danisevskisb1673db2021-02-08 18:11:57 -0800679 .map(|(hat, state)| {
680 (hat, AuthInfo { state, key_usage_limited, confirmation_token_receiver })
681 })
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800682 }
683
684 fn find_auth_token<F>(p: F) -> Result<Option<(AuthTokenEntry, MonotonicRawTime)>>
685 where
686 F: Fn(&AuthTokenEntry) -> bool,
687 {
688 DB.with(|db| {
689 let mut db = db.borrow_mut();
690 db.find_auth_token_entry(p).context("Trying to find auth token.")
691 })
692 .context("In find_auth_token.")
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000693 }
694
695 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
696 /// set) the given time (in milliseconds)
697 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
698 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
699
700 let time_since_epoch = match duration_since_epoch {
701 Ok(duration) => duration.as_millis(),
702 Err(_) => return false,
703 };
704
705 if is_given_time_inclusive {
706 time_since_epoch >= (given_time as u128)
707 } else {
708 time_since_epoch > (given_time as u128)
709 }
710 }
711
712 /// Check if the device is locked for the given user. If there's no entry yet for the user,
713 /// we assume that the device is locked
714 fn is_device_locked(&self, user_id: i32) -> bool {
715 // unwrap here because there's no way this mutex guard can be poisoned and
716 // because there's no way to recover, even if it is poisoned.
717 let set = self.device_unlocked_set.lock().unwrap();
718 !set.contains(&user_id)
719 }
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000720
721 /// Sets the device locked status for the user. This method is called externally.
722 pub fn set_device_locked(&self, user_id: i32, device_locked_status: 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 mut set = self.device_unlocked_set.lock().unwrap();
726 if device_locked_status {
727 set.remove(&user_id);
728 } else {
729 set.insert(user_id);
730 }
731 }
732
733 /// Add this auth token to the database.
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800734 /// Then present the auth token to the op auth map. If an operation is waiting for this
735 /// auth token this fulfills the request and removes the receiver from the map.
736 pub fn add_auth_token(&self, hat: HardwareAuthToken) -> Result<()> {
737 DB.with(|db| db.borrow_mut().insert_auth_token(&hat)).context("In add_auth_token.")?;
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000738
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800739 self.op_auth_map.add_auth_token(hat);
Hasini Gunasinghe557b1032020-11-10 01:35:30 +0000740 Ok(())
741 }
Hasini Gunasinghe888dd352020-11-17 23:08:39 +0000742
743 /// This allows adding an entry to the op_auth_map, indexed by the operation challenge.
744 /// This is to be called by create_operation, once it has received the operation challenge
745 /// from keymint for an operation whose authorization decision is OpAuthRequired, as signalled
Janis Danisevskis5ed8c532021-01-11 14:19:42 -0800746 /// by the DeferredAuthState.
747 fn register_op_auth_receiver(&self, challenge: i64, recv: TokenReceiver) {
748 self.op_auth_map.add_receiver(challenge, recv);
Hasini Gunasinghef04d07a2020-11-25 22:41:35 +0000749 }
Hasini Gunasinghedeab85d2021-02-01 21:10:02 +0000750
751 /// Given the set of key parameters and flags, check if super encryption is required.
752 pub fn super_encryption_required(key_parameters: &[KeyParameter], flags: Option<i32>) -> bool {
753 let auth_bound = key_parameters.iter().any(|kp| kp.get_tag() == Tag::USER_SECURE_ID);
754
755 let skip_lskf_binding = if let Some(flags) = flags {
756 (flags & KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING) != 0
757 } else {
758 false
759 };
760
761 auth_bound && !skip_lskf_binding
762 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000763}
764
765impl Default for Enforcements {
766 fn default() -> Self {
767 Self::new()
768 }
769}
770
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000771// TODO: Add tests to enforcement module (b/175578618).