Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion tap-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ tempfile = { version = "3.8", optional = true }
# Crypto backends (optional)
ed25519-dalek = { version = "2.2", features = ["rand_core"], optional = true }
curve25519-dalek = { version = "4.1", features = ["digest"], optional = true }
x25519-dalek = { version = "2.0", features = ["static_secrets"], optional = true }
p256 = { version = "0.13", features = ["ecdh", "ecdsa"], optional = true }
k256 = { version = "0.13", features = ["ecdsa"], optional = true }
rand = { version = "0.8", optional = true }
Expand Down Expand Up @@ -86,6 +87,6 @@ wasm = [
]

# Crypto features
crypto-ed25519 = ["dep:ed25519-dalek", "dep:curve25519-dalek", "dep:rand"]
crypto-ed25519 = ["dep:ed25519-dalek", "dep:curve25519-dalek", "dep:x25519-dalek", "dep:rand"]
crypto-p256 = ["dep:p256", "dep:rand"]
crypto-secp256k1 = ["dep:k256", "dep:rand"]
4 changes: 2 additions & 2 deletions tap-agent/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1466,8 +1466,8 @@ impl crate::agent::Agent for TapAgent {
// Check if it's an encrypted message (JWE) or signed message (JWS)
let is_encrypted =
json_value.get("protected").is_some() && json_value.get("recipients").is_some();
let is_signed =
json_value.get("payload").is_some() && json_value.get("signatures").is_some();
let is_signed = json_value.get("payload").is_some()
&& (json_value.get("signatures").is_some() || json_value.get("signature").is_some());

debug!(
"Message type detection: encrypted={}, signed={}",
Expand Down
37 changes: 36 additions & 1 deletion tap-agent/src/agent_key_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,42 @@ impl KeyManager for AgentKeyManager {
return Ok(verification_key);
}

// In a full implementation, we would use a DID Resolver here
// Resolve did:key DIDs directly from the DID string (public key is embedded)
let did = kid.split('#').next().unwrap_or(kid);
if did.starts_with("did:key:") {
let resolver = crate::did::KeyResolver::new();
#[cfg(not(target_arch = "wasm32"))]
let did_doc_result = {
use crate::did::DIDMethodResolver;
resolver.resolve_method(did).await
};
#[cfg(target_arch = "wasm32")]
let did_doc_result = {
use crate::did::WasmDIDMethodResolver;
resolver.resolve_method(did)
};

if let Ok(Some(did_doc)) = did_doc_result {
// Find the verification method matching the kid
if let Some(vm) = did_doc.verification_method.iter().find(|vm| vm.id == kid) {
if let Ok(vk) = PublicVerificationKey::from_verification_material(
kid.to_string(),
&vm.verification_material,
) {
let verification_key =
Arc::new(vk) as Arc<dyn VerificationKey + Send + Sync>;

// Cache for future lookups
if let Ok(mut verification_keys) = self.verification_keys.write() {
verification_keys.insert(kid.to_string(), verification_key.clone());
}

return Ok(verification_key);
}
}
}
}

Err(Error::Cryptography(format!(
"No verification key found with ID: {}",
kid
Expand Down
46 changes: 38 additions & 8 deletions tap-agent/src/key_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::local_agent_key::{LocalAgentKey, PublicVerificationKey};
use crate::message_packing::{KeyManagerPacking, MessageError};

use async_trait::async_trait;
use base64::Engine;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
Expand Down Expand Up @@ -621,7 +620,40 @@ impl KeyManager for DefaultKeyManager {
return Ok(verification_key);
}

// In a real implementation, we would use a DID Resolver here
// Resolve did:key DIDs directly from the DID string (public key is embedded)
let did = kid.split('#').next().unwrap_or(kid);
if did.starts_with("did:key:") {
let resolver = crate::did::KeyResolver::new();
#[cfg(not(target_arch = "wasm32"))]
let did_doc_result = {
use crate::did::DIDMethodResolver;
resolver.resolve_method(did).await
};
#[cfg(target_arch = "wasm32")]
let did_doc_result = {
use crate::did::WasmDIDMethodResolver;
resolver.resolve_method(did)
};

if let Ok(Some(did_doc)) = did_doc_result {
if let Some(vm) = did_doc.verification_method.iter().find(|vm| vm.id == kid) {
if let Ok(vk) = PublicVerificationKey::from_verification_material(
kid.to_string(),
&vm.verification_material,
) {
let verification_key =
Arc::new(vk) as Arc<dyn VerificationKey + Send + Sync>;

if let Ok(mut verification_keys) = self.verification_keys.write() {
verification_keys.insert(kid.to_string(), verification_key.clone());
}

return Ok(verification_key);
}
}
}
}

Err(Error::Cryptography(format!(
"No verification key found with ID: {}",
kid
Expand Down Expand Up @@ -679,9 +711,8 @@ impl KeyManager for DefaultKeyManager {
.ok_or_else(|| Error::Cryptography("No kid found in JWS signature".to_string()))?;
let verification_key = KeyManager::resolve_verification_key(self, &kid).await?;

// Decode the signature
let signature_bytes = base64::engine::general_purpose::STANDARD
.decode(&signature.signature)
// Decode the signature (accept both base64 and base64url)
let signature_bytes = crate::message::base64_decode_flexible(&signature.signature)
.map_err(|e| Error::Cryptography(format!("Failed to decode signature: {}", e)))?;

// Create the signing input (protected.payload)
Expand All @@ -699,9 +730,8 @@ impl KeyManager for DefaultKeyManager {
));
}

// Decode the payload
let payload_bytes = base64::engine::general_purpose::STANDARD
.decode(&jws.payload)
// Decode the payload (accept both base64 and base64url)
let payload_bytes = crate::message::base64_decode_flexible(&jws.payload)
.map_err(|e| Error::Cryptography(format!("Failed to decode payload: {}", e)))?;

Ok(payload_bytes)
Expand Down
Loading