Coverage Report

Created: 2025-11-16 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/OpenSK/libraries/opensk/src/ctap/client_pin.rs
Line
Count
Source
1
// Copyright 2020-2023 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use super::command::AuthenticatorClientPinParameters;
16
use super::data_formats::{
17
    ok_or_missing, ClientPinSubCommand, CoseKey, GetAssertionHmacSecretInput, PinUvAuthProtocol,
18
};
19
#[cfg(feature = "fingerprint")]
20
use super::fingerprint::perform_built_in_uv;
21
use super::pin_protocol::{verify_pin_uv_auth_token, PinProtocol, SharedSecret};
22
use super::response::{AuthenticatorClientPinResponse, ResponseData};
23
use super::secret::Secret;
24
use super::status_code::{Ctap2StatusCode, CtapResult};
25
use super::token_state::PinUvAuthTokenState;
26
use super::{storage, Channel};
27
#[cfg(test)]
28
use crate::api::crypto::ecdh::SecretKey as _;
29
use crate::api::crypto::hmac256::Hmac256;
30
use crate::api::crypto::sha256::Sha256;
31
use crate::api::customization::Customization;
32
use crate::api::key_store::KeyStore;
33
use crate::api::persist::Persist;
34
#[cfg(test)]
35
use crate::env::EcdhSk;
36
use crate::env::{Env, Hmac, Sha};
37
use alloc::str;
38
use alloc::string::String;
39
use alloc::vec::Vec;
40
use arrayref::array_ref;
41
#[cfg(test)]
42
use enum_iterator::IntoEnumIterator;
43
use subtle::ConstantTimeEq;
44
45
/// The prefix length of the PIN hash that is stored and compared.
46
///
47
/// The code assumes that this value is a multiple of the AES block length, fits
48
/// an u8 and is at most as long as a SHA256. The value is fixed for all PIN
49
/// protocols.
50
pub const PIN_AUTH_LENGTH: usize = 16;
51
52
/// The length of the pinUvAuthToken used throughout PIN protocols.
53
///
54
/// The code assumes that this value is a multiple of the AES block length. It
55
/// is fixed since CTAP2.1, and the specification suggests that it coincides
56
/// with the HMAC key length. Therefore a change would require a more general
57
/// HMAC implementation.
58
pub const PIN_TOKEN_LENGTH: usize = 32;
59
60
/// The length of the encrypted PINs when received by SetPin or ChangePin.
61
///
62
/// The code assumes that this value is a multiple of the AES block length. It
63
/// is fixed since CTAP2.1.
64
const PIN_PADDED_LENGTH: usize = 64;
65
66
/// Decrypts the new_pin_enc and outputs the found PIN.
67
0
fn decrypt_pin<E: Env>(
68
0
    shared_secret: &SharedSecret<E>,
69
0
    new_pin_enc: Vec<u8>,
70
0
) -> CtapResult<Secret<[u8]>> {
71
0
    let decrypted_pin = shared_secret.decrypt(&new_pin_enc)?;
72
0
    if decrypted_pin.len() != PIN_PADDED_LENGTH {
73
0
        return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
74
0
    }
75
    // In CTAP 2.1, the specification changed. The new wording might lead to
76
    // different behavior when there are non-zero bytes after zero bytes.
77
    // This implementation consistently ignores those degenerate cases.
78
0
    let len = decrypted_pin
79
0
        .iter()
80
0
        .position(|&c| c == 0)
81
0
        .unwrap_or(decrypted_pin.len());
82
0
    let mut result = Secret::new(len);
83
0
    result.copy_from_slice(&decrypted_pin[..len]);
84
0
    Ok(result)
85
0
}
86
87
/// Stores a hash prefix of the new PIN in the persistent storage, if correct.
88
///
89
/// The new PIN is passed encrypted, so it is first decrypted and stripped from
90
/// padding. Next, it is checked against the PIN policy. Last, it is hashed and
91
/// truncated for persistent storage.
92
0
fn check_and_store_new_pin<E: Env>(
93
0
    env: &mut E,
94
0
    shared_secret: &SharedSecret<E>,
95
0
    new_pin_enc: Vec<u8>,
96
0
) -> CtapResult<()> {
97
0
    let pin = decrypt_pin(shared_secret, new_pin_enc)?;
98
0
    let min_pin_length = storage::min_pin_length(env)? as usize;
99
0
    let pin_length = str::from_utf8(&pin).unwrap_or("").chars().count();
100
0
    if pin_length < min_pin_length || pin.len() == PIN_PADDED_LENGTH {
101
0
        return Err(Ctap2StatusCode::CTAP2_ERR_PIN_POLICY_VIOLATION);
102
0
    }
103
0
    let mut pin_hash = Secret::default();
104
0
    Sha::<E>::digest_mut(&pin, &mut pin_hash);
105
0
    let pin_hash = env
106
0
        .key_store()
107
0
        .encrypt_pin_hash(array_ref![pin_hash, 0, PIN_AUTH_LENGTH])?;
108
    // The PIN length is always < PIN_PADDED_LENGTH < 256.
109
0
    env.persist()
110
0
        .set_pin(array_ref!(pin_hash, 0, PIN_AUTH_LENGTH), pin_length as u8)?;
111
0
    Ok(())
112
0
}
113
114
#[cfg_attr(test, derive(IntoEnumIterator))]
115
pub enum PinPermission {
116
    // All variants should use integers with a single bit set.
117
    MakeCredential = 0x01,
118
    GetAssertion = 0x02,
119
    CredentialManagement = 0x04,
120
    #[cfg(feature = "fingerprint")]
121
    BioEnrollment = 0x08,
122
    LargeBlobWrite = 0x10,
123
    AuthenticatorConfiguration = 0x20,
124
}
125
126
pub struct ClientPin<E: Env> {
127
    pin_protocol_v1: PinProtocol<E>,
128
    pin_protocol_v2: PinProtocol<E>,
129
    consecutive_pin_mismatches: u8,
130
    pin_uv_auth_token_state: PinUvAuthTokenState<E>,
131
}
132
133
impl<E: Env> ClientPin<E> {
134
16.5k
    pub fn new(env: &mut E) -> Self {
135
16.5k
        ClientPin {
136
16.5k
            pin_protocol_v1: PinProtocol::new(env),
137
16.5k
            pin_protocol_v2: PinProtocol::new(env),
138
16.5k
            consecutive_pin_mismatches: 0,
139
16.5k
            pin_uv_auth_token_state: PinUvAuthTokenState::new(),
140
16.5k
        }
141
16.5k
    }
142
143
    /// Checks if a PIN UV token is in use.
144
    pub fn has_token(&mut self, env: &mut E) -> bool {
145
        self.update_timeouts(env);
146
        self.pin_uv_auth_token_state.is_in_use()
147
    }
148
149
    /// Gets a reference to the PIN protocol of the given version.
150
1.86k
    fn get_pin_protocol(&self, pin_uv_auth_protocol: PinUvAuthProtocol) -> &PinProtocol<E> {
151
1.86k
        match pin_uv_auth_protocol {
152
954
            PinUvAuthProtocol::V1 => &self.pin_protocol_v1,
153
912
            PinUvAuthProtocol::V2 => &self.pin_protocol_v2,
154
        }
155
1.86k
    }
156
157
    /// Gets a mutable reference to the PIN protocol of the given version.
158
0
    fn get_mut_pin_protocol(
159
0
        &mut self,
160
0
        pin_uv_auth_protocol: PinUvAuthProtocol,
161
0
    ) -> &mut PinProtocol<E> {
162
0
        match pin_uv_auth_protocol {
163
0
            PinUvAuthProtocol::V1 => &mut self.pin_protocol_v1,
164
0
            PinUvAuthProtocol::V2 => &mut self.pin_protocol_v2,
165
        }
166
0
    }
167
168
    /// Computes the shared secret for the given version.
169
393
    fn get_shared_secret(
170
393
        &self,
171
393
        pin_uv_auth_protocol: PinUvAuthProtocol,
172
393
        key_agreement: CoseKey,
173
393
    ) -> CtapResult<SharedSecret<E>> {
174
393
        self.get_pin_protocol(pin_uv_auth_protocol)
175
393
            .decapsulate(key_agreement, pin_uv_auth_protocol)
176
393
    }
177
178
    /// Checks the given encrypted PIN hash against the stored PIN hash.
179
    ///
180
    /// Decrypts the encrypted pin_hash and compares it to the stored pin_hash.
181
    /// Resets or decreases the PIN retries, depending on success or failure.
182
    /// Also, in case of failure, the key agreement key is randomly reset.
183
0
    fn verify_pin_hash_enc(
184
0
        &mut self,
185
0
        env: &mut E,
186
0
        pin_uv_auth_protocol: PinUvAuthProtocol,
187
0
        shared_secret: &SharedSecret<E>,
188
0
        pin_hash_enc: Vec<u8>,
189
0
    ) -> CtapResult<()> {
190
0
        match env.persist().pin_hash()? {
191
0
            Some(pin_hash) => {
192
0
                if self.consecutive_pin_mismatches >= 3 {
193
0
                    return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_BLOCKED);
194
0
                }
195
0
                storage::decr_pin_retries(env)?;
196
0
                let pin_hash = env.key_store().decrypt_pin_hash(&pin_hash)?;
197
0
                let pin_hash_dec = shared_secret
198
0
                    .decrypt(&pin_hash_enc)
199
0
                    .map_err(|_| Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)?;
200
201
0
                if !bool::from(pin_hash.ct_eq(&pin_hash_dec)) {
202
0
                    self.get_mut_pin_protocol(pin_uv_auth_protocol)
203
0
                        .regenerate(env);
204
0
                    if storage::pin_retries(env)? == 0 {
205
0
                        return Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED);
206
0
                    }
207
0
                    self.consecutive_pin_mismatches += 1;
208
0
                    if self.consecutive_pin_mismatches >= 3 {
209
0
                        return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_BLOCKED);
210
0
                    }
211
0
                    return Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID);
212
0
                }
213
            }
214
            // This status code is not explicitly mentioned in the specification.
215
0
            None => return Err(Ctap2StatusCode::CTAP2_ERR_PUAT_REQUIRED),
216
        }
217
0
        storage::reset_pin_retries(env)?;
218
        #[cfg(feature = "fingerprint")]
219
        storage::reset_uv_retries(env)?;
220
0
        self.consecutive_pin_mismatches = 0;
221
0
        Ok(())
222
0
    }
223
224
620
    fn process_get_pin_retries(&self, env: &mut E) -> CtapResult<AuthenticatorClientPinResponse> {
225
        Ok(AuthenticatorClientPinResponse {
226
620
            key_agreement: None,
227
620
            pin_uv_auth_token: None,
228
620
            retries: Some(storage::pin_retries(env)? as u64),
229
620
            power_cycle_state: Some(self.consecutive_pin_mismatches >= 3),
230
620
            uv_retries: None,
231
        })
232
620
    }
233
234
1.47k
    fn process_get_key_agreement(
235
1.47k
        &self,
236
1.47k
        client_pin_params: AuthenticatorClientPinParameters,
237
1.47k
    ) -> CtapResult<AuthenticatorClientPinResponse> {
238
1.47k
        let key_agreement = Some(
239
1.47k
            self.get_pin_protocol(client_pin_params.pin_uv_auth_protocol)
240
1.47k
                .get_public_key(),
241
1.47k
        );
242
1.47k
        Ok(AuthenticatorClientPinResponse {
243
1.47k
            key_agreement,
244
1.47k
            pin_uv_auth_token: None,
245
1.47k
            retries: None,
246
1.47k
            power_cycle_state: None,
247
1.47k
            uv_retries: None,
248
1.47k
        })
249
1.47k
    }
250
251
534
    fn process_set_pin(
252
534
        &mut self,
253
534
        env: &mut E,
254
534
        client_pin_params: AuthenticatorClientPinParameters,
255
534
    ) -> CtapResult<()> {
256
        let AuthenticatorClientPinParameters {
257
534
            pin_uv_auth_protocol,
258
534
            key_agreement,
259
534
            pin_uv_auth_param,
260
534
            new_pin_enc,
261
            ..
262
534
        } = client_pin_params;
263
534
        let key_agreement = ok_or_missing(key_agreement)?;
264
370
        let pin_uv_auth_param = ok_or_missing(pin_uv_auth_param)?;
265
360
        let new_pin_enc = ok_or_missing(new_pin_enc)?;
266
267
356
        if env.persist().pin_hash()?.is_some() {
268
0
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID);
269
356
        }
270
356
        let shared_secret = self.get_shared_secret(pin_uv_auth_protocol, key_agreement)?;
271
0
        shared_secret.verify(&new_pin_enc, &pin_uv_auth_param)?;
272
273
0
        check_and_store_new_pin(env, &shared_secret, new_pin_enc)?;
274
0
        storage::reset_pin_retries(env)?;
275
0
        Ok(())
276
534
    }
277
278
209
    fn process_change_pin(
279
209
        &mut self,
280
209
        env: &mut E,
281
209
        client_pin_params: AuthenticatorClientPinParameters,
282
209
    ) -> CtapResult<()> {
283
        let AuthenticatorClientPinParameters {
284
209
            pin_uv_auth_protocol,
285
209
            key_agreement,
286
209
            pin_uv_auth_param,
287
209
            new_pin_enc,
288
209
            pin_hash_enc,
289
            ..
290
209
        } = client_pin_params;
291
209
        let key_agreement = ok_or_missing(key_agreement)?;
292
30
        let pin_uv_auth_param = ok_or_missing(pin_uv_auth_param)?;
293
20
        let new_pin_enc = ok_or_missing(new_pin_enc)?;
294
9
        let pin_hash_enc = ok_or_missing(pin_hash_enc)?;
295
296
6
        if storage::pin_retries(env)? == 0 {
297
0
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED);
298
6
        }
299
6
        let shared_secret = self.get_shared_secret(pin_uv_auth_protocol, key_agreement)?;
300
0
        let mut auth_param_data = new_pin_enc.clone();
301
0
        auth_param_data.extend(&pin_hash_enc);
302
0
        shared_secret.verify(&auth_param_data, &pin_uv_auth_param)?;
303
0
        self.verify_pin_hash_enc(env, pin_uv_auth_protocol, &shared_secret, pin_hash_enc)?;
304
305
0
        check_and_store_new_pin(env, &shared_secret, new_pin_enc)?;
306
0
        self.pin_protocol_v1.reset_pin_uv_auth_token(env);
307
0
        self.pin_protocol_v2.reset_pin_uv_auth_token(env);
308
0
        Ok(())
309
209
    }
310
311
242
    fn process_get_pin_token(
312
242
        &mut self,
313
242
        env: &mut E,
314
242
        client_pin_params: AuthenticatorClientPinParameters,
315
242
    ) -> CtapResult<AuthenticatorClientPinResponse> {
316
        let AuthenticatorClientPinParameters {
317
242
            pin_uv_auth_protocol,
318
242
            key_agreement,
319
242
            pin_hash_enc,
320
242
            permissions,
321
242
            permissions_rp_id,
322
            ..
323
242
        } = client_pin_params;
324
242
        let key_agreement = ok_or_missing(key_agreement)?;
325
71
        let pin_hash_enc = ok_or_missing(pin_hash_enc)?;
326
51
        if permissions.is_some() || permissions_rp_id.is_some() {
327
20
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
328
31
        }
329
330
31
        if storage::pin_retries(env)? == 0 {
331
0
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED);
332
31
        }
333
31
        let shared_secret = self.get_shared_secret(pin_uv_auth_protocol, key_agreement)?;
334
0
        self.verify_pin_hash_enc(env, pin_uv_auth_protocol, &shared_secret, pin_hash_enc)?;
335
0
        if env.persist().has_force_pin_change()? {
336
0
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID);
337
0
        }
338
339
0
        self.pin_protocol_v1.reset_pin_uv_auth_token(env);
340
0
        self.pin_protocol_v2.reset_pin_uv_auth_token(env);
341
0
        self.pin_uv_auth_token_state
342
0
            .begin_using_pin_uv_auth_token(env, false);
343
0
        self.pin_uv_auth_token_state.set_default_permissions();
344
0
        let pin_uv_auth_token = shared_secret.encrypt(
345
0
            env,
346
0
            self.get_pin_protocol(pin_uv_auth_protocol)
347
0
                .get_pin_uv_auth_token(),
348
0
        )?;
349
350
0
        Ok(AuthenticatorClientPinResponse {
351
0
            key_agreement: None,
352
0
            pin_uv_auth_token: Some(pin_uv_auth_token),
353
0
            retries: None,
354
0
            power_cycle_state: None,
355
0
            uv_retries: None,
356
0
        })
357
242
    }
358
359
    #[cfg(feature = "fingerprint")]
360
    fn process_get_pin_uv_auth_token_using_uv_with_permissions(
361
        &mut self,
362
        env: &mut E,
363
        client_pin_params: AuthenticatorClientPinParameters,
364
        channel: Channel,
365
    ) -> CtapResult<AuthenticatorClientPinResponse> {
366
        let AuthenticatorClientPinParameters {
367
            pin_uv_auth_protocol,
368
            key_agreement,
369
            permissions,
370
            permissions_rp_id,
371
            ..
372
        } = client_pin_params;
373
        let key_agreement = ok_or_missing(key_agreement)?;
374
        let permissions = permissions.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?;
375
376
        if permissions == 0 {
377
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
378
        }
379
        // Since credMgmt, uvBioEnroll and largeBlobs are always true in the options,
380
        // we only have to check uvAcfg for step 3.4 in CTAP 2.2.
381
        // TODO implement perCredMgmtRO
382
        #[cfg(not(feature = "config_command"))]
383
        if permissions & PinPermission::AuthenticatorConfiguration as u8 > 0 {
384
            return Err(Ctap2StatusCode::CTAP2_ERR_UNAUTHORIZED_PERMISSION);
385
        }
386
        // This check is not mentioned protocol steps, but mentioned in a side note.
387
        // Unsure if this is intended by the specification, so I'll keep it strict for now.
388
        let mc_gw_permission =
389
            PinPermission::MakeCredential as u8 | PinPermission::GetAssertion as u8;
390
        if permissions & mc_gw_permission != 0 && permissions_rp_id.is_none() {
391
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
392
        }
393
394
        let internal_retry = env.customization().preferred_platform_uv_attempts() == 1;
395
        perform_built_in_uv(env, channel, internal_retry)?;
396
397
        let shared_secret = self.get_shared_secret(pin_uv_auth_protocol, key_agreement)?;
398
        if env.persist().has_force_pin_change()? {
399
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID);
400
        }
401
402
        self.pin_protocol_v1.reset_pin_uv_auth_token(env);
403
        self.pin_protocol_v2.reset_pin_uv_auth_token(env);
404
        self.pin_uv_auth_token_state
405
            .begin_using_pin_uv_auth_token(env, true);
406
        let pin_uv_auth_token = shared_secret.encrypt(
407
            env,
408
            self.get_pin_protocol(pin_uv_auth_protocol)
409
                .get_pin_uv_auth_token(),
410
        )?;
411
412
        self.pin_uv_auth_token_state.set_permissions(permissions);
413
        self.pin_uv_auth_token_state
414
            .set_permissions_rp_id(permissions_rp_id);
415
416
        Ok(AuthenticatorClientPinResponse {
417
            key_agreement: None,
418
            pin_uv_auth_token: Some(pin_uv_auth_token),
419
            retries: None,
420
            power_cycle_state: None,
421
            uv_retries: None,
422
        })
423
    }
424
425
    #[cfg(not(feature = "fingerprint"))]
426
135
    fn process_get_pin_uv_auth_token_using_uv_with_permissions(
427
135
        &mut self,
428
135
        _env: &mut E,
429
135
        _client_pin_params: AuthenticatorClientPinParameters,
430
135
        _channel: Channel,
431
135
    ) -> CtapResult<AuthenticatorClientPinResponse> {
432
135
        Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND)
433
135
    }
434
435
    #[cfg(feature = "fingerprint")]
436
    fn process_get_uv_retries(&self, env: &mut E) -> CtapResult<AuthenticatorClientPinResponse> {
437
        Ok(AuthenticatorClientPinResponse {
438
            key_agreement: None,
439
            pin_uv_auth_token: None,
440
            retries: None,
441
            power_cycle_state: None,
442
            uv_retries: Some(storage::uv_retries(env)? as u64),
443
        })
444
    }
445
446
    #[cfg(not(feature = "fingerprint"))]
447
124
    fn process_get_uv_retries(&self, _env: &mut E) -> CtapResult<AuthenticatorClientPinResponse> {
448
124
        Err(Ctap2StatusCode::CTAP2_ERR_INVALID_SUBCOMMAND)
449
124
    }
450
451
275
    fn process_get_pin_uv_auth_token_using_pin_with_permissions(
452
275
        &mut self,
453
275
        env: &mut E,
454
275
        mut client_pin_params: AuthenticatorClientPinParameters,
455
275
    ) -> CtapResult<AuthenticatorClientPinResponse> {
456
        // Mutating client_pin_params is just an optimization to move it into
457
        // process_get_pin_token, without cloning permissions_rp_id here.
458
        // getPinToken requires permissions* to be None.
459
275
        let permissions = ok_or_missing(client_pin_params.permissions.take())?;
460
118
        let permissions_rp_id = client_pin_params.permissions_rp_id.take();
461
462
118
        if permissions == 0 {
463
27
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
464
91
        }
465
        // Since credMgmt, uvBioEnroll and largeBlobs are always true in the options,
466
        // and noMcGaPermissionsWithClientPin and noMcGaPermissionsWithClientPin are both false,
467
        // we only have to check uvAcfg for step 3.4 in CTAP 2.2.
468
        // TODO implement perCredMgmtRO
469
        #[cfg(not(feature = "config_command"))]
470
        if permissions & PinPermission::AuthenticatorConfiguration as u8 > 0 {
471
            return Err(Ctap2StatusCode::CTAP2_ERR_UNAUTHORIZED_PERMISSION);
472
        }
473
        // This check is not mentioned protocol steps, but mentioned in a side note.
474
        // Unsure if this is intended by the specification, so I'll keep it strict for now.
475
91
        let mc_gw_permission =
476
91
            PinPermission::MakeCredential as u8 | PinPermission::GetAssertion as u8;
477
91
        if permissions & mc_gw_permission != 0 && permissions_rp_id.is_none() {
478
12
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
479
79
        }
480
481
79
        let response = self.process_get_pin_token(env, client_pin_params)?;
482
0
        self.pin_uv_auth_token_state.set_permissions(permissions);
483
0
        self.pin_uv_auth_token_state
484
0
            .set_permissions_rp_id(permissions_rp_id);
485
486
0
        Ok(response)
487
275
    }
488
489
    /// Processes the authenticatorClientPin command.
490
3.53k
    pub fn process_command(
491
3.53k
        &mut self,
492
3.53k
        env: &mut E,
493
3.53k
        client_pin_params: AuthenticatorClientPinParameters,
494
3.53k
        channel: Channel,
495
3.53k
    ) -> CtapResult<ResponseData> {
496
3.53k
        if !env.customization().allows_pin_protocol_v1()
497
0
            && client_pin_params.pin_uv_auth_protocol == PinUvAuthProtocol::V1
498
        {
499
0
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
500
3.53k
        }
501
3.53k
        let response = match client_pin_params.sub_command {
502
620
            ClientPinSubCommand::GetPinRetries => Some(self.process_get_pin_retries(env)?),
503
            ClientPinSubCommand::GetKeyAgreement => {
504
1.47k
                Some(self.process_get_key_agreement(client_pin_params)?)
505
            }
506
            ClientPinSubCommand::SetPin => {
507
534
                self.process_set_pin(env, client_pin_params)?;
508
0
                None
509
            }
510
            ClientPinSubCommand::ChangePin => {
511
209
                self.process_change_pin(env, client_pin_params)?;
512
0
                None
513
            }
514
            ClientPinSubCommand::GetPinToken => {
515
163
                Some(self.process_get_pin_token(env, client_pin_params)?)
516
            }
517
            ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions => Some(
518
135
                self.process_get_pin_uv_auth_token_using_uv_with_permissions(
519
135
                    env,
520
135
                    client_pin_params,
521
135
                    channel,
522
135
                )?,
523
            ),
524
124
            ClientPinSubCommand::GetUvRetries => Some(self.process_get_uv_retries(env)?),
525
            ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions => Some(
526
275
                self.process_get_pin_uv_auth_token_using_pin_with_permissions(
527
275
                    env,
528
275
                    client_pin_params,
529
275
                )?,
530
            ),
531
        };
532
2.09k
        Ok(ResponseData::AuthenticatorClientPin(response))
533
3.53k
    }
534
535
    /// Verifies the HMAC for the pinUvAuthToken of the given version.
536
50
    pub fn verify_pin_uv_auth_token(
537
50
        &self,
538
50
        hmac_contents: &[u8],
539
50
        pin_uv_auth_param: &[u8],
540
50
        pin_uv_auth_protocol: PinUvAuthProtocol,
541
50
    ) -> CtapResult<()> {
542
50
        if !self.pin_uv_auth_token_state.is_in_use() {
543
50
            return Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID);
544
0
        }
545
0
        verify_pin_uv_auth_token::<E>(
546
0
            self.get_pin_protocol(pin_uv_auth_protocol)
547
0
                .get_pin_uv_auth_token(),
548
0
            hmac_contents,
549
0
            pin_uv_auth_param,
550
0
            pin_uv_auth_protocol,
551
        )
552
50
    }
553
554
    /// Resets all held state.
555
33
    pub fn reset(&mut self, env: &mut E) {
556
33
        self.pin_protocol_v1.regenerate(env);
557
33
        self.pin_protocol_v1.reset_pin_uv_auth_token(env);
558
33
        self.pin_protocol_v2.regenerate(env);
559
33
        self.pin_protocol_v2.reset_pin_uv_auth_token(env);
560
33
        self.consecutive_pin_mismatches = 0;
561
33
        self.pin_uv_auth_token_state.stop_using_pin_uv_auth_token();
562
33
    }
563
564
    /// Verifies, computes and encrypts the HMAC-secret outputs.
565
    ///
566
    /// The salt_enc is
567
    /// - verified with the shared secret and salt_auth,
568
    /// - decrypted with the shared secret,
569
    /// - HMAC'ed with cred_random.
570
    ///
571
    /// The length of the output matches salt_enc and has to be 1 or 2 blocks of
572
    /// 32 byte.
573
0
    pub fn process_hmac_secret(
574
0
        &self,
575
0
        env: &mut E,
576
0
        hmac_secret_input: GetAssertionHmacSecretInput,
577
0
        cred_random: &[u8; 32],
578
0
    ) -> CtapResult<Vec<u8>> {
579
        let GetAssertionHmacSecretInput {
580
0
            key_agreement,
581
0
            salt_enc,
582
0
            salt_auth,
583
0
            pin_uv_auth_protocol,
584
0
        } = hmac_secret_input;
585
0
        let shared_secret = self
586
0
            .get_pin_protocol(pin_uv_auth_protocol)
587
0
            .decapsulate(key_agreement, pin_uv_auth_protocol)?;
588
0
        shared_secret.verify(&salt_enc, &salt_auth)?;
589
590
0
        let decrypted_salts = shared_secret.decrypt(&salt_enc)?;
591
0
        if decrypted_salts.len() != 32 && decrypted_salts.len() != 64 {
592
0
            return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
593
0
        }
594
0
        let mut output = Secret::new(decrypted_salts.len());
595
0
        Hmac::<E>::mac(
596
0
            cred_random,
597
0
            &decrypted_salts[..32],
598
0
            array_mut_ref![&mut output, 0, 32],
599
        );
600
0
        if decrypted_salts.len() == 64 {
601
0
            Hmac::<E>::mac(
602
0
                cred_random,
603
0
                &decrypted_salts[32..],
604
0
                array_mut_ref![&mut output, 32, 32],
605
0
            );
606
0
        }
607
0
        shared_secret.encrypt(env, &output)
608
0
    }
609
610
    /// Consumes flags and permissions related to the pinUvAuthToken.
611
3.16k
    pub fn clear_token_flags(&mut self) {
612
3.16k
        self.pin_uv_auth_token_state.clear_user_present_flag();
613
3.16k
        self.pin_uv_auth_token_state.clear_user_verified_flag();
614
3.16k
        self.pin_uv_auth_token_state
615
3.16k
            .clear_pin_uv_auth_token_permissions_except_lbw();
616
3.16k
    }
617
618
    /// Updates the running timers, triggers timeout events.
619
14.7k
    pub fn update_timeouts(&mut self, env: &mut E) {
620
14.7k
        self.pin_uv_auth_token_state
621
14.7k
            .pin_uv_auth_token_usage_timer_observer(env);
622
14.7k
    }
623
624
    /// Returns if user presence is cached for use of the pinUvAuthToken.
625
0
    pub fn get_user_present_flag(&mut self) -> bool {
626
0
        self.pin_uv_auth_token_state.get_user_present_flag_value()
627
0
    }
628
629
    /// Checks if user verification is cached for use of the pinUvAuthToken.
630
0
    pub fn check_user_verified_flag(&mut self) -> CtapResult<()> {
631
0
        if self.pin_uv_auth_token_state.get_user_verified_flag_value() {
632
0
            Ok(())
633
        } else {
634
0
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
635
        }
636
0
    }
637
638
    /// Check if the required command's token permission is granted.
639
0
    pub fn has_permission(&self, permission: PinPermission) -> CtapResult<()> {
640
0
        self.pin_uv_auth_token_state.has_permission(permission)
641
0
    }
642
643
    /// Check if no RP ID is associated with the token permission.
644
0
    pub fn has_no_rp_id_permission(&self) -> CtapResult<()> {
645
0
        self.pin_uv_auth_token_state.has_no_permissions_rp_id()
646
0
    }
647
648
    /// Check if no or the passed RP ID is associated with the token permission.
649
0
    pub fn has_no_or_rp_id_permission(&mut self, rp_id: &str) -> CtapResult<()> {
650
0
        self.pin_uv_auth_token_state
651
0
            .has_no_permissions_rp_id()
652
0
            .or_else(|_| self.pin_uv_auth_token_state.has_permissions_rp_id(rp_id))
653
0
    }
654
655
    /// Check if no RP ID is associated with the token permission, or it matches the hash.
656
0
    pub fn has_no_or_rp_id_hash_permission(&self, rp_id_hash: &[u8]) -> CtapResult<()> {
657
0
        self.pin_uv_auth_token_state
658
0
            .has_no_permissions_rp_id()
659
0
            .or_else(|_| {
660
0
                self.pin_uv_auth_token_state
661
0
                    .has_permissions_rp_id_hash(rp_id_hash)
662
0
            })
663
0
    }
664
665
    /// Check if the passed RP ID is associated with the token permission.
666
    ///
667
    /// If no RP ID is associated, associate the passed RP ID as a side effect.
668
0
    pub fn ensure_rp_id_permission(&mut self, rp_id: &str) -> CtapResult<()> {
669
0
        if self
670
0
            .pin_uv_auth_token_state
671
0
            .has_no_permissions_rp_id()
672
0
            .is_ok()
673
        {
674
0
            self.pin_uv_auth_token_state
675
0
                .set_permissions_rp_id(Some(String::from(rp_id)));
676
0
            return Ok(());
677
0
        }
678
0
        self.pin_uv_auth_token_state.has_permissions_rp_id(rp_id)
679
0
    }
680
681
    #[cfg(test)]
682
    pub fn new_test(
683
        env: &mut E,
684
        key_agreement_key: EcdhSk<E>,
685
        pin_uv_auth_token: [u8; PIN_TOKEN_LENGTH],
686
        pin_uv_auth_protocol: PinUvAuthProtocol,
687
    ) -> Self {
688
        let random_key = EcdhSk::<E>::random(env.rng());
689
        let (key_agreement_key_v1, key_agreement_key_v2) = match pin_uv_auth_protocol {
690
            PinUvAuthProtocol::V1 => (key_agreement_key, random_key),
691
            PinUvAuthProtocol::V2 => (random_key, key_agreement_key),
692
        };
693
        let mut pin_uv_auth_token_state = PinUvAuthTokenState::new();
694
        pin_uv_auth_token_state.set_permissions(0xFF);
695
        pin_uv_auth_token_state.begin_using_pin_uv_auth_token(env, true);
696
        Self {
697
            pin_protocol_v1: PinProtocol::new_test(key_agreement_key_v1, pin_uv_auth_token),
698
            pin_protocol_v2: PinProtocol::new_test(key_agreement_key_v2, pin_uv_auth_token),
699
            consecutive_pin_mismatches: 0,
700
            pin_uv_auth_token_state,
701
        }
702
    }
703
}
704
705
#[cfg(test)]
706
mod test {
707
    use super::super::pin_protocol::authenticate_pin_uv_auth_token;
708
    use super::*;
709
    use crate::api::crypto::HASH_SIZE;
710
    use crate::env::test::TestEnv;
711
    use crate::env::EcdhSk;
712
    use alloc::vec;
713
714
    // Dummy channel to send keepalives on.
715
    const DUMMY_CHANNEL: Channel = Channel::MainHid([0x12, 0x34, 0x56, 0x78]);
716
717
    /// Stores a PIN hash corresponding to the dummy PIN "1234".
718
    fn set_standard_pin(env: &mut TestEnv) {
719
        let mut pin = [0u8; 64];
720
        pin[..4].copy_from_slice(b"1234");
721
        let mut pin_hash = [0u8; 16];
722
        pin_hash.copy_from_slice(&Sha::<TestEnv>::digest(&pin[..])[..16]);
723
        env.persist().set_pin(&pin_hash, 4).unwrap();
724
    }
725
726
    /// Fails on PINs bigger than 64 bytes.
727
    fn encrypt_pin(shared_secret: &SharedSecret<TestEnv>, pin: Vec<u8>) -> Vec<u8> {
728
        assert!(pin.len() <= 64);
729
        let mut env = TestEnv::default();
730
        let mut padded_pin = [0u8; 64];
731
        padded_pin[..pin.len()].copy_from_slice(&pin[..]);
732
        shared_secret.encrypt(&mut env, &padded_pin).unwrap()
733
    }
734
735
    /// Generates a ClientPin instance and a shared secret for testing.
736
    ///
737
    /// The shared secret for the desired PIN protocol is generated in a
738
    /// handshake with itself. The other protocol has a random private key, so
739
    /// tests using the wrong combination of PIN protocol and shared secret
740
    /// should fail.
741
    fn create_client_pin_and_shared_secret(
742
        pin_uv_auth_protocol: PinUvAuthProtocol,
743
    ) -> (ClientPin<TestEnv>, SharedSecret<TestEnv>) {
744
        let mut env = TestEnv::default();
745
        let key_agreement_key = EcdhSk::<TestEnv>::random(env.rng());
746
        let pk = key_agreement_key.public_key();
747
        let key_agreement = CoseKey::from_ecdh_public_key::<TestEnv>(pk);
748
        let pin_uv_auth_token = [0x91; PIN_TOKEN_LENGTH];
749
        let client_pin = ClientPin::<TestEnv>::new_test(
750
            &mut env,
751
            key_agreement_key,
752
            pin_uv_auth_token,
753
            pin_uv_auth_protocol,
754
        );
755
        let shared_secret = client_pin
756
            .get_pin_protocol(pin_uv_auth_protocol)
757
            .decapsulate(key_agreement, pin_uv_auth_protocol)
758
            .unwrap();
759
        (client_pin, shared_secret)
760
    }
761
762
    /// Generates standard input parameters to the ClientPin command.
763
    ///
764
    /// All fields are populated for simplicity, even though most are unused.
765
    fn create_client_pin_and_parameters(
766
        pin_uv_auth_protocol: PinUvAuthProtocol,
767
        sub_command: ClientPinSubCommand,
768
    ) -> (ClientPin<TestEnv>, AuthenticatorClientPinParameters) {
769
        let mut env = TestEnv::default();
770
        let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
771
772
        let pin = b"1234";
773
        let mut padded_pin = [0u8; 64];
774
        padded_pin[..pin.len()].copy_from_slice(&pin[..]);
775
        let pin_hash = Sha::<TestEnv>::digest(&padded_pin);
776
        let new_pin_enc = shared_secret.encrypt(&mut env, &padded_pin).unwrap();
777
        let pin_uv_auth_param = shared_secret.authenticate(&new_pin_enc);
778
        let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash[..16]).unwrap();
779
        let (permissions, permissions_rp_id) = match sub_command {
780
            ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions
781
            | ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions => {
782
                (Some(0x03), Some("example.com".to_string()))
783
            }
784
            _ => (None, None),
785
        };
786
        let params = AuthenticatorClientPinParameters {
787
            pin_uv_auth_protocol,
788
            sub_command,
789
            key_agreement: Some(
790
                client_pin
791
                    .get_pin_protocol(pin_uv_auth_protocol)
792
                    .get_public_key(),
793
            ),
794
            pin_uv_auth_param: Some(pin_uv_auth_param),
795
            new_pin_enc: Some(new_pin_enc),
796
            pin_hash_enc: Some(pin_hash_enc),
797
            permissions,
798
            permissions_rp_id,
799
        };
800
        (client_pin, params)
801
    }
802
803
    #[test]
804
    fn test_mix_pin_protocols() {
805
        let mut env = TestEnv::default();
806
        let client_pin = ClientPin::<TestEnv>::new(&mut env);
807
        let pin_protocol_v1 = client_pin.get_pin_protocol(PinUvAuthProtocol::V1);
808
        let pin_protocol_v2 = client_pin.get_pin_protocol(PinUvAuthProtocol::V2);
809
        let message = vec![0xAA; 16];
810
811
        let shared_secret_v1 = pin_protocol_v1
812
            .decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V1)
813
            .unwrap();
814
        let shared_secret_v2 = pin_protocol_v2
815
            .decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V2)
816
            .unwrap();
817
        let ciphertext = shared_secret_v1.encrypt(&mut env, &message).unwrap();
818
        let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
819
        assert_ne!(&message, &*plaintext);
820
        let ciphertext = shared_secret_v2.encrypt(&mut env, &message).unwrap();
821
        let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
822
        assert_ne!(&message, &*plaintext);
823
824
        let fake_secret_v1 = pin_protocol_v1
825
            .decapsulate(pin_protocol_v2.get_public_key(), PinUvAuthProtocol::V1)
826
            .unwrap();
827
        let ciphertext = shared_secret_v1.encrypt(&mut env, &message).unwrap();
828
        let plaintext = fake_secret_v1.decrypt(&ciphertext).unwrap();
829
        assert_ne!(&message, &*plaintext);
830
        let ciphertext = fake_secret_v1.encrypt(&mut env, &message).unwrap();
831
        let plaintext = shared_secret_v1.decrypt(&ciphertext).unwrap();
832
        assert_ne!(&message, &*plaintext);
833
834
        let fake_secret_v2 = pin_protocol_v2
835
            .decapsulate(pin_protocol_v1.get_public_key(), PinUvAuthProtocol::V2)
836
            .unwrap();
837
        let ciphertext = shared_secret_v2.encrypt(&mut env, &message).unwrap();
838
        let plaintext = fake_secret_v2.decrypt(&ciphertext).unwrap();
839
        assert_ne!(&message, &*plaintext);
840
        let ciphertext = fake_secret_v2.encrypt(&mut env, &message).unwrap();
841
        let plaintext = shared_secret_v2.decrypt(&ciphertext).unwrap();
842
        assert_ne!(&message, &*plaintext);
843
    }
844
845
    fn test_helper_verify_pin_hash_enc(pin_uv_auth_protocol: PinUvAuthProtocol) {
846
        let mut env = TestEnv::default();
847
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
848
        let pin_protocol = client_pin.get_pin_protocol(pin_uv_auth_protocol);
849
        let shared_secret = pin_protocol
850
            .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
851
            .unwrap();
852
        // The PIN is "1234".
853
        let pin_hash = [
854
            0x01, 0xD9, 0x88, 0x40, 0x50, 0xBB, 0xD0, 0x7A, 0x23, 0x1A, 0xEB, 0x69, 0xD8, 0x36,
855
            0xC4, 0x12,
856
        ];
857
        env.persist().set_pin(&pin_hash, 4).unwrap();
858
859
        let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash).unwrap();
860
        assert_eq!(
861
            client_pin.verify_pin_hash_enc(
862
                &mut env,
863
                pin_uv_auth_protocol,
864
                &shared_secret,
865
                pin_hash_enc
866
            ),
867
            Ok(())
868
        );
869
870
        let pin_hash_enc = vec![0xEE; 16];
871
        assert_eq!(
872
            client_pin.verify_pin_hash_enc(
873
                &mut env,
874
                pin_uv_auth_protocol,
875
                &shared_secret,
876
                pin_hash_enc
877
            ),
878
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
879
        );
880
881
        let pin_hash_enc = shared_secret.encrypt(&mut env, &pin_hash).unwrap();
882
        client_pin.consecutive_pin_mismatches = 3;
883
        assert_eq!(
884
            client_pin.verify_pin_hash_enc(
885
                &mut env,
886
                pin_uv_auth_protocol,
887
                &shared_secret,
888
                pin_hash_enc
889
            ),
890
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_BLOCKED)
891
        );
892
        client_pin.consecutive_pin_mismatches = 0;
893
894
        let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH - 1];
895
        assert_eq!(
896
            client_pin.verify_pin_hash_enc(
897
                &mut env,
898
                pin_uv_auth_protocol,
899
                &shared_secret,
900
                pin_hash_enc
901
            ),
902
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
903
        );
904
905
        let pin_hash_enc = vec![0x77; PIN_AUTH_LENGTH + 1];
906
        assert_eq!(
907
            client_pin.verify_pin_hash_enc(
908
                &mut env,
909
                pin_uv_auth_protocol,
910
                &shared_secret,
911
                pin_hash_enc
912
            ),
913
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
914
        );
915
    }
916
917
    #[test]
918
    fn test_verify_pin_hash_enc_v1() {
919
        test_helper_verify_pin_hash_enc(PinUvAuthProtocol::V1);
920
    }
921
922
    #[test]
923
    fn test_verify_pin_hash_enc_v2() {
924
        test_helper_verify_pin_hash_enc(PinUvAuthProtocol::V2);
925
    }
926
927
    fn test_helper_process_get_pin_retries(pin_uv_auth_protocol: PinUvAuthProtocol) {
928
        let (mut client_pin, params) = create_client_pin_and_parameters(
929
            pin_uv_auth_protocol,
930
            ClientPinSubCommand::GetPinRetries,
931
        );
932
        let mut env = TestEnv::default();
933
        let expected_response = Some(AuthenticatorClientPinResponse {
934
            key_agreement: None,
935
            pin_uv_auth_token: None,
936
            retries: Some(storage::pin_retries(&mut env).unwrap() as u64),
937
            power_cycle_state: Some(false),
938
            uv_retries: None,
939
        });
940
        assert_eq!(
941
            client_pin.process_command(&mut env, params.clone(), DUMMY_CHANNEL),
942
            Ok(ResponseData::AuthenticatorClientPin(expected_response))
943
        );
944
945
        client_pin.consecutive_pin_mismatches = 3;
946
        let expected_response = Some(AuthenticatorClientPinResponse {
947
            key_agreement: None,
948
            pin_uv_auth_token: None,
949
            retries: Some(storage::pin_retries(&mut env).unwrap() as u64),
950
            power_cycle_state: Some(true),
951
            uv_retries: None,
952
        });
953
        assert_eq!(
954
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
955
            Ok(ResponseData::AuthenticatorClientPin(expected_response))
956
        );
957
    }
958
959
    #[test]
960
    fn test_process_get_pin_retries_v1() {
961
        test_helper_process_get_pin_retries(PinUvAuthProtocol::V1);
962
    }
963
964
    #[test]
965
    fn test_process_get_pin_retries_v2() {
966
        test_helper_process_get_pin_retries(PinUvAuthProtocol::V2);
967
    }
968
969
    fn test_helper_process_get_key_agreement(pin_uv_auth_protocol: PinUvAuthProtocol) {
970
        let (mut client_pin, params) = create_client_pin_and_parameters(
971
            pin_uv_auth_protocol,
972
            ClientPinSubCommand::GetKeyAgreement,
973
        );
974
        let mut env = TestEnv::default();
975
        let expected_response = Some(AuthenticatorClientPinResponse {
976
            key_agreement: params.key_agreement.clone(),
977
            pin_uv_auth_token: None,
978
            retries: None,
979
            power_cycle_state: None,
980
            uv_retries: None,
981
        });
982
        assert_eq!(
983
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
984
            Ok(ResponseData::AuthenticatorClientPin(expected_response))
985
        );
986
    }
987
988
    #[test]
989
    fn test_process_get_key_agreement_v1() {
990
        test_helper_process_get_key_agreement(PinUvAuthProtocol::V1);
991
    }
992
993
    #[test]
994
    fn test_process_get_key_agreement_v2() {
995
        test_helper_process_get_key_agreement(PinUvAuthProtocol::V2);
996
    }
997
998
    #[test]
999
    fn test_process_get_key_agreement_v1_not_allowed() {
1000
        let (mut client_pin, params) = create_client_pin_and_parameters(
1001
            PinUvAuthProtocol::V1,
1002
            ClientPinSubCommand::GetKeyAgreement,
1003
        );
1004
        let mut env = TestEnv::default();
1005
        env.customization_mut().set_allows_pin_protocol_v1(false);
1006
        assert_eq!(
1007
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
1008
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1009
        );
1010
    }
1011
1012
    fn test_helper_process_set_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
1013
        let (mut client_pin, params) =
1014
            create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin);
1015
        let mut env = TestEnv::default();
1016
        assert_eq!(
1017
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
1018
            Ok(ResponseData::AuthenticatorClientPin(None))
1019
        );
1020
    }
1021
1022
    #[test]
1023
    fn test_process_set_pin_v1() {
1024
        test_helper_process_set_pin(PinUvAuthProtocol::V1);
1025
    }
1026
1027
    #[test]
1028
    fn test_process_set_pin_v2() {
1029
        test_helper_process_set_pin(PinUvAuthProtocol::V2);
1030
    }
1031
1032
    fn test_helper_process_change_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
1033
        let (mut client_pin, mut params) =
1034
            create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::ChangePin);
1035
        let shared_secret = client_pin
1036
            .get_pin_protocol(pin_uv_auth_protocol)
1037
            .decapsulate(
1038
                params.key_agreement.clone().unwrap(),
1039
                params.pin_uv_auth_protocol,
1040
            )
1041
            .unwrap();
1042
        let mut env = TestEnv::default();
1043
        set_standard_pin(&mut env);
1044
1045
        let mut auth_param_data = params.new_pin_enc.clone().unwrap();
1046
        auth_param_data.extend(params.pin_hash_enc.as_ref().unwrap());
1047
        let pin_uv_auth_param = shared_secret.authenticate(&auth_param_data);
1048
        params.pin_uv_auth_param = Some(pin_uv_auth_param);
1049
        assert_eq!(
1050
            client_pin.process_command(&mut env, params.clone(), DUMMY_CHANNEL),
1051
            Ok(ResponseData::AuthenticatorClientPin(None))
1052
        );
1053
1054
        let mut bad_params = params.clone();
1055
        bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
1056
        assert_eq!(
1057
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1058
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1059
        );
1060
1061
        while storage::pin_retries(&mut env).unwrap() > 0 {
1062
            storage::decr_pin_retries(&mut env).unwrap();
1063
        }
1064
        assert_eq!(
1065
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
1066
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_BLOCKED)
1067
        );
1068
    }
1069
1070
    #[test]
1071
    fn test_process_change_pin_v1() {
1072
        test_helper_process_change_pin(PinUvAuthProtocol::V1);
1073
    }
1074
1075
    #[test]
1076
    fn test_process_change_pin_v2() {
1077
        test_helper_process_change_pin(PinUvAuthProtocol::V2);
1078
    }
1079
1080
    fn test_helper_process_get_pin_token(pin_uv_auth_protocol: PinUvAuthProtocol) {
1081
        let (mut client_pin, params) = create_client_pin_and_parameters(
1082
            pin_uv_auth_protocol,
1083
            ClientPinSubCommand::GetPinToken,
1084
        );
1085
        let shared_secret = client_pin
1086
            .get_pin_protocol(pin_uv_auth_protocol)
1087
            .decapsulate(
1088
                params.key_agreement.clone().unwrap(),
1089
                params.pin_uv_auth_protocol,
1090
            )
1091
            .unwrap();
1092
        let mut env = TestEnv::default();
1093
        set_standard_pin(&mut env);
1094
1095
        let response = client_pin
1096
            .process_command(&mut env, params.clone(), DUMMY_CHANNEL)
1097
            .unwrap();
1098
        let encrypted_token = match response {
1099
            ResponseData::AuthenticatorClientPin(Some(response)) => {
1100
                response.pin_uv_auth_token.unwrap()
1101
            }
1102
            _ => panic!("Invalid response type"),
1103
        };
1104
        assert_eq!(
1105
            &*shared_secret.decrypt(&encrypted_token).unwrap(),
1106
            client_pin
1107
                .get_pin_protocol(pin_uv_auth_protocol)
1108
                .get_pin_uv_auth_token()
1109
        );
1110
        assert_eq!(
1111
            client_pin
1112
                .pin_uv_auth_token_state
1113
                .has_permission(PinPermission::MakeCredential),
1114
            Ok(())
1115
        );
1116
        assert_eq!(
1117
            client_pin
1118
                .pin_uv_auth_token_state
1119
                .has_permission(PinPermission::GetAssertion),
1120
            Ok(())
1121
        );
1122
        assert_eq!(
1123
            client_pin
1124
                .pin_uv_auth_token_state
1125
                .has_no_permissions_rp_id(),
1126
            Ok(())
1127
        );
1128
1129
        let mut bad_params = params;
1130
        bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
1131
        assert_eq!(
1132
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1133
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
1134
        );
1135
    }
1136
1137
    #[test]
1138
    fn test_process_get_pin_token_v1() {
1139
        test_helper_process_get_pin_token(PinUvAuthProtocol::V1);
1140
    }
1141
1142
    #[test]
1143
    fn test_process_get_pin_token_v2() {
1144
        test_helper_process_get_pin_token(PinUvAuthProtocol::V2);
1145
    }
1146
1147
    fn test_helper_process_get_pin_token_force_pin_change(pin_uv_auth_protocol: PinUvAuthProtocol) {
1148
        let (mut client_pin, params) = create_client_pin_and_parameters(
1149
            pin_uv_auth_protocol,
1150
            ClientPinSubCommand::GetPinToken,
1151
        );
1152
        let mut env = TestEnv::default();
1153
        set_standard_pin(&mut env);
1154
1155
        assert_eq!(env.persist().force_pin_change(), Ok(()));
1156
        assert_eq!(
1157
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
1158
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID),
1159
        );
1160
    }
1161
1162
    #[test]
1163
    fn test_process_get_pin_token_force_pin_change_v1() {
1164
        test_helper_process_get_pin_token_force_pin_change(PinUvAuthProtocol::V1);
1165
    }
1166
1167
    #[test]
1168
    fn test_process_get_pin_token_force_pin_change_v2() {
1169
        test_helper_process_get_pin_token_force_pin_change(PinUvAuthProtocol::V2);
1170
    }
1171
1172
    #[cfg(feature = "fingerprint")]
1173
    fn test_helper_process_get_pin_uv_auth_token_using_uv_with_permissions(
1174
        pin_uv_auth_protocol: PinUvAuthProtocol,
1175
    ) {
1176
        let (mut client_pin, params) = create_client_pin_and_parameters(
1177
            pin_uv_auth_protocol,
1178
            ClientPinSubCommand::GetPinUvAuthTokenUsingUvWithPermissions,
1179
        );
1180
        let shared_secret = client_pin
1181
            .get_pin_protocol(pin_uv_auth_protocol)
1182
            .decapsulate(
1183
                params.key_agreement.clone().unwrap(),
1184
                params.pin_uv_auth_protocol,
1185
            )
1186
            .unwrap();
1187
        let mut env = TestEnv::default();
1188
        set_standard_pin(&mut env);
1189
        assert!(env.create_fingerprint().is_ok());
1190
1191
        let response = client_pin
1192
            .process_command(&mut env, params.clone(), DUMMY_CHANNEL)
1193
            .unwrap();
1194
        let encrypted_token = match response {
1195
            ResponseData::AuthenticatorClientPin(Some(response)) => {
1196
                response.pin_uv_auth_token.unwrap()
1197
            }
1198
            _ => panic!("Invalid response type"),
1199
        };
1200
        assert_eq!(
1201
            &*shared_secret.decrypt(&encrypted_token).unwrap(),
1202
            client_pin
1203
                .get_pin_protocol(pin_uv_auth_protocol)
1204
                .get_pin_uv_auth_token()
1205
        );
1206
        assert_eq!(
1207
            client_pin
1208
                .pin_uv_auth_token_state
1209
                .has_permission(PinPermission::MakeCredential),
1210
            Ok(())
1211
        );
1212
        assert_eq!(
1213
            client_pin
1214
                .pin_uv_auth_token_state
1215
                .has_permission(PinPermission::GetAssertion),
1216
            Ok(())
1217
        );
1218
        assert_eq!(
1219
            client_pin
1220
                .pin_uv_auth_token_state
1221
                .has_permissions_rp_id("example.com"),
1222
            Ok(())
1223
        );
1224
1225
        let mut bad_params = params.clone();
1226
        bad_params.permissions = Some(0x00);
1227
        assert_eq!(
1228
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1229
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1230
        );
1231
1232
        let mut bad_params = params;
1233
        bad_params.permissions_rp_id = None;
1234
        assert_eq!(
1235
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1236
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1237
        );
1238
    }
1239
1240
    #[test]
1241
    #[cfg(feature = "fingerprint")]
1242
    fn test_process_get_pin_uv_auth_token_using_uv_with_permissions_v1() {
1243
        test_helper_process_get_pin_uv_auth_token_using_uv_with_permissions(PinUvAuthProtocol::V1);
1244
    }
1245
1246
    #[test]
1247
    #[cfg(feature = "fingerprint")]
1248
    fn test_process_get_pin_uv_auth_token_using_uv_with_permissions_v2() {
1249
        test_helper_process_get_pin_uv_auth_token_using_uv_with_permissions(PinUvAuthProtocol::V2);
1250
    }
1251
1252
    #[cfg(feature = "fingerprint")]
1253
    fn test_helper_process_get_uv_retries(pin_uv_auth_protocol: PinUvAuthProtocol) {
1254
        let (mut client_pin, params) = create_client_pin_and_parameters(
1255
            pin_uv_auth_protocol,
1256
            ClientPinSubCommand::GetUvRetries,
1257
        );
1258
        let mut env = TestEnv::default();
1259
        let expected_response = Some(AuthenticatorClientPinResponse {
1260
            key_agreement: None,
1261
            pin_uv_auth_token: None,
1262
            retries: None,
1263
            power_cycle_state: None,
1264
            uv_retries: Some(storage::uv_retries(&mut env).unwrap() as u64),
1265
        });
1266
        assert_eq!(
1267
            client_pin.process_command(&mut env, params.clone(), DUMMY_CHANNEL),
1268
            Ok(ResponseData::AuthenticatorClientPin(expected_response))
1269
        );
1270
    }
1271
1272
    #[test]
1273
    #[cfg(feature = "fingerprint")]
1274
    fn test_process_get_uv_retries_v1() {
1275
        test_helper_process_get_uv_retries(PinUvAuthProtocol::V1);
1276
    }
1277
1278
    #[test]
1279
    #[cfg(feature = "fingerprint")]
1280
    fn test_process_get_uv_retries_v2() {
1281
        test_helper_process_get_uv_retries(PinUvAuthProtocol::V2);
1282
    }
1283
1284
    fn test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions(
1285
        pin_uv_auth_protocol: PinUvAuthProtocol,
1286
    ) {
1287
        let (mut client_pin, params) = create_client_pin_and_parameters(
1288
            pin_uv_auth_protocol,
1289
            ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
1290
        );
1291
        let shared_secret = client_pin
1292
            .get_pin_protocol(pin_uv_auth_protocol)
1293
            .decapsulate(
1294
                params.key_agreement.clone().unwrap(),
1295
                params.pin_uv_auth_protocol,
1296
            )
1297
            .unwrap();
1298
        let mut env = TestEnv::default();
1299
        set_standard_pin(&mut env);
1300
1301
        let response = client_pin
1302
            .process_command(&mut env, params.clone(), DUMMY_CHANNEL)
1303
            .unwrap();
1304
        let encrypted_token = match response {
1305
            ResponseData::AuthenticatorClientPin(Some(response)) => {
1306
                response.pin_uv_auth_token.unwrap()
1307
            }
1308
            _ => panic!("Invalid response type"),
1309
        };
1310
        assert_eq!(
1311
            &*shared_secret.decrypt(&encrypted_token).unwrap(),
1312
            client_pin
1313
                .get_pin_protocol(pin_uv_auth_protocol)
1314
                .get_pin_uv_auth_token()
1315
        );
1316
        assert_eq!(
1317
            client_pin
1318
                .pin_uv_auth_token_state
1319
                .has_permission(PinPermission::MakeCredential),
1320
            Ok(())
1321
        );
1322
        assert_eq!(
1323
            client_pin
1324
                .pin_uv_auth_token_state
1325
                .has_permission(PinPermission::GetAssertion),
1326
            Ok(())
1327
        );
1328
        assert_eq!(
1329
            client_pin
1330
                .pin_uv_auth_token_state
1331
                .has_permissions_rp_id("example.com"),
1332
            Ok(())
1333
        );
1334
1335
        let mut bad_params = params.clone();
1336
        bad_params.permissions = Some(0x00);
1337
        assert_eq!(
1338
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1339
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1340
        );
1341
1342
        let mut bad_params = params.clone();
1343
        bad_params.permissions_rp_id = None;
1344
        assert_eq!(
1345
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1346
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1347
        );
1348
1349
        let mut bad_params = params;
1350
        bad_params.pin_hash_enc = Some(vec![0xEE; 16]);
1351
        assert_eq!(
1352
            client_pin.process_command(&mut env, bad_params, DUMMY_CHANNEL),
1353
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
1354
        );
1355
    }
1356
1357
    #[test]
1358
    fn test_process_get_pin_uv_auth_token_using_pin_with_permissions_v1() {
1359
        test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions(PinUvAuthProtocol::V1);
1360
    }
1361
1362
    #[test]
1363
    fn test_process_get_pin_uv_auth_token_using_pin_with_permissions_v2() {
1364
        test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions(PinUvAuthProtocol::V2);
1365
    }
1366
1367
    fn test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions_force_pin_change(
1368
        pin_uv_auth_protocol: PinUvAuthProtocol,
1369
    ) {
1370
        let (mut client_pin, params) = create_client_pin_and_parameters(
1371
            pin_uv_auth_protocol,
1372
            ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
1373
        );
1374
        let mut env = TestEnv::default();
1375
        set_standard_pin(&mut env);
1376
1377
        assert_eq!(env.persist().force_pin_change(), Ok(()));
1378
        assert_eq!(
1379
            client_pin.process_command(&mut env, params, DUMMY_CHANNEL),
1380
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_INVALID)
1381
        );
1382
    }
1383
1384
    #[test]
1385
    fn test_process_get_pin_uv_auth_token_using_pin_with_permissions_force_pin_change_v1() {
1386
        test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions_force_pin_change(
1387
            PinUvAuthProtocol::V1,
1388
        );
1389
    }
1390
1391
    #[test]
1392
    fn test_process_get_pin_uv_auth_token_using_pin_with_permissions_force_pin_change_v2() {
1393
        test_helper_process_get_pin_uv_auth_token_using_pin_with_permissions_force_pin_change(
1394
            PinUvAuthProtocol::V2,
1395
        );
1396
    }
1397
1398
    fn test_helper_decrypt_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
1399
        let mut env = TestEnv::default();
1400
        let pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
1401
        let shared_secret = pin_protocol
1402
            .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
1403
            .unwrap();
1404
1405
        let new_pin_enc = encrypt_pin(&shared_secret, b"1234".to_vec());
1406
        assert_eq!(
1407
            &*decrypt_pin::<TestEnv>(&shared_secret, new_pin_enc).unwrap(),
1408
            b"1234",
1409
        );
1410
1411
        let new_pin_enc = encrypt_pin(&shared_secret, b"123".to_vec());
1412
        assert_eq!(
1413
            &*decrypt_pin::<TestEnv>(&shared_secret, new_pin_enc).unwrap(),
1414
            b"123",
1415
        );
1416
1417
        // Encrypted PIN is too short.
1418
        let new_pin_enc = vec![0x44; 63];
1419
        assert_eq!(
1420
            decrypt_pin::<TestEnv>(&shared_secret, new_pin_enc),
1421
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1422
        );
1423
1424
        // Encrypted PIN is too long.
1425
        let new_pin_enc = vec![0x44; 65];
1426
        assert_eq!(
1427
            decrypt_pin::<TestEnv>(&shared_secret, new_pin_enc),
1428
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1429
        );
1430
    }
1431
1432
    #[test]
1433
    fn test_decrypt_pin_v1() {
1434
        test_helper_decrypt_pin(PinUvAuthProtocol::V1);
1435
    }
1436
1437
    #[test]
1438
    fn test_decrypt_pin_v2() {
1439
        test_helper_decrypt_pin(PinUvAuthProtocol::V2);
1440
    }
1441
1442
    fn test_helper_check_and_store_new_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
1443
        let mut env = TestEnv::default();
1444
        let pin_protocol = PinProtocol::<TestEnv>::new(&mut env);
1445
        let shared_secret = pin_protocol
1446
            .decapsulate(pin_protocol.get_public_key(), pin_uv_auth_protocol)
1447
            .unwrap();
1448
1449
        let test_cases = vec![
1450
            // Accept PIN "1234".
1451
            (b"1234".to_vec(), Ok(())),
1452
            // Reject PIN "123" since it is too short.
1453
            (
1454
                b"123".to_vec(),
1455
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_POLICY_VIOLATION),
1456
            ),
1457
            // Reject PIN "12'\0'4" (a zero byte at index 2).
1458
            (
1459
                [b'1', b'2', 0, b'4'].to_vec(),
1460
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_POLICY_VIOLATION),
1461
            ),
1462
            // PINs must be at most 63 bytes long, to allow for a trailing 0u8 padding.
1463
            (
1464
                vec![0x30; 64],
1465
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_POLICY_VIOLATION),
1466
            ),
1467
        ];
1468
        for (pin, result) in test_cases {
1469
            let old_pin_hash = env.persist().pin_hash().unwrap();
1470
            let new_pin_enc = encrypt_pin(&shared_secret, pin);
1471
1472
            assert_eq!(
1473
                check_and_store_new_pin(&mut env, &shared_secret, new_pin_enc),
1474
                result
1475
            );
1476
            if result.is_ok() {
1477
                assert_ne!(old_pin_hash, env.persist().pin_hash().unwrap());
1478
            } else {
1479
                assert_eq!(old_pin_hash, env.persist().pin_hash().unwrap());
1480
            }
1481
        }
1482
    }
1483
1484
    #[test]
1485
    fn test_check_and_store_new_pin_v1() {
1486
        test_helper_check_and_store_new_pin(PinUvAuthProtocol::V1);
1487
    }
1488
1489
    #[test]
1490
    fn test_check_and_store_new_pin_v2() {
1491
        test_helper_check_and_store_new_pin(PinUvAuthProtocol::V2);
1492
    }
1493
1494
    /// Generates valid inputs for process_hmac_secret and returns the output.
1495
    fn get_process_hmac_secret_decrypted_output(
1496
        pin_uv_auth_protocol: PinUvAuthProtocol,
1497
        cred_random: &[u8; 32],
1498
        salt: Vec<u8>,
1499
    ) -> CtapResult<Vec<u8>> {
1500
        let mut env = TestEnv::default();
1501
        let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
1502
1503
        let salt_enc = shared_secret.encrypt(&mut env, &salt).unwrap();
1504
        let salt_auth = shared_secret.authenticate(&salt_enc);
1505
        let hmac_secret_input = GetAssertionHmacSecretInput {
1506
            key_agreement: client_pin
1507
                .get_pin_protocol(pin_uv_auth_protocol)
1508
                .get_public_key(),
1509
            salt_enc,
1510
            salt_auth,
1511
            pin_uv_auth_protocol,
1512
        };
1513
        let output = client_pin.process_hmac_secret(&mut env, hmac_secret_input, cred_random);
1514
        output.map(|v| shared_secret.decrypt(&v).unwrap().expose_secret_to_vec())
1515
    }
1516
1517
    fn test_helper_process_hmac_secret_bad_salt_auth(pin_uv_auth_protocol: PinUvAuthProtocol) {
1518
        let mut env = TestEnv::default();
1519
        let (client_pin, shared_secret) = create_client_pin_and_shared_secret(pin_uv_auth_protocol);
1520
        let cred_random = [0xC9; 32];
1521
1522
        let salt_enc = vec![0x01; 32];
1523
        let mut salt_auth = shared_secret.authenticate(&salt_enc);
1524
        salt_auth[0] ^= 0x01;
1525
        let hmac_secret_input = GetAssertionHmacSecretInput {
1526
            key_agreement: client_pin
1527
                .get_pin_protocol(pin_uv_auth_protocol)
1528
                .get_public_key(),
1529
            salt_enc,
1530
            salt_auth,
1531
            pin_uv_auth_protocol,
1532
        };
1533
        let output = client_pin.process_hmac_secret(&mut env, hmac_secret_input, &cred_random);
1534
        assert_eq!(output, Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID));
1535
    }
1536
1537
    #[test]
1538
    fn test_process_hmac_secret_bad_salt_auth_v1() {
1539
        test_helper_process_hmac_secret_bad_salt_auth(PinUvAuthProtocol::V1);
1540
    }
1541
1542
    #[test]
1543
    fn test_process_hmac_secret_bad_salt_auth_v2() {
1544
        test_helper_process_hmac_secret_bad_salt_auth(PinUvAuthProtocol::V2);
1545
    }
1546
1547
    fn test_helper_process_hmac_secret_one_salt(pin_uv_auth_protocol: PinUvAuthProtocol) {
1548
        let cred_random = [0xC9; 32];
1549
1550
        let salt = vec![0x01; 32];
1551
        let mut expected_output = [0; HASH_SIZE];
1552
        Hmac::<TestEnv>::mac(&cred_random, &salt, &mut expected_output);
1553
1554
        let output =
1555
            get_process_hmac_secret_decrypted_output(pin_uv_auth_protocol, &cred_random, salt)
1556
                .unwrap();
1557
        assert_eq!(&*output, &expected_output);
1558
    }
1559
1560
    #[test]
1561
    fn test_process_hmac_secret_one_salt_v1() {
1562
        test_helper_process_hmac_secret_one_salt(PinUvAuthProtocol::V1);
1563
    }
1564
1565
    #[test]
1566
    fn test_process_hmac_secret_one_salt_v2() {
1567
        test_helper_process_hmac_secret_one_salt(PinUvAuthProtocol::V2);
1568
    }
1569
1570
    fn test_helper_process_hmac_secret_two_salts(pin_uv_auth_protocol: PinUvAuthProtocol) {
1571
        let cred_random = [0xC9; 32];
1572
1573
        let salt1 = [0x01; 32];
1574
        let salt2 = [0x02; 32];
1575
        let mut expected_output1 = [0; HASH_SIZE];
1576
        let mut expected_output2 = [0; HASH_SIZE];
1577
        Hmac::<TestEnv>::mac(&cred_random, &salt1, &mut expected_output1);
1578
        Hmac::<TestEnv>::mac(&cred_random, &salt2, &mut expected_output2);
1579
1580
        let mut salt12 = vec![0x00; 64];
1581
        salt12[..32].copy_from_slice(&salt1);
1582
        salt12[32..].copy_from_slice(&salt2);
1583
        let output =
1584
            get_process_hmac_secret_decrypted_output(pin_uv_auth_protocol, &cred_random, salt12)
1585
                .unwrap();
1586
        assert_eq!(&output[..32], &expected_output1);
1587
        assert_eq!(&output[32..], &expected_output2);
1588
1589
        let mut salt02 = vec![0x00; 64];
1590
        salt02[32..].copy_from_slice(&salt2);
1591
        let output =
1592
            get_process_hmac_secret_decrypted_output(pin_uv_auth_protocol, &cred_random, salt02)
1593
                .unwrap();
1594
        assert_eq!(&output[32..], &expected_output2);
1595
1596
        let mut salt10 = vec![0x00; 64];
1597
        salt10[..32].copy_from_slice(&salt1);
1598
        let output =
1599
            get_process_hmac_secret_decrypted_output(pin_uv_auth_protocol, &cred_random, salt10)
1600
                .unwrap();
1601
        assert_eq!(&output[..32], &expected_output1);
1602
    }
1603
1604
    #[test]
1605
    fn test_process_hmac_secret_two_salts_v1() {
1606
        test_helper_process_hmac_secret_two_salts(PinUvAuthProtocol::V1);
1607
    }
1608
1609
    #[test]
1610
    fn test_process_hmac_secret_two_salts_v2() {
1611
        test_helper_process_hmac_secret_two_salts(PinUvAuthProtocol::V2);
1612
    }
1613
1614
    fn test_helper_process_hmac_secret_wrong_length(pin_uv_auth_protocol: PinUvAuthProtocol) {
1615
        let cred_random = [0xC9; 32];
1616
1617
        let output = get_process_hmac_secret_decrypted_output(
1618
            pin_uv_auth_protocol,
1619
            &cred_random,
1620
            vec![0x5E; 48],
1621
        );
1622
        assert_eq!(output, Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER));
1623
    }
1624
1625
    #[test]
1626
    fn test_process_hmac_secret_wrong_length_v1() {
1627
        test_helper_process_hmac_secret_wrong_length(PinUvAuthProtocol::V1);
1628
    }
1629
1630
    #[test]
1631
    fn test_process_hmac_secret_wrong_length_v2() {
1632
        test_helper_process_hmac_secret_wrong_length(PinUvAuthProtocol::V2);
1633
    }
1634
1635
    #[test]
1636
    fn test_has_permission() {
1637
        let mut env = TestEnv::default();
1638
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1639
        client_pin.pin_uv_auth_token_state.set_permissions(0x7F);
1640
        for permission in PinPermission::into_enum_iter() {
1641
            assert_eq!(
1642
                client_pin
1643
                    .pin_uv_auth_token_state
1644
                    .has_permission(permission),
1645
                Ok(())
1646
            );
1647
        }
1648
        client_pin.pin_uv_auth_token_state.set_permissions(0x00);
1649
        for permission in PinPermission::into_enum_iter() {
1650
            assert_eq!(
1651
                client_pin
1652
                    .pin_uv_auth_token_state
1653
                    .has_permission(permission),
1654
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1655
            );
1656
        }
1657
    }
1658
1659
    #[test]
1660
    fn test_has_no_rp_id_permission() {
1661
        let mut env = TestEnv::default();
1662
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1663
        assert_eq!(client_pin.has_no_rp_id_permission(), Ok(()));
1664
        client_pin
1665
            .pin_uv_auth_token_state
1666
            .set_permissions_rp_id(Some("example.com".to_string()));
1667
        assert_eq!(
1668
            client_pin.has_no_rp_id_permission(),
1669
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1670
        );
1671
    }
1672
1673
    #[test]
1674
    fn test_has_no_or_rp_id_permission() {
1675
        let mut env = TestEnv::default();
1676
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1677
        assert_eq!(client_pin.has_no_or_rp_id_permission("example.com"), Ok(()));
1678
        client_pin
1679
            .pin_uv_auth_token_state
1680
            .set_permissions_rp_id(Some("example.com".to_string()));
1681
        assert_eq!(client_pin.has_no_or_rp_id_permission("example.com"), Ok(()));
1682
        assert_eq!(
1683
            client_pin.has_no_or_rp_id_permission("another.example.com"),
1684
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1685
        );
1686
    }
1687
1688
    #[test]
1689
    fn test_has_no_or_rp_id_hash_permission() {
1690
        let mut env = TestEnv::default();
1691
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1692
        let rp_id_hash = Sha::<TestEnv>::digest(b"example.com");
1693
        assert_eq!(
1694
            client_pin.has_no_or_rp_id_hash_permission(&rp_id_hash),
1695
            Ok(())
1696
        );
1697
        client_pin
1698
            .pin_uv_auth_token_state
1699
            .set_permissions_rp_id(Some("example.com".to_string()));
1700
        assert_eq!(
1701
            client_pin.has_no_or_rp_id_hash_permission(&rp_id_hash),
1702
            Ok(())
1703
        );
1704
        assert_eq!(
1705
            client_pin.has_no_or_rp_id_hash_permission(&[0x4A; 32]),
1706
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1707
        );
1708
    }
1709
1710
    #[test]
1711
    fn test_ensure_rp_id_permission() {
1712
        let mut env = TestEnv::default();
1713
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1714
        assert_eq!(client_pin.ensure_rp_id_permission("example.com"), Ok(()));
1715
        assert_eq!(
1716
            client_pin
1717
                .pin_uv_auth_token_state
1718
                .has_permissions_rp_id("example.com"),
1719
            Ok(())
1720
        );
1721
        assert_eq!(client_pin.ensure_rp_id_permission("example.com"), Ok(()));
1722
        assert_eq!(
1723
            client_pin.ensure_rp_id_permission("another.example.com"),
1724
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1725
        );
1726
    }
1727
1728
    #[test]
1729
    fn test_verify_pin_uv_auth_token() {
1730
        let mut env = TestEnv::default();
1731
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1732
        let message = [0xAA];
1733
        assert!(!client_pin.has_token(&mut env));
1734
        client_pin
1735
            .pin_uv_auth_token_state
1736
            .begin_using_pin_uv_auth_token(&mut env, false);
1737
        assert!(client_pin.has_token(&mut env));
1738
1739
        let pin_uv_auth_token_v1 = client_pin
1740
            .get_pin_protocol(PinUvAuthProtocol::V1)
1741
            .get_pin_uv_auth_token();
1742
        let pin_uv_auth_param_v1 =
1743
            authenticate_pin_uv_auth_token(pin_uv_auth_token_v1, &message, PinUvAuthProtocol::V1);
1744
        let pin_uv_auth_token_v2 = client_pin
1745
            .get_pin_protocol(PinUvAuthProtocol::V2)
1746
            .get_pin_uv_auth_token();
1747
        let pin_uv_auth_param_v2 =
1748
            authenticate_pin_uv_auth_token(pin_uv_auth_token_v2, &message, PinUvAuthProtocol::V2);
1749
        let pin_uv_auth_param_v1_from_v2_token =
1750
            authenticate_pin_uv_auth_token(pin_uv_auth_token_v2, &message, PinUvAuthProtocol::V1);
1751
        let pin_uv_auth_param_v2_from_v1_token =
1752
            authenticate_pin_uv_auth_token(pin_uv_auth_token_v1, &message, PinUvAuthProtocol::V2);
1753
1754
        assert_eq!(
1755
            client_pin.verify_pin_uv_auth_token(
1756
                &message,
1757
                &pin_uv_auth_param_v1,
1758
                PinUvAuthProtocol::V1
1759
            ),
1760
            Ok(())
1761
        );
1762
        assert_eq!(
1763
            client_pin.verify_pin_uv_auth_token(
1764
                &message,
1765
                &pin_uv_auth_param_v2,
1766
                PinUvAuthProtocol::V2
1767
            ),
1768
            Ok(())
1769
        );
1770
        assert_eq!(
1771
            client_pin.verify_pin_uv_auth_token(
1772
                &message,
1773
                &pin_uv_auth_param_v1,
1774
                PinUvAuthProtocol::V2
1775
            ),
1776
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1777
        );
1778
        assert_eq!(
1779
            client_pin.verify_pin_uv_auth_token(
1780
                &message,
1781
                &pin_uv_auth_param_v2,
1782
                PinUvAuthProtocol::V1
1783
            ),
1784
            Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
1785
        );
1786
        assert_eq!(
1787
            client_pin.verify_pin_uv_auth_token(
1788
                &message,
1789
                &pin_uv_auth_param_v1_from_v2_token,
1790
                PinUvAuthProtocol::V1
1791
            ),
1792
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1793
        );
1794
        assert_eq!(
1795
            client_pin.verify_pin_uv_auth_token(
1796
                &message,
1797
                &pin_uv_auth_param_v2_from_v1_token,
1798
                PinUvAuthProtocol::V2
1799
            ),
1800
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1801
        );
1802
    }
1803
1804
    #[test]
1805
    fn test_verify_pin_uv_auth_token_not_in_use() {
1806
        let mut env = TestEnv::default();
1807
        let client_pin = ClientPin::<TestEnv>::new(&mut env);
1808
        let message = [0xAA];
1809
1810
        let pin_uv_auth_token_v1 = client_pin
1811
            .get_pin_protocol(PinUvAuthProtocol::V1)
1812
            .get_pin_uv_auth_token();
1813
        let pin_uv_auth_param_v1 =
1814
            authenticate_pin_uv_auth_token(pin_uv_auth_token_v1, &message, PinUvAuthProtocol::V1);
1815
1816
        assert_eq!(
1817
            client_pin.verify_pin_uv_auth_token(
1818
                &message,
1819
                &pin_uv_auth_param_v1,
1820
                PinUvAuthProtocol::V1
1821
            ),
1822
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1823
        );
1824
    }
1825
1826
    #[test]
1827
    fn test_reset() {
1828
        let mut env = TestEnv::default();
1829
        let mut client_pin = ClientPin::<TestEnv>::new(&mut env);
1830
        let public_key_v1 = client_pin.pin_protocol_v1.get_public_key();
1831
        let public_key_v2 = client_pin.pin_protocol_v2.get_public_key();
1832
        let token_v1 = *client_pin.pin_protocol_v1.get_pin_uv_auth_token();
1833
        let token_v2 = *client_pin.pin_protocol_v2.get_pin_uv_auth_token();
1834
        client_pin.pin_uv_auth_token_state.set_permissions(0xFF);
1835
        client_pin
1836
            .pin_uv_auth_token_state
1837
            .set_permissions_rp_id(Some(String::from("example.com")));
1838
        client_pin.reset(&mut env);
1839
        assert_ne!(public_key_v1, client_pin.pin_protocol_v1.get_public_key());
1840
        assert_ne!(public_key_v2, client_pin.pin_protocol_v2.get_public_key());
1841
        assert_ne!(
1842
            &token_v1,
1843
            client_pin.pin_protocol_v1.get_pin_uv_auth_token()
1844
        );
1845
        assert_ne!(
1846
            &token_v2,
1847
            client_pin.pin_protocol_v2.get_pin_uv_auth_token()
1848
        );
1849
        for permission in PinPermission::into_enum_iter() {
1850
            assert_eq!(
1851
                client_pin.has_permission(permission),
1852
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1853
            );
1854
        }
1855
        assert_eq!(client_pin.has_no_rp_id_permission(), Ok(()));
1856
    }
1857
1858
    #[test]
1859
    fn test_update_timeouts() {
1860
        let (mut client_pin, mut params) = create_client_pin_and_parameters(
1861
            PinUvAuthProtocol::V2,
1862
            ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
1863
        );
1864
        let mut env = TestEnv::default();
1865
        set_standard_pin(&mut env);
1866
        params.permissions = Some(0xFF);
1867
1868
        assert!(client_pin
1869
            .process_command(&mut env, params, DUMMY_CHANNEL)
1870
            .is_ok());
1871
        for permission in PinPermission::into_enum_iter() {
1872
            assert_eq!(
1873
                client_pin
1874
                    .pin_uv_auth_token_state
1875
                    .has_permission(permission),
1876
                Ok(())
1877
            );
1878
        }
1879
        assert_eq!(
1880
            client_pin
1881
                .pin_uv_auth_token_state
1882
                .has_permissions_rp_id("example.com"),
1883
            Ok(())
1884
        );
1885
        assert!(client_pin.has_token(&mut env));
1886
1887
        env.clock().advance(30001);
1888
        client_pin.update_timeouts(&mut env);
1889
        for permission in PinPermission::into_enum_iter() {
1890
            assert_eq!(
1891
                client_pin
1892
                    .pin_uv_auth_token_state
1893
                    .has_permission(permission),
1894
                Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1895
            );
1896
        }
1897
        assert_eq!(
1898
            client_pin
1899
                .pin_uv_auth_token_state
1900
                .has_permissions_rp_id("example.com"),
1901
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1902
        );
1903
        assert!(!client_pin.has_token(&mut env));
1904
    }
1905
1906
    #[test]
1907
    fn test_clear_token_flags() {
1908
        let (mut client_pin, mut params) = create_client_pin_and_parameters(
1909
            PinUvAuthProtocol::V2,
1910
            ClientPinSubCommand::GetPinUvAuthTokenUsingPinWithPermissions,
1911
        );
1912
        let mut env = TestEnv::default();
1913
        set_standard_pin(&mut env);
1914
        params.permissions = Some(0xFF);
1915
        #[cfg(not(feature = "config_command"))]
1916
        {
1917
            params.permissions = params
1918
                .permissions
1919
                .map(|p| p & !(PinPermission::AuthenticatorConfiguration as u8));
1920
        }
1921
1922
        assert!(client_pin
1923
            .process_command(&mut env, params, DUMMY_CHANNEL)
1924
            .is_ok());
1925
        for permission in PinPermission::into_enum_iter() {
1926
            assert_eq!(
1927
                client_pin
1928
                    .pin_uv_auth_token_state
1929
                    .has_permission(permission),
1930
                Ok(())
1931
            );
1932
        }
1933
        assert_eq!(client_pin.check_user_verified_flag(), Ok(()));
1934
1935
        client_pin.clear_token_flags();
1936
        assert_eq!(
1937
            client_pin
1938
                .pin_uv_auth_token_state
1939
                .has_permission(PinPermission::CredentialManagement),
1940
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1941
        );
1942
        assert_eq!(
1943
            client_pin
1944
                .pin_uv_auth_token_state
1945
                .has_permission(PinPermission::LargeBlobWrite),
1946
            Ok(())
1947
        );
1948
        assert_eq!(
1949
            client_pin.check_user_verified_flag(),
1950
            Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
1951
        );
1952
    }
1953
}