1use credential_management::CredentialManagement;
4use ctap_types::{
5 ctap2::{
6 self, client_pin::Permissions, AttestationFormatsPreference, AttestationStatement,
7 AttestationStatementFormat, Authenticator, NoneAttestationStatement,
8 PackedAttestationStatement, VendorOperation,
9 },
10 heapless::{String, Vec},
11 heapless_bytes::Bytes,
12 sizes,
13 webauthn::PublicKeyCredentialUserEntity,
14 ByteArray, Error,
15};
16use littlefs2_core::{path, Path, PathBuf};
17use sha2::{Digest as _, Sha256};
18
19use trussed_core::{
20 syscall, try_syscall,
21 types::{KeyId, Location, Mechanism, MediumData, Message, StorageAttributes},
22};
23
24use crate::{
25 constants::{self, MAX_RESIDENT_CREDENTIALS_GUESSTIMATE},
26 credential::{self, Credential, FullCredential, Key, StrippedCredential},
27 format_hex, state, Result, SigningAlgorithm, TrussedRequirements, UserPresence,
28};
29
30#[allow(unused_imports)]
31use crate::msp;
32
33pub mod credential_management;
34pub mod large_blobs;
35pub mod pin;
36
37use pin::{PinProtocol, PinProtocolVersion, RpScope, SharedSecret};
38
39pub const RK_DIR: &Path = path!("rk");
40
41impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenticator<UP, T> {
43 #[inline(never)]
44 fn get_info(&mut self) -> ctap2::get_info::Response {
45 use ctap2::get_info::{Extension, Transport, Version};
46
47 debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
48
49 let mut versions = Vec::new();
50 versions.push(Version::U2fV2).unwrap();
51 versions.push(Version::Fido2_0).unwrap();
52 versions.push(Version::Fido2_1).unwrap();
53
54 let mut extensions = Vec::new();
55 extensions.push(Extension::CredProtect).unwrap();
56 extensions.push(Extension::HmacSecret).unwrap();
57 if self.config.supports_large_blobs() {
58 extensions.push(Extension::LargeBlobKey).unwrap();
59 }
60 extensions.push(Extension::ThirdPartyPayment).unwrap();
61
62 let mut pin_protocols = Vec::new();
63 for pin_protocol in self.pin_protocols() {
64 pin_protocols.push(u8::from(*pin_protocol)).unwrap();
65 }
66
67 let mut options = ctap2::get_info::CtapOptions::default();
68 options.rk = true;
69 options.up = true;
70 options.plat = Some(false);
71 options.cred_mgmt = Some(true);
72 options.client_pin = match self.state.persistent.pin_is_set() {
73 true => Some(true),
74 false => Some(false),
75 };
76 options.large_blobs = Some(self.config.supports_large_blobs());
77 options.pin_uv_auth_token = Some(true);
78 options.make_cred_uv_not_rqd = Some(true);
79
80 let mut transports = Vec::new();
81 if self.config.nfc_transport {
82 transports.push(Transport::Nfc).unwrap();
83 }
84 transports.push(Transport::Usb).unwrap();
85
86 let mut attestation_formats = Vec::new();
87 attestation_formats
88 .push(AttestationStatementFormat::Packed)
89 .unwrap();
90 attestation_formats
91 .push(AttestationStatementFormat::None)
92 .unwrap();
93
94 let (_, aaguid) = self.state.identity.attestation(&mut self.trussed);
95
96 let mut response = ctap2::get_info::Response::default();
97 response.versions = versions;
98 response.extensions = Some(extensions);
99 response.aaguid = Bytes::from(&aaguid);
100 response.options = Some(options);
101 response.transports = Some(transports);
102 response.max_msg_size = Some(self.config.max_msg_size);
104 response.pin_protocols = Some(pin_protocols);
105 response.max_creds_in_list = Some(ctap_types::sizes::MAX_CREDENTIAL_COUNT_IN_LIST);
106 response.max_cred_id_length = Some(ctap_types::sizes::MAX_CREDENTIAL_ID_LENGTH);
107 response.attestation_formats = Some(attestation_formats);
108 response
109 }
110
111 #[inline(never)]
112 fn get_next_assertion(&mut self) -> Result<ctap2::get_assertion::Response> {
113 if false {
116 self.state.runtime.clear_credential_cache();
117 self.state.runtime.active_get_assertion = None;
118 return Err(Error::NotAllowed);
119 }
120 if self.state.runtime.active_get_assertion.is_none() {
128 return Err(Error::NotAllowed);
129 }
130 let credential = self
131 .state
132 .runtime
133 .pop_credential(&mut self.trussed)
134 .ok_or(Error::NotAllowed)?;
135
136 self.assert_with_credential(None, Credential::Full(credential))
143 }
144
145 #[inline(never)]
146 fn make_credential(
147 &mut self,
148 parameters: &ctap2::make_credential::Request,
149 ) -> Result<ctap2::make_credential::Response> {
150 let rp_id_hash = self.hash(parameters.rp.id.as_ref());
151
152 if let Some(options) = parameters.options.as_ref() {
154 if options.up.is_some() {
156 return Err(Error::InvalidOption);
157 }
158 }
159 if parameters.enterprise_attestation.is_some() {
160 return Err(Error::InvalidParameter);
161 }
162 let uv_performed = self.pin_prechecks(
163 ¶meters.options,
164 parameters.pin_auth.map(AsRef::as_ref),
165 parameters.pin_protocol,
166 parameters.client_data_hash.as_ref(),
167 Permissions::MAKE_CREDENTIAL,
168 ¶meters.rp.id,
169 )?;
170
171 if let Some(exclude_list) = ¶meters.exclude_list {
177 for descriptor in exclude_list.iter() {
178 let result = Credential::try_from(self, &rp_id_hash, descriptor);
179 if let Ok(excluded_cred) = result {
180 use credential::CredentialProtectionPolicy;
181 if !(excluded_cred.cred_protect() == Some(CredentialProtectionPolicy::Required))
183 || uv_performed
184 {
185 info_now!("Excluded!");
186 self.up
187 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
188 return Err(Error::CredentialExcluded);
189 }
190 }
191 }
192 }
193
194 let mut algorithm: Option<SigningAlgorithm> = None;
197 for param in parameters.pub_key_cred_params.0.iter() {
198 match param.alg {
199 -7 => {
200 if algorithm.is_none() {
201 algorithm = Some(SigningAlgorithm::P256);
202 }
203 }
204 -8 => {
205 algorithm = Some(SigningAlgorithm::Ed25519);
206 }
207 _ => {}
208 }
209 }
210 let algorithm = algorithm.ok_or(Error::UnsupportedAlgorithm)?;
211 info_now!("algo: {:?}", algorithm as i32);
212
213 let mut rk_requested = false;
216 let mut _uv_requested = false;
218 let _up_requested = true; info_now!("MC options: {:?}", ¶meters.options);
221 if let Some(ref options) = ¶meters.options {
222 if Some(true) == options.rk {
223 rk_requested = true;
224 }
225 if Some(true) == options.uv {
226 _uv_requested = true;
227 }
228 }
229
230 let mut hmac_secret_requested = None;
232 let mut cred_protect_requested = None;
234 let mut large_blob_key_requested = false;
235 let mut third_party_payment_requested = false;
236 if let Some(extensions) = ¶meters.extensions {
237 hmac_secret_requested = extensions.hmac_secret;
238
239 if let Some(policy) = &extensions.cred_protect {
240 cred_protect_requested =
241 Some(credential::CredentialProtectionPolicy::try_from(*policy)?);
242 }
243
244 if self.config.supports_large_blobs() {
245 if let Some(large_blob_key) = extensions.large_blob_key {
246 if large_blob_key {
247 if !rk_requested {
248 return Err(Error::InvalidOption);
250 }
251 large_blob_key_requested = true;
252 } else {
253 return Err(Error::InvalidOption);
255 }
256 }
257 }
258
259 third_party_payment_requested = extensions.third_party_payment.unwrap_or_default();
260 }
261
262 self.up
266 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
267
268 let location = match rk_requested {
270 true => Location::Internal,
271 false => Location::Volatile,
272 };
273 let private_key = algorithm.generate_private_key(&mut self.trussed, location);
274 let cose_public_key = algorithm.derive_public_key(&mut self.trussed, private_key);
275
276 let key_parameter = match rk_requested {
280 true => Key::ResidentKey(private_key),
281 false => {
282 let wrapping_key = self.state.persistent.key_wrapping_key(&mut self.trussed)?;
284 let wrapped_key = syscall!(self.trussed.wrap_key_chacha8poly1305(
285 wrapping_key,
286 private_key,
287 &[],
288 None
289 ))
290 .wrapped_key;
291
292 Key::WrappedKey(Bytes::try_from(&*wrapped_key).map_err(|_| Error::Other)?)
297 }
298 };
299
300 let nonce = self.nonce();
302 info_now!("nonce = {:?}", &nonce);
303
304 let kek = self
306 .state
307 .persistent
308 .key_encryption_key(&mut self.trussed)?;
309
310 let large_blob_key = if large_blob_key_requested {
314 let key = syscall!(self.trussed.random_bytes(32)).bytes;
315 Some(ByteArray::new(key.as_slice().try_into().unwrap()))
316 } else {
317 None
318 };
319
320 let credential = FullCredential::new(
321 credential::CtapVersion::Fido21Pre,
322 ¶meters.rp,
323 ¶meters.user,
324 algorithm as i32,
325 key_parameter,
326 self.state.persistent.timestamp(&mut self.trussed)?,
327 hmac_secret_requested,
328 cred_protect_requested,
329 large_blob_key,
330 third_party_payment_requested.then_some(true),
331 nonce,
332 );
333
334 let credential_id =
336 StrippedCredential::from(&credential).id(&mut self.trussed, kek, &rp_id_hash)?;
337
338 if rk_requested {
339 let serialized_credential = credential.serialize()?;
341
342 self.delete_resident_key_by_user_id(&rp_id_hash, credential.user.id())
344 .ok();
345
346 let mut key_store_full = self.can_fit(serialized_credential.len()) == Some(false)
347 || CredentialManagement::new(self).count_credentials()?
348 >= self
349 .config
350 .max_resident_credential_count
351 .unwrap_or(MAX_RESIDENT_CREDENTIALS_GUESSTIMATE);
352
353 if !key_store_full {
354 let credential_id_hash = self.hash(credential_id.0.as_ref());
356 let result = try_syscall!(self.trussed.write_file(
357 Location::Internal,
358 rk_path(&rp_id_hash, &credential_id_hash),
359 serialized_credential,
360 None,
363 ));
364 key_store_full = result.is_err();
365 }
366
367 if key_store_full {
368 return Err(Error::KeyStoreFull);
369 }
370 }
371
372 use ctap2::AuthenticatorDataFlags as Flags;
376 info_now!("MC created cred id");
377
378 let (attestation_maybe, aaguid) = self.state.identity.attestation(&mut self.trussed);
379
380 let authenticator_data = ctap2::make_credential::AuthenticatorData {
381 rp_id_hash: &rp_id_hash,
382
383 flags: {
384 let mut flags = Flags::USER_PRESENCE;
385 if uv_performed {
386 flags |= Flags::USER_VERIFIED;
387 }
388 if true {
389 flags |= Flags::ATTESTED_CREDENTIAL_DATA;
390 }
391 if hmac_secret_requested.is_some() || cred_protect_requested.is_some() {
392 flags |= Flags::EXTENSION_DATA;
393 }
394 flags
395 },
396
397 sign_count: self.state.persistent.timestamp(&mut self.trussed)?,
398
399 attested_credential_data: {
400 let attested_credential_data = ctap2::make_credential::AttestedCredentialData {
402 aaguid: &aaguid,
403 credential_id: &credential_id.0,
404 credential_public_key: &cose_public_key,
405 };
406 Some(attested_credential_data)
408 },
409
410 extensions: {
411 if hmac_secret_requested.is_some() || cred_protect_requested.is_some() {
412 let mut extensions = ctap2::make_credential::Extensions::default();
413 extensions.cred_protect = parameters.extensions.as_ref().unwrap().cred_protect;
414 extensions.hmac_secret = parameters.extensions.as_ref().unwrap().hmac_secret;
415 Some(extensions)
416 } else {
417 None
418 }
419 },
420 };
421 let serialized_auth_data = authenticator_data.serialize()?;
424
425 let att_stmt_fmt = parameters
427 .attestation_formats_preference
428 .as_ref()
429 .map(SupportedAttestationFormat::select)
430 .unwrap_or(Some(SupportedAttestationFormat::Packed));
431 let att_stmt = if let Some(format) = att_stmt_fmt {
432 match format {
433 SupportedAttestationFormat::None => {
434 Some(AttestationStatement::None(NoneAttestationStatement {}))
435 }
436 SupportedAttestationFormat::Packed => {
437 let mut commitment = Bytes::<1024>::new();
438 commitment
439 .extend_from_slice(&serialized_auth_data)
440 .map_err(|_| Error::Other)?;
441 commitment
442 .extend_from_slice(parameters.client_data_hash)
443 .map_err(|_| Error::Other)?;
444
445 let (attestation_key, attestation_algorithm) = attestation_maybe
446 .as_ref()
447 .map(|attestation| (attestation.0, SigningAlgorithm::P256))
448 .unwrap_or((private_key, algorithm));
449 let signature =
450 attestation_algorithm.sign(&mut self.trussed, attestation_key, &commitment);
451 let packed = PackedAttestationStatement {
452 alg: attestation_algorithm.into(),
453 sig: Bytes::try_from(&*signature).map_err(|_| Error::Other)?,
454 x5c: attestation_maybe.as_ref().map(|attestation| {
455 let cert = attestation.1.clone();
457 let mut x5c = Vec::new();
458 x5c.push(cert).ok();
459 x5c
460 }),
461 };
462 Some(AttestationStatement::Packed(packed))
463 }
464 }
465 } else {
466 None
467 };
468
469 if !rk_requested {
470 let _success = syscall!(self.trussed.delete(private_key)).success;
471 info_now!("deleted private credential key: {}", _success);
472 }
473
474 let mut attestation_object = ctap2::make_credential::ResponseBuilder {
475 fmt: att_stmt_fmt
476 .map(From::from)
477 .unwrap_or(AttestationStatementFormat::None),
478 auth_data: serialized_auth_data,
479 }
480 .build();
481 attestation_object.att_stmt = att_stmt;
482 attestation_object.large_blob_key = large_blob_key;
483 Ok(attestation_object)
484 }
485
486 #[inline(never)]
487 fn reset(&mut self) -> Result<()> {
488 let uptime = syscall!(self.trussed.uptime()).uptime;
490 debug_now!("uptime: {:?}", uptime);
491 if uptime.as_secs() > 10 {
492 #[cfg(not(feature = "disable-reset-time-window"))]
493 return Err(Error::NotAllowed);
494 }
495 self.up
499 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
500
501 syscall!(self.trussed.delete_all(Location::Internal));
503 syscall!(self
504 .trussed
505 .remove_dir_all(Location::Internal, RK_DIR.into()));
506
507 large_blobs::reset(&mut self.trussed);
509
510 self.state.persistent.reset(&mut self.trussed)?;
512
513 self.state.runtime.reset(&mut self.trussed);
515
516 Ok(())
517 }
518
519 fn selection(&mut self) -> Result<()> {
520 self.up
521 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)
522 }
523
524 #[inline(never)]
525 fn client_pin(
526 &mut self,
527 parameters: &ctap2::client_pin::Request<'_>,
528 ) -> Result<ctap2::client_pin::Response> {
529 use ctap2::client_pin::PinV1Subcommand as Subcommand;
530 debug_now!("CTAP2.PIN...");
531 let pin_protocol = parameters
534 .pin_protocol
535 .ok_or(Error::MissingParameter)
536 .and_then(|pin_protocol| self.parse_pin_protocol(pin_protocol));
537 let mut response = ctap2::client_pin::Response::default();
538
539 match parameters.sub_command {
540 Subcommand::GetRetries => {
541 debug_now!("CTAP2.Pin.GetRetries");
542
543 response.retries = Some(self.state.persistent.retries());
544 }
545
546 Subcommand::GetKeyAgreement => {
547 debug_now!("CTAP2.Pin.GetKeyAgreement");
548
549 let pin_protocol = pin_protocol?;
550 response.key_agreement = Some(self.pin_protocol(pin_protocol).key_agreement_key());
551 }
552
553 Subcommand::SetPin => {
554 debug_now!("CTAP2.Pin.SetPin");
555 let platform_kek = match parameters.key_agreement.as_ref() {
557 Some(key) => key,
558 None => {
559 return Err(Error::MissingParameter);
560 }
561 };
562 let new_pin_enc = match parameters.new_pin_enc.as_ref() {
563 Some(pin) => pin,
564 None => {
565 return Err(Error::MissingParameter);
566 }
567 };
568 let pin_auth = match parameters.pin_auth.as_ref() {
569 Some(auth) => auth,
570 None => {
571 return Err(Error::MissingParameter);
572 }
573 };
574 let pin_protocol = pin_protocol?;
575
576 if self.state.persistent.pin_is_set() {
578 return Err(Error::NotAllowed);
579 }
580
581 let mut pin_protocol = self.pin_protocol(pin_protocol);
583 let shared_secret = pin_protocol.shared_secret(platform_kek)?;
584
585 pin_protocol.verify_pin_auth(&shared_secret, new_pin_enc, pin_auth)?;
591
592 let new_pin = self.decrypt_pin_check_length(&shared_secret, new_pin_enc)?;
594
595 shared_secret.delete(&mut self.trussed);
596
597 self.hash_store_pin(&new_pin)?;
599 self.state
600 .reset_retries(&mut self.trussed)
601 .map_err(|_| Error::Other)?;
602 }
603
604 Subcommand::ChangePin => {
605 debug_now!("CTAP2.Pin.ChangePin");
606
607 let platform_kek = match parameters.key_agreement.as_ref() {
609 Some(key) => key,
610 None => {
611 return Err(Error::MissingParameter);
612 }
613 };
614 let pin_hash_enc = match parameters.pin_hash_enc.as_ref() {
615 Some(hash) => hash,
616 None => {
617 return Err(Error::MissingParameter);
618 }
619 };
620 let new_pin_enc = match parameters.new_pin_enc.as_ref() {
621 Some(pin) => pin,
622 None => {
623 return Err(Error::MissingParameter);
624 }
625 };
626 let pin_auth = match parameters.pin_auth.as_ref() {
627 Some(auth) => auth,
628 None => {
629 return Err(Error::MissingParameter);
630 }
631 };
632 let pin_protocol = pin_protocol?;
633
634 self.state.pin_blocked()?;
636
637 let mut pin_protocol_impl = self.pin_protocol(pin_protocol);
639 let shared_secret = pin_protocol_impl.shared_secret(platform_kek)?;
640
641 let mut data = MediumData::new();
643 data.extend_from_slice(new_pin_enc)
644 .map_err(|_| Error::InvalidParameter)?;
645 data.extend_from_slice(pin_hash_enc)
646 .map_err(|_| Error::InvalidParameter)?;
647 pin_protocol_impl.verify_pin_auth(&shared_secret, &data, pin_auth)?;
648
649 self.state.decrement_retries(&mut self.trussed)?;
651
652 self.decrypt_pin_hash_and_maybe_escalate(
654 pin_protocol,
655 &shared_secret,
656 pin_hash_enc,
657 )?;
658
659 self.state.reset_retries(&mut self.trussed)?;
661
662 let new_pin = self.decrypt_pin_check_length(&shared_secret, new_pin_enc)?;
664
665 shared_secret.delete(&mut self.trussed);
666
667 self.hash_store_pin(&new_pin)?;
669
670 self.pin_protocol(pin_protocol).reset_pin_tokens();
671 }
672
673 Subcommand::GetPinToken => {
675 debug_now!("CTAP2.Pin.GetPinToken");
676
677 let key_agreement = parameters
679 .key_agreement
680 .as_ref()
681 .ok_or(Error::MissingParameter)?;
682 let pin_hash_enc = parameters
683 .pin_hash_enc
684 .as_ref()
685 .ok_or(Error::MissingParameter)?;
686
687 let pin_protocol = pin_protocol?;
689
690 if parameters.permissions.is_some() || parameters.rp_id.is_some() {
692 return Err(Error::InvalidParameter);
693 }
694
695 self.state.pin_blocked()?;
697
698 let shared_secret = self
700 .pin_protocol(pin_protocol)
701 .shared_secret(key_agreement)?;
702
703 self.state.decrement_retries(&mut self.trussed)?;
707
708 self.decrypt_pin_hash_and_maybe_escalate(
710 pin_protocol,
711 &shared_secret,
712 pin_hash_enc,
713 )?;
714
715 self.state.reset_retries(&mut self.trussed)?;
717
718 let mut pin_protocol = self.pin_protocol(pin_protocol);
723 let mut pin_token = pin_protocol.reset_and_begin_using_pin_token(false);
724
725 let mut permissions = Permissions::empty();
727 permissions.insert(Permissions::MAKE_CREDENTIAL);
728 permissions.insert(Permissions::GET_ASSERTION);
729 pin_token.restrict(permissions, None);
730
731 response.pin_token = Some(pin_token.encrypt(&shared_secret)?);
733
734 shared_secret.delete(&mut self.trussed);
735 }
736
737 Subcommand::GetPinUvAuthTokenUsingPinWithPermissions => {
739 debug_now!("CTAP2.Pin.GetPinUvAuthTokenUsingPinWithPermissions");
740
741 let key_agreement = parameters
743 .key_agreement
744 .as_ref()
745 .ok_or(Error::MissingParameter)?;
746 let pin_hash_enc = parameters
747 .pin_hash_enc
748 .as_ref()
749 .ok_or(Error::MissingParameter)?;
750 let permissions = parameters.permissions.ok_or(Error::MissingParameter)?;
751
752 let pin_protocol = pin_protocol?;
754
755 let permissions = Permissions::from_bits_truncate(permissions);
757 if permissions.is_empty() {
758 return Err(Error::InvalidParameter);
759 }
760
761 let mut unauthorized_permissions = Permissions::empty();
763 unauthorized_permissions.insert(Permissions::BIO_ENROLLMENT);
764 if !self.config.supports_large_blobs() {
765 unauthorized_permissions.insert(Permissions::LARGE_BLOB_WRITE);
766 }
767 unauthorized_permissions.insert(Permissions::AUTHENTICATOR_CONFIGURATION);
768 if permissions.intersects(unauthorized_permissions) {
769 return Err(Error::UnauthorizedPermission);
770 }
771
772 self.state.pin_blocked()?;
774
775 let shared_secret = self
777 .pin_protocol(pin_protocol)
778 .shared_secret(key_agreement)?;
779
780 self.state.decrement_retries(&mut self.trussed)?;
784
785 self.decrypt_pin_hash_and_maybe_escalate(
787 pin_protocol,
788 &shared_secret,
789 pin_hash_enc,
790 )?;
791
792 self.state.reset_retries(&mut self.trussed)?;
794
795 let mut pin_protocol = self.pin_protocol(pin_protocol);
800 let mut pin_token = pin_protocol.reset_and_begin_using_pin_token(false);
801
802 let rp_id = parameters
805 .rp_id
806 .map(TryInto::try_into)
807 .transpose()
808 .map_err(|_| Error::InvalidParameter)?;
809 pin_token.restrict(permissions, rp_id);
810
811 response.pin_token = Some(pin_token.encrypt(&shared_secret)?);
813
814 shared_secret.delete(&mut self.trussed);
815 }
816
817 Subcommand::GetPinUvAuthTokenUsingUvWithPermissions | Subcommand::GetUVRetries => {
818 return Err(Error::InvalidParameter);
820 }
821
822 _ => {
823 return Err(Error::InvalidParameter);
824 }
825 }
826
827 Ok(response)
828 }
829
830 #[inline(never)]
831 fn credential_management(
832 &mut self,
833 parameters: &ctap2::credential_management::Request<'_>,
834 ) -> Result<ctap2::credential_management::Response> {
835 use credential_management as cm;
836 use ctap2::credential_management::Subcommand;
837
838 self.verify_credential_management_pin_auth(parameters)?;
839
840 let mut cred_mgmt = cm::CredentialManagement::new(self);
841 let sub_parameters = ¶meters.sub_command_params;
842 match parameters.sub_command {
844 Subcommand::GetCredsMetadata => cred_mgmt.get_creds_metadata(),
846
847 Subcommand::EnumerateRpsBegin => cred_mgmt.first_relying_party(),
849
850 Subcommand::EnumerateRpsGetNextRp => cred_mgmt.next_relying_party(),
852
853 Subcommand::EnumerateCredentialsBegin => {
855 let sub_parameters = sub_parameters.as_ref().ok_or(Error::MissingParameter)?;
856
857 cred_mgmt.first_credential(
858 sub_parameters
859 .rp_id_hash
860 .as_ref()
861 .ok_or(Error::MissingParameter)?,
862 )
863 }
864
865 Subcommand::EnumerateCredentialsGetNextCredential => cred_mgmt.next_credential(),
867
868 Subcommand::DeleteCredential => {
870 let sub_parameters = sub_parameters.as_ref().ok_or(Error::MissingParameter)?;
871
872 cred_mgmt.delete_credential(
873 sub_parameters
874 .credential_id
875 .as_ref()
876 .ok_or(Error::MissingParameter)?,
877 )
878 }
879
880 Subcommand::UpdateUserInformation => {
882 let sub_parameters = sub_parameters.as_ref().ok_or(Error::MissingParameter)?;
883 let credential_id = sub_parameters
884 .credential_id
885 .as_ref()
886 .ok_or(Error::MissingParameter)?;
887 let user = sub_parameters
888 .user
889 .as_ref()
890 .ok_or(Error::MissingParameter)?;
891
892 cred_mgmt.update_user_information(credential_id, user)
893 }
894
895 _ => Err(Error::InvalidParameter),
896 }
897 }
898
899 #[inline(never)]
900 fn vendor(&mut self, op: VendorOperation) -> Result<()> {
901 info_now!("hello VO {:?}", &op);
902 match op.into() {
903 0x79 => {
904 #[allow(deprecated)]
905 {
906 syscall!(self.trussed.debug_dump_store());
907 }
908 Err(Error::InvalidCommand)
909 }
910 _ => Err(Error::InvalidCommand),
911 }
912 }
913
914 #[inline(never)]
915 fn get_assertion(
916 &mut self,
917 parameters: &ctap2::get_assertion::Request,
918 ) -> Result<ctap2::get_assertion::Response> {
919 debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
920
921 let rp_id_hash = self.hash(parameters.rp_id.as_ref());
922
923 let uv_performed = match self.pin_prechecks(
925 ¶meters.options,
926 parameters.pin_auth.map(AsRef::as_ref),
927 parameters.pin_protocol,
928 parameters.client_data_hash.as_ref(),
929 Permissions::GET_ASSERTION,
930 parameters.rp_id,
931 ) {
932 Ok(b) => b,
933 Err(Error::PinRequired) => {
934 false
936 }
937 Err(err) => return Err(err),
938 };
939
940 let (credential, num_credentials) = self
946 .prepare_credentials(&rp_id_hash, ¶meters.allow_list, uv_performed)?
947 .ok_or(Error::NoCredentials)?;
948
949 info_now!("found {:?} applicable credentials", num_credentials);
950 info_now!("{:?}", &credential);
951
952 if parameters
956 .options
957 .as_ref()
958 .and_then(|options| options.rk)
959 .is_some()
960 {
961 return Err(Error::InvalidOption);
962 }
963
964 let do_up = if let Some(options) = parameters.options.as_ref() {
966 options.up.unwrap_or(true)
967 } else {
968 true
969 };
970
971 let up_performed = if do_up {
973 if !self.skip_up_check() {
974 info_now!("asking for up");
975 self.up
976 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
977 }
978 true
979 } else {
980 info_now!("not asking for up");
981 false
982 };
983
984 let multiple_credentials = num_credentials > 1;
985 self.state.runtime.active_get_assertion = Some(state::ActiveGetAssertionData {
986 rp_id_hash: {
987 let mut buf = [0u8; 32];
988 buf.copy_from_slice(&rp_id_hash);
989 buf
990 },
991 client_data_hash: {
992 let mut buf = [0u8; 32];
993 buf.copy_from_slice(parameters.client_data_hash);
994 buf
995 },
996 uv_performed,
997 up_performed,
998 multiple_credentials,
999 extensions: parameters.extensions.clone(),
1000 attestation_formats_preference: parameters.attestation_formats_preference.clone(),
1001 });
1002
1003 let num_credentials = match num_credentials {
1004 1 => None,
1005 n => Some(n),
1006 };
1007
1008 self.assert_with_credential(num_credentials, credential)
1009 }
1010
1011 #[inline(never)]
1012 fn large_blobs(
1013 &mut self,
1014 request: &ctap2::large_blobs::Request,
1015 ) -> Result<ctap2::large_blobs::Response> {
1016 let Some(config) = self.config.large_blobs else {
1017 return Err(Error::InvalidCommand);
1018 };
1019
1020 match (request.get, request.set) {
1024 (None, None) | (Some(_), Some(_)) => Err(Error::InvalidParameter),
1025 (Some(get), None) => self.large_blobs_get(request, config, get),
1027 (None, Some(set)) => self.large_blobs_set(request, config, set),
1029 }
1030 }
1031}
1032
1033impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
1035 fn parse_pin_protocol(&self, version: impl TryInto<u8>) -> Result<PinProtocolVersion> {
1036 if let Ok(version) = version.try_into() {
1037 for pin_protocol in self.pin_protocols() {
1038 if u8::from(*pin_protocol) == version {
1039 return Ok(*pin_protocol);
1040 }
1041 }
1042 }
1043 Err(Error::InvalidParameter)
1044 }
1045
1046 fn pin_protocols(&self) -> &'static [PinProtocolVersion] {
1048 &[PinProtocolVersion::V2, PinProtocolVersion::V1]
1049 }
1050
1051 fn pin_protocol(&mut self, pin_protocol: PinProtocolVersion) -> PinProtocol<'_, T> {
1052 let state = self.state.runtime.pin_protocol(&mut self.trussed);
1053 PinProtocol::new(&mut self.trussed, state, pin_protocol)
1054 }
1055
1056 #[inline(never)]
1057 fn check_credential_applicable(
1058 &mut self,
1059 credential: &Credential,
1060 allowlist_passed: bool,
1061 uv_performed: bool,
1062 ) -> bool {
1063 if !self.check_key_exists(credential.algorithm(), credential.key()) {
1064 return false;
1065 }
1066
1067 if !{
1068 use credential::CredentialProtectionPolicy as Policy;
1069 debug_now!("CredentialProtectionPolicy {:?}", credential.cred_protect());
1070 match credential.cred_protect() {
1071 None | Some(Policy::Optional) => true,
1072 Some(Policy::OptionalWithCredentialIdList) => allowlist_passed || uv_performed,
1073 Some(Policy::Required) => uv_performed,
1074 }
1075 } {
1076 return false;
1077 }
1078 true
1079 }
1080
1081 #[inline(never)]
1082 fn prepare_credentials(
1083 &mut self,
1084 rp_id_hash: &[u8; 32],
1085 allow_list: &Option<ctap2::get_assertion::AllowList>,
1086 uv_performed: bool,
1087 ) -> Result<Option<(Credential, u32)>> {
1088 debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
1089
1090 self.state.runtime.clear_credential_cache();
1091 self.state.runtime.active_get_assertion = None;
1092
1093 if let Some(allow_list) = allow_list {
1103 debug_now!("Allowlist of len {} passed, filtering", allow_list.len());
1104 if !allow_list.is_empty() {
1111 for credential_id in allow_list {
1112 let credential = match Credential::try_from(self, rp_id_hash, credential_id) {
1113 Ok(credential) => credential,
1114 _ => continue,
1115 };
1116
1117 if !self.check_credential_applicable(&credential, true, uv_performed) {
1118 continue;
1119 }
1120
1121 return Ok(Some((credential, 1)));
1122 }
1123
1124 return Ok(None);
1126 }
1127 }
1128
1129 debug_now!("Allowlist not passed, fetching RKs");
1131 self.prepare_cache(rp_id_hash, uv_performed)?;
1132
1133 let num_credentials = self.state.runtime.remaining_credentials();
1134 let credential = self.state.runtime.pop_credential(&mut self.trussed);
1135 Ok(credential.map(|credential| (Credential::Full(credential), num_credentials)))
1136 }
1137
1138 #[inline(never)]
1140 fn prepare_cache(&mut self, rp_id_hash: &[u8; 32], uv_performed: bool) -> Result<()> {
1141 use crate::state::CachedCredential;
1142 use core::str::FromStr;
1143
1144 let file_name_prefix = rp_file_name_prefix(rp_id_hash);
1145 let mut maybe_entry = syscall!(self.trussed.read_dir_first_alphabetical(
1146 Location::Internal,
1147 PathBuf::from(RK_DIR),
1148 Some(file_name_prefix.clone())
1149 ))
1150 .entry;
1151
1152 while let Some(entry) = maybe_entry.take() {
1153 if !entry
1154 .file_name()
1155 .as_ref()
1156 .starts_with(file_name_prefix.as_ref())
1157 {
1158 break;
1160 }
1161
1162 if entry.file_name() == &*file_name_prefix {
1163 debug_assert!(entry.metadata().is_dir());
1164 error!("Migration missing");
1165 return Err(Error::Other);
1166 }
1167
1168 let credential_data = syscall!(self
1169 .trussed
1170 .read_file(Location::Internal, entry.path().into(),))
1171 .data;
1172
1173 let credential = FullCredential::deserialize(&credential_data).map_err(|_err| {
1174 error!("Failed to deserialize credential: {_err:?}");
1175 Error::Other
1176 })?;
1177 let timestamp = credential.creation_time;
1178 let credential = Credential::Full(credential);
1179
1180 if self.check_credential_applicable(&credential, false, uv_performed) {
1181 self.state.runtime.push_credential(CachedCredential {
1182 timestamp,
1183 path: String::from_str(entry.path().as_str_ref_with_trailing_nul())
1184 .map_err(|_| Error::Other)?,
1185 });
1186 }
1187
1188 maybe_entry = syscall!(self.trussed.read_dir_next()).entry;
1189 }
1190 Ok(())
1191 }
1192
1193 fn decrypt_pin_hash_and_maybe_escalate(
1194 &mut self,
1195 pin_protocol: PinProtocolVersion,
1196 shared_secret: &SharedSecret,
1197 pin_hash_enc: &[u8],
1198 ) -> Result<()> {
1199 let pin_hash = shared_secret
1200 .decrypt(&mut self.trussed, pin_hash_enc)
1201 .ok_or(Error::Other)?;
1202
1203 let stored_pin_hash = match self.state.persistent.pin_hash() {
1204 Some(hash) => hash,
1205 None => {
1206 return Err(Error::PinNotSet);
1207 }
1208 };
1209
1210 if pin_hash != stored_pin_hash {
1211 self.pin_protocol(pin_protocol).regenerate();
1213 self.state.pin_blocked()?;
1214 return Err(Error::PinInvalid);
1215 }
1216
1217 Ok(())
1218 }
1219
1220 fn hash_store_pin(&mut self, pin: &Message) -> Result<()> {
1221 let pin_hash_32 = syscall!(self.trussed.hash_sha256(pin)).hash;
1222 let pin_hash: [u8; 16] = pin_hash_32[..16].try_into().unwrap();
1223 self.state
1224 .persistent
1225 .set_pin_hash(&mut self.trussed, pin_hash)
1226 .unwrap();
1227
1228 Ok(())
1229 }
1230
1231 fn decrypt_pin_check_length(
1232 &mut self,
1233 shared_secret: &SharedSecret,
1234 pin_enc: &[u8],
1235 ) -> Result<Message> {
1236 if pin_enc.len() < 64 {
1238 return Err(Error::PinPolicyViolation);
1240 }
1241
1242 let mut pin = shared_secret
1243 .decrypt(&mut self.trussed, pin_enc)
1244 .ok_or(Error::Other)?;
1245
1246 let pin_length = pin.iter().position(|&b| b == b'\0').unwrap_or(pin.len());
1252 if !(4..64).contains(&pin_length) {
1253 return Err(Error::PinPolicyViolation);
1254 }
1255
1256 pin.resize_zero(pin_length).unwrap();
1257
1258 Ok(pin)
1259 }
1260
1261 fn verify_credential_management_pin_auth(
1262 &mut self,
1263 parameters: &ctap2::credential_management::Request,
1264 ) -> Result<()> {
1265 use ctap2::credential_management::Subcommand;
1266 let rp_scope = match parameters.sub_command {
1267 Subcommand::EnumerateCredentialsBegin => {
1268 let rp_id_hash = parameters
1269 .sub_command_params
1270 .as_ref()
1271 .and_then(|subparams| subparams.rp_id_hash)
1272 .ok_or(Error::MissingParameter)?;
1273 RpScope::RpIdHash(rp_id_hash)
1274 }
1275 Subcommand::DeleteCredential | Subcommand::UpdateUserInformation => {
1276 RpScope::All
1278 }
1279 _ => RpScope::All,
1280 };
1281 match parameters.sub_command {
1282 Subcommand::GetCredsMetadata
1283 | Subcommand::EnumerateRpsBegin
1284 | Subcommand::EnumerateCredentialsBegin
1285 | Subcommand::DeleteCredential
1286 | Subcommand::UpdateUserInformation => {
1287 let pin_protocol = parameters.pin_protocol.ok_or(Error::MissingParameter)?;
1289 let pin_protocol = self.parse_pin_protocol(pin_protocol)?;
1290
1291 let mut data: Bytes<{ sizes::MAX_CREDENTIAL_ID_LENGTH_PLUS_256 }> =
1293 Bytes::from(&[parameters.sub_command as u8]);
1294 let len = 1 + match parameters.sub_command {
1295 Subcommand::EnumerateCredentialsBegin
1296 | Subcommand::DeleteCredential
1297 | Subcommand::UpdateUserInformation => {
1298 data.resize_to_capacity();
1299 ctap_types::serde::cbor_serialize(
1301 ¶meters
1302 .sub_command_params
1303 .as_ref()
1304 .ok_or(Error::MissingParameter)?,
1305 &mut data[1..],
1306 )
1307 .map_err(|_| Error::LimitExceeded)?
1308 .len()
1309 }
1310 _ => 0,
1311 };
1312
1313 let pin_auth = parameters
1314 .pin_auth
1315 .as_ref()
1316 .ok_or(Error::MissingParameter)?;
1317
1318 let mut pin_protocol = self.pin_protocol(pin_protocol);
1319 if let Ok(pin_token) = pin_protocol.verify_pin_token(&data[..len], pin_auth) {
1320 info_now!("passed pinauth");
1321 pin_token.require_permissions(Permissions::CREDENTIAL_MANAGEMENT)?;
1322 pin_token.require_valid_for_rp(rp_scope)?;
1323 Ok(())
1324 } else {
1325 info_now!("failed pinauth!");
1326 self.state.decrement_retries(&mut self.trussed)?;
1327 let maybe_blocked = self.state.pin_blocked();
1328 if maybe_blocked.is_err() {
1329 info_now!("blocked");
1330 maybe_blocked
1331 } else {
1332 info_now!("pinAuthInvalid");
1333 Err(Error::PinAuthInvalid)
1334 }
1335 }
1336 }
1337
1338 Subcommand::EnumerateRpsGetNextRp
1341 | Subcommand::EnumerateCredentialsGetNextCredential => Ok(()),
1342
1343 _ => Err(Error::InvalidParameter),
1344 }
1345 }
1346
1347 fn pin_prechecks(
1349 &mut self,
1350 options: &Option<ctap2::AuthenticatorOptions>,
1351 pin_auth: Option<&[u8]>,
1352 pin_protocol: Option<u32>,
1353 data: &[u8],
1354 permissions: Permissions,
1355 rp_id: &str,
1356 ) -> Result<bool> {
1357 if let Some(pin_auth) = pin_auth {
1363 if pin_auth.is_empty() {
1364 self.up
1365 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
1366 if !self.state.persistent.pin_is_set() {
1367 return Err(Error::PinNotSet);
1368 } else {
1369 return Err(Error::PinAuthInvalid);
1370 }
1371 }
1372 }
1373
1374 let pin_protocol = if pin_auth.is_some() {
1376 let pin_protocol = pin_protocol.ok_or(Error::MissingParameter)?;
1377 let pin_protocol = self.parse_pin_protocol(pin_protocol)?;
1378 Some(pin_protocol)
1379 } else {
1380 None
1381 };
1382
1383 if !self.state.persistent.pin_is_set() {
1386 if let Some(ref options) = &options {
1387 if Some(true) == options.uv {
1388 return Err(Error::InvalidOption);
1389 }
1390 }
1391 if pin_auth.is_some() {
1392 return Err(Error::InvalidOption);
1393 }
1394 }
1395
1396 if pin_auth.is_none() && options.as_ref().and_then(|options| options.uv) == Some(true) {
1400 return Err(Error::InvalidOption);
1401 }
1402
1403 if self.state.persistent.pin_is_set() {
1404 if let Some(pin_auth) = pin_auth {
1406 if let Some(pin_protocol) = pin_protocol {
1409 let mut pin_protocol = self.pin_protocol(pin_protocol);
1413 let pin_token = pin_protocol.verify_pin_token(data, pin_auth)?;
1414 pin_token.require_permissions(permissions)?;
1415 pin_token.require_valid_for_rp(RpScope::RpId(rp_id))?;
1416
1417 return Ok(true);
1418 } else {
1419 return Err(Error::PinAuthInvalid);
1421 }
1422 } else {
1423 if options.as_ref().and_then(|options| options.rk) == Some(true) {
1425 return Err(Error::PinRequired);
1426 }
1427 }
1428 }
1429
1430 Ok(false)
1431 }
1432
1433 #[inline(never)]
1434 fn check_key_exists(&mut self, alg: i32, key: &Key) -> bool {
1435 match key {
1436 Key::WrappedKey(_) => true,
1439 Key::ResidentKey(key) => {
1440 debug_now!("checking if ResidentKey {:?} exists", key);
1441 SigningAlgorithm::try_from(alg)
1442 .map(|alg| syscall!(self.trussed.exists(alg.mechanism(), *key)).exists)
1443 .unwrap_or_default()
1444 }
1445 }
1446 }
1447
1448 #[inline(never)]
1449 fn process_assertion_extensions(
1450 &mut self,
1451 get_assertion_state: &state::ActiveGetAssertionData,
1452 extensions: &ctap2::get_assertion::ExtensionsInput,
1453 credential: &Credential,
1454 credential_key: KeyId,
1455 ) -> Result<Option<ctap2::get_assertion::ExtensionsOutput>> {
1456 let mut output = ctap2::get_assertion::ExtensionsOutput::default();
1457
1458 if let Some(hmac_secret) = &extensions.hmac_secret {
1459 let pin_protocol = hmac_secret
1460 .pin_protocol
1461 .map(|i| self.parse_pin_protocol(i))
1462 .transpose()?
1463 .unwrap_or(PinProtocolVersion::V1);
1464
1465 if !get_assertion_state.up_performed {
1466 return Err(Error::UnsupportedOption);
1467 }
1468
1469 let cred_random = syscall!(self.trussed.derive_key(
1473 Mechanism::HmacSha256,
1474 credential_key,
1475 Some(Bytes::from(&[get_assertion_state.uv_performed as u8])),
1476 StorageAttributes::new().set_persistence(Location::Volatile)
1477 ))
1478 .key;
1479
1480 let mut pin_protocol = self.pin_protocol(pin_protocol);
1482 let shared_secret = pin_protocol.shared_secret(&hmac_secret.key_agreement)?;
1483 pin_protocol.verify_pin_auth(
1484 &shared_secret,
1485 &hmac_secret.salt_enc,
1486 &hmac_secret.salt_auth,
1487 )?;
1488
1489 let salts = shared_secret
1491 .decrypt(&mut self.trussed, &hmac_secret.salt_enc)
1492 .ok_or(Error::InvalidOption)?;
1493
1494 if salts.len() != 32 && salts.len() != 64 {
1495 debug_now!("invalid hmac-secret length");
1496 return Err(Error::InvalidLength);
1497 }
1498
1499 let mut salt_output: Bytes<64> = Bytes::new();
1500
1501 let output1 =
1503 syscall!(self.trussed.sign_hmacsha256(cred_random, &salts[0..32])).signature;
1504
1505 salt_output.extend_from_slice(&output1).unwrap();
1506
1507 if salts.len() == 64 {
1508 let output2 =
1510 syscall!(self.trussed.sign_hmacsha256(cred_random, &salts[32..64])).signature;
1511
1512 salt_output.extend_from_slice(&output2).unwrap();
1513 }
1514
1515 syscall!(self.trussed.delete(cred_random));
1516
1517 let output_enc = shared_secret.encrypt(&mut self.trussed, &salt_output);
1519
1520 shared_secret.delete(&mut self.trussed);
1521
1522 output.hmac_secret = Some(Bytes::try_from(&*output_enc).unwrap());
1523 }
1524
1525 if extensions.third_party_payment.unwrap_or_default() {
1526 output.third_party_payment = Some(credential.third_party_payment().unwrap_or_default());
1527 }
1528
1529 Ok(output.is_set().then_some(output))
1530 }
1531
1532 #[inline(never)]
1533 fn assert_with_credential(
1534 &mut self,
1535 num_credentials: Option<u32>,
1536 credential: Credential,
1537 ) -> Result<ctap2::get_assertion::Response> {
1538 let data = self.state.runtime.active_get_assertion.clone().unwrap();
1539 let rp_id_hash = &data.rp_id_hash;
1540
1541 let (key, is_rk) = match credential.key().clone() {
1542 Key::ResidentKey(key) => (key, true),
1543 Key::WrappedKey(bytes) => {
1544 let wrapping_key = self.state.persistent.key_wrapping_key(&mut self.trussed)?;
1545 let key_result = syscall!(self.trussed.unwrap_key_chacha8poly1305(
1547 wrapping_key,
1548 &bytes,
1549 &[],
1550 Location::Volatile,
1551 ))
1552 .key;
1553 info_now!("key result");
1555 match key_result {
1556 Some(key) => (key, false),
1557 None => {
1558 return Err(Error::Other);
1559 }
1560 }
1561 }
1562 };
1563
1564 let mut large_blob_key_requested = false;
1566 let extensions_output = if let Some(extensions) = &data.extensions {
1567 if self.config.supports_large_blobs() {
1568 if extensions.large_blob_key == Some(false) {
1569 return Err(Error::InvalidOption);
1571 }
1572 large_blob_key_requested = extensions.large_blob_key == Some(true);
1573 }
1574 self.process_assertion_extensions(&data, extensions, &credential, key)?
1575 } else {
1576 None
1577 };
1578
1579 let kek = self
1583 .state
1584 .persistent
1585 .key_encryption_key(&mut self.trussed)?;
1586 let credential_id = credential.id(&mut self.trussed, kek, rp_id_hash)?;
1587
1588 use ctap2::AuthenticatorDataFlags as Flags;
1589
1590 let sig_count = self.state.persistent.timestamp(&mut self.trussed)?;
1591
1592 let authenticator_data = ctap2::get_assertion::AuthenticatorData {
1593 rp_id_hash,
1594
1595 flags: {
1596 let mut flags = Flags::empty();
1597 if data.up_performed {
1598 flags |= Flags::USER_PRESENCE;
1599 }
1600 if data.uv_performed {
1601 flags |= Flags::USER_VERIFIED;
1602 }
1603 if extensions_output.is_some() {
1604 flags |= Flags::EXTENSION_DATA;
1605 }
1606 flags
1607 },
1608
1609 sign_count: sig_count,
1610 attested_credential_data: None,
1611 extensions: extensions_output,
1612 };
1613
1614 let serialized_auth_data = authenticator_data.serialize()?;
1615
1616 let mut commitment = Bytes::<1024>::new();
1617 commitment
1618 .extend_from_slice(&serialized_auth_data)
1619 .map_err(|_| Error::Other)?;
1620 commitment
1621 .extend_from_slice(&data.client_data_hash)
1622 .map_err(|_| Error::Other)?;
1623
1624 let signing_algorithm =
1625 SigningAlgorithm::try_from(credential.algorithm()).map_err(|_| Error::Other)?;
1626 let signature =
1627 Bytes::try_from(&*signing_algorithm.sign(&mut self.trussed, key, &commitment)).unwrap();
1628
1629 let att_stmt_fmt = data
1631 .attestation_formats_preference
1632 .as_ref()
1633 .and_then(SupportedAttestationFormat::select);
1634 let att_stmt = if let Some(format) = att_stmt_fmt {
1635 match format {
1636 SupportedAttestationFormat::None => {
1637 Some(AttestationStatement::None(NoneAttestationStatement {}))
1638 }
1639 SupportedAttestationFormat::Packed => {
1640 let (attestation_maybe, _) = self.state.identity.attestation(&mut self.trussed);
1641 let (signature, attestation_algorithm) = {
1642 if let Some(attestation) = attestation_maybe.as_ref() {
1643 let signing_algorithm = SigningAlgorithm::P256;
1644 let signature = signing_algorithm.sign(
1645 &mut self.trussed,
1646 attestation.0,
1647 &commitment,
1648 );
1649 (
1650 Bytes::try_from(&*signature).map_err(|_| Error::Other)?,
1651 signing_algorithm.into(),
1652 )
1653 } else {
1654 (signature.clone(), credential.algorithm())
1655 }
1656 };
1657 let packed = PackedAttestationStatement {
1658 alg: attestation_algorithm,
1659 sig: signature,
1660 x5c: attestation_maybe.as_ref().map(|attestation| {
1661 let cert = attestation.1.clone();
1663 let mut x5c = Vec::new();
1664 x5c.push(cert).ok();
1665 x5c
1666 }),
1667 };
1668 Some(AttestationStatement::Packed(packed))
1669 }
1670 }
1671 } else {
1672 None
1673 };
1674
1675 if !is_rk {
1676 syscall!(self.trussed.delete(key));
1677 }
1678
1679 let mut response = ctap2::get_assertion::ResponseBuilder {
1680 credential: credential_id.into(),
1681 auth_data: serialized_auth_data,
1682 signature,
1683 }
1684 .build();
1685 response.number_of_credentials = num_credentials;
1686 response.att_stmt = att_stmt;
1687
1688 if is_rk {
1690 if let Credential::Full(credential) = &credential {
1691 if !credential.user.id().is_empty() {
1692 let mut user: PublicKeyCredentialUserEntity = credential.user.clone().into();
1693 if !data.uv_performed || !data.multiple_credentials {
1697 user.icon = None;
1698 user.name = None;
1699 user.display_name = None;
1700 }
1701 response.user = Some(user);
1702 }
1703 }
1704
1705 if large_blob_key_requested {
1706 debug!("Sending largeBlobKey in getAssertion");
1707 response.large_blob_key = match credential {
1708 Credential::Stripped(stripped) => stripped.large_blob_key,
1709 Credential::Full(full) => full.data.large_blob_key,
1710 };
1711 }
1712 }
1713
1714 Ok(response)
1715 }
1716
1717 #[inline(never)]
1718 fn delete_resident_key_by_user_id(
1719 &mut self,
1720 rp_id_hash: &[u8; 32],
1721 user_id: &Bytes<64>,
1722 ) -> Result<()> {
1723 let file_name_prefix = rp_file_name_prefix(rp_id_hash);
1725 let mut maybe_entry = syscall!(self.trussed.read_dir_first_alphabetical(
1726 Location::Internal,
1727 PathBuf::from(RK_DIR),
1728 Some(file_name_prefix.clone())
1729 ))
1730 .entry;
1731
1732 while let Some(entry) = maybe_entry.take() {
1733 if !entry
1734 .file_name()
1735 .as_ref()
1736 .starts_with(file_name_prefix.as_ref())
1737 {
1738 break;
1740 }
1741
1742 if entry.file_name() == &*file_name_prefix {
1743 debug_assert!(entry.metadata().is_dir());
1744 error!("Migration missing");
1745 return Err(Error::Other);
1746 }
1747
1748 info_now!("this may be an RK: {:?}", &entry);
1749 let rk_path = PathBuf::from(entry.path());
1750
1751 info_now!("checking RK {:?} for userId ", &rk_path);
1752 let credential_data =
1753 syscall!(self.trussed.read_file(Location::Internal, rk_path.clone(),)).data;
1754 let credential_maybe = FullCredential::deserialize(&credential_data);
1755
1756 if let Ok(old_credential) = credential_maybe {
1757 if old_credential.user.id() == user_id {
1758 match old_credential.key {
1759 credential::Key::ResidentKey(key) => {
1760 info_now!(":: deleting resident key");
1761 syscall!(self.trussed.delete(key));
1762 }
1763 _ => {
1764 warn_now!(":: WARNING: unexpected server credential in rk.");
1765 }
1766 }
1767 syscall!(self.trussed.remove_file(Location::Internal, rk_path,));
1768
1769 info_now!("Overwriting previous rk tied to this userId.");
1770 break;
1771 }
1772 } else {
1773 warn_now!("WARNING: Could not read RK.");
1774 }
1775
1776 maybe_entry = syscall!(self.trussed.read_dir_next()).entry;
1778 }
1779
1780 Ok(())
1781 }
1782
1783 #[inline(never)]
1784 pub(crate) fn delete_resident_key_by_path(&mut self, rk_path: &Path) -> Result<()> {
1785 info_now!("deleting RK {:?}", &rk_path);
1786 let credential_data = syscall!(self
1787 .trussed
1788 .read_file(Location::Internal, PathBuf::from(rk_path),))
1789 .data;
1790 let credential_maybe = FullCredential::deserialize(&credential_data);
1791 if let Ok(credential) = credential_maybe {
1794 match credential.key {
1795 credential::Key::ResidentKey(key) => {
1796 info_now!(":: deleting resident key");
1797 syscall!(self.trussed.delete(key));
1798 }
1799 credential::Key::WrappedKey(_) => {}
1800 }
1801 } else {
1802 info_now!("Warning! Orpaning a key.");
1805 }
1806
1807 info_now!(":: deleting RK file {:?} itself", &rk_path);
1808 syscall!(self
1809 .trussed
1810 .remove_file(Location::Internal, PathBuf::from(rk_path),));
1811
1812 Ok(())
1813 }
1814
1815 fn large_blobs_get(
1816 &mut self,
1817 request: &ctap2::large_blobs::Request,
1818 config: large_blobs::Config,
1819 length: u32,
1820 ) -> Result<ctap2::large_blobs::Response> {
1821 debug!(
1822 "large_blobs_get: length = {length}, offset = {}",
1823 request.offset
1824 );
1825 if request.length.is_some()
1827 || request.pin_uv_auth_param.is_some()
1828 || request.pin_uv_auth_protocol.is_some()
1829 {
1830 error!("length/pin set");
1831 return Err(Error::InvalidParameter);
1832 }
1833 let Ok(length) = usize::try_from(length) else {
1835 return Err(Error::InvalidLength);
1836 };
1837 if length > self.config.max_msg_size.saturating_sub(64) {
1838 return Err(Error::InvalidLength);
1839 }
1840 let Ok(offset) = usize::try_from(request.offset) else {
1842 error!("offset too large");
1843 return Err(Error::InvalidParameter);
1844 };
1845 let stored_length = large_blobs::size(&mut self.trussed, config.location)?;
1846 if offset > stored_length {
1847 error!("offset: {offset}, stored_length: {stored_length}");
1848 return Err(Error::InvalidParameter);
1849 };
1850 info!("Reading large-blob array from offset {offset}");
1852 let data = large_blobs::read_chunk(&mut self.trussed, config.location, offset, length)?;
1853 let mut response = ctap2::large_blobs::Response::default();
1854 response.config = Some(data);
1855 Ok(response)
1856 }
1857
1858 fn large_blobs_set(
1859 &mut self,
1860 request: &ctap2::large_blobs::Request,
1861 config: large_blobs::Config,
1862 data: &[u8],
1863 ) -> Result<ctap2::large_blobs::Response> {
1864 debug!(
1865 "large_blobs_set: |data| = {}, offset = {}, length = {:?}",
1866 data.len(),
1867 request.offset,
1868 request.length
1869 );
1870 if data.len() > self.config.max_msg_size.saturating_sub(64) {
1872 return Err(Error::InvalidLength);
1873 }
1874 if request.offset == 0 {
1875 let Some(length) = request.length else {
1878 return Err(Error::InvalidParameter);
1879 };
1880 let Ok(length) = usize::try_from(length) else {
1882 return Err(Error::LargeBlobStorageFull);
1883 };
1884 if length > config.max_size() {
1885 return Err(Error::LargeBlobStorageFull);
1886 }
1887 if length < large_blobs::MIN_SIZE {
1889 return Err(Error::InvalidParameter);
1890 }
1891 self.state.runtime.large_blobs.expected_length = length;
1893 self.state.runtime.large_blobs.expected_next_offset = 0;
1894 } else {
1895 if request.length.is_some() {
1897 return Err(Error::InvalidParameter);
1898 }
1899 }
1900
1901 let Ok(offset) = usize::try_from(request.offset) else {
1903 return Err(Error::InvalidSeq);
1904 };
1905 if offset != self.state.runtime.large_blobs.expected_next_offset {
1906 return Err(Error::InvalidSeq);
1907 }
1908
1909 if self.state.persistent.pin_is_set() {
1912 let Some(pin_uv_auth_param) = request.pin_uv_auth_param else {
1913 return Err(Error::PinRequired);
1914 };
1915 let Some(pin_uv_auth_protocol) = request.pin_uv_auth_protocol else {
1916 return Err(Error::PinRequired);
1917 };
1918 if pin_uv_auth_protocol != 1 {
1919 return Err(Error::PinAuthInvalid);
1920 }
1921 let pin_protocol = self.parse_pin_protocol(pin_uv_auth_protocol)?;
1922 let pin_auth: [u8; 16] = pin_uv_auth_param
1924 .as_ref()
1925 .try_into()
1926 .map_err(|_| Error::PinAuthInvalid)?;
1927
1928 let mut auth_data: Bytes<70> = Bytes::new();
1929 auth_data.resize(32, 0xff).unwrap();
1931 auth_data.push(0x0c).unwrap();
1933 auth_data.push(0x00).unwrap();
1934 auth_data
1936 .extend_from_slice(&request.offset.to_le_bytes())
1937 .unwrap();
1938 auth_data.extend_from_slice(&Sha256::digest(data)).unwrap();
1940
1941 let mut pin_protocol = self.pin_protocol(pin_protocol);
1942 let pin_token = pin_protocol.verify_pin_token(&pin_auth, &auth_data)?;
1943 pin_token.require_permissions(Permissions::LARGE_BLOB_WRITE)?;
1944 }
1945
1946 if offset + data.len() > self.state.runtime.large_blobs.expected_length {
1948 return Err(Error::InvalidParameter);
1949 }
1950
1951 info!("Writing large-blob array to offset {offset}");
1953 large_blobs::write_chunk(
1954 &mut self.trussed,
1955 &mut self.state.runtime.large_blobs,
1956 config.location,
1957 data,
1958 )?;
1959
1960 Ok(ctap2::large_blobs::Response::default())
1961 }
1962}
1963
1964#[derive(Clone, Copy, Debug)]
1965enum SupportedAttestationFormat {
1966 None,
1967 Packed,
1968}
1969
1970impl SupportedAttestationFormat {
1971 fn select(preference: &AttestationFormatsPreference) -> Option<Self> {
1972 if preference.known_formats() == [AttestationStatementFormat::None]
1973 && !preference.includes_unknown_formats()
1974 {
1975 return None;
1977 }
1978 let format = preference
1980 .known_formats()
1981 .iter()
1982 .copied()
1983 .flat_map(Self::try_from)
1984 .next()
1985 .unwrap_or(Self::Packed);
1986 Some(format)
1987 }
1988}
1989
1990impl From<SupportedAttestationFormat> for AttestationStatementFormat {
1991 fn from(format: SupportedAttestationFormat) -> Self {
1992 match format {
1993 SupportedAttestationFormat::None => Self::None,
1994 SupportedAttestationFormat::Packed => Self::Packed,
1995 }
1996 }
1997}
1998
1999impl TryFrom<AttestationStatementFormat> for SupportedAttestationFormat {
2000 type Error = Error;
2001
2002 fn try_from(format: AttestationStatementFormat) -> core::result::Result<Self, Self::Error> {
2003 match format {
2004 AttestationStatementFormat::None => Ok(Self::None),
2005 AttestationStatementFormat::Packed => Ok(Self::Packed),
2006 _ => Err(Error::Other),
2007 }
2008 }
2009}
2010
2011fn rp_file_name_prefix(rp_id_hash: &[u8; 32]) -> PathBuf {
2019 let mut hex = [b'0'; 16];
2020 super::format_hex(&rp_id_hash[..8], &mut hex);
2021 PathBuf::try_from(&hex).unwrap()
2022}
2023
2024fn rk_path(rp_id_hash: &[u8; 32], credential_id_hash: &[u8; 32]) -> PathBuf {
2025 let mut buf = [0; 34];
2027 buf[16] = b'.';
2028 format_hex(&rp_id_hash[..8], &mut buf[..16]);
2029 format_hex(&credential_id_hash[..8], &mut buf[17..33]);
2030
2031 let mut path = PathBuf::from(RK_DIR);
2032 path.push(Path::from_bytes_with_nul(&buf).unwrap());
2033 path
2034}
2035
2036#[cfg(test)]
2037mod tests {
2038 use super::{rk_path, rp_file_name_prefix};
2039
2040 const TEST_HASH: &[u8; 32] = &[
2041 134, 54, 157, 96, 10, 28, 233, 79, 219, 59, 195, 125, 165, 251, 120, 14, 49, 152, 212, 191,
2042 114, 137, 180, 207, 255, 177, 187, 106, 173, 1, 203, 171,
2043 ];
2044 const TEST_HASH_HEX: &str = "86369d600a1ce94f";
2045
2046 #[test]
2047 fn test_rp_file_name_prefix() {
2048 assert_eq!(rp_file_name_prefix(&[0; 32]).as_str(), "0000000000000000");
2049 assert_eq!(rp_file_name_prefix(TEST_HASH).as_str(), TEST_HASH_HEX);
2050 }
2051
2052 #[test]
2053 fn test_rk_path() {
2054 fn test(rp_id_hash: &[u8; 32], credential_id_hash: &[u8; 32], expected: &str) {
2055 println!("rp_id_hash: {rp_id_hash:?}");
2056 println!("credential_id_hash: {credential_id_hash:?}");
2057 let actual = rk_path(rp_id_hash, credential_id_hash);
2058 assert_eq!(actual.as_str(), expected);
2059 }
2060
2061 let input_zero = &[0; 32];
2062 let output_zero = "0000000000000000";
2063 let input_nonzero = TEST_HASH;
2064 let output_nonzero = TEST_HASH_HEX;
2065
2066 test(
2067 input_zero,
2068 input_zero,
2069 &format!("rk/{output_zero}.{output_zero}"),
2070 );
2071 test(
2072 input_zero,
2073 input_nonzero,
2074 &format!("rk/{output_zero}.{output_nonzero}"),
2075 );
2076 test(
2077 input_nonzero,
2078 input_zero,
2079 &format!("rk/{output_nonzero}.{output_zero}"),
2080 );
2081 test(
2082 input_nonzero,
2083 input_nonzero,
2084 &format!("rk/{output_nonzero}.{output_nonzero}"),
2085 );
2086 }
2087}