Skip to content

Commit d638060

Browse files
sarroutbiclaude
andcommitted
Fix agent handling of 403 registration responses
The agent was incorrectly interpreting 403 Forbidden responses from the registrar as API version incompatibility errors. This caused two problems: 1. The agent would try all enabled API versions, even though 403 indicates a permanent security rejection (e.g., TPM identity mismatch during re-registration) 2. The agent would continue running after registration failure, making it appear operational when it was not properly registered This issue became apparent with the Python keylime registrar security fix for CVE-2025-13609 (duplicate UUID vulnerability), which returns 403 Forbidden when an agent attempts to re-register with a different TPM identity. The agent will now correctly fail fast when the registrar rejects registration for security reasons. Related: keylime/keylime#1820 (Python registrar UUID spoofing fix) Co-Authored-By: Claude <[email protected]> Signed-off-by: Sergio Arroutbi <[email protected]>
1 parent a7cafe7 commit d638060

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

keylime-agent/src/main.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,10 +623,24 @@ async fn main() -> Result<()> {
623623
ak_handle,
624624
retry_config: None,
625625
};
626+
use keylime::error::Error;
627+
use keylime::registrar_client::RegistrarClientError;
628+
626629
match keylime::agent_registration::register_agent(aa, &mut ctx).await {
627630
Ok(()) => (),
631+
Err(Error::RegistrarClient(
632+
RegistrarClientError::RegistrationForbidden { message },
633+
)) => {
634+
error!("Failed to register agent: Registration forbidden - {message}");
635+
error!("This indicates a security rejection (403 Forbidden), likely due to TPM identity mismatch or UUID spoofing attempt.");
636+
error!("The existing agent record must be deleted before re-registering with a different TPM.");
637+
return Err(Error::RegistrarClient(
638+
RegistrarClientError::RegistrationForbidden { message },
639+
));
640+
}
628641
Err(e) => {
629642
error!("Failed to register agent: {e:?}");
643+
error!("Registration failed with a non-security error. The agent will continue but may have degraded functionality.");
630644
}
631645
}
632646

keylime/src/registrar_client.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ pub enum RegistrarClientError {
245245
#[error("Failed to register agent: received {code} from {addr}")]
246246
Registration { addr: String, code: u16 },
247247

248+
/// Registration forbidden - TPM identity mismatch or security rejection
249+
#[error("Registration forbidden: {message}. This may indicate a TPM identity change or UUID spoofing attempt. The existing agent record must be deleted before re-registering with a different TPM.")]
250+
RegistrationForbidden { message: String },
251+
248252
/// Reqwest error
249253
#[error("Reqwest error: {0}")]
250254
Reqwest(#[from] reqwest::Error),
@@ -387,6 +391,16 @@ impl RegistrarClient {
387391
};
388392

389393
if !resp.status().is_success() {
394+
// Check if this is a 403 Forbidden - indicates security rejection
395+
if resp.status() == StatusCode::FORBIDDEN {
396+
let error_message = resp
397+
.text()
398+
.await
399+
.unwrap_or_else(|_| "Unknown error".to_string());
400+
return Err(RegistrarClientError::RegistrationForbidden {
401+
message: error_message,
402+
});
403+
}
390404
return Err(RegistrarClientError::Registration {
391405
addr,
392406
code: resp.status().as_u16(),
@@ -438,6 +452,15 @@ impl RegistrarClient {
438452
info!("Trying to register agent using API version {api_version}");
439453
let r = self.try_register_agent(ai, api_version).await;
440454

455+
// Check if this is a security rejection (403 Forbidden)
456+
// If so, return immediately - don't try other API versions
457+
if let Err(RegistrarClientError::RegistrationForbidden {
458+
..
459+
}) = r
460+
{
461+
return r;
462+
}
463+
441464
// If successful, cache the API version for future requests
442465
if r.is_ok() {
443466
self.api_version = api_version.to_string();
@@ -458,6 +481,17 @@ impl RegistrarClient {
458481
let r =
459482
self.try_register_agent(ai, api_version).await;
460483

484+
// Check if this is a security rejection (403 Forbidden)
485+
// If so, return immediately - don't try other API versions
486+
if let Err(
487+
RegistrarClientError::RegistrationForbidden {
488+
..
489+
},
490+
) = r
491+
{
492+
return r;
493+
}
494+
461495
// If successful, cache the API version for future requests
462496
if r.is_ok() {
463497
self.api_version = api_version.to_string();

0 commit comments

Comments
 (0)