Skip to content

Commit

Permalink
credential_management: Implement UpdateUserInformation
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-nitrokey committed Mar 1, 2024
1 parent c53bbea commit 1ea7a46
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ features = ["dispatch"]

[patch.crates-io]
# ctap-types = { git = "https://github.com/trussed-dev/ctap-types.git", rev = "f0db7acb87cced69edde1e33f41e1bdf1eee54c0" }
ctap-types = { git = "https://github.com/Nitrokey/ctap-types.git", branch = "pin-protocol-2-permissions" }
ctap-types = { git = "https://github.com/Nitrokey/ctap-types.git", branch = "pin-protocol-2-permissions-cm-uui" }
ctaphid-dispatch = { git = "https://github.com/trussed-dev/ctaphid-dispatch.git", rev = "57cb3317878a8593847595319aa03ef17c29ec5b" }
apdu-dispatch = { git = "https://github.com/trussed-dev/apdu-dispatch.git", rev = "915fc237103fcecc29d0f0b73391f19abf6576de" }
serde-indexed = { git = "https://github.com/sosthene-nitrokey/serde-indexed.git", rev = "5005d23cb4ee8622e62188ea0f9466146f851f0d" }
Expand Down
22 changes: 20 additions & 2 deletions src/ctap2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,21 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
.ok_or(Error::MissingParameter)?,
)
}

// 0x7
Subcommand::UpdateUserInformation => {
let sub_parameters = sub_parameters.as_ref().ok_or(Error::MissingParameter)?;
let credential_id = sub_parameters
.credential_id
.as_ref()
.ok_or(Error::MissingParameter)?;
let user = sub_parameters
.user
.as_ref()
.ok_or(Error::MissingParameter)?;

cred_mgmt.update_user_information(credential_id, user)
}
}
}

Expand Down Expand Up @@ -1337,7 +1352,8 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
sub_command @ Subcommand::GetCredsMetadata
| sub_command @ Subcommand::EnumerateRpsBegin
| sub_command @ Subcommand::EnumerateCredentialsBegin
| sub_command @ Subcommand::DeleteCredential => {
| sub_command @ Subcommand::DeleteCredential
| sub_command @ Subcommand::UpdateUserInformation => {
// check pinProtocol
let pin_protocol = parameters
// .sub_command_params.as_ref().ok_or(Error::MissingParameter)?
Expand All @@ -1349,7 +1365,9 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
let mut data: Bytes<{ sizes::MAX_CREDENTIAL_ID_LENGTH_PLUS_256 }> =
Bytes::from_slice(&[sub_command as u8]).unwrap();
let len = 1 + match sub_command {
Subcommand::EnumerateCredentialsBegin | Subcommand::DeleteCredential => {
Subcommand::EnumerateCredentialsBegin
| Subcommand::DeleteCredential
| Subcommand::UpdateUserInformation => {
data.resize_to_capacity();
// ble, need to reserialize
ctap_types::serde::cbor_serialize(
Expand Down
70 changes: 60 additions & 10 deletions src/ctap2/credential_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
use core::convert::TryFrom;

use trussed::{
syscall,
syscall, try_syscall,
types::{DirEntry, Location, Path, PathBuf},
};

use ctap_types::{
cose::PublicKey,
ctap2::credential_management::{CredentialProtectionPolicy, Response},
heapless_bytes::Bytes,
webauthn::PublicKeyCredentialDescriptor,
webauthn::{PublicKeyCredentialDescriptor, PublicKeyCredentialUserEntity},
Error,
};

Expand Down Expand Up @@ -460,22 +460,27 @@ where
Ok(response)
}

pub fn delete_credential(
&mut self,
credential_descriptor: &PublicKeyCredentialDescriptor,
) -> Result<Response> {
info!("delete credential");
let credential_id_hash = self.hash(&credential_descriptor.id[..]);
fn find_credential(&mut self, credential: &PublicKeyCredentialDescriptor) -> Option<PathBuf> {
let credential_id_hash = self.hash(&credential.id[..]);
let mut hex = [b'0'; 16];
super::format_hex(&credential_id_hash[..8], &mut hex);
let dir = PathBuf::from(b"rk");
let filename = PathBuf::from(&hex);

let rk_path = syscall!(self
syscall!(self
.trussed
.locate_file(Location::Internal, Some(dir), filename,))
.path
.ok_or(Error::InvalidCredential)?;
}

pub fn delete_credential(
&mut self,
credential_descriptor: &PublicKeyCredentialDescriptor,
) -> Result<Response> {
info!("delete credential");
let rk_path = self
.find_credential(credential_descriptor)
.ok_or(Error::InvalidCredential)?;

// DELETE
self.delete_resident_key_by_path(&rk_path)?;
Expand All @@ -491,4 +496,49 @@ where
let response = Default::default();
Ok(response)
}

pub fn update_user_information(
&mut self,
credential_descriptor: &PublicKeyCredentialDescriptor,
user: &PublicKeyCredentialUserEntity,
) -> Result<Response> {
info!("update user information");

// locate and parse existing credential
let rk_path = self
.find_credential(credential_descriptor)
.ok_or(Error::NoCredentials)?;
let serialized = syscall!(self.trussed.read_file(Location::Internal, rk_path.clone())).data;
let mut credential =
FullCredential::deserialize(&serialized).map_err(|_| Error::InvalidCredential)?;

// TODO: check remaining space, return KeyStoreFull

// the updated user ID must match the stored 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())
.map(Clone::clone);
credential.data.user.display_name = user
.display_name
.as_ref()
.filter(|s| !s.is_empty())
.map(Clone::clone);

// write updated credential
let serialized = credential.serialize()?;
try_syscall!(self
.trussed
.write_file(Location::Internal, rk_path, serialized, None))
.map_err(|_| Error::KeyStoreFull)?;

Ok(Default::default())
}
}

0 comments on commit 1ea7a46

Please sign in to comment.