mirror of
https://github.com/trussed-dev/fido-authenticator.git
synced 2026-06-20 04:16:16 -07:00
Keep old credential ID for existing credentials
In #59, we changed the format for serialized credentials to use shorter field names for the RP and user entities. This has an unintended side effect: For non-discoverable credentials that were generated with older crate versions, the stripped data embedded into the credential ID includes the RP and user. If we change their serialization format, we also change these credential IDs. We already supported deserializing both formats using a serde alias. This patch introduces helper enums that deserialize both formats using a custom Deserialize implementation and keep track of the used format. This format is then also used for serialization (using serde’s untagged mechanism that is not available for deserialization in no-std contexts). https://github.com/Nitrokey/fido-authenticator/pull/59 Fixes: https://github.com/Nitrokey/fido-authenticator/issues/111
This commit is contained in:
+499
-285
File diff suppressed because it is too large
Load Diff
+8
-6
@@ -9,7 +9,9 @@ use ctap_types::{
|
||||
},
|
||||
heapless::{String, Vec},
|
||||
heapless_bytes::Bytes,
|
||||
sizes, ByteArray, Error,
|
||||
sizes,
|
||||
webauthn::PublicKeyCredentialUserEntity,
|
||||
ByteArray, Error,
|
||||
};
|
||||
use littlefs2_core::path;
|
||||
use sha2::{Digest as _, Sha256};
|
||||
@@ -388,7 +390,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
|
||||
let serialized_credential = credential.serialize()?;
|
||||
|
||||
// first delete any other RK cred with same RP + UserId if there is one.
|
||||
self.delete_resident_key_by_user_id(&rp_id_hash, &credential.user.id)
|
||||
self.delete_resident_key_by_user_id(&rp_id_hash, credential.user.id())
|
||||
.ok();
|
||||
|
||||
let mut key_store_full = self.can_fit(serialized_credential.len()) == Some(false)
|
||||
@@ -1739,8 +1741,8 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
// User with empty IDs are ignored for compatibility
|
||||
if is_rk {
|
||||
if let Credential::Full(credential) = &credential {
|
||||
if !credential.user.id.is_empty() {
|
||||
let mut user = credential.user.clone();
|
||||
if !credential.user.id().is_empty() {
|
||||
let mut user: PublicKeyCredentialUserEntity = credential.user.clone().into();
|
||||
// User identifiable information (name, DisplayName, icon) MUST not
|
||||
// be returned if user verification is not done by the authenticator.
|
||||
// For single account per RP case, authenticator returns "id" field.
|
||||
@@ -1749,7 +1751,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
user.name = None;
|
||||
user.display_name = None;
|
||||
}
|
||||
response.user = Some(user.into());
|
||||
response.user = Some(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1793,7 +1795,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
|
||||
let credential_maybe = FullCredential::deserialize(&credential_data);
|
||||
|
||||
if let Ok(old_credential) = credential_maybe {
|
||||
if old_credential.user.id == user_id {
|
||||
if old_credential.user.id() == user_id {
|
||||
match old_credential.key {
|
||||
credential::Key::ResidentKey(key) => {
|
||||
info_now!(":: deleting resident key");
|
||||
|
||||
@@ -174,7 +174,7 @@ where
|
||||
|
||||
let rp = credential.data.rp;
|
||||
|
||||
response.rp_id_hash = Some(ByteArray::new(self.hash(rp.id.as_ref())));
|
||||
response.rp_id_hash = Some(ByteArray::new(self.hash(rp.id().as_ref())));
|
||||
response.rp = Some(rp.into());
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@ where
|
||||
|
||||
let rp = credential.data.rp;
|
||||
|
||||
response.rp_id_hash = Some(ByteArray::new(self.hash(rp.id.as_ref())));
|
||||
response.rp_id_hash = Some(ByteArray::new(self.hash(rp.id().as_ref())));
|
||||
response.rp = Some(rp.into());
|
||||
|
||||
// cache state for next call
|
||||
@@ -524,18 +524,22 @@ where
|
||||
// TODO: check remaining space, return KeyStoreFull
|
||||
|
||||
// the updated user ID must match the stored user ID
|
||||
if credential.user.id != user.id {
|
||||
if credential.user.id() != &user.id {
|
||||
error!("updated user ID does not match original user ID");
|
||||
return Err(Error::InvalidParameter);
|
||||
}
|
||||
|
||||
// update user name and display name unless the values are not set or empty
|
||||
credential.data.user.name = user.name.as_ref().filter(|s| !s.is_empty()).cloned();
|
||||
credential.data.user.display_name = user
|
||||
.display_name
|
||||
.as_ref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.cloned();
|
||||
credential
|
||||
.data
|
||||
.user
|
||||
.set_name(user.name.as_ref().filter(|s| !s.is_empty()).cloned());
|
||||
credential.data.user.set_display_name(
|
||||
user.display_name
|
||||
.as_ref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.cloned(),
|
||||
);
|
||||
|
||||
// write updated credential
|
||||
let serialized = credential.serialize()?;
|
||||
|
||||
Reference in New Issue
Block a user