1 // Copyright 2022, 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 //! TA functionality related to in-progress crypto operations. 16 17 use alloc::{boxed::Box, vec::Vec}; 18 use kmr_common::{ 19 crypto, 20 crypto::{aes, AadOperation, AccumulatingOperation, EmittingOperation, KeyMaterial}, 21 get_bool_tag_value, get_opt_tag_value, get_tag_value, keyblob, km_err, tag, try_to_vec, Error, 22 FallibleAllocExt, 23 }; 24 use kmr_wire::{ 25 keymint::{ErrorCode, HardwareAuthToken, KeyParam, KeyPurpose}, 26 secureclock::{TimeStampToken, Timestamp}, 27 InternalBeginResult, 28 }; 29 use log::{error, info, warn}; 30 31 /// A trusted confirmation token should be the size of HMAC-SHA256 output. 32 const CONFIRMATION_TOKEN_SIZE: usize = 32; 33 34 /// Trusted confirmation data prefix, from IConfirmationResultCallback.hal. 35 const CONFIRMATION_DATA_PREFIX: &[u8] = b"confirmation token"; 36 37 /// Maximum size of messages with `Tag::TrustedConfirmationRequired` set. 38 /// See <https://source.android.com/security/protected-confirmation/implementation> 39 const CONFIRMATION_MESSAGE_MAX_LEN: usize = 6144; 40 41 /// Union holder for in-progress cryptographic operations, each of which is an instance 42 /// of the relevant trait. 43 pub(crate) enum CryptoOperation { 44 Aes(Box<dyn EmittingOperation>), 45 AesGcm(Box<dyn AadOperation>), 46 Des(Box<dyn EmittingOperation>), 47 HmacSign(Box<dyn AccumulatingOperation>, usize), // tag length 48 HmacVerify(Box<dyn AccumulatingOperation>, core::ops::Range<usize>), 49 RsaDecrypt(Box<dyn AccumulatingOperation>), 50 RsaSign(Box<dyn AccumulatingOperation>), 51 EcAgree(Box<dyn AccumulatingOperation>), 52 EcSign(Box<dyn AccumulatingOperation>), 53 } 54 55 /// Current state of an operation. 56 pub(crate) struct Operation { 57 /// Random handle used to identify the operation, also used as a challenge. 58 pub handle: OpHandle, 59 60 /// Whether update_aad() is allowed (only ever true for AEADs before data has arrived). 61 pub aad_allowed: bool, 62 63 /// Secure deletion slot to delete on successful completion of the operation. 64 pub slot_to_delete: Option<keyblob::SecureDeletionSlot>, 65 66 /// Buffer to accumulate data being signed that must have a trusted confirmation. This 67 /// data matches what was been fed into `crypto_op`'s `update` method (but has a size 68 /// limit so will not grow unboundedly). 69 pub trusted_conf_data: Option<Vec<u8>>, 70 71 /// Authentication data to check. 72 pub auth_info: Option<AuthInfo>, 73 74 pub crypto_op: CryptoOperation, 75 76 /// Accumulated input size. 77 pub input_size: usize, 78 } 79 80 impl Operation { 81 /// Check whether `len` additional bytes of data can be accommodated by the `Operation`. check_size(&mut self, len: usize) -> Result<(), Error>82 fn check_size(&mut self, len: usize) -> Result<(), Error> { 83 self.input_size += len; 84 let max_size = match &self.crypto_op { 85 CryptoOperation::HmacSign(op, _) 86 | CryptoOperation::HmacVerify(op, _) 87 | CryptoOperation::RsaDecrypt(op) 88 | CryptoOperation::RsaSign(op) 89 | CryptoOperation::EcAgree(op) 90 | CryptoOperation::EcSign(op) => op.max_input_size(), 91 _ => None, 92 }; 93 if let Some(max_size) = max_size { 94 if self.input_size > max_size { 95 return Err(km_err!( 96 InvalidInputLength, 97 "too much input accumulated for operation" 98 )); 99 } 100 } 101 Ok(()) 102 } 103 } 104 105 /// Newtype for operation handles. 106 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 107 pub(crate) struct OpHandle(pub i64); 108 109 /// Authentication requirements associated with an operation. 110 pub(crate) struct AuthInfo { 111 secure_ids: Vec<u64>, 112 auth_type: u32, 113 timeout_secs: Option<u32>, 114 } 115 116 impl AuthInfo { 117 /// Optionally build an `AuthInfo` from key characteristics. If no authentication is needed on 118 /// `update()`/`update_aad()`/`finish()`, return `None`. new(key_chars: &[KeyParam]) -> Result<Option<AuthInfo>, Error>119 fn new(key_chars: &[KeyParam]) -> Result<Option<AuthInfo>, Error> { 120 let mut secure_ids = Vec::new(); 121 let mut auth_type = None; 122 let mut timeout_secs = None; 123 let mut no_auth_required = false; 124 125 for param in key_chars { 126 match param { 127 KeyParam::UserSecureId(sid) => secure_ids.try_push(*sid)?, 128 KeyParam::UserAuthType(atype) => { 129 if auth_type.is_none() { 130 auth_type = Some(*atype); 131 } else { 132 return Err(km_err!(InvalidKeyBlob, "duplicate UserAuthType tag found")); 133 } 134 } 135 KeyParam::AuthTimeout(secs) => { 136 if timeout_secs.is_none() { 137 timeout_secs = Some(*secs) 138 } else { 139 return Err(km_err!(InvalidKeyBlob, "duplicate AuthTimeout tag found")); 140 } 141 } 142 KeyParam::NoAuthRequired => no_auth_required = true, 143 _ => {} 144 } 145 } 146 147 if secure_ids.is_empty() { 148 Ok(None) 149 } else if let Some(auth_type) = auth_type { 150 if no_auth_required { 151 Err(km_err!(InvalidKeyBlob, "found both NO_AUTH_REQUIRED and USER_SECURE_ID")) 152 } else { 153 Ok(Some(AuthInfo { secure_ids, auth_type, timeout_secs })) 154 } 155 } else { 156 Err(km_err!(KeyUserNotAuthenticated, "found USER_SECURE_ID but no USER_AUTH_TYPE")) 157 } 158 } 159 } 160 161 impl crate::KeyMintTa { begin_operation( &mut self, purpose: KeyPurpose, key_blob: &[u8], params: Vec<KeyParam>, auth_token: Option<HardwareAuthToken>, ) -> Result<InternalBeginResult, Error>162 pub(crate) fn begin_operation( 163 &mut self, 164 purpose: KeyPurpose, 165 key_blob: &[u8], 166 params: Vec<KeyParam>, 167 auth_token: Option<HardwareAuthToken>, 168 ) -> Result<InternalBeginResult, Error> { 169 let op_idx = self.new_operation_index()?; 170 171 // Parse and decrypt the keyblob, which requires extra hidden params. 172 let (keyblob, sdd_slot) = self.keyblob_parse_decrypt(key_blob, ¶ms)?; 173 let keyblob::PlaintextKeyBlob { characteristics, key_material } = keyblob; 174 175 // Validate parameters. 176 let key_chars = 177 kmr_common::tag::characteristics_at(&characteristics, self.hw_info.security_level)?; 178 tag::check_begin_params(key_chars, purpose, ¶ms)?; 179 self.check_begin_auths(key_chars, key_blob)?; 180 181 let trusted_conf_data = if purpose == KeyPurpose::Sign 182 && get_bool_tag_value!(key_chars, TrustedConfirmationRequired)? 183 { 184 // Trusted confirmation is required; accumulate the signed data in an extra buffer, 185 // starting with a prefix. 186 Some(try_to_vec(CONFIRMATION_DATA_PREFIX)?) 187 } else { 188 None 189 }; 190 191 let slot_to_delete = if let Some(&1) = get_opt_tag_value!(key_chars, UsageCountLimit)? { 192 warn!("single-use key will be deleted on operation completion"); 193 sdd_slot 194 } else { 195 None 196 }; 197 198 // At most one operation involving proof of user presence can be in-flight at a time. 199 let presence_required = get_bool_tag_value!(key_chars, TrustedUserPresenceRequired)?; 200 if presence_required && self.presence_required_op.is_some() { 201 return Err(km_err!( 202 ConcurrentProofOfPresenceRequested, 203 "additional op with proof-of-presence requested" 204 )); 205 } 206 207 let mut op_auth_info = AuthInfo::new(key_chars)?; 208 if let Some(auth_info) = &op_auth_info { 209 // Authentication checks are required on begin() if there's a timeout that 210 // we can check. 211 if let Some(timeout_secs) = auth_info.timeout_secs { 212 if let Some(clock) = &self.imp.clock { 213 let now: Timestamp = clock.now().into(); 214 let auth_token = auth_token.ok_or_else(|| { 215 km_err!(KeyUserNotAuthenticated, "no auth token on begin()") 216 })?; 217 self.check_auth_token( 218 auth_token, 219 auth_info, 220 Some(now), 221 Some(timeout_secs), 222 None, 223 )?; 224 225 // Auth already checked, nothing needed on subsequent calls 226 op_auth_info = None; 227 } else if let Some(auth_token) = auth_token { 228 self.check_auth_token(auth_token, auth_info, None, None, None)?; 229 } 230 } 231 } 232 233 // Re-use the same random value for both: 234 // - op_handle: the way to identify which operation is involved 235 // - challenge: the value used as part of the input for authentication tokens 236 let op_handle = self.new_op_handle(); 237 let challenge = op_handle.0; 238 let mut ret_params = Vec::new(); 239 let op = match key_material { 240 KeyMaterial::Aes(key) => { 241 let caller_nonce = get_opt_tag_value!(¶ms, Nonce)?; 242 let mode = aes::Mode::new(¶ms, caller_nonce, &mut *self.imp.rng)?; 243 let dir = match purpose { 244 KeyPurpose::Encrypt => crypto::SymmetricOperation::Encrypt, 245 KeyPurpose::Decrypt => crypto::SymmetricOperation::Decrypt, 246 _ => { 247 return Err(km_err!( 248 IncompatiblePurpose, 249 "invalid purpose {:?} for AES key", 250 purpose 251 )) 252 } 253 }; 254 if caller_nonce.is_none() { 255 // Need to return any randomly-generated nonce to the caller. 256 match &mode { 257 aes::Mode::Cipher(aes::CipherMode::EcbNoPadding) 258 | aes::Mode::Cipher(aes::CipherMode::EcbPkcs7Padding) => {} 259 aes::Mode::Cipher(aes::CipherMode::CbcNoPadding { nonce: n }) 260 | aes::Mode::Cipher(aes::CipherMode::CbcPkcs7Padding { nonce: n }) => { 261 ret_params.try_push(KeyParam::Nonce(try_to_vec(n)?))? 262 } 263 aes::Mode::Cipher(aes::CipherMode::Ctr { nonce: n }) => { 264 ret_params.try_push(KeyParam::Nonce(try_to_vec(n)?))? 265 } 266 aes::Mode::Aead(aes::GcmMode::GcmTag12 { nonce: n }) 267 | aes::Mode::Aead(aes::GcmMode::GcmTag13 { nonce: n }) 268 | aes::Mode::Aead(aes::GcmMode::GcmTag14 { nonce: n }) 269 | aes::Mode::Aead(aes::GcmMode::GcmTag15 { nonce: n }) 270 | aes::Mode::Aead(aes::GcmMode::GcmTag16 { nonce: n }) => { 271 ret_params.try_push(KeyParam::Nonce(try_to_vec(n)?))? 272 } 273 } 274 } 275 match &mode { 276 aes::Mode::Cipher(mode) => Operation { 277 handle: op_handle, 278 aad_allowed: false, 279 input_size: 0, 280 slot_to_delete, 281 trusted_conf_data, 282 auth_info: op_auth_info, 283 crypto_op: CryptoOperation::Aes(self.imp.aes.begin(key, *mode, dir)?), 284 }, 285 aes::Mode::Aead(mode) => Operation { 286 handle: op_handle, 287 aad_allowed: true, 288 input_size: 0, 289 slot_to_delete, 290 trusted_conf_data, 291 auth_info: op_auth_info, 292 crypto_op: CryptoOperation::AesGcm( 293 self.imp.aes.begin_aead(key, *mode, dir)?, 294 ), 295 }, 296 } 297 } 298 KeyMaterial::TripleDes(key) => { 299 let caller_nonce = get_opt_tag_value!(¶ms, Nonce)?; 300 let mode = crypto::des::Mode::new(¶ms, caller_nonce, &mut *self.imp.rng)?; 301 let dir = match purpose { 302 KeyPurpose::Encrypt => crypto::SymmetricOperation::Encrypt, 303 KeyPurpose::Decrypt => crypto::SymmetricOperation::Decrypt, 304 _ => { 305 return Err(km_err!( 306 IncompatiblePurpose, 307 "invalid purpose {:?} for DES key", 308 purpose 309 )) 310 } 311 }; 312 if caller_nonce.is_none() { 313 // Need to return any randomly-generated nonce to the caller. 314 match &mode { 315 crypto::des::Mode::EcbNoPadding | crypto::des::Mode::EcbPkcs7Padding => {} 316 crypto::des::Mode::CbcNoPadding { nonce: n } 317 | crypto::des::Mode::CbcPkcs7Padding { nonce: n } => { 318 ret_params.try_push(KeyParam::Nonce(try_to_vec(n)?))? 319 } 320 } 321 } 322 Operation { 323 handle: op_handle, 324 aad_allowed: false, 325 input_size: 0, 326 slot_to_delete, 327 trusted_conf_data, 328 auth_info: op_auth_info, 329 crypto_op: CryptoOperation::Des(self.imp.des.begin(key, mode, dir)?), 330 } 331 } 332 KeyMaterial::Hmac(key) => { 333 let digest = tag::get_digest(¶ms)?; 334 335 Operation { 336 handle: op_handle, 337 aad_allowed: false, 338 input_size: 0, 339 slot_to_delete, 340 trusted_conf_data, 341 auth_info: op_auth_info, 342 crypto_op: match purpose { 343 KeyPurpose::Sign => { 344 let tag_len = 345 get_tag_value!(¶ms, MacLength, ErrorCode::MissingMacLength)? 346 as usize 347 / 8; 348 CryptoOperation::HmacSign(self.imp.hmac.begin(key, digest)?, tag_len) 349 } 350 KeyPurpose::Verify => { 351 // Remember the acceptable tag lengths. 352 let min_tag_len = get_tag_value!( 353 key_chars, 354 MinMacLength, 355 ErrorCode::MissingMinMacLength 356 )? as usize 357 / 8; 358 let max_tag_len = kmr_common::tag::digest_len(digest)? as usize; 359 CryptoOperation::HmacVerify( 360 self.imp.hmac.begin(key, digest)?, 361 min_tag_len..max_tag_len, 362 ) 363 } 364 _ => { 365 return Err(km_err!( 366 IncompatiblePurpose, 367 "invalid purpose {:?} for HMAC key", 368 purpose 369 )) 370 } 371 }, 372 } 373 } 374 KeyMaterial::Rsa(key) => Operation { 375 handle: op_handle, 376 aad_allowed: false, 377 input_size: 0, 378 slot_to_delete, 379 trusted_conf_data, 380 auth_info: op_auth_info, 381 crypto_op: match purpose { 382 KeyPurpose::Decrypt => { 383 let mode = crypto::rsa::DecryptionMode::new(¶ms)?; 384 CryptoOperation::RsaDecrypt(self.imp.rsa.begin_decrypt(key, mode)?) 385 } 386 KeyPurpose::Sign => { 387 let mode = crypto::rsa::SignMode::new(¶ms)?; 388 CryptoOperation::RsaSign(self.imp.rsa.begin_sign(key, mode)?) 389 } 390 _ => { 391 return Err(km_err!( 392 IncompatiblePurpose, 393 "invalid purpose {:?} for RSA key", 394 purpose 395 )) 396 } 397 }, 398 }, 399 KeyMaterial::Ec(_, _, key) => Operation { 400 handle: op_handle, 401 aad_allowed: false, 402 input_size: 0, 403 slot_to_delete, 404 trusted_conf_data, 405 auth_info: op_auth_info, 406 crypto_op: match purpose { 407 KeyPurpose::AgreeKey => CryptoOperation::EcAgree(self.imp.ec.begin_agree(key)?), 408 KeyPurpose::Sign => { 409 let digest = tag::get_digest(¶ms)?; 410 CryptoOperation::EcSign(self.imp.ec.begin_sign(key, digest)?) 411 } 412 _ => { 413 return Err(km_err!( 414 IncompatiblePurpose, 415 "invalid purpose {:?} for EC key", 416 purpose 417 )) 418 } 419 }, 420 }, 421 }; 422 self.operations[op_idx] = Some(op); 423 if presence_required { 424 info!("this operation requires proof-of-presence"); 425 self.presence_required_op = Some(op_handle); 426 } 427 Ok(InternalBeginResult { challenge, params: ret_params, op_handle: op_handle.0 }) 428 } 429 op_update_aad( &mut self, op_handle: OpHandle, data: &[u8], auth_token: Option<HardwareAuthToken>, timestamp_token: Option<TimeStampToken>, ) -> Result<(), Error>430 pub(crate) fn op_update_aad( 431 &mut self, 432 op_handle: OpHandle, 433 data: &[u8], 434 auth_token: Option<HardwareAuthToken>, 435 timestamp_token: Option<TimeStampToken>, 436 ) -> Result<(), Error> { 437 self.with_authed_operation(op_handle, auth_token, timestamp_token, |op| { 438 if !op.aad_allowed { 439 return Err(km_err!(InvalidTag, "update-aad not allowed")); 440 } 441 match &mut op.crypto_op { 442 CryptoOperation::AesGcm(op) => op.update_aad(data), 443 _ => Err(km_err!(InvalidOperation, "operation does not support update_aad")), 444 } 445 }) 446 } 447 op_update( &mut self, op_handle: OpHandle, data: &[u8], auth_token: Option<HardwareAuthToken>, timestamp_token: Option<TimeStampToken>, ) -> Result<Vec<u8>, Error>448 pub(crate) fn op_update( 449 &mut self, 450 op_handle: OpHandle, 451 data: &[u8], 452 auth_token: Option<HardwareAuthToken>, 453 timestamp_token: Option<TimeStampToken>, 454 ) -> Result<Vec<u8>, Error> { 455 let check_presence = if self.presence_required_op == Some(op_handle) { 456 self.presence_required_op = None; 457 true 458 } else { 459 false 460 }; 461 let tup_available = self.dev.tup.available(); 462 self.with_authed_operation(op_handle, auth_token, timestamp_token, |op| { 463 if check_presence && !tup_available { 464 return Err(km_err!( 465 ProofOfPresenceRequired, 466 "trusted proof of presence required but not available" 467 )); 468 } 469 if let Some(trusted_conf_data) = &mut op.trusted_conf_data { 470 if trusted_conf_data.len() + data.len() 471 > CONFIRMATION_DATA_PREFIX.len() + CONFIRMATION_MESSAGE_MAX_LEN 472 { 473 return Err(km_err!( 474 InvalidArgument, 475 "trusted confirmation data of size {} + {} too big", 476 trusted_conf_data.len(), 477 data.len() 478 )); 479 } 480 trusted_conf_data.try_extend_from_slice(data)?; 481 } 482 op.aad_allowed = false; 483 op.check_size(data.len())?; 484 match &mut op.crypto_op { 485 CryptoOperation::Aes(op) => op.update(data), 486 CryptoOperation::AesGcm(op) => op.update(data), 487 CryptoOperation::Des(op) => op.update(data), 488 CryptoOperation::HmacSign(op, _) | CryptoOperation::HmacVerify(op, _) => { 489 op.update(data)?; 490 Ok(Vec::new()) 491 } 492 CryptoOperation::RsaDecrypt(op) => { 493 op.update(data)?; 494 Ok(Vec::new()) 495 } 496 CryptoOperation::RsaSign(op) => { 497 op.update(data)?; 498 Ok(Vec::new()) 499 } 500 CryptoOperation::EcAgree(op) => { 501 op.update(data)?; 502 Ok(Vec::new()) 503 } 504 CryptoOperation::EcSign(op) => { 505 op.update(data)?; 506 Ok(Vec::new()) 507 } 508 } 509 }) 510 } 511 op_finish( &mut self, op_handle: OpHandle, data: Option<&[u8]>, signature: Option<&[u8]>, auth_token: Option<HardwareAuthToken>, timestamp_token: Option<TimeStampToken>, confirmation_token: Option<&[u8]>, ) -> Result<Vec<u8>, Error>512 pub(crate) fn op_finish( 513 &mut self, 514 op_handle: OpHandle, 515 data: Option<&[u8]>, 516 signature: Option<&[u8]>, 517 auth_token: Option<HardwareAuthToken>, 518 timestamp_token: Option<TimeStampToken>, 519 confirmation_token: Option<&[u8]>, 520 ) -> Result<Vec<u8>, Error> { 521 let mut op = self.take_operation(op_handle)?; 522 self.check_subsequent_auth(&op, auth_token, timestamp_token)?; 523 524 if self.presence_required_op == Some(op_handle) { 525 self.presence_required_op = None; 526 if !self.dev.tup.available() { 527 return Err(km_err!( 528 ProofOfPresenceRequired, 529 "trusted proof of presence required but not available" 530 )); 531 } 532 } 533 if let (Some(trusted_conf_data), Some(data)) = (&mut op.trusted_conf_data, data) { 534 if trusted_conf_data.len() + data.len() 535 > CONFIRMATION_DATA_PREFIX.len() + CONFIRMATION_MESSAGE_MAX_LEN 536 { 537 return Err(km_err!( 538 InvalidArgument, 539 "data of size {} + {} too big", 540 trusted_conf_data.len(), 541 data.len() 542 )); 543 } 544 trusted_conf_data.try_extend_from_slice(data)?; 545 } 546 547 op.check_size(data.map_or(0, |v| v.len()))?; 548 let result = match op.crypto_op { 549 CryptoOperation::Aes(mut op) => { 550 let mut result = if let Some(data) = data { op.update(data)? } else { Vec::new() }; 551 result.try_extend_from_slice(&op.finish()?)?; 552 Ok(result) 553 } 554 CryptoOperation::AesGcm(mut op) => { 555 let mut result = if let Some(data) = data { op.update(data)? } else { Vec::new() }; 556 result.try_extend_from_slice(&op.finish()?)?; 557 Ok(result) 558 } 559 CryptoOperation::Des(mut op) => { 560 let mut result = if let Some(data) = data { op.update(data)? } else { Vec::new() }; 561 result.try_extend_from_slice(&op.finish()?)?; 562 Ok(result) 563 } 564 CryptoOperation::HmacSign(mut op, tag_len) => { 565 if let Some(data) = data { 566 op.update(data)?; 567 }; 568 let mut tag = op.finish()?; 569 tag.truncate(tag_len); 570 Ok(tag) 571 } 572 CryptoOperation::HmacVerify(mut op, tag_len_range) => { 573 let sig = signature 574 .ok_or_else(|| km_err!(InvalidArgument, "signature missing for HMAC verify"))?; 575 if !tag_len_range.contains(&sig.len()) { 576 return Err(km_err!( 577 InvalidArgument, 578 "signature length invalid: {} not in {:?}", 579 sig.len(), 580 tag_len_range 581 )); 582 } 583 584 if let Some(data) = data { 585 op.update(data)?; 586 }; 587 let got = op.finish()?; 588 589 if self.imp.compare.eq(&got[..sig.len()], sig) { 590 Ok(Vec::new()) 591 } else { 592 Err(km_err!(VerificationFailed, "HMAC verify failed")) 593 } 594 } 595 CryptoOperation::RsaDecrypt(mut op) => { 596 if let Some(data) = data { 597 op.update(data)?; 598 }; 599 op.finish() 600 } 601 CryptoOperation::RsaSign(mut op) => { 602 if let Some(data) = data { 603 op.update(data)?; 604 }; 605 op.finish() 606 } 607 CryptoOperation::EcAgree(mut op) => { 608 if let Some(data) = data { 609 op.update(data)?; 610 }; 611 op.finish() 612 } 613 CryptoOperation::EcSign(mut op) => { 614 if let Some(data) = data { 615 op.update(data)?; 616 }; 617 op.finish() 618 } 619 }; 620 if result.is_ok() { 621 if let Some(trusted_conf_data) = op.trusted_conf_data { 622 // Accumulated input must be checked against the trusted confirmation token. 623 self.verify_confirmation_token(&trusted_conf_data, confirmation_token)?; 624 } 625 if let (Some(slot), Some(sdd_mgr)) = (op.slot_to_delete, &mut self.dev.sdd_mgr) { 626 // A successful use of a key with UsageCountLimit(1) triggers deletion. 627 warn!("Deleting single-use key after use"); 628 if let Err(e) = sdd_mgr.delete_secret(slot) { 629 error!("Failed to delete single-use key after use: {:?}", e); 630 } 631 } 632 } 633 result 634 } 635 op_abort(&mut self, op_handle: OpHandle) -> Result<(), Error>636 pub(crate) fn op_abort(&mut self, op_handle: OpHandle) -> Result<(), Error> { 637 if self.presence_required_op == Some(op_handle) { 638 self.presence_required_op = None; 639 } 640 let _op = self.take_operation(op_handle)?; 641 Ok(()) 642 } 643 644 /// Check TA-specific key authorizations on `begin()`. check_begin_auths(&mut self, key_chars: &[KeyParam], key_blob: &[u8]) -> Result<(), Error>645 fn check_begin_auths(&mut self, key_chars: &[KeyParam], key_blob: &[u8]) -> Result<(), Error> { 646 if self.dev.bootloader.done() && get_bool_tag_value!(key_chars, BootloaderOnly)? { 647 return Err(km_err!( 648 InvalidKeyBlob, 649 "attempt to use bootloader-only key after bootloader done" 650 )); 651 } 652 if !self.in_early_boot && get_bool_tag_value!(key_chars, EarlyBootOnly)? { 653 return Err(km_err!(EarlyBootEnded, "attempt to use EARLY_BOOT key after early boot")); 654 } 655 656 if let Some(max_uses) = get_opt_tag_value!(key_chars, MaxUsesPerBoot)? { 657 // Track the use count for this key. 658 let key_id = self.key_id(key_blob)?; 659 self.update_use_count(key_id, *max_uses)?; 660 } 661 Ok(()) 662 } 663 664 /// Validate a `[keymint::HardwareAuthToken`]. check_auth_token( &self, auth_token: HardwareAuthToken, auth_info: &AuthInfo, now: Option<Timestamp>, timeout_secs: Option<u32>, challenge: Option<i64>, ) -> Result<(), Error>665 fn check_auth_token( 666 &self, 667 auth_token: HardwareAuthToken, 668 auth_info: &AuthInfo, 669 now: Option<Timestamp>, 670 timeout_secs: Option<u32>, 671 challenge: Option<i64>, 672 ) -> Result<(), Error> { 673 // Common check: confirm the HMAC tag in the token is valid. 674 let mac_input = crate::hardware_auth_token_mac_input(&auth_token)?; 675 if !self.verify_device_hmac(&mac_input, &auth_token.mac)? { 676 return Err(km_err!(KeyUserNotAuthenticated, "failed to authenticate auth_token")); 677 } 678 // Common check: token's auth type should match key's USER_AUTH_TYPE. 679 if (auth_token.authenticator_type as u32 & auth_info.auth_type) == 0 { 680 return Err(km_err!( 681 KeyUserNotAuthenticated, 682 "token auth type {:?} doesn't overlap with key auth type {:?}", 683 auth_token.authenticator_type, 684 auth_info.auth_type, 685 )); 686 } 687 688 // Common check: token's authenticator or user ID should match key's USER_SECURE_ID. 689 if !auth_info.secure_ids.iter().any(|sid| { 690 auth_token.user_id == *sid as i64 || auth_token.authenticator_id == *sid as i64 691 }) { 692 return Err(km_err!( 693 KeyUserNotAuthenticated, 694 "neither user id {:?} nor authenticator id {:?} matches key", 695 auth_token.user_id, 696 auth_token.authenticator_id 697 )); 698 } 699 700 // Optional check: token is in time range. 701 if let (Some(now), Some(timeout_secs)) = (now, timeout_secs) { 702 if now.milliseconds > auth_token.timestamp.milliseconds + 1000 * timeout_secs as i64 { 703 return Err(km_err!( 704 KeyUserNotAuthenticated, 705 "now {:?} is later than auth token time {:?} + {} seconds", 706 now, 707 auth_token.timestamp, 708 timeout_secs, 709 )); 710 } 711 } 712 713 // Optional check: challenge matches. 714 if let Some(challenge) = challenge { 715 if auth_token.challenge != challenge { 716 return Err(km_err!(KeyUserNotAuthenticated, "challenge mismatch")); 717 } 718 } 719 Ok(()) 720 } 721 722 /// Verify that an optional confirmation token matches the provided `data`. verify_confirmation_token(&self, data: &[u8], token: Option<&[u8]>) -> Result<(), Error>723 fn verify_confirmation_token(&self, data: &[u8], token: Option<&[u8]>) -> Result<(), Error> { 724 if let Some(token) = token { 725 if token.len() != CONFIRMATION_TOKEN_SIZE { 726 return Err(km_err!( 727 InvalidArgument, 728 "confirmation token wrong length {}", 729 token.len() 730 )); 731 } 732 if self.verify_device_hmac(data, token).map_err(|e| { 733 km_err!(VerificationFailed, "failed to perform HMAC on confirmation token: {:?}", e) 734 })? { 735 Ok(()) 736 } else { 737 Err(km_err!(NoUserConfirmation, "trusted confirmation token did not match")) 738 } 739 } else { 740 Err(km_err!(NoUserConfirmation, "no trusted confirmation token provided")) 741 } 742 } 743 744 /// Return the index of a free slot in the operations table. new_operation_index(&mut self) -> Result<usize, Error>745 fn new_operation_index(&mut self) -> Result<usize, Error> { 746 self.operations.iter().position(Option::is_none).ok_or_else(|| { 747 km_err!(TooManyOperations, "current op count {} >= limit", self.operations.len()) 748 }) 749 } 750 751 /// Return a new operation handle value that is not currently in use in the 752 /// operations table. new_op_handle(&mut self) -> OpHandle753 fn new_op_handle(&mut self) -> OpHandle { 754 loop { 755 let op_handle = OpHandle(self.imp.rng.next_u64() as i64); 756 if self.op_index(op_handle).is_err() { 757 return op_handle; 758 } 759 // op_handle already in use, go around again. 760 } 761 } 762 763 /// Return the index into the operations table of an operation identified by `op_handle`. op_index(&self, op_handle: OpHandle) -> Result<usize, Error>764 fn op_index(&self, op_handle: OpHandle) -> Result<usize, Error> { 765 self.operations 766 .iter() 767 .position(|op| match op { 768 Some(op) if op.handle == op_handle => true, 769 Some(_op) => false, 770 None => false, 771 }) 772 .ok_or_else(|| km_err!(InvalidOperation, "operation handle {:?} not found", op_handle)) 773 } 774 775 /// Execute the provided lambda over the associated [`Operation`], handling 776 /// errors. with_authed_operation<F, T>( &mut self, op_handle: OpHandle, auth_token: Option<HardwareAuthToken>, timestamp_token: Option<TimeStampToken>, f: F, ) -> Result<T, Error> where F: FnOnce(&mut Operation) -> Result<T, Error>,777 fn with_authed_operation<F, T>( 778 &mut self, 779 op_handle: OpHandle, 780 auth_token: Option<HardwareAuthToken>, 781 timestamp_token: Option<TimeStampToken>, 782 f: F, 783 ) -> Result<T, Error> 784 where 785 F: FnOnce(&mut Operation) -> Result<T, Error>, 786 { 787 let op_idx = self.op_index(op_handle)?; 788 let check_again = self.check_subsequent_auth( 789 self.operations[op_idx].as_ref().unwrap(/* safe: op_index() checks */ ), 790 auth_token, 791 timestamp_token, 792 )?; 793 let op = self.operations[op_idx].as_mut().unwrap(/* safe: op_index() checks */); 794 if !check_again { 795 op.auth_info = None; 796 } 797 let result = f(op); 798 if result.is_err() { 799 // A failure destroys the operation. 800 if self.presence_required_op == Some(op_handle) { 801 self.presence_required_op = None; 802 } 803 self.operations[op_idx] = None; 804 } 805 result 806 } 807 808 /// Return the associated [`Operation`], removing it. take_operation(&mut self, op_handle: OpHandle) -> Result<Operation, Error>809 fn take_operation(&mut self, op_handle: OpHandle) -> Result<Operation, Error> { 810 let op_idx = self.op_index(op_handle)?; 811 Ok(self.operations[op_idx].take().unwrap(/* safe: op_index() checks */)) 812 } 813 814 /// Check authentication for an operation that has already begun. Returns an indication as to 815 /// whether future invocations also need to check authentication. check_subsequent_auth( &self, op: &Operation, auth_token: Option<HardwareAuthToken>, timestamp_token: Option<TimeStampToken>, ) -> Result<bool, Error>816 fn check_subsequent_auth( 817 &self, 818 op: &Operation, 819 auth_token: Option<HardwareAuthToken>, 820 timestamp_token: Option<TimeStampToken>, 821 ) -> Result<bool, Error> { 822 if let Some(auth_info) = &op.auth_info { 823 let auth_token = auth_token.ok_or_else(|| { 824 km_err!(KeyUserNotAuthenticated, "no auth token on subsequent op") 825 })?; 826 827 // Most auth checks happen on begin(), but there are two exceptions. 828 // a) There is no AUTH_TIMEOUT: there should be a valid auth token on every invocation. 829 // b) There is an AUTH_TIMEOUT but we have no clock: the first invocation on the 830 // operation (after `begin()`) should check the timeout, based on a provided 831 // timestamp token. 832 if let Some(timeout_secs) = auth_info.timeout_secs { 833 if self.imp.clock.is_some() { 834 return Err(km_err!( 835 InvalidAuthorizationTimeout, 836 "attempt to check auth timeout after begin() on device with clock!" 837 )); 838 } 839 840 // Check that the timestamp token is valid. 841 let timestamp_token = timestamp_token 842 .ok_or_else(|| km_err!(InvalidArgument, "no timestamp token provided"))?; 843 if timestamp_token.challenge != op.handle.0 { 844 return Err(km_err!(InvalidArgument, "timestamp challenge mismatch")); 845 } 846 let mac_input = crate::clock::timestamp_token_mac_input(×tamp_token)?; 847 if !self.verify_device_hmac(&mac_input, ×tamp_token.mac)? { 848 return Err(km_err!(InvalidArgument, "timestamp MAC not verified")); 849 } 850 851 self.check_auth_token( 852 auth_token, 853 auth_info, 854 Some(timestamp_token.timestamp), 855 Some(timeout_secs), 856 Some(op.handle.0), 857 )?; 858 859 // No need to check again. 860 Ok(false) 861 } else { 862 self.check_auth_token(auth_token, auth_info, None, None, Some(op.handle.0))?; 863 // Check on every invocation 864 Ok(true) 865 } 866 } else { 867 Ok(false) 868 } 869 } 870 } 871