From 7f9b2a8768eb67a047997ebf3ee050afe79e56e6 Mon Sep 17 00:00:00 2001 From: silverpill Date: Wed, 2 Nov 2022 12:16:10 +0000 Subject: [PATCH] Verify activities containing EIP-155 integrity proof --- src/activitypub/authentication.rs | 65 ++++++++++++++++++++++--------- src/json_signatures/verify.rs | 40 +++++++++++++++++-- 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/activitypub/authentication.rs b/src/activitypub/authentication.rs index 8908968..5d758d1 100644 --- a/src/activitypub/authentication.rs +++ b/src/activitypub/authentication.rs @@ -12,10 +12,14 @@ use crate::http_signatures::verify::{ use crate::json_signatures::verify::{ get_json_signature, verify_jcs_rsa_signature, + verify_jcs_eip191_signature, JsonSignatureVerificationError as JsonSignatureError, JsonSigner, }; -use crate::models::profiles::queries::get_profile_by_remote_actor_id; +use crate::models::profiles::queries::{ + get_profile_by_remote_actor_id, + search_profiles_by_did_only, +}; use crate::models::profiles::types::DbActorProfile; use crate::utils::crypto::deserialize_public_key; use super::fetcher::helpers::get_or_import_profile_by_actor_id; @@ -108,25 +112,50 @@ pub async fn verify_signed_activity( } })?; - let JsonSigner::ActorKeyId(ref key_id) = signature_data.signer; - let actor_id = key_id_to_actor_id(key_id)?; - let actor_profile = match get_or_import_profile_by_actor_id( - db_client, - &config.instance(), - &config.media_dir(), - &actor_id, - ).await { - Ok(profile) => profile, - Err(HandlerError::DatabaseError(error)) => return Err(error.into()), - Err(other_error) => { - return Err(AuthenticationError::ActorError(other_error.to_string())); + let actor_profile = match signature_data.signer { + JsonSigner::ActorKeyId(ref key_id) => { + let actor_id = key_id_to_actor_id(key_id)?; + let actor_profile = match get_or_import_profile_by_actor_id( + db_client, + &config.instance(), + &config.media_dir(), + &actor_id, + ).await { + Ok(profile) => profile, + Err(HandlerError::DatabaseError(error)) => { + return Err(error.into()); + }, + Err(other_error) => { + return Err(AuthenticationError::ActorError(other_error.to_string())); + }, + }; + let actor = actor_profile.actor_json.as_ref() + .ok_or(AuthenticationError::ActorError("invalid profile".to_string()))?; + let public_key = + deserialize_public_key(&actor.public_key.public_key_pem)?; + verify_jcs_rsa_signature(&signature_data, &public_key)?; + actor_profile + }, + JsonSigner::DidPkh(ref signer) => { + let mut profiles = search_profiles_by_did_only(db_client, signer).await?; + if profiles.len() > 1 { + log::info!( + "signer with multiple profiles ({})", + profiles.len(), + ); + }; + if let Some(profile) = profiles.pop() { + verify_jcs_eip191_signature( + signer, + &signature_data.message, + &signature_data.signature, + )?; + profile + } else { + return Err(AuthenticationError::ActorError("unknown signer".to_string())); + } }, }; - let actor = actor_profile.actor_json.as_ref() - .ok_or(AuthenticationError::ActorError("invalid profile".to_string()))?; - let public_key = deserialize_public_key(&actor.public_key.public_key_pem)?; - - verify_jcs_rsa_signature(&signature_data, &public_key)?; Ok(actor_profile) } diff --git a/src/json_signatures/verify.rs b/src/json_signatures/verify.rs index f50ec49..6f72a71 100644 --- a/src/json_signatures/verify.rs +++ b/src/json_signatures/verify.rs @@ -10,6 +10,7 @@ use crate::utils::crypto::verify_signature; use super::canonicalization::{canonicalize_object, CanonicalizationError}; use super::create::{ IntegrityProof, + PROOF_TYPE_JCS_EIP191, PROOF_TYPE_JCS_RSA, PROOF_KEY, PROOF_PURPOSE, @@ -18,6 +19,7 @@ use super::create::{ #[derive(Debug, PartialEq)] pub enum JsonSigner { ActorKeyId(String), + DidPkh(DidPkh), } pub struct SignatureData { @@ -62,10 +64,19 @@ pub fn get_json_signature( if proof.proof_purpose != PROOF_PURPOSE { return Err(VerificationError::InvalidProof("invalid proof purpose")); }; - if proof.proof_type != PROOF_TYPE_JCS_RSA { - return Err(VerificationError::InvalidProof("unsupported proof type")); + let signer = match proof.proof_type.as_str() { + PROOF_TYPE_JCS_EIP191 => { + let did = proof.verification_method.parse() + .map_err(|_| VerificationError::InvalidProof("invalid DID"))?; + JsonSigner::DidPkh(did) + }, + PROOF_TYPE_JCS_RSA => { + JsonSigner::ActorKeyId(proof.verification_method) + }, + _ => { + return Err(VerificationError::InvalidProof("unsupported proof type")); + }, }; - let signer = JsonSigner::ActorKeyId(proof.verification_method); let message = canonicalize_object(&object)?; let signature_data = SignatureData { signer: signer, @@ -110,8 +121,31 @@ mod tests { use serde_json::json; use crate::json_signatures::create::sign_object; use crate::utils::crypto::generate_weak_private_key; + use crate::utils::currencies::Currency; use super::*; + #[test] + fn test_get_json_signature_eip155() { + let signed_object = json!({ + "type": "Test", + "id": "https://example.org/objects/1", + "proof": { + "type": "JcsEip191Signature2022", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a", + "created": "2020-11-05T19:23:24Z", + "proofValue": "xxx", + }, + }); + let signature_data = get_json_signature(&signed_object).unwrap(); + let expected_signer = JsonSigner::DidPkh(DidPkh::from_address( + &Currency::Ethereum, + "0xb9c5714089478a327f09197987f16f9e5d936e8a", + )); + assert_eq!(signature_data.signer, expected_signer); + assert_eq!(signature_data.signature, "xxx"); + } + #[test] fn test_create_and_verify_signature() { let signer_key = generate_weak_private_key().unwrap();