diff --git a/src/principal.rs b/src/principal.rs index 7267fa9..8f38761 100644 --- a/src/principal.rs +++ b/src/principal.rs @@ -233,26 +233,26 @@ pub fn sign_credential( Ok(format!("{}.{}", payload_b64, sig_b64)) } -/// Verify and decode a signed credential, returning the claims if valid. +/// Verify the cryptographic signature and expiry of a signed credential. /// -/// Checks performed: -/// 1. Signature verification (HMAC-SHA256) -/// 2. Expiry verification -/// 3. Pod identity binding +/// This performs only the pure cryptographic checks that require no external state: +/// 1. Parse the credential format +/// 2. Verify HMAC-SHA256 signature +/// 3. Check expiry /// -/// Revocation and attempt-active checks require external state (database) and -/// must be performed by the caller after this returns `Ok`. -pub fn verify_credential( +/// Returns the verified claims on success. The caller is responsible for +/// performing persistence-level validation (pod binding, attempt active, +/// revocation) after this returns `Ok`. +pub fn verify_signature( credential: &str, secret: &[u8], - expected_pod_id: Uuid, ) -> Result { use base64::Engine; use hmac::{Hmac, Mac}; use sha2::Sha256; - let (payload_b64, sig_b64) = SignedCredential::parse(credential) - .ok_or(CredentialError::MalformedPayload)?; + let (payload_b64, sig_b64) = + SignedCredential::parse(credential).ok_or(CredentialError::MalformedPayload)?; // Decode payload let payload_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD @@ -276,6 +276,25 @@ pub fn verify_credential( return Err(CredentialError::Expired); } + Ok(claims) +} + +/// Verify and decode a signed credential, returning the claims if valid. +/// +/// Checks performed: +/// 1. Signature verification (HMAC-SHA256) +/// 2. Expiry verification +/// 3. Pod identity binding +/// +/// Revocation and attempt-active checks require external state (database) and +/// must be performed by the caller after this returns `Ok`. +pub fn verify_credential( + credential: &str, + secret: &[u8], + expected_pod_id: Uuid, +) -> Result { + let claims = verify_signature(credential, secret)?; + // Check pod binding if claims.pod_id != expected_pod_id { return Err(CredentialError::PodMismatch);