feat(auth): implement attestation status verification for public keys
Some checks failed
ci/woodpecker/pr/server-audit Pipeline was successful
ci/woodpecker/pr/server-lint Pipeline failed
ci/woodpecker/pr/server-vet Pipeline failed
ci/woodpecker/pr/server-test Pipeline failed
ci/woodpecker/pr/useragent-analyze Pipeline failed

This commit is contained in:
CleverWild
2026-04-04 12:10:45 +02:00
parent 881f16bb1a
commit 0bb6e596ac

View File

@@ -14,6 +14,13 @@ use crate::{
db::schema, db::schema,
}; };
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttestationStatus {
Attested,
NotAttested,
Unavailable,
}
pub struct ChallengeRequest { pub struct ChallengeRequest {
pub pubkey: AuthPublicKey, pub pubkey: AuthPublicKey,
} }
@@ -133,8 +140,12 @@ where
&mut self, &mut self,
ChallengeRequest { pubkey }: ChallengeRequest, ChallengeRequest { pubkey }: ChallengeRequest,
) -> Result<ChallengeContext, Self::Error> { ) -> Result<ChallengeContext, Self::Error> {
self.verify_pubkey_integrity_before_challenge(&pubkey) match self.verify_pubkey_attestation_status(&pubkey).await? {
.await?; AttestationStatus::Attested | AttestationStatus::Unavailable => {}
AttestationStatus::NotAttested => {
return Err(Error::InvalidChallengeSolution);
}
}
let stored_bytes = pubkey.to_stored_bytes(); let stored_bytes = pubkey.to_stored_bytes();
let nonce = create_nonce(&self.conn.db, &stored_bytes, pubkey.key_type()).await?; let nonce = create_nonce(&self.conn.db, &stored_bytes, pubkey.key_type()).await?;
@@ -290,10 +301,10 @@ where
} }
} }
async fn verify_pubkey_integrity_before_challenge( async fn verify_pubkey_attestation_status(
&self, &self,
pubkey: &AuthPublicKey, pubkey: &AuthPublicKey,
) -> Result<(), Error> { ) -> Result<AttestationStatus, Error> {
let stored_tag: Option<Option<Vec<u8>>> = { let stored_tag: Option<Option<Vec<u8>>> = {
let mut conn = self.conn.db.get().await.map_err(|e| { let mut conn = self.conn.db.get().await.map_err(|e| {
error!(error = ?e, "Database pool error"); error!(error = ?e, "Database pool error");
@@ -319,19 +330,19 @@ where
let Some(expected_tag) = self.try_sign_pubkey_integrity_tag(pubkey).await? else { let Some(expected_tag) = self.try_sign_pubkey_integrity_tag(pubkey).await? else {
// Vault sealed/unbootstrapped: cannot verify integrity yet. // Vault sealed/unbootstrapped: cannot verify integrity yet.
return Ok(()); return Ok(AttestationStatus::Unavailable);
}; };
let Some(stored_tag) = stored_tag else { match stored_tag {
error!("Missing pubkey integrity tag for registered key while vault is unsealed"); Some(stored_tag) if stored_tag == expected_tag => Ok(AttestationStatus::Attested),
return Err(Error::InvalidChallengeSolution); Some(_) => {
};
if stored_tag != expected_tag {
error!("User-agent pubkey integrity tag mismatch"); error!("User-agent pubkey integrity tag mismatch");
return Err(Error::InvalidChallengeSolution); Ok(AttestationStatus::NotAttested)
}
None => {
error!("Missing pubkey integrity tag for registered key while vault is unsealed");
Ok(AttestationStatus::NotAttested)
}
} }
Ok(())
} }
} }