ctap2: refactor make_credential / get_assertion to take &mut Response

This commit is contained in:
Emanuele Cesena
2026-06-01 17:38:06 +02:00
committed by Robin Krahl
parent 4c38096af6
commit 0084256898
5 changed files with 43 additions and 44 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
-
- Update to `ctap-types` v0.6.0-rc.4.
## [v0.4.0-rc.2](https://github.com/trussed-dev/fido-authenticator/releases/tag/v0.4.0-rc.2) (2026-05-31)
+1 -1
View File
@@ -12,7 +12,7 @@ description = "FIDO authenticator Trussed app"
apdu-app = { version = "0.2", optional = true }
cbor-smol = "0.5"
cosey = "0.4"
ctap-types = { version = "=0.6.0-rc.3", features = ["get-info-full", "large-blobs", "third-party-payment"] }
ctap-types = { version = "=0.6.0-rc.4", features = ["get-info-full", "large-blobs", "third-party-payment"] }
ctaphid-app = { version = "0.2", optional = true }
delog = "0.1"
heapless = "0.9"
+7 -2
View File
@@ -1,6 +1,10 @@
#![no_main]
use ctap_types::{authenticator::Request, ctap1::Authenticator as _, ctap2::Authenticator as _};
use ctap_types::{
authenticator::Request,
ctap1::Authenticator as _,
ctap2::{Authenticator as _, Response},
};
use fido_authenticator::{Authenticator, Config, Conforming};
use trussed::virt::StoreConfig;
use trussed_staging::virt;
@@ -30,7 +34,8 @@ fuzz_target!(|requests: Vec<Request<'_>>| {
authenticator.call_ctap1(&request).ok();
}
Request::Ctap2(request) => {
authenticator.call_ctap2(&request).ok();
let mut response = Response::Reset;
authenticator.call_ctap2(&request, &mut response).ok();
}
}
}
+26 -27
View File
@@ -205,14 +205,17 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
// 7. reset timer
// 8. increment credential counter (not applicable)
self.assert_with_credential(None, Credential::Full(credential))
let mut response = ctap2::get_assertion::Response::empty();
self.assert_with_credential(None, &Credential::Full(credential), &mut response)?;
Ok(response)
}
#[inline(never)]
fn make_credential(
fn make_credential_into(
&mut self,
parameters: &ctap2::make_credential::Request,
) -> Result<ctap2::make_credential::Response> {
response: &mut ctap2::make_credential::Response,
) -> Result<()> {
let rp_id_hash = self.hash(parameters.rp.id.as_ref());
// 1-4.
@@ -614,16 +617,13 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
info_now!("deleted private credential key: {}", _success);
}
let mut attestation_object = ctap2::make_credential::ResponseBuilder {
fmt: att_stmt_fmt
.map(From::from)
.unwrap_or(AttestationStatementFormat::None),
auth_data: serialized_auth_data,
}
.build();
attestation_object.att_stmt = att_stmt;
attestation_object.large_blob_key = large_blob_key;
Ok(attestation_object)
response.fmt = att_stmt_fmt
.map(From::from)
.unwrap_or(AttestationStatementFormat::None);
response.auth_data = serialized_auth_data;
response.att_stmt = att_stmt;
response.large_blob_key = large_blob_key;
Ok(())
}
#[inline(never)]
@@ -1207,10 +1207,11 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
}
#[inline(never)]
fn get_assertion(
fn get_assertion_into(
&mut self,
parameters: &ctap2::get_assertion::Request,
) -> Result<ctap2::get_assertion::Response> {
response: &mut ctap2::get_assertion::Response,
) -> Result<()> {
debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000);
let rp_id_hash = self.hash(parameters.rp_id.as_ref());
@@ -1315,7 +1316,7 @@ impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenti
n => Some(n),
};
self.assert_with_credential(num_credentials, credential)
self.assert_with_credential(num_credentials, &credential, response)
}
#[inline(never)]
@@ -2044,8 +2045,9 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
fn assert_with_credential(
&mut self,
num_credentials: Option<u32>,
credential: Credential,
) -> Result<ctap2::get_assertion::Response> {
credential: &Credential,
response: &mut ctap2::get_assertion::Response,
) -> Result<()> {
let data = self.state.runtime.active_get_assertion.clone().unwrap();
let credential_id_version = self.state.persistent.credential_id_version();
let rp_id_hash = &data.rp_id_hash;
@@ -2078,7 +2080,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
}
large_blob_key_requested = extensions.large_blob_key == Some(true);
}
self.process_assertion_extensions(&data, extensions, &credential, key)?
self.process_assertion_extensions(&data, extensions, credential, key)?
} else {
None
};
@@ -2184,18 +2186,15 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
syscall!(self.trussed.delete(key));
}
let mut response = ctap2::get_assertion::ResponseBuilder {
credential: credential_id.into(),
auth_data: serialized_auth_data,
signature,
}
.build();
response.credential = credential_id.into();
response.auth_data = serialized_auth_data;
response.signature = signature;
response.number_of_credentials = num_credentials;
response.att_stmt = att_stmt;
// User with empty IDs are ignored for compatibility
if is_rk {
if let Credential::Full(credential) = &credential {
if let Credential::Full(credential) = credential {
if !credential.user.id().is_empty() {
let mut user: PublicKeyCredentialUserEntity = credential.user.clone().into();
// User identifiable information (name, DisplayName, icon) MUST not
@@ -2219,7 +2218,7 @@ impl<UP: UserPresence, T: TrussedRequirements> crate::Authenticator<UP, T> {
}
}
Ok(response)
Ok(())
}
#[inline(never)]
+8 -13
View File
@@ -145,13 +145,11 @@ where
msp() - 0x2000_0000
);
// let ctap_request = ctap2::Request::deserialize(data)
// .map_err(|error| error as u8)?;
// let ctap_response = ctap2::Authenticator::call_ctap2(authenticator, &ctap_request)
// .map_err(|error| error as u8)?;
// Goal of these nested scopes is to keep stack small.
let ctap_response = try_get_ctap2_response(authenticator, data)?;
// ctap_response lives here (this is the only stack slot for the
// ~6 KB ctap2::Response with mldsa44). Inner layers fill it in
// place via &mut, avoiding by-value copies.
let mut ctap_response = ctap2::Response::Reset;
try_get_ctap2_response(authenticator, data, &mut ctap_response)?;
ctap_response.serialize(response);
Ok(())
}
@@ -160,7 +158,8 @@ where
fn try_get_ctap2_response<T, UP>(
authenticator: &mut Authenticator<UP, T>,
data: &[u8],
) -> Result<ctap2::Response, u8>
ctap_response: &mut ctap2::Response,
) -> Result<(), u8>
where
T: TrussedRequirements,
UP: UserPresence,
@@ -190,11 +189,7 @@ where
debug!("2a SP: {:X}", msp());
use ctap2::Authenticator;
authenticator
.call_ctap2(&ctap_request)
.inspect(|_response| {
info!("Sending CTAP2 response {:?}", response_operation(_response));
trace!("CTAP2 response: {:?}", _response);
})
.call_ctap2(&ctap_request, ctap_response)
.map_err(|error| {
info!("CTAP2 error: {:?}", error);
error as u8