Skip to main content

tap_agent/
agent_key.rs

1//! Agent Key Abstraction for the TAP Agent
2//!
3//! This module provides a trait-based abstraction for cryptographic keys used by the TAP Agent.
4//! It defines traits for signing, verification, encryption, and decryption operations, allowing
5//! for a unified interface that can support both local keys and remote keys (e.g., HSM-backed).
6
7use crate::error::{Error, Result};
8use crate::message::{Jwe, JweProtected, JwsProtected};
9use async_trait::async_trait;
10use serde_json::Value;
11use std::fmt::Debug;
12use std::sync::Arc;
13
14/// Defines core capabilities of a cryptographic key used by an agent.
15///
16/// This trait is the foundation for all agent key operations, providing
17/// basic properties that all keys should have regardless of their specific
18/// cryptographic capabilities.
19#[async_trait]
20pub trait AgentKey: Send + Sync + Debug {
21    /// Returns the unique identifier for this key
22    fn key_id(&self) -> &str;
23
24    /// Exports the public key material as a JWK
25    fn public_key_jwk(&self) -> Result<Value>;
26
27    /// Returns the DID associated with this key
28    fn did(&self) -> &str;
29
30    /// Returns the key type (e.g., Ed25519, P-256, secp256k1)
31    fn key_type(&self) -> &str;
32}
33
34/// JWS algorithm identifier
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub enum JwsAlgorithm {
37    /// Ed25519 signatures
38    EdDSA,
39    /// P-256 ECDSA signatures
40    ES256,
41    /// secp256k1 ECDSA signatures
42    ES256K,
43}
44
45impl JwsAlgorithm {
46    /// Returns the algorithm identifier as a string
47    pub fn as_str(&self) -> &'static str {
48        match self {
49            JwsAlgorithm::EdDSA => "EdDSA",
50            JwsAlgorithm::ES256 => "ES256",
51            JwsAlgorithm::ES256K => "ES256K",
52        }
53    }
54}
55
56/// JWE algorithm identifier (for key encryption)
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub enum JweAlgorithm {
59    /// ECDH-ES + AES key wrap with 256-bit key
60    EcdhEsA256kw,
61    /// ECDH-ES (direct key agreement)
62    EcdhEs,
63}
64
65impl JweAlgorithm {
66    /// Returns the algorithm identifier as a string
67    pub fn as_str(&self) -> &'static str {
68        match self {
69            JweAlgorithm::EcdhEsA256kw => "ECDH-ES+A256KW",
70            JweAlgorithm::EcdhEs => "ECDH-ES",
71        }
72    }
73}
74
75/// JWE encryption algorithm identifier (for content encryption)
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum JweEncryption {
78    /// AES-GCM with 256-bit key
79    A256GCM,
80}
81
82impl JweEncryption {
83    /// Returns the algorithm identifier as a string
84    pub fn as_str(&self) -> &'static str {
85        match self {
86            JweEncryption::A256GCM => "A256GCM",
87        }
88    }
89}
90
91/// Agent key capable of signing data for JWS creation.
92///
93/// Implementations of this trait can sign data to create JWS signatures.
94#[async_trait]
95pub trait SigningKey: AgentKey {
96    /// Signs the provided data using this key
97    async fn sign(&self, data: &[u8]) -> Result<Vec<u8>>;
98
99    /// Returns the recommended JWS algorithm for this key
100    fn recommended_jws_alg(&self) -> JwsAlgorithm;
101
102    /// Signs and creates a JWS with the provided payload
103    async fn create_jws(
104        &self,
105        payload: &[u8],
106        protected_header: Option<JwsProtected>,
107    ) -> Result<crate::message::Jws>;
108}
109
110/// A key (typically public) capable of verifying a JWS signature.
111///
112/// This trait might be implemented by a struct holding a public JWK,
113/// or by an AgentKey that can expose its public verification capabilities.
114#[async_trait]
115pub trait VerificationKey: Send + Sync + Debug {
116    /// The key ID associated with this verification key
117    fn key_id(&self) -> &str;
118
119    /// Exports the public key material as a JWK
120    fn public_key_jwk(&self) -> Result<Value>;
121
122    /// Verifies the provided signature against the payload and protected header
123    async fn verify_signature(
124        &self,
125        payload: &[u8],
126        signature: &[u8],
127        protected_header: &JwsProtected,
128    ) -> Result<bool>;
129}
130
131/// Agent key capable of encrypting data for JWE creation.
132///
133/// Implementations of this trait can encrypt data for specific
134/// recipients to create JWEs.
135#[async_trait]
136pub trait EncryptionKey: AgentKey {
137    /// Encrypts plaintext data for a specific recipient
138    async fn encrypt(
139        &self,
140        plaintext: &[u8],
141        aad: Option<&[u8]>,
142        recipient_public_key: &dyn VerificationKey,
143    ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)>; // (ciphertext, iv, tag)
144
145    /// Returns the recommended JWE algorithm and encryption for this key
146    fn recommended_jwe_alg_enc(&self) -> (JweAlgorithm, JweEncryption);
147
148    /// Creates a JWE for multiple recipients
149    async fn create_jwe(
150        &self,
151        plaintext: &[u8],
152        recipients: &[Arc<dyn VerificationKey>],
153        protected_header: Option<JweProtected>,
154    ) -> Result<Jwe>;
155}
156
157/// Agent key capable of decrypting JWE data.
158///
159/// Implementations of this trait can decrypt JWE ciphertexts
160/// that were encrypted for this key.
161#[async_trait]
162pub trait DecryptionKey: AgentKey {
163    /// Decrypts the provided ciphertext
164    async fn decrypt(
165        &self,
166        ciphertext: &[u8],
167        encrypted_key: &[u8],
168        iv: &[u8],
169        tag: &[u8],
170        aad: Option<&[u8]>,
171        sender_key: Option<&dyn VerificationKey>,
172    ) -> Result<Vec<u8>>;
173
174    /// Unwraps a JWE to retrieve the plaintext
175    async fn unwrap_jwe(&self, jwe: &Jwe) -> Result<Vec<u8>>;
176}
177
178/// Error type specific to agent key operations
179#[derive(Debug, thiserror::Error)]
180pub enum AgentKeyError {
181    #[error("Key operation failed: {0}")]
182    Operation(String),
183
184    #[error("Invalid key: {0}")]
185    InvalidKey(String),
186
187    #[error("Unsupported algorithm: {0}")]
188    UnsupportedAlgorithm(String),
189
190    #[error("Verification failed")]
191    VerificationFailed,
192
193    #[error("Decryption failed: {0}")]
194    DecryptionFailed(String),
195
196    #[error("Serialization error: {0}")]
197    Serialization(String),
198
199    #[error("Invalid format: {0}")]
200    InvalidFormat(String),
201}
202
203impl From<AgentKeyError> for Error {
204    fn from(err: AgentKeyError) -> Self {
205        Error::Cryptography(err.to_string())
206    }
207}