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_slice(&aaguid).unwrap();
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(wrapped_key.to_bytes().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: signature.to_bytes().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 => syscall!(self.trussed.debug_dump_store()),
904 _ => return Err(Error::InvalidCommand),
905 };
906
907 Ok(())
908 }
909
910 #[inline(never)]
911 fn get_assertion(
912 &mut self,
913 parameters: &ctap2::get_assertion::Request,
914 ) -> Result<ctap2::get_assertion::Response> {
915 debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
916
917 let rp_id_hash = self.hash(parameters.rp_id.as_ref());
918
919 let uv_performed = match self.pin_prechecks(
921 ¶meters.options,
922 parameters.pin_auth.map(AsRef::as_ref),
923 parameters.pin_protocol,
924 parameters.client_data_hash.as_ref(),
925 Permissions::GET_ASSERTION,
926 parameters.rp_id,
927 ) {
928 Ok(b) => b,
929 Err(Error::PinRequired) => {
930 false
932 }
933 Err(err) => return Err(err),
934 };
935
936 let (credential, num_credentials) = self
942 .prepare_credentials(&rp_id_hash, ¶meters.allow_list, uv_performed)?
943 .ok_or(Error::NoCredentials)?;
944
945 info_now!("found {:?} applicable credentials", num_credentials);
946 info_now!("{:?}", &credential);
947
948 if parameters
952 .options
953 .as_ref()
954 .and_then(|options| options.rk)
955 .is_some()
956 {
957 return Err(Error::InvalidOption);
958 }
959
960 let do_up = if let Some(options) = parameters.options.as_ref() {
962 options.up.unwrap_or(true)
963 } else {
964 true
965 };
966
967 let up_performed = if do_up {
969 if !self.skip_up_check() {
970 info_now!("asking for up");
971 self.up
972 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
973 }
974 true
975 } else {
976 info_now!("not asking for up");
977 false
978 };
979
980 let multiple_credentials = num_credentials > 1;
981 self.state.runtime.active_get_assertion = Some(state::ActiveGetAssertionData {
982 rp_id_hash: {
983 let mut buf = [0u8; 32];
984 buf.copy_from_slice(&rp_id_hash);
985 buf
986 },
987 client_data_hash: {
988 let mut buf = [0u8; 32];
989 buf.copy_from_slice(parameters.client_data_hash);
990 buf
991 },
992 uv_performed,
993 up_performed,
994 multiple_credentials,
995 extensions: parameters.extensions.clone(),
996 attestation_formats_preference: parameters.attestation_formats_preference.clone(),
997 });
998
999 let num_credentials = match num_credentials {
1000 1 => None,
1001 n => Some(n),
1002 };
1003
1004 self.assert_with_credential(num_credentials, credential)
1005 }
1006
1007 #[inline(never)]
1008 fn large_blobs(
1009 &mut self,
1010 request: &ctap2::large_blobs::Request,
1011 ) -> Result<ctap2::large_blobs::Response> {
1012 let Some(config) = self.config.large_blobs else {
1013 return Err(Error::InvalidCommand);
1014 };
1015
1016 match (request.get, request.set) {
1020 (None, None) | (Some(_), Some(_)) => Err(Error::InvalidParameter),
1021 (Some(get), None) => self.large_blobs_get(request, config, get),
1023 (None, Some(set)) => self.large_blobs_set(request, config, set),
1025 }
1026 }
1027}
1028
1029impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
1031 fn parse_pin_protocol(&self, version: impl TryInto<u8>) -> Result<PinProtocolVersion> {
1032 if let Ok(version) = version.try_into() {
1033 for pin_protocol in self.pin_protocols() {
1034 if u8::from(*pin_protocol) == version {
1035 return Ok(*pin_protocol);
1036 }
1037 }
1038 }
1039 Err(Error::InvalidParameter)
1040 }
1041
1042 fn pin_protocols(&self) -> &'static [PinProtocolVersion] {
1044 &[PinProtocolVersion::V2, PinProtocolVersion::V1]
1045 }
1046
1047 fn pin_protocol(&mut self, pin_protocol: PinProtocolVersion) -> PinProtocol<'_, T> {
1048 let state = self.state.runtime.pin_protocol(&mut self.trussed);
1049 PinProtocol::new(&mut self.trussed, state, pin_protocol)
1050 }
1051
1052 #[inline(never)]
1053 fn check_credential_applicable(
1054 &mut self,
1055 credential: &Credential,
1056 allowlist_passed: bool,
1057 uv_performed: bool,
1058 ) -> bool {
1059 if !self.check_key_exists(credential.algorithm(), credential.key()) {
1060 return false;
1061 }
1062
1063 if !{
1064 use credential::CredentialProtectionPolicy as Policy;
1065 debug_now!("CredentialProtectionPolicy {:?}", credential.cred_protect());
1066 match credential.cred_protect() {
1067 None | Some(Policy::Optional) => true,
1068 Some(Policy::OptionalWithCredentialIdList) => allowlist_passed || uv_performed,
1069 Some(Policy::Required) => uv_performed,
1070 }
1071 } {
1072 return false;
1073 }
1074 true
1075 }
1076
1077 #[inline(never)]
1078 fn prepare_credentials(
1079 &mut self,
1080 rp_id_hash: &[u8; 32],
1081 allow_list: &Option<ctap2::get_assertion::AllowList>,
1082 uv_performed: bool,
1083 ) -> Result<Option<(Credential, u32)>> {
1084 debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
1085
1086 self.state.runtime.clear_credential_cache();
1087 self.state.runtime.active_get_assertion = None;
1088
1089 if let Some(allow_list) = allow_list {
1099 debug_now!("Allowlist of len {} passed, filtering", allow_list.len());
1100 if !allow_list.is_empty() {
1107 for credential_id in allow_list {
1108 let credential = match Credential::try_from(self, rp_id_hash, credential_id) {
1109 Ok(credential) => credential,
1110 _ => continue,
1111 };
1112
1113 if !self.check_credential_applicable(&credential, true, uv_performed) {
1114 continue;
1115 }
1116
1117 return Ok(Some((credential, 1)));
1118 }
1119
1120 return Ok(None);
1122 }
1123 }
1124
1125 debug_now!("Allowlist not passed, fetching RKs");
1127 self.prepare_cache(rp_id_hash, uv_performed)?;
1128
1129 let num_credentials = self.state.runtime.remaining_credentials();
1130 let credential = self.state.runtime.pop_credential(&mut self.trussed);
1131 Ok(credential.map(|credential| (Credential::Full(credential), num_credentials)))
1132 }
1133
1134 #[inline(never)]
1136 fn prepare_cache(&mut self, rp_id_hash: &[u8; 32], uv_performed: bool) -> Result<()> {
1137 use crate::state::CachedCredential;
1138 use core::str::FromStr;
1139
1140 let file_name_prefix = rp_file_name_prefix(rp_id_hash);
1141 let mut maybe_entry = syscall!(self.trussed.read_dir_first_alphabetical(
1142 Location::Internal,
1143 PathBuf::from(RK_DIR),
1144 Some(file_name_prefix.clone())
1145 ))
1146 .entry;
1147
1148 while let Some(entry) = maybe_entry.take() {
1149 if !entry
1150 .file_name()
1151 .as_ref()
1152 .starts_with(file_name_prefix.as_ref())
1153 {
1154 break;
1156 }
1157
1158 if entry.file_name() == &*file_name_prefix {
1159 debug_assert!(entry.metadata().is_dir());
1160 error!("Migration missing");
1161 return Err(Error::Other);
1162 }
1163
1164 let credential_data = syscall!(self
1165 .trussed
1166 .read_file(Location::Internal, entry.path().into(),))
1167 .data;
1168
1169 let credential = FullCredential::deserialize(&credential_data).map_err(|_err| {
1170 error!("Failed to deserialize credential: {_err:?}");
1171 Error::Other
1172 })?;
1173 let timestamp = credential.creation_time;
1174 let credential = Credential::Full(credential);
1175
1176 if self.check_credential_applicable(&credential, false, uv_performed) {
1177 self.state.runtime.push_credential(CachedCredential {
1178 timestamp,
1179 path: String::from_str(entry.path().as_str_ref_with_trailing_nul())
1180 .map_err(|_| Error::Other)?,
1181 });
1182 }
1183
1184 maybe_entry = syscall!(self.trussed.read_dir_next()).entry;
1185 }
1186 Ok(())
1187 }
1188
1189 fn decrypt_pin_hash_and_maybe_escalate(
1190 &mut self,
1191 pin_protocol: PinProtocolVersion,
1192 shared_secret: &SharedSecret,
1193 pin_hash_enc: &[u8],
1194 ) -> Result<()> {
1195 let pin_hash = shared_secret
1196 .decrypt(&mut self.trussed, pin_hash_enc)
1197 .ok_or(Error::Other)?;
1198
1199 let stored_pin_hash = match self.state.persistent.pin_hash() {
1200 Some(hash) => hash,
1201 None => {
1202 return Err(Error::PinNotSet);
1203 }
1204 };
1205
1206 if pin_hash != stored_pin_hash {
1207 self.pin_protocol(pin_protocol).regenerate();
1209 self.state.pin_blocked()?;
1210 return Err(Error::PinInvalid);
1211 }
1212
1213 Ok(())
1214 }
1215
1216 fn hash_store_pin(&mut self, pin: &Message) -> Result<()> {
1217 let pin_hash_32 = syscall!(self.trussed.hash_sha256(pin)).hash;
1218 let pin_hash: [u8; 16] = pin_hash_32[..16].try_into().unwrap();
1219 self.state
1220 .persistent
1221 .set_pin_hash(&mut self.trussed, pin_hash)
1222 .unwrap();
1223
1224 Ok(())
1225 }
1226
1227 fn decrypt_pin_check_length(
1228 &mut self,
1229 shared_secret: &SharedSecret,
1230 pin_enc: &[u8],
1231 ) -> Result<Message> {
1232 if pin_enc.len() < 64 {
1234 return Err(Error::PinPolicyViolation);
1236 }
1237
1238 let mut pin = shared_secret
1239 .decrypt(&mut self.trussed, pin_enc)
1240 .ok_or(Error::Other)?;
1241
1242 let pin_length = pin.iter().position(|&b| b == b'\0').unwrap_or(pin.len());
1248 if !(4..64).contains(&pin_length) {
1249 return Err(Error::PinPolicyViolation);
1250 }
1251
1252 pin.resize_default(pin_length).unwrap();
1253
1254 Ok(pin)
1255 }
1256
1257 fn verify_credential_management_pin_auth(
1258 &mut self,
1259 parameters: &ctap2::credential_management::Request,
1260 ) -> Result<()> {
1261 use ctap2::credential_management::Subcommand;
1262 let rp_scope = match parameters.sub_command {
1263 Subcommand::EnumerateCredentialsBegin => {
1264 let rp_id_hash = parameters
1265 .sub_command_params
1266 .as_ref()
1267 .and_then(|subparams| subparams.rp_id_hash)
1268 .ok_or(Error::MissingParameter)?;
1269 RpScope::RpIdHash(rp_id_hash)
1270 }
1271 Subcommand::DeleteCredential | Subcommand::UpdateUserInformation => {
1272 RpScope::All
1274 }
1275 _ => RpScope::All,
1276 };
1277 match parameters.sub_command {
1278 Subcommand::GetCredsMetadata
1279 | Subcommand::EnumerateRpsBegin
1280 | Subcommand::EnumerateCredentialsBegin
1281 | Subcommand::DeleteCredential
1282 | Subcommand::UpdateUserInformation => {
1283 let pin_protocol = parameters.pin_protocol.ok_or(Error::MissingParameter)?;
1285 let pin_protocol = self.parse_pin_protocol(pin_protocol)?;
1286
1287 let mut data: Bytes<{ sizes::MAX_CREDENTIAL_ID_LENGTH_PLUS_256 }> =
1289 Bytes::from_slice(&[parameters.sub_command as u8]).unwrap();
1290 let len = 1 + match parameters.sub_command {
1291 Subcommand::EnumerateCredentialsBegin
1292 | Subcommand::DeleteCredential
1293 | Subcommand::UpdateUserInformation => {
1294 data.resize_to_capacity();
1295 ctap_types::serde::cbor_serialize(
1297 ¶meters
1298 .sub_command_params
1299 .as_ref()
1300 .ok_or(Error::MissingParameter)?,
1301 &mut data[1..],
1302 )
1303 .map_err(|_| Error::LimitExceeded)?
1304 .len()
1305 }
1306 _ => 0,
1307 };
1308
1309 let pin_auth = parameters
1310 .pin_auth
1311 .as_ref()
1312 .ok_or(Error::MissingParameter)?;
1313
1314 let mut pin_protocol = self.pin_protocol(pin_protocol);
1315 if let Ok(pin_token) = pin_protocol.verify_pin_token(&data[..len], pin_auth) {
1316 info_now!("passed pinauth");
1317 pin_token.require_permissions(Permissions::CREDENTIAL_MANAGEMENT)?;
1318 pin_token.require_valid_for_rp(rp_scope)?;
1319 Ok(())
1320 } else {
1321 info_now!("failed pinauth!");
1322 self.state.decrement_retries(&mut self.trussed)?;
1323 let maybe_blocked = self.state.pin_blocked();
1324 if maybe_blocked.is_err() {
1325 info_now!("blocked");
1326 maybe_blocked
1327 } else {
1328 info_now!("pinAuthInvalid");
1329 Err(Error::PinAuthInvalid)
1330 }
1331 }
1332 }
1333
1334 Subcommand::EnumerateRpsGetNextRp
1337 | Subcommand::EnumerateCredentialsGetNextCredential => Ok(()),
1338
1339 _ => Err(Error::InvalidParameter),
1340 }
1341 }
1342
1343 fn pin_prechecks(
1345 &mut self,
1346 options: &Option<ctap2::AuthenticatorOptions>,
1347 pin_auth: Option<&[u8]>,
1348 pin_protocol: Option<u32>,
1349 data: &[u8],
1350 permissions: Permissions,
1351 rp_id: &str,
1352 ) -> Result<bool> {
1353 if let Some(pin_auth) = pin_auth {
1359 if pin_auth.is_empty() {
1360 self.up
1361 .user_present(&mut self.trussed, constants::FIDO2_UP_TIMEOUT)?;
1362 if !self.state.persistent.pin_is_set() {
1363 return Err(Error::PinNotSet);
1364 } else {
1365 return Err(Error::PinAuthInvalid);
1366 }
1367 }
1368 }
1369
1370 let pin_protocol = if pin_auth.is_some() {
1372 let pin_protocol = pin_protocol.ok_or(Error::MissingParameter)?;
1373 let pin_protocol = self.parse_pin_protocol(pin_protocol)?;
1374 Some(pin_protocol)
1375 } else {
1376 None
1377 };
1378
1379 if !self.state.persistent.pin_is_set() {
1382 if let Some(ref options) = &options {
1383 if Some(true) == options.uv {
1384 return Err(Error::InvalidOption);
1385 }
1386 }
1387 if pin_auth.is_some() {
1388 return Err(Error::InvalidOption);
1389 }
1390 }
1391
1392 if pin_auth.is_none() && options.as_ref().and_then(|options| options.uv) == Some(true) {
1396 return Err(Error::InvalidOption);
1397 }
1398
1399 if self.state.persistent.pin_is_set() {
1400 if let Some(pin_auth) = pin_auth {
1402 if let Some(pin_protocol) = pin_protocol {
1405 let mut pin_protocol = self.pin_protocol(pin_protocol);
1409 let pin_token = pin_protocol.verify_pin_token(data, pin_auth)?;
1410 pin_token.require_permissions(permissions)?;
1411 pin_token.require_valid_for_rp(RpScope::RpId(rp_id))?;
1412
1413 return Ok(true);
1414 } else {
1415 return Err(Error::PinAuthInvalid);
1417 }
1418 } else {
1419 if options.as_ref().and_then(|options| options.rk) == Some(true) {
1421 return Err(Error::PinRequired);
1422 }
1423 }
1424 }
1425
1426 Ok(false)
1427 }
1428
1429 #[inline(never)]
1430 fn check_key_exists(&mut self, alg: i32, key: &Key) -> bool {
1431 match key {
1432 Key::WrappedKey(_) => true,
1435 Key::ResidentKey(key) => {
1436 debug_now!("checking if ResidentKey {:?} exists", key);
1437 SigningAlgorithm::try_from(alg)
1438 .map(|alg| syscall!(self.trussed.exists(alg.mechanism(), *key)).exists)
1439 .unwrap_or_default()
1440 }
1441 }
1442 }
1443
1444 #[inline(never)]
1445 fn process_assertion_extensions(
1446 &mut self,
1447 get_assertion_state: &state::ActiveGetAssertionData,
1448 extensions: &ctap2::get_assertion::ExtensionsInput,
1449 credential: &Credential,
1450 credential_key: KeyId,
1451 ) -> Result<Option<ctap2::get_assertion::ExtensionsOutput>> {
1452 let mut output = ctap2::get_assertion::ExtensionsOutput::default();
1453
1454 if let Some(hmac_secret) = &extensions.hmac_secret {
1455 let pin_protocol = hmac_secret
1456 .pin_protocol
1457 .map(|i| self.parse_pin_protocol(i))
1458 .transpose()?
1459 .unwrap_or(PinProtocolVersion::V1);
1460
1461 if !get_assertion_state.up_performed {
1462 return Err(Error::UnsupportedOption);
1463 }
1464
1465 let cred_random = syscall!(self.trussed.derive_key(
1469 Mechanism::HmacSha256,
1470 credential_key,
1471 Some(Bytes::from_slice(&[get_assertion_state.uv_performed as u8]).unwrap()),
1472 StorageAttributes::new().set_persistence(Location::Volatile)
1473 ))
1474 .key;
1475
1476 let mut pin_protocol = self.pin_protocol(pin_protocol);
1478 let shared_secret = pin_protocol.shared_secret(&hmac_secret.key_agreement)?;
1479 pin_protocol.verify_pin_auth(
1480 &shared_secret,
1481 &hmac_secret.salt_enc,
1482 &hmac_secret.salt_auth,
1483 )?;
1484
1485 let salts = shared_secret
1487 .decrypt(&mut self.trussed, &hmac_secret.salt_enc)
1488 .ok_or(Error::InvalidOption)?;
1489
1490 if salts.len() != 32 && salts.len() != 64 {
1491 debug_now!("invalid hmac-secret length");
1492 return Err(Error::InvalidLength);
1493 }
1494
1495 let mut salt_output: Bytes<64> = Bytes::new();
1496
1497 let output1 =
1499 syscall!(self.trussed.sign_hmacsha256(cred_random, &salts[0..32])).signature;
1500
1501 salt_output.extend_from_slice(&output1).unwrap();
1502
1503 if salts.len() == 64 {
1504 let output2 =
1506 syscall!(self.trussed.sign_hmacsha256(cred_random, &salts[32..64])).signature;
1507
1508 salt_output.extend_from_slice(&output2).unwrap();
1509 }
1510
1511 syscall!(self.trussed.delete(cred_random));
1512
1513 let output_enc = shared_secret.encrypt(&mut self.trussed, &salt_output);
1515
1516 shared_secret.delete(&mut self.trussed);
1517
1518 output.hmac_secret = Some(Bytes::from_slice(&output_enc).unwrap());
1519 }
1520
1521 if extensions.third_party_payment.unwrap_or_default() {
1522 output.third_party_payment = Some(credential.third_party_payment().unwrap_or_default());
1523 }
1524
1525 Ok(output.is_set().then_some(output))
1526 }
1527
1528 #[inline(never)]
1529 fn assert_with_credential(
1530 &mut self,
1531 num_credentials: Option<u32>,
1532 credential: Credential,
1533 ) -> Result<ctap2::get_assertion::Response> {
1534 let data = self.state.runtime.active_get_assertion.clone().unwrap();
1535 let rp_id_hash = &data.rp_id_hash;
1536
1537 let (key, is_rk) = match credential.key().clone() {
1538 Key::ResidentKey(key) => (key, true),
1539 Key::WrappedKey(bytes) => {
1540 let wrapping_key = self.state.persistent.key_wrapping_key(&mut self.trussed)?;
1541 let key_result = syscall!(self.trussed.unwrap_key_chacha8poly1305(
1543 wrapping_key,
1544 &bytes,
1545 &[],
1546 Location::Volatile,
1547 ))
1548 .key;
1549 info_now!("key result");
1551 match key_result {
1552 Some(key) => (key, false),
1553 None => {
1554 return Err(Error::Other);
1555 }
1556 }
1557 }
1558 };
1559
1560 let mut large_blob_key_requested = false;
1562 let extensions_output = if let Some(extensions) = &data.extensions {
1563 if self.config.supports_large_blobs() {
1564 if extensions.large_blob_key == Some(false) {
1565 return Err(Error::InvalidOption);
1567 }
1568 large_blob_key_requested = extensions.large_blob_key == Some(true);
1569 }
1570 self.process_assertion_extensions(&data, extensions, &credential, key)?
1571 } else {
1572 None
1573 };
1574
1575 let kek = self
1579 .state
1580 .persistent
1581 .key_encryption_key(&mut self.trussed)?;
1582 let credential_id = credential.id(&mut self.trussed, kek, rp_id_hash)?;
1583
1584 use ctap2::AuthenticatorDataFlags as Flags;
1585
1586 let sig_count = self.state.persistent.timestamp(&mut self.trussed)?;
1587
1588 let authenticator_data = ctap2::get_assertion::AuthenticatorData {
1589 rp_id_hash,
1590
1591 flags: {
1592 let mut flags = Flags::empty();
1593 if data.up_performed {
1594 flags |= Flags::USER_PRESENCE;
1595 }
1596 if data.uv_performed {
1597 flags |= Flags::USER_VERIFIED;
1598 }
1599 if extensions_output.is_some() {
1600 flags |= Flags::EXTENSION_DATA;
1601 }
1602 flags
1603 },
1604
1605 sign_count: sig_count,
1606 attested_credential_data: None,
1607 extensions: extensions_output,
1608 };
1609
1610 let serialized_auth_data = authenticator_data.serialize()?;
1611
1612 let mut commitment = Bytes::<1024>::new();
1613 commitment
1614 .extend_from_slice(&serialized_auth_data)
1615 .map_err(|_| Error::Other)?;
1616 commitment
1617 .extend_from_slice(&data.client_data_hash)
1618 .map_err(|_| Error::Other)?;
1619
1620 let signing_algorithm =
1621 SigningAlgorithm::try_from(credential.algorithm()).map_err(|_| Error::Other)?;
1622 let signature = signing_algorithm
1623 .sign(&mut self.trussed, key, &commitment)
1624 .to_bytes()
1625 .unwrap();
1626
1627 let att_stmt_fmt = data
1629 .attestation_formats_preference
1630 .as_ref()
1631 .and_then(SupportedAttestationFormat::select);
1632 let att_stmt = if let Some(format) = att_stmt_fmt {
1633 match format {
1634 SupportedAttestationFormat::None => {
1635 Some(AttestationStatement::None(NoneAttestationStatement {}))
1636 }
1637 SupportedAttestationFormat::Packed => {
1638 let (attestation_maybe, _) = self.state.identity.attestation(&mut self.trussed);
1639 let (signature, attestation_algorithm) = {
1640 if let Some(attestation) = attestation_maybe.as_ref() {
1641 let signing_algorithm = SigningAlgorithm::P256;
1642 let signature = signing_algorithm.sign(
1643 &mut self.trussed,
1644 attestation.0,
1645 &commitment,
1646 );
1647 (
1648 signature.to_bytes().map_err(|_| Error::Other)?,
1649 signing_algorithm.into(),
1650 )
1651 } else {
1652 (signature.clone(), credential.algorithm())
1653 }
1654 };
1655 let packed = PackedAttestationStatement {
1656 alg: attestation_algorithm,
1657 sig: signature,
1658 x5c: attestation_maybe.as_ref().map(|attestation| {
1659 let cert = attestation.1.clone();
1661 let mut x5c = Vec::new();
1662 x5c.push(cert).ok();
1663 x5c
1664 }),
1665 };
1666 Some(AttestationStatement::Packed(packed))
1667 }
1668 }
1669 } else {
1670 None
1671 };
1672
1673 if !is_rk {
1674 syscall!(self.trussed.delete(key));
1675 }
1676
1677 let mut response = ctap2::get_assertion::ResponseBuilder {
1678 credential: credential_id.into(),
1679 auth_data: serialized_auth_data,
1680 signature,
1681 }
1682 .build();
1683 response.number_of_credentials = num_credentials;
1684 response.att_stmt = att_stmt;
1685
1686 if is_rk {
1688 if let Credential::Full(credential) = &credential {
1689 if !credential.user.id().is_empty() {
1690 let mut user: PublicKeyCredentialUserEntity = credential.user.clone().into();
1691 if !data.uv_performed || !data.multiple_credentials {
1695 user.icon = None;
1696 user.name = None;
1697 user.display_name = None;
1698 }
1699 response.user = Some(user);
1700 }
1701 }
1702
1703 if large_blob_key_requested {
1704 debug!("Sending largeBlobKey in getAssertion");
1705 response.large_blob_key = match credential {
1706 Credential::Stripped(stripped) => stripped.large_blob_key,
1707 Credential::Full(full) => full.data.large_blob_key,
1708 };
1709 }
1710 }
1711
1712 Ok(response)
1713 }
1714
1715 #[inline(never)]
1716 fn delete_resident_key_by_user_id(
1717 &mut self,
1718 rp_id_hash: &[u8; 32],
1719 user_id: &Bytes<64>,
1720 ) -> Result<()> {
1721 let file_name_prefix = rp_file_name_prefix(rp_id_hash);
1723 let mut maybe_entry = syscall!(self.trussed.read_dir_first_alphabetical(
1724 Location::Internal,
1725 PathBuf::from(RK_DIR),
1726 Some(file_name_prefix.clone())
1727 ))
1728 .entry;
1729
1730 while let Some(entry) = maybe_entry.take() {
1731 if !entry
1732 .file_name()
1733 .as_ref()
1734 .starts_with(file_name_prefix.as_ref())
1735 {
1736 break;
1738 }
1739
1740 if entry.file_name() == &*file_name_prefix {
1741 debug_assert!(entry.metadata().is_dir());
1742 error!("Migration missing");
1743 return Err(Error::Other);
1744 }
1745
1746 info_now!("this may be an RK: {:?}", &entry);
1747 let rk_path = PathBuf::from(entry.path());
1748
1749 info_now!("checking RK {:?} for userId ", &rk_path);
1750 let credential_data =
1751 syscall!(self.trussed.read_file(Location::Internal, rk_path.clone(),)).data;
1752 let credential_maybe = FullCredential::deserialize(&credential_data);
1753
1754 if let Ok(old_credential) = credential_maybe {
1755 if old_credential.user.id() == user_id {
1756 match old_credential.key {
1757 credential::Key::ResidentKey(key) => {
1758 info_now!(":: deleting resident key");
1759 syscall!(self.trussed.delete(key));
1760 }
1761 _ => {
1762 warn_now!(":: WARNING: unexpected server credential in rk.");
1763 }
1764 }
1765 syscall!(self.trussed.remove_file(Location::Internal, rk_path,));
1766
1767 info_now!("Overwriting previous rk tied to this userId.");
1768 break;
1769 }
1770 } else {
1771 warn_now!("WARNING: Could not read RK.");
1772 }
1773
1774 maybe_entry = syscall!(self.trussed.read_dir_next()).entry;
1776 }
1777
1778 Ok(())
1779 }
1780
1781 #[inline(never)]
1782 pub(crate) fn delete_resident_key_by_path(&mut self, rk_path: &Path) -> Result<()> {
1783 info_now!("deleting RK {:?}", &rk_path);
1784 let credential_data = syscall!(self
1785 .trussed
1786 .read_file(Location::Internal, PathBuf::from(rk_path),))
1787 .data;
1788 let credential_maybe = FullCredential::deserialize(&credential_data);
1789 if let Ok(credential) = credential_maybe {
1792 match credential.key {
1793 credential::Key::ResidentKey(key) => {
1794 info_now!(":: deleting resident key");
1795 syscall!(self.trussed.delete(key));
1796 }
1797 credential::Key::WrappedKey(_) => {}
1798 }
1799 } else {
1800 info_now!("Warning! Orpaning a key.");
1803 }
1804
1805 info_now!(":: deleting RK file {:?} itself", &rk_path);
1806 syscall!(self
1807 .trussed
1808 .remove_file(Location::Internal, PathBuf::from(rk_path),));
1809
1810 Ok(())
1811 }
1812
1813 fn large_blobs_get(
1814 &mut self,
1815 request: &ctap2::large_blobs::Request,
1816 config: large_blobs::Config,
1817 length: u32,
1818 ) -> Result<ctap2::large_blobs::Response> {
1819 debug!(
1820 "large_blobs_get: length = {length}, offset = {}",
1821 request.offset
1822 );
1823 if request.length.is_some()
1825 || request.pin_uv_auth_param.is_some()
1826 || request.pin_uv_auth_protocol.is_some()
1827 {
1828 error!("length/pin set");
1829 return Err(Error::InvalidParameter);
1830 }
1831 let Ok(length) = usize::try_from(length) else {
1833 return Err(Error::InvalidLength);
1834 };
1835 if length > self.config.max_msg_size.saturating_sub(64) {
1836 return Err(Error::InvalidLength);
1837 }
1838 let Ok(offset) = usize::try_from(request.offset) else {
1840 error!("offset too large");
1841 return Err(Error::InvalidParameter);
1842 };
1843 let stored_length = large_blobs::size(&mut self.trussed, config.location)?;
1844 if offset > stored_length {
1845 error!("offset: {offset}, stored_length: {stored_length}");
1846 return Err(Error::InvalidParameter);
1847 };
1848 info!("Reading large-blob array from offset {offset}");
1850 let data = large_blobs::read_chunk(&mut self.trussed, config.location, offset, length)?;
1851 let mut response = ctap2::large_blobs::Response::default();
1852 response.config = Some(data);
1853 Ok(response)
1854 }
1855
1856 fn large_blobs_set(
1857 &mut self,
1858 request: &ctap2::large_blobs::Request,
1859 config: large_blobs::Config,
1860 data: &[u8],
1861 ) -> Result<ctap2::large_blobs::Response> {
1862 debug!(
1863 "large_blobs_set: |data| = {}, offset = {}, length = {:?}",
1864 data.len(),
1865 request.offset,
1866 request.length
1867 );
1868 if data.len() > self.config.max_msg_size.saturating_sub(64) {
1870 return Err(Error::InvalidLength);
1871 }
1872 if request.offset == 0 {
1873 let Some(length) = request.length else {
1876 return Err(Error::InvalidParameter);
1877 };
1878 let Ok(length) = usize::try_from(length) else {
1880 return Err(Error::LargeBlobStorageFull);
1881 };
1882 if length > config.max_size() {
1883 return Err(Error::LargeBlobStorageFull);
1884 }
1885 if length < large_blobs::MIN_SIZE {
1887 return Err(Error::InvalidParameter);
1888 }
1889 self.state.runtime.large_blobs.expected_length = length;
1891 self.state.runtime.large_blobs.expected_next_offset = 0;
1892 } else {
1893 if request.length.is_some() {
1895 return Err(Error::InvalidParameter);
1896 }
1897 }
1898
1899 let Ok(offset) = usize::try_from(request.offset) else {
1901 return Err(Error::InvalidSeq);
1902 };
1903 if offset != self.state.runtime.large_blobs.expected_next_offset {
1904 return Err(Error::InvalidSeq);
1905 }
1906
1907 if self.state.persistent.pin_is_set() {
1910 let Some(pin_uv_auth_param) = request.pin_uv_auth_param else {
1911 return Err(Error::PinRequired);
1912 };
1913 let Some(pin_uv_auth_protocol) = request.pin_uv_auth_protocol else {
1914 return Err(Error::PinRequired);
1915 };
1916 if pin_uv_auth_protocol != 1 {
1917 return Err(Error::PinAuthInvalid);
1918 }
1919 let pin_protocol = self.parse_pin_protocol(pin_uv_auth_protocol)?;
1920 let pin_auth: [u8; 16] = pin_uv_auth_param
1922 .as_ref()
1923 .try_into()
1924 .map_err(|_| Error::PinAuthInvalid)?;
1925
1926 let mut auth_data: Bytes<70> = Bytes::new();
1927 auth_data.resize(32, 0xff).unwrap();
1929 auth_data.push(0x0c).unwrap();
1931 auth_data.push(0x00).unwrap();
1932 auth_data
1934 .extend_from_slice(&request.offset.to_le_bytes())
1935 .unwrap();
1936 auth_data.extend_from_slice(&Sha256::digest(data)).unwrap();
1938
1939 let mut pin_protocol = self.pin_protocol(pin_protocol);
1940 let pin_token = pin_protocol.verify_pin_token(&pin_auth, &auth_data)?;
1941 pin_token.require_permissions(Permissions::LARGE_BLOB_WRITE)?;
1942 }
1943
1944 if offset + data.len() > self.state.runtime.large_blobs.expected_length {
1946 return Err(Error::InvalidParameter);
1947 }
1948
1949 info!("Writing large-blob array to offset {offset}");
1951 large_blobs::write_chunk(
1952 &mut self.trussed,
1953 &mut self.state.runtime.large_blobs,
1954 config.location,
1955 data,
1956 )?;
1957
1958 Ok(ctap2::large_blobs::Response::default())
1959 }
1960}
1961
1962#[derive(Clone, Copy, Debug)]
1963enum SupportedAttestationFormat {
1964 None,
1965 Packed,
1966}
1967
1968impl SupportedAttestationFormat {
1969 fn select(preference: &AttestationFormatsPreference) -> Option<Self> {
1970 if preference.known_formats() == [AttestationStatementFormat::None]
1971 && !preference.includes_unknown_formats()
1972 {
1973 return None;
1975 }
1976 let format = preference
1978 .known_formats()
1979 .iter()
1980 .copied()
1981 .flat_map(Self::try_from)
1982 .next()
1983 .unwrap_or(Self::Packed);
1984 Some(format)
1985 }
1986}
1987
1988impl From<SupportedAttestationFormat> for AttestationStatementFormat {
1989 fn from(format: SupportedAttestationFormat) -> Self {
1990 match format {
1991 SupportedAttestationFormat::None => Self::None,
1992 SupportedAttestationFormat::Packed => Self::Packed,
1993 }
1994 }
1995}
1996
1997impl TryFrom<AttestationStatementFormat> for SupportedAttestationFormat {
1998 type Error = Error;
1999
2000 fn try_from(format: AttestationStatementFormat) -> core::result::Result<Self, Self::Error> {
2001 match format {
2002 AttestationStatementFormat::None => Ok(Self::None),
2003 AttestationStatementFormat::Packed => Ok(Self::Packed),
2004 _ => Err(Error::Other),
2005 }
2006 }
2007}
2008
2009fn rp_file_name_prefix(rp_id_hash: &[u8; 32]) -> PathBuf {
2017 let mut hex = [b'0'; 16];
2018 super::format_hex(&rp_id_hash[..8], &mut hex);
2019 PathBuf::try_from(&hex).unwrap()
2020}
2021
2022fn rk_path(rp_id_hash: &[u8; 32], credential_id_hash: &[u8; 32]) -> PathBuf {
2023 let mut buf = [0; 34];
2025 buf[16] = b'.';
2026 format_hex(&rp_id_hash[..8], &mut buf[..16]);
2027 format_hex(&credential_id_hash[..8], &mut buf[17..33]);
2028
2029 let mut path = PathBuf::from(RK_DIR);
2030 path.push(Path::from_bytes_with_nul(&buf).unwrap());
2031 path
2032}
2033
2034#[cfg(test)]
2035mod tests {
2036 use super::{rk_path, rp_file_name_prefix};
2037
2038 const TEST_HASH: &[u8; 32] = &[
2039 134, 54, 157, 96, 10, 28, 233, 79, 219, 59, 195, 125, 165, 251, 120, 14, 49, 152, 212, 191,
2040 114, 137, 180, 207, 255, 177, 187, 106, 173, 1, 203, 171,
2041 ];
2042 const TEST_HASH_HEX: &str = "86369d600a1ce94f";
2043
2044 #[test]
2045 fn test_rp_file_name_prefix() {
2046 assert_eq!(rp_file_name_prefix(&[0; 32]).as_str(), "0000000000000000");
2047 assert_eq!(rp_file_name_prefix(TEST_HASH).as_str(), TEST_HASH_HEX);
2048 }
2049
2050 #[test]
2051 fn test_rk_path() {
2052 fn test(rp_id_hash: &[u8; 32], credential_id_hash: &[u8; 32], expected: &str) {
2053 println!("rp_id_hash: {rp_id_hash:?}");
2054 println!("credential_id_hash: {credential_id_hash:?}");
2055 let actual = rk_path(rp_id_hash, credential_id_hash);
2056 assert_eq!(actual.as_str(), expected);
2057 }
2058
2059 let input_zero = &[0; 32];
2060 let output_zero = "0000000000000000";
2061 let input_nonzero = TEST_HASH;
2062 let output_nonzero = TEST_HASH_HEX;
2063
2064 test(
2065 input_zero,
2066 input_zero,
2067 &format!("rk/{output_zero}.{output_zero}"),
2068 );
2069 test(
2070 input_zero,
2071 input_nonzero,
2072 &format!("rk/{output_zero}.{output_nonzero}"),
2073 );
2074 test(
2075 input_nonzero,
2076 input_zero,
2077 &format!("rk/{output_nonzero}.{output_zero}"),
2078 );
2079 test(
2080 input_nonzero,
2081 input_nonzero,
2082 &format!("rk/{output_nonzero}.{output_nonzero}"),
2083 );
2084 }
2085}