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