From 40f1f286efd9da216d3ac9277878d44d1a3154be Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Mon, 24 Jun 2024 14:40:45 +1000 Subject: [PATCH] negative test Signed-off-by: George Mulhearn --- .../did_exchange/state_machine/helpers.rs | 1 - .../transition/transition_result.rs | 1 + aries/aries_vcx/tests/test_did_exchange.rs | 231 ++++++++++++++---- 3 files changed, 185 insertions(+), 48 deletions(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 3ffb44c8cc..4690f76102 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -236,7 +236,6 @@ pub(crate) async fn jws_sign_attach( /// Verifies that the given has a JWS signature attached, which is a valid signature given /// the expected signer key. -/// // NOTE: Does not handle attachments with multiple signatures. // NOTE: this is the specific use case where the signer is known by the function caller. Therefore // we do not need to attempt to decode key within the protected nor unprotected header. diff --git a/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs b/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs index 15b1153054..6e4b79a165 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs @@ -1,5 +1,6 @@ // TODO: Somehow enforce using both #[must_use] +#[derive(Debug)] pub struct TransitionResult { pub state: T, pub output: U, diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 2ad620c030..0b35f92daf 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -4,6 +4,7 @@ use std::{error::Error, sync::Arc, thread, time::Duration}; use aries_vcx::{ common::ledger::transactions::write_endpoint_from_service, + errors::error::AriesVcxErrorKind, protocols::did_exchange::{ resolve_enc_key_from_invitation, state_machine::{ @@ -19,7 +20,12 @@ use aries_vcx::{ encryption_envelope::EncryptionEnvelope, }, }; -use aries_vcx_ledger::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; +use aries_vcx_anoncreds::anoncreds::base_anoncreds::BaseAnonCreds; +use aries_vcx_ledger::ledger::{ + base_ledger::{AnoncredsLedgerRead, AnoncredsLedgerWrite, IndyLedgerRead, IndyLedgerWrite}, + indy_vdr_ledger::DefaultIndyLedgerRead, +}; +use aries_vcx_wallet::wallet::base_wallet::BaseWallet; use did_doc::schema::{ did_doc::DidDocument, service::typed::{didcommv1::ServiceDidCommV1, ServiceType}, @@ -36,6 +42,7 @@ use messages::msg_fields::protocols::out_of_band::invitation::{ use pretty_assertions::assert_eq; use test_utils::devsetup::{dev_build_profile_vdr_ledger, SetupPoolDirectory}; use url::Url; +use utils::test_agent::TestAgent; use crate::utils::test_agent::{ create_test_agent, create_test_agent_endorser_2, create_test_agent_trustee, @@ -50,56 +57,29 @@ fn assert_key_agreement(a: DidDocument, b: DidDocument) { assert_eq!(a_key, b_key); } -#[tokio::test] -#[ignore] -async fn did_exchange_test() -> Result<(), Box> { - let setup = SetupPoolDirectory::init().await; +async fn did_exchange_test( + inviter_did: String, + agent_inviter: TestAgent< + impl IndyLedgerRead + AnoncredsLedgerRead, + impl IndyLedgerWrite + AnoncredsLedgerWrite, + impl BaseAnonCreds, + impl BaseWallet, + >, + agent_invitee: TestAgent< + impl IndyLedgerRead + AnoncredsLedgerRead, + impl IndyLedgerWrite + AnoncredsLedgerWrite, + impl BaseAnonCreds, + impl BaseWallet, + >, + resolver_registry: Arc, +) -> Result<(), Box> { let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); - let agent_trustee = create_test_agent_trustee(setup.genesis_file_path.clone()).await; - // todo: patrik: update create_test_agent_endorser_2 to not consume trustee agent - let agent_inviter = - create_test_agent_endorser_2(&setup.genesis_file_path, agent_trustee).await?; - let create_service = ServiceDidCommV1::new( - Uri::new("#service-0").unwrap(), - dummy_url.clone(), - 0, - vec![], - vec![], - ); - write_endpoint_from_service( - &agent_inviter.wallet, - &agent_inviter.ledger_write, - &agent_inviter.institution_did, - &create_service.try_into()?, - ) - .await?; - thread::sleep(Duration::from_millis(100)); - - let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; - - let (ledger_read_2, _) = dev_build_profile_vdr_ledger(setup.genesis_file_path); - let ledger_read_2_arc = Arc::new(ledger_read_2); - - // if we were to use, more generally, the `dev_build_featured_indy_ledger`, we would need to - // here the type based on the feature flag (indy vs proxy vdr client) which is pain - // we need to improve DidSovResolver such that Rust compiler can fully infer the return type - let did_sov_resolver: DidSovResolver, DefaultIndyLedgerRead> = - DidSovResolver::new(ledger_read_2_arc); - - let resolver_registry = Arc::new( - ResolverRegistry::new() - .register_resolver::("peer".into(), PeerDidResolver::new()) - .register_resolver("sov".into(), did_sov_resolver), - ); let invitation = Invitation::builder() .id("test_invite_id".to_owned()) .content( InvitationContent::builder() - .services(vec![OobService::Did(format!( - "did:sov:{}", - agent_inviter.institution_did - ))]) + .services(vec![OobService::Did(inviter_did)]) .build(), ) .build(); @@ -138,7 +118,7 @@ async fn did_exchange_test() -> Result<(), Box> { ); let (responders_peer_did, _our_verkey) = - create_peer_did_4(&agent_invitee.wallet, dummy_url.clone(), vec![]).await?; + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; let responders_did_document = responders_peer_did.resolve_did_doc()?; info!("Responder prepares did document: {responders_did_document}"); @@ -211,9 +191,166 @@ async fn did_exchange_test() -> Result<(), Box> { let requesters_peer_did = requesters_peer_did.resolve_did_doc()?; let expected_sender_vk = resolve_ed25519_base58_key_agreement(&requesters_peer_did)?; let unpacked = - EncryptionEnvelope::auth_unpack(&agent_invitee.wallet, m.0, &expected_sender_vk).await?; + EncryptionEnvelope::auth_unpack(&agent_inviter.wallet, m.0, &expected_sender_vk).await?; info!("Unpacked message: {:?}", unpacked); Ok(()) } + +#[tokio::test] +#[ignore] +async fn did_exchange_test_sov_inviter() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + let agent_trustee = create_test_agent_trustee(setup.genesis_file_path.clone()).await; + // todo: patrik: update create_test_agent_endorser_2 to not consume trustee agent + let agent_inviter = + create_test_agent_endorser_2(&setup.genesis_file_path, agent_trustee).await?; + let create_service = ServiceDidCommV1::new( + Uri::new("#service-0").unwrap(), + dummy_url.clone(), + 0, + vec![], + vec![], + ); + write_endpoint_from_service( + &agent_inviter.wallet, + &agent_inviter.ledger_write, + &agent_inviter.institution_did, + &create_service.try_into()?, + ) + .await?; + thread::sleep(Duration::from_millis(100)); + + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let (ledger_read_2, _) = dev_build_profile_vdr_ledger(setup.genesis_file_path); + let ledger_read_2_arc = Arc::new(ledger_read_2); + + // if we were to use, more generally, the `dev_build_featured_indy_ledger`, we would need to + // here the type based on the feature flag (indy vs proxy vdr client) which is pain + // we need to improve DidSovResolver such that Rust compiler can fully infer the return type + let did_sov_resolver: DidSovResolver, DefaultIndyLedgerRead> = + DidSovResolver::new(ledger_read_2_arc); + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()) + .register_resolver("sov".into(), did_sov_resolver), + ); + + did_exchange_test( + format!("did:sov:{}", agent_inviter.institution_did), + agent_inviter, + agent_invitee, + resolver_registry, + ) + .await +} + +#[tokio::test] +#[ignore] +async fn did_exchange_test_peer_to_peer() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let agent_inviter = create_test_agent(setup.genesis_file_path.clone()).await; + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()), + ); + + let (inviter_peer_did, _) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + did_exchange_test( + inviter_peer_did.to_string(), + agent_inviter, + agent_invitee, + resolver_registry, + ) + .await +} + +#[tokio::test] +#[ignore] +async fn did_exchange_test_with_invalid_rotation_signature() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let agent_inviter = create_test_agent(setup.genesis_file_path.clone()).await; + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()), + ); + + let (inviter_peer_did, _) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let invitation = Invitation::builder() + .id("test_invite_id".to_owned()) + .content( + InvitationContent::builder() + .services(vec![OobService::Did(inviter_peer_did.to_string())]) + .build(), + ) + .build(); + let real_invitation_key = + resolve_enc_key_from_invitation(&invitation, &resolver_registry).await?; + + let (requesters_peer_did, _our_verkey) = + create_peer_did_4(&agent_invitee.wallet, dummy_url.clone(), vec![]).await?; + let did_inviter: Did = invitation_get_first_did_service(&invitation)?; + + let TransitionResult { + state: requester, + output: request, + } = DidExchangeRequester::::construct_request( + resolver_registry.clone(), + Some(invitation.id), + &did_inviter, + &requesters_peer_did, + "some-label".to_owned(), + ) + .await?; + + let (responders_peer_did, incorrect_invitation_key) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + // create a response with a DID Rotate signed by the wrong key (not the original invitation key) + let TransitionResult { + output: response, + state: _, + } = DidExchangeResponder::::receive_request( + &agent_inviter.wallet, + resolver_registry.clone(), + request, + &responders_peer_did, + // sign with NOT the invitation key + Some(incorrect_invitation_key), + ) + .await?; + + // receiving the response should fail when verifying the signature + let res = requester + .receive_response( + &agent_invitee.wallet, + &real_invitation_key, + response, + &resolver_registry, + ) + .await; + assert_eq!( + res.unwrap_err().error.kind(), + AriesVcxErrorKind::InvalidInput + ); + + Ok(()) +}