okami 0.2.0

Post-quantum cryptographic identity for AI agents
Documentation
//! Exploit attempt: demonstrates that DelegationToken::verify rejects issuer spoofing.
//!
//! Finding #1 from the /cso audit: an attacker who generates their own keypair
//! can mint a token that claims to be issued by any SPIFFE ID by:
//!   1. Generating a legitimate AgentIdentity (attacker's own)
//!   2. Using DelegationToken::issue() to create a valid token as the attacker
//!   3. Post-issue: swapping the `issuer` field to claim victim's SPIFFE ID
//!   4. Calling verify() — the embedded credential's spiffe_id still names the
//!      attacker, while issuer now names the victim.
//!
//! Before the fix: verify() returned Ok because it only checked the signature
//! against the embedded key, not whether the embedded key belongs to the claimed issuer.
//! After the fix: verify() returns Err(ChainVerificationFailed) with "does not match".

use okami::delegation::{Capability, DelegationToken};
use okami::identity::{AgentIdentity, SpiffeId};
use std::time::Duration;

fn main() {
    println!("=== Exploit Attempt: Issuer Spoofing (Finding #1) ===\n");

    // Step 1: Attacker generates their own legitimate keypair.
    let attacker = AgentIdentity::new("evil.example", "attacker").expect("attacker identity");

    // Step 2: Attacker picks a victim SPIFFE ID they want to impersonate.
    let victim_spiffe = SpiffeId::new("corp.internal", "admin").expect("victim spiffe id");

    // Step 3: Attacker issues a valid token from their own identity to some subject.
    // (This part is fine — attacker is allowed to issue tokens as themselves.)
    let subject = SpiffeId::new("evil.example", "puppet").expect("subject spiffe id");
    let scopes = vec![Capability::new("write:payroll").expect("scope")];

    let mut forged_token = DelegationToken::issue(
        &attacker,
        subject,
        scopes.clone(),
        &scopes,
        Duration::from_secs(3600),
        None,
    )
    .expect("issue attacker token");

    println!("Step 1-3: Attacker issues a valid token as themselves.");
    println!("  Real attacker SPIFFE ID:  {}", attacker.spiffe_id());
    println!("  Token issuer (pre-swap):   {}", forged_token.issuer);
    println!(
        "  Embedded cred subject:     {}",
        forged_token.issuer_credential.spiffe_id
    );

    // Step 4: Attacker swaps the `issuer` field to claim victim's identity.
    // The embedded issuer_credential still has attacker's SPIFFE ID and key.
    // The signature remains valid (it was signed by attacker's key over the
    // original payload bytes). This is the core of the exploit.
    forged_token.issuer = victim_spiffe.clone();

    println!("\nStep 4: Attacker swaps issuer field to impersonate victim.");
    println!("  Token issuer (post-swap):  {}", forged_token.issuer);
    println!(
        "  Embedded cred subject:     {}",
        forged_token.issuer_credential.spiffe_id
    );
    println!("  Claimed scope:             write:payroll");

    // Step 5: Attempt verification. Before the fix this would return Ok.
    println!("\nStep 5: Calling token.verify(None)...");
    let result = forged_token.verify(None);

    match &result {
        Ok(()) => {
            eprintln!("\n[FAIL] VULNERABILITY PRESENT: forged token verified successfully!");
            eprintln!("  The exploit succeeded — attacker can impersonate {victim_spiffe}");
            std::process::exit(1);
        }
        Err(e) => {
            println!("\n[PASS] Exploit blocked. verify() returned:");
            println!("  Err({e})");
            let msg = e.to_string();
            if msg.contains("does not match") {
                println!("\nFix confirmed: error mentions \"does not match\" as expected.");
                println!(
                    "An attacker cannot forge tokens claiming to be issued by {victim_spiffe}."
                );
            } else {
                println!(
                    "\nNote: error does not contain \"does not match\" — may be a different guard."
                );
            }
        }
    }
}