Skip to content

Commit

Permalink
Make encryption envelope api more general and safer
Browse files Browse the repository at this point in the history
Signed-off-by: Patrik Stas <[email protected]>
  • Loading branch information
Patrik-Stas committed Jan 4, 2024
1 parent 8c284ca commit d0fdfcd
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 38 deletions.
51 changes: 33 additions & 18 deletions aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use aries_vcx::{
did_doc::schema::{service::typed::ServiceType, types::uri::Uri},
messages::{
msg_fields::protocols::{
did_exchange::{
Expand All @@ -25,7 +26,6 @@ use aries_vcx_core::wallet::{base_wallet::BaseWallet, indy::IndySdkWallet};
use did_peer::peer_did::{numalgos::numalgo2::Numalgo2, PeerDid};
use did_resolver_registry::ResolverRegistry;
use did_resolver_sov::did_resolver::did_doc::schema::did_doc::DidDocument;
use url::Url;

use super::connection::ServiceEndpoint;
use crate::{
Expand Down Expand Up @@ -83,10 +83,17 @@ impl ServiceDidExchange {
.thid;
let ddo_their = requester.their_did_doc();
let ddo_our = requester.our_did_document();
let encryption_envelope =
pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &request.into()).await?;
let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?;
let encryption_envelope = pairwise_encrypt(
ddo_our,
ddo_their,
self.wallet.as_ref(),
&request.into(),
service.id(),
)
.await?;
VcxHttpClient
.send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?)
.send_message(encryption_envelope.0, service.service_endpoint().clone())
.await?;
self.did_exchange.insert(&request_id, requester.clone())
}
Expand Down Expand Up @@ -127,10 +134,17 @@ impl ServiceDidExchange {
.await?;
let ddo_their = responder.their_did_doc();
let ddo_our = responder.our_did_document();
let encryption_envelope =
pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &response.into()).await?;
let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?;
let encryption_envelope = pairwise_encrypt(
ddo_our,
ddo_their,
self.wallet.as_ref(),
&response.into(),
service.id(),
)
.await?;
VcxHttpClient
.send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?)
.send_message(encryption_envelope.0, service.service_endpoint().clone())
.await?;
self.did_exchange.insert(&request_id, responder.clone())
}
Expand All @@ -144,10 +158,17 @@ impl ServiceDidExchange {
.await?;
let ddo_their = requester.their_did_doc();
let ddo_our = requester.our_did_document();
let encryption_envelope =
pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &complete.into()).await?;
let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?;
let encryption_envelope = pairwise_encrypt(
ddo_our,
ddo_their,
self.wallet.as_ref(),
&complete.into(),
service.id(),
)
.await?;
VcxHttpClient
.send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?)
.send_message(encryption_envelope.0, service.service_endpoint().clone())
.await?;
self.did_exchange.insert(&thread_id, requester.clone())
}
Expand Down Expand Up @@ -187,25 +208,19 @@ impl ServiceDidExchange {
}
}

pub fn get_first_endpoint(did_document: &DidDocument) -> AgentResult<Url> {
let service = did_document.service().first().ok_or(AgentError::from_msg(
AgentErrorKind::InvalidState,
"No service found",
))?;
Ok(service.service_endpoint().clone())
}

pub async fn pairwise_encrypt(
our_did_doc: &DidDocument,
their_did_doc: &DidDocument,
wallet: &impl BaseWallet,
message: &AriesMessage,
their_service_id: &Uri,
) -> AgentResult<EncryptionEnvelope> {
EncryptionEnvelope::create(
wallet,
serde_json::json!(message).to_string().as_bytes(),
our_did_doc,
their_did_doc,
their_service_id,
)
.await
.map_err(|err| {
Expand Down
19 changes: 5 additions & 14 deletions aries/aries_vcx/src/utils/didcomm_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use did_doc::schema::{
did_doc::DidDocument, service::service_key_kind::ServiceKeyKind,
did_doc::DidDocument, service::service_key_kind::ServiceKeyKind, types::uri::Uri,
verification_method::VerificationMethodType,
};
use public_key::Key;
Expand Down Expand Up @@ -41,27 +41,18 @@ pub fn resolve_base58_key_agreement(did_document: &DidDocument) -> VcxResult<Str
VerificationMethodType::X25519KeyAgreementKey2019,
VerificationMethodType::X25519KeyAgreementKey2020,
];
let key_base58 = did_document.find_key_agreement_of_type(&key_types)?;
let key_base58 = did_document.get_key_agreement_of_type(&key_types)?;
Ok(key_base58.public_key()?.base58())
}

pub fn get_routing_keys(our_did_doc: &DidDocument) -> VcxResult<Vec<String>> {
let service = our_did_doc
.service()
.first()
.ok_or_else(|| {
AriesVcxError::from_msg(
AriesVcxErrorKind::InvalidState,
"No Service object found on our did document",
)
})?
.clone();
pub fn get_routing_keys(their_did_doc: &DidDocument, service_id: &Uri) -> VcxResult<Vec<String>> {
let service = their_did_doc.get_service_by_id(service_id)?;
match service.extra_field_routing_keys() {
Ok(routing_keys) => {
let mut naked_routing_keys = Vec::new();
for key in routing_keys.iter() {
naked_routing_keys
.push(resolve_service_key_to_typed_key(key, our_did_doc)?.base58());
.push(resolve_service_key_to_typed_key(key, their_did_doc)?.base58());
}
Ok(naked_routing_keys)
}
Expand Down
17 changes: 15 additions & 2 deletions aries/aries_vcx/src/utils/encryption_envelope.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use agency_client::testing::mocking::AgencyMockDecrypted;
use aries_vcx_core::{global::settings::VERKEY, wallet::base_wallet::BaseWallet};
use did_doc::schema::did_doc::DidDocument;
use did_doc::schema::{did_doc::DidDocument, types::uri::Uri};
use diddoc_legacy::aries::diddoc::AriesDidDoc;
use messages::{
msg_fields::protocols::routing::{Forward, ForwardContent},
Expand Down Expand Up @@ -43,15 +43,28 @@ impl EncryptionEnvelope {
Self::create_from_keys(wallet, data, sender_vk, recipient_key, routing_keys).await
}

/// Create encrypted message based on key agreement keys of our did document, counterparties
/// did document and their specific service, identified by id, which must be part of their
/// did document
///
/// # Arguments
///
/// * `our_did_doc` - Our did_document, which the counterparty should already be in possession
/// of
/// * `their_did_doc` - The did document of the counterparty, the recipient of the encrypted
/// message
/// * `their_service_id` - Id of service where message will be sent. The counterparty did
/// document must contain Service object identified with such value.
pub async fn create(
wallet: &impl BaseWallet,
data: &[u8],
our_did_doc: &DidDocument,
their_did_doc: &DidDocument,
their_service_id: &Uri,
) -> VcxResult<EncryptionEnvelope> {
let sender_vk = resolve_base58_key_agreement(our_did_doc)?;
let recipient_key = resolve_base58_key_agreement(their_did_doc)?;
let routing_keys = get_routing_keys(their_did_doc)?;
let routing_keys = get_routing_keys(their_did_doc, their_service_id)?;

EncryptionEnvelope::create_from_keys(
wallet,
Expand Down
8 changes: 7 additions & 1 deletion aries/aries_vcx/tests/test_did_exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use aries_vcx::{
};
use aries_vcx_core::ledger::indy_vdr_ledger::DefaultIndyLedgerRead;
use did_doc::schema::{
did_doc::DidDocument, service::typed::didcommv1::ServiceDidCommV1, types::uri::Uri,
did_doc::DidDocument,
service::typed::{didcommv1::ServiceDidCommV1, ServiceType},
types::uri::Uri,
};
use did_parser::Did;
use did_peer::{
Expand Down Expand Up @@ -179,11 +181,15 @@ async fn did_exchange_test() -> Result<(), Box<dyn Error>> {
);

let data = "Hello world";
let service = requester
.their_did_doc()
.get_service_of_type(&ServiceType::DIDCommV1)?;
let m = EncryptionEnvelope::create(
&agent_invitee.wallet,
data.as_bytes(),
requester.our_did_doc(),
requester.their_did_doc(),
service.id(),
)
.await?;

Expand Down
1 change: 1 addition & 0 deletions aries/misc/shared/src/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ lazy_static! {
};
}

// todo: take Url by reference
pub async fn post_message(body_content: Vec<u8>, url: Url) -> HttpResult<Vec<u8>> {
debug!("post_message >> http client sending request POST {}", &url);

Expand Down
7 changes: 7 additions & 0 deletions did_core/did_doc/src/schema/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ impl Service {
&self.id
}

pub fn contains_service_type(&self, tested_service_type: &ServiceType) -> bool {
match &self.service_type {
OneOrList::One(service_type) => tested_service_type == service_type,
OneOrList::List(service_types) => service_types.contains(tested_service_type),
}
}

pub fn service_type(&self) -> &OneOrList<ServiceType> {
&self.service_type
}
Expand Down
35 changes: 32 additions & 3 deletions did_core/did_doc/src/schema/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::{
error::DidDocumentBuilderError,
schema::{
did_doc::DidDocument,
service::{typed::ServiceType, Service},
types::uri::Uri,
verification_method::{VerificationMethod, VerificationMethodKind, VerificationMethodType},
},
};
Expand Down Expand Up @@ -36,7 +38,7 @@ impl<T: Display + Debug> Display for OneOrList<T> {
}

impl DidDocument {
pub fn find_key_agreement_of_type(
pub fn get_key_agreement_of_type(
&self,
key_types: &[VerificationMethodType],
) -> Result<VerificationMethod, DidDocumentBuilderError> {
Expand Down Expand Up @@ -65,6 +67,33 @@ impl DidDocument {
"No supported key_agreement keys have been found".to_string(),
))
}

pub fn get_service_of_type(
&self,
service_type: &ServiceType,
) -> Result<Service, DidDocumentBuilderError> {
for service in self.service() {
if service.contains_service_type(service_type) {
return Ok(service.clone());
}
}
Err(DidDocumentBuilderError::CustomError(format!(
"No service of type {}",
service_type
)))
}

pub fn get_service_by_id(&self, id: &Uri) -> Result<Service, DidDocumentBuilderError> {
for service in self.service() {
if service.id() == id {
return Ok(service.clone());
}
}
Err(DidDocumentBuilderError::CustomError(format!(
"No service found by id {}",
id
)))
}
}

#[cfg(test)]
Expand Down Expand Up @@ -106,7 +135,7 @@ mod tests {
VerificationMethodType::Ed25519VerificationKey2020,
VerificationMethodType::X25519KeyAgreementKey2020,
];
let key = did_document.find_key_agreement_of_type(methods).unwrap();
let key = did_document.get_key_agreement_of_type(methods).unwrap();
assert_eq!(key.id().to_string(), "#bar")
}

Expand All @@ -115,7 +144,7 @@ mod tests {
let did_document: DidDocument = serde_json::from_str(DID_DOC).unwrap();
let methods = &vec![VerificationMethodType::Bls12381G1Key2020];
let err = did_document
.find_key_agreement_of_type(methods)
.get_key_agreement_of_type(methods)
.expect_err("expected error");
assert!(err
.to_string()
Expand Down

0 comments on commit d0fdfcd

Please sign in to comment.