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