blob: 1c64833c2fc8a5bd94486c1a9d96c4305caeb1f6 [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
15//TODO: remove this after implementing the methods.
16#![allow(dead_code)]
17
18//! This is the Keystore 2.0 Enforcements module.
19// TODO: more description to follow.
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000020use crate::auth_token_handler::AuthTokenHandler;
21use crate::database::AuthTokenEntry;
22use crate::error::Error as KeystoreError;
23use crate::key_parameter::{KeyParameter, KeyParameterValue};
24use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000025 Algorithm::Algorithm, ErrorCode::ErrorCode as Ec, HardwareAuthToken::HardwareAuthToken,
26 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyPurpose::KeyPurpose,
27 SecurityLevel::SecurityLevel, Tag::Tag,
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000028};
29use android_system_keystore2::aidl::android::system::keystore2::OperationChallenge::OperationChallenge;
30use anyhow::{Context, Result};
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000031use std::collections::{HashMap, HashSet};
32use std::sync::Mutex;
Hasini Gunasinghe5112c702020-11-09 22:13:25 +000033use std::time::SystemTime;
Hasini Gunasinghe3410f792020-09-14 17:55:21 +000034
35/// Enforcements data structure
36pub struct Enforcements {
37 // This hash set contains the user ids for whom the device is currently unlocked. If a user id
38 // is not in the set, it implies that the device is locked for the user.
39 device_unlocked_set: Mutex<HashSet<i32>>,
40 // This maps the operation challenge to an optional auth token, to maintain op-auth tokens
41 // in-memory, until they are picked up and given to the operation by authorise_update_finish().
42 op_auth_map: Mutex<HashMap<i64, Option<HardwareAuthToken>>>,
43}
44
45impl Enforcements {
46 /// Creates an enforcement object with the two data structures it holds.
47 pub fn new() -> Self {
48 Enforcements {
49 device_unlocked_set: Mutex::new(HashSet::new()),
50 op_auth_map: Mutex::new(HashMap::new()),
51 }
52 }
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +000053
54 /// Checks if update or finish calls are authorized. If the operation is based on per-op key,
55 /// try to receive the auth token from the op_auth_map. We assume that by the time update/finish
56 /// is called, the auth token has been delivered to keystore. Therefore, we do not wait for it
57 /// and if the auth token is not found in the map, an error is returned.
58 pub fn authorize_update_or_finish(
59 &self,
60 key_params: &[KeyParameter],
61 op_challenge: Option<OperationChallenge>,
62 ) -> Result<AuthTokenHandler> {
63 let mut user_auth_type: Option<HardwareAuthenticatorType> = None;
64 let mut user_secure_ids = Vec::<i64>::new();
65 let mut is_timeout_key = false;
66
67 for key_param in key_params.iter() {
68 match key_param.key_parameter_value() {
69 KeyParameterValue::NoAuthRequired => {
70 // unlike in authorize_create, we do not check if both NoAuthRequired and user
71 // secure id are present, because that is already checked in authorize_create.
72 return Ok(AuthTokenHandler::NoAuthRequired);
73 }
74 KeyParameterValue::AuthTimeout(_) => {
75 is_timeout_key = true;
76 }
77 KeyParameterValue::HardwareAuthenticatorType(a) => {
78 user_auth_type = Some(*a);
79 }
80 KeyParameterValue::UserSecureID(u) => {
81 user_secure_ids.push(*u);
82 }
83 _ => {}
84 }
85 }
86
87 // If either of auth_type or secure_id is present and the other is not present,
88 // authorize_create would have already returned error.
89 // At this point, if UserSecureID is present and AuthTimeout is not present in
90 // key parameters, per-op auth is required.
91 // Obtain and validate the auth token.
92 if !is_timeout_key && !user_secure_ids.is_empty() {
93 let challenge =
94 op_challenge.ok_or(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
95 "In authorize_update_or_finish: Auth required, but operation challenge is not
96 present.",
97 )?;
98 let auth_type =
99 user_auth_type.ok_or(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
100 "In authorize_update_or_finish: Auth required, but authenticator type is not
101 present.",
102 )?;
103 // It is ok to unwrap here, because there is no way this lock can get poisoned and
104 // and there is no way to recover if it is poisoned.
105 let mut op_auth_map_guard = self.op_auth_map.lock().unwrap();
106 let auth_entry = op_auth_map_guard.remove(&(challenge.challenge));
107
108 match auth_entry {
109 Some(Some(auth_token)) => {
110 if AuthTokenEntry::satisfies_auth(&auth_token, &user_secure_ids, auth_type) {
111 return Ok(AuthTokenHandler::Token(auth_token, None));
112 } else {
113 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED))
114 .context("In authorize_update_or_finish: Auth token does not match.");
115 }
116 }
117 _ => {
118 // there was no auth token
119 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
120 "In authorize_update_or_finish: Auth required, but an auth token
121 is not found for the given operation challenge, in the op_auth_map.",
122 );
123 }
124 }
125 }
126
127 // If we don't find HardwareAuthenticatorType and UserSecureID, we assume that
128 // authentication is not required, because in legacy keys, authentication related
129 // key parameters may not present.
130 // TODO: METRICS: count how many times (if any) this code path is executed, in order
131 // to identify if any such keys are in use
132 Ok(AuthTokenHandler::NoAuthRequired)
133 }
Hasini Gunasinghe5112c702020-11-09 22:13:25 +0000134
135 /// Checks if a create call is authorized, given key parameters and operation parameters.
136 /// With regard to auth tokens, the following steps are taken:
137 /// If the key is time-bound, find a matching auth token from the database.
138 /// If the above step is successful, and if the security level is STRONGBOX, return a
139 /// VerificationRequired variant of the AuthTokenHandler with the found auth token to signal
140 /// the operation that it may need to obtain a verification token from TEE KeyMint.
141 /// If the security level is not STRONGBOX, return a Token variant of the AuthTokenHandler with
142 /// the found auth token to signal the operation that no more authorization required.
143 /// If the key is per-op, return an OpAuthRequired variant of the AuthTokenHandler to signal
144 /// create_operation() that it needs to add the operation challenge to the op_auth_map, once it
145 /// is received from the keymint, and that operation needs to be authorized before update/finish
146 /// is called.
147 pub fn authorize_create(
148 &self,
149 purpose: KeyPurpose,
150 key_params: &[KeyParameter],
151 op_params: &[KeyParameter],
152 // security_level will be used in the next CL
153 _security_level: SecurityLevel,
154 ) -> Result<AuthTokenHandler> {
155 match purpose {
156 // Allow SIGN, DECRYPT for both symmetric and asymmetric keys.
157 KeyPurpose::SIGN | KeyPurpose::DECRYPT => {}
158 // Rule out WRAP_KEY purpose
159 KeyPurpose::WRAP_KEY => {
160 return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
161 .context("In authorize_create: WRAP_KEY purpose is not allowed here.");
162 }
163 KeyPurpose::VERIFY | KeyPurpose::ENCRYPT => {
164 // We do not support ENCRYPT and VERIFY (the remaining two options of purpose) for
165 // asymmetric keys.
166 for kp in key_params.iter() {
167 match *kp.key_parameter_value() {
168 KeyParameterValue::Algorithm(Algorithm::RSA)
169 | KeyParameterValue::Algorithm(Algorithm::EC) => {
170 return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE)).context(
171 "In authorize_create: public operations on asymmetric keys are not
172 supported.",
173 );
174 }
175 _ => {}
176 }
177 }
178 }
179 _ => {
180 return Err(KeystoreError::Km(Ec::UNSUPPORTED_PURPOSE))
181 .context("In authorize_create: specified purpose is not supported.");
182 }
183 }
184 // The following variables are to record information from key parameters to be used in
185 // enforcements, when two or more such pieces of information are required for enforcements.
186 // There is only one additional variable than what legacy keystore has, but this helps
187 // reduce the number of for loops on key parameters from 3 to 1, compared to legacy keystore
188 let mut key_purpose_authorized: bool = false;
189 let mut is_time_out_key: bool = false;
190 let mut auth_type: Option<HardwareAuthenticatorType> = None;
191 let mut no_auth_required: bool = false;
192 let mut caller_nonce_allowed = false;
193 let mut user_id: i32 = -1;
194 let mut user_secure_ids = Vec::<i64>::new();
195
196 // iterate through key parameters, recording information we need for authorization
197 // enforcements later, or enforcing authorizations in place, where applicable
198 for key_param in key_params.iter() {
199 match key_param.key_parameter_value() {
200 KeyParameterValue::NoAuthRequired => {
201 no_auth_required = true;
202 }
203 KeyParameterValue::AuthTimeout(_) => {
204 is_time_out_key = true;
205 }
206 KeyParameterValue::HardwareAuthenticatorType(a) => {
207 auth_type = Some(*a);
208 }
209 KeyParameterValue::KeyPurpose(p) => {
210 // Note: if there can be multiple KeyPurpose key parameters (TODO: confirm this),
211 // following check has the effect of key_params.contains(purpose)
212 // Also, authorizing purpose can not be completed here, if there can be multiple
213 // key parameters for KeyPurpose
214 if !key_purpose_authorized && *p == purpose {
215 key_purpose_authorized = true;
216 }
217 }
218 KeyParameterValue::CallerNonce => {
219 caller_nonce_allowed = true;
220 }
221 KeyParameterValue::ActiveDateTime(a) => {
222 if !Enforcements::is_given_time_passed(*a, true) {
223 return Err(KeystoreError::Km(Ec::KEY_NOT_YET_VALID))
224 .context("In authorize_create: key is not yet active.");
225 }
226 }
227 KeyParameterValue::OriginationExpireDateTime(o) => {
228 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
229 && Enforcements::is_given_time_passed(*o, false)
230 {
231 return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
232 .context("In authorize_create: key is expired.");
233 }
234 }
235 KeyParameterValue::UsageExpireDateTime(u) => {
236 if (purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY)
237 && Enforcements::is_given_time_passed(*u, false)
238 {
239 return Err(KeystoreError::Km(Ec::KEY_EXPIRED))
240 .context("In authorize_create: key is expired.");
241 }
242 }
243 KeyParameterValue::UserSecureID(s) => {
244 user_secure_ids.push(*s);
245 }
246 KeyParameterValue::UserID(u) => {
247 user_id = *u;
248 }
249 KeyParameterValue::UnlockedDeviceRequired => {
250 // check the device locked status. If locked, operations on the key are not
251 // allowed.
252 if self.is_device_locked(user_id) {
253 return Err(KeystoreError::Km(Ec::DEVICE_LOCKED))
254 .context("In authorize_create: device is locked.");
255 }
256 }
257 // NOTE: as per offline discussion, sanitizing key parameters and rejecting
258 // create operation if any non-allowed tags are present, is not done in
259 // authorize_create (unlike in legacy keystore where AuthorizeBegin is rejected if
260 // a subset of non-allowed tags are present). Because santizing key parameters
261 // should have been done during generate/import key, by KeyMint.
262 _ => { /*Do nothing on all the other key parameters, as in legacy keystore*/ }
263 }
264 }
265
266 // authorize the purpose
267 if !key_purpose_authorized {
268 return Err(KeystoreError::Km(Ec::INCOMPATIBLE_PURPOSE))
269 .context("In authorize_create: the purpose is not authorized.");
270 }
271
272 // if both NO_AUTH_REQUIRED and USER_SECURE_ID tags are present, return error
273 if !user_secure_ids.is_empty() && no_auth_required {
274 return Err(KeystoreError::Km(Ec::INVALID_KEY_BLOB)).context(
275 "In authorize_create: key has both NO_AUTH_REQUIRED
276 and USER_SECURE_ID tags.",
277 );
278 }
279
280 // if either of auth_type or secure_id is present and the other is not present, return error
281 if (auth_type.is_some() && user_secure_ids.is_empty())
282 || (auth_type.is_none() && !user_secure_ids.is_empty())
283 {
284 return Err(KeystoreError::Km(Ec::KEY_USER_NOT_AUTHENTICATED)).context(
285 "In authorize_create: Auth required, but either auth type or secure ids
286 are not present.",
287 );
288 }
289 // validate caller nonce for origination purposes
290 if (purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN)
291 && !caller_nonce_allowed
292 && op_params.iter().any(|kp| kp.get_tag() == Tag::NONCE)
293 {
294 return Err(KeystoreError::Km(Ec::CALLER_NONCE_PROHIBITED)).context(
295 "In authorize_create, NONCE is present,
296 although CALLER_NONCE is not present",
297 );
298 }
299
300 if !user_secure_ids.is_empty() {
301 // per op auth token
302 if !is_time_out_key {
303 return Ok(AuthTokenHandler::OpAuthRequired);
304 } else {
305 //time out token
306 // TODO: retrieve it from the database
307 // - in an upcoming CL
308 }
309 }
310
311 // If we reach here, all authorization enforcements have passed and no auth token required.
312 Ok(AuthTokenHandler::NoAuthRequired)
313 }
314
315 /// Checks if the time now since epoch is greater than (or equal, if is_given_time_inclusive is
316 /// set) the given time (in milliseconds)
317 fn is_given_time_passed(given_time: i64, is_given_time_inclusive: bool) -> bool {
318 let duration_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
319
320 let time_since_epoch = match duration_since_epoch {
321 Ok(duration) => duration.as_millis(),
322 Err(_) => return false,
323 };
324
325 if is_given_time_inclusive {
326 time_since_epoch >= (given_time as u128)
327 } else {
328 time_since_epoch > (given_time as u128)
329 }
330 }
331
332 /// Check if the device is locked for the given user. If there's no entry yet for the user,
333 /// we assume that the device is locked
334 fn is_device_locked(&self, user_id: i32) -> bool {
335 // unwrap here because there's no way this mutex guard can be poisoned and
336 // because there's no way to recover, even if it is poisoned.
337 let set = self.device_unlocked_set.lock().unwrap();
338 !set.contains(&user_id)
339 }
Hasini Gunasinghe3410f792020-09-14 17:55:21 +0000340}
341
342impl Default for Enforcements {
343 fn default() -> Self {
344 Self::new()
345 }
346}
347
Hasini Gunasinghe52333ba2020-11-06 01:24:16 +0000348// TODO: Add tests to enforcement module (b/175578618).